Merge pull request #1102 from ethereum/tests-with-sigs

Tests with signatures, fixes #1074
This commit is contained in:
Danny Ryan 2019-05-22 16:41:37 -04:00 committed by GitHub
commit 43bb64ea1e
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
42 changed files with 1106 additions and 709 deletions

View File

@ -13,7 +13,7 @@ from typing import (
Tuple,
)
from eth2spec.utils.minimal_ssz import *
from eth2spec.utils.bls_stub import *
from eth2spec.utils.bls import *
""")
for i in (1, 2, 3, 4, 8, 32, 48, 96):

View File

@ -1756,7 +1756,8 @@ def process_deposit(state: BeaconState, deposit: Deposit) -> None:
amount = deposit.data.amount
validator_pubkeys = [v.pubkey for v in state.validator_registry]
if pubkey not in validator_pubkeys:
# Verify the deposit signature (proof of possession)
# Verify the deposit signature (proof of possession).
# Invalid signatures are allowed by the deposit contract, and hence included on-chain, but must not be processed.
if not bls_verify(pubkey, signing_root(deposit.data), deposit.data.signature, get_domain(state, DOMAIN_DEPOSIT)):
return

View File

@ -58,7 +58,7 @@ It's recommended to extend the base-generator.
Create a `requirements.txt` in the root of your generator directory:
```
eth-utils==1.4.1
eth-utils==1.6.0
../../test_libs/gen_helpers
../../test_libs/config_helpers
../../test_libs/pyspec

View File

@ -1,3 +1,3 @@
py-ecc==1.6.0
eth-utils==1.4.1
eth-utils==1.6.0
../../test_libs/gen_helpers

View File

@ -1,4 +1,4 @@
eth-utils==1.4.1
eth-utils==1.6.0
../../test_libs/gen_helpers
../../test_libs/config_helpers
../../test_libs/pyspec

View File

@ -15,7 +15,7 @@ def generate_from_tests(pkg):
for name in fn_names:
tfn = getattr(pkg, name)
try:
out.append(tfn(generator_mode=True))
out.append(tfn(generator_mode=True, bls_active=True))
except AssertionError:
print("ERROR: failed to generate vector from test: %s (pkg: %s)" % (name, pkg.__name__))
return out
@ -34,6 +34,6 @@ def create_suite(operation_name: str, config_name: str, get_cases: Callable[[],
forks=["phase0"],
config=config_name,
runner="operations",
handler=config_name,
handler=operation_name,
test_cases=get_cases()))
return suite_definition

View File

@ -1,4 +1,4 @@
eth-utils==1.4.1
eth-utils==1.6.0
../../test_libs/gen_helpers
../../test_libs/config_helpers
../../test_libs/pyspec

View File

@ -1,4 +1,4 @@
eth-utils==1.4.1
eth-utils==1.6.0
../../test_libs/gen_helpers
../../test_libs/config_helpers
ssz==0.1.0a2

View File

@ -1,4 +1,4 @@
eth-utils==1.4.1
eth-utils==1.6.0
../../test_libs/gen_helpers
../../test_libs/config_helpers
../../test_libs/pyspec

View File

@ -1 +1 @@
ruamel.yaml==0.15.87
ruamel.yaml==0.15.96

View File

@ -4,6 +4,6 @@ setup(
name='config_helpers',
packages=['preset_loader'],
install_requires=[
"ruamel.yaml==0.15.87"
"ruamel.yaml==0.15.96"
]
)

View File

@ -1,2 +1,2 @@
ruamel.yaml==0.15.87
eth-utils==1.4.1
ruamel.yaml==0.15.96
eth-utils==1.6.0

View File

@ -4,7 +4,7 @@ setup(
name='gen_helpers',
packages=['gen_base'],
install_requires=[
"ruamel.yaml==0.15.87",
"eth-utils==1.4.1"
"ruamel.yaml==0.15.96",
"eth-utils==1.6.0"
]
)

View File

@ -1,22 +1,23 @@
from copy import deepcopy
import eth2spec.phase0.spec as spec
from eth2spec.phase0.state_transition import (
state_transition,
)
from eth2spec.phase0.spec import (
get_current_epoch,
process_attestation
)
from eth2spec.test.helpers import (
build_empty_block_for_next_slot,
from eth2spec.phase0.state_transition import (
state_transition_to,
)
from eth2spec.test.context import spec_state_test, expect_assertion_error, always_bls
from eth2spec.test.helpers.attestations import (
get_valid_attestation,
sign_attestation,
)
from eth2spec.test.helpers.state import (
next_epoch,
next_slot,
)
from eth2spec.test.context import spec_state_test, expect_assertion_error
from eth2spec.test.helpers.block import apply_empty_block
def run_attestation_processing(state, attestation, valid=True):
@ -56,7 +57,7 @@ def run_attestation_processing(state, attestation, valid=True):
@spec_state_test
def test_success(state):
attestation = get_valid_attestation(state)
attestation = get_valid_attestation(state, signed=True)
state.slot += spec.MIN_ATTESTATION_INCLUSION_DELAY
yield from run_attestation_processing(state, attestation)
@ -64,17 +65,25 @@ def test_success(state):
@spec_state_test
def test_success_previous_epoch(state):
attestation = get_valid_attestation(state)
block = build_empty_block_for_next_slot(state)
block.slot = state.slot + spec.SLOTS_PER_EPOCH
state_transition(state, block)
attestation = get_valid_attestation(state, signed=True)
next_epoch(state)
apply_empty_block(state)
yield from run_attestation_processing(state, attestation)
@always_bls
@spec_state_test
def test_invalid_attestation_signature(state):
attestation = get_valid_attestation(state, signed=False)
state.slot += spec.MIN_ATTESTATION_INCLUSION_DELAY
yield from run_attestation_processing(state, attestation, False)
@spec_state_test
def test_before_inclusion_delay(state):
attestation = get_valid_attestation(state)
attestation = get_valid_attestation(state, signed=True)
# do not increment slot to allow for inclusion delay
yield from run_attestation_processing(state, attestation, False)
@ -82,11 +91,10 @@ def test_before_inclusion_delay(state):
@spec_state_test
def test_after_epoch_slots(state):
attestation = get_valid_attestation(state)
block = build_empty_block_for_next_slot(state)
attestation = get_valid_attestation(state, signed=True)
# increment past latest inclusion slot
block.slot = state.slot + spec.SLOTS_PER_EPOCH + 1
state_transition(state, block)
state_transition_to(state, state.slot + spec.SLOTS_PER_EPOCH + 1)
apply_empty_block(state)
yield from run_attestation_processing(state, attestation, False)
@ -97,7 +105,7 @@ def test_old_source_epoch(state):
state.finalized_epoch = 2
state.previous_justified_epoch = 3
state.current_justified_epoch = 4
attestation = get_valid_attestation(state, slot=(spec.SLOTS_PER_EPOCH * 3) + 1)
attestation = get_valid_attestation(state, slot=(spec.SLOTS_PER_EPOCH * 3) + 1, signed=False)
# test logic sanity check: make sure the attestation is pointing to oldest known source epoch
assert attestation.data.source_epoch == state.previous_justified_epoch
@ -105,36 +113,44 @@ def test_old_source_epoch(state):
# Now go beyond that, it will be invalid
attestation.data.source_epoch -= 1
sign_attestation(state, attestation)
yield from run_attestation_processing(state, attestation, False)
@spec_state_test
def test_wrong_shard(state):
attestation = get_valid_attestation(state)
attestation = get_valid_attestation(state, signed=False)
state.slot += spec.MIN_ATTESTATION_INCLUSION_DELAY
attestation.data.shard += 1
sign_attestation(state, attestation)
yield from run_attestation_processing(state, attestation, False)
@spec_state_test
def test_new_source_epoch(state):
attestation = get_valid_attestation(state)
attestation = get_valid_attestation(state, signed=False)
state.slot += spec.MIN_ATTESTATION_INCLUSION_DELAY
attestation.data.source_epoch += 1
sign_attestation(state, attestation)
yield from run_attestation_processing(state, attestation, False)
@spec_state_test
def test_source_root_is_target_root(state):
attestation = get_valid_attestation(state)
attestation = get_valid_attestation(state, signed=False)
state.slot += spec.MIN_ATTESTATION_INCLUSION_DELAY
attestation.data.source_root = attestation.data.target_root
sign_attestation(state, attestation)
yield from run_attestation_processing(state, attestation, False)
@ -149,7 +165,7 @@ def test_invalid_current_source_root(state):
state.current_justified_epoch = 4
state.current_justified_root = b'\xff' * 32
attestation = get_valid_attestation(state, slot=(spec.SLOTS_PER_EPOCH * 3) + 1)
attestation = get_valid_attestation(state, slot=(spec.SLOTS_PER_EPOCH * 3) + 1, signed=False)
state.slot += spec.MIN_ATTESTATION_INCLUSION_DELAY
# Test logic sanity checks:
@ -159,56 +175,81 @@ def test_invalid_current_source_root(state):
# Make attestation source root invalid: should be previous justified, not current one
attestation.data.source_root = state.current_justified_root
sign_attestation(state, attestation)
yield from run_attestation_processing(state, attestation, False)
@spec_state_test
def test_bad_source_root(state):
attestation = get_valid_attestation(state)
attestation = get_valid_attestation(state, signed=False)
state.slot += spec.MIN_ATTESTATION_INCLUSION_DELAY
attestation.data.source_root = b'\x42' * 32
sign_attestation(state, attestation)
yield from run_attestation_processing(state, attestation, False)
@spec_state_test
def test_non_zero_crosslink_data_root(state):
attestation = get_valid_attestation(state)
attestation = get_valid_attestation(state, signed=False)
state.slot += spec.MIN_ATTESTATION_INCLUSION_DELAY
attestation.data.crosslink_data_root = b'\x42' * 32
sign_attestation(state, attestation)
yield from run_attestation_processing(state, attestation, False)
@spec_state_test
def test_bad_previous_crosslink(state):
next_epoch(state)
attestation = get_valid_attestation(state)
apply_empty_block(state)
attestation = get_valid_attestation(state, signed=True)
for _ in range(spec.MIN_ATTESTATION_INCLUSION_DELAY):
next_slot(state)
apply_empty_block(state)
state.current_crosslinks[attestation.data.shard].epoch += 10
yield from run_attestation_processing(state, attestation, False)
@spec_state_test
def test_inconsistent_bitfields(state):
attestation = get_valid_attestation(state, signed=False)
state.slot += spec.MIN_ATTESTATION_INCLUSION_DELAY
attestation.custody_bitfield = deepcopy(attestation.aggregation_bitfield) + b'\x00'
sign_attestation(state, attestation)
yield from run_attestation_processing(state, attestation, False)
@spec_state_test
def test_non_empty_custody_bitfield(state):
attestation = get_valid_attestation(state)
attestation = get_valid_attestation(state, signed=False)
state.slot += spec.MIN_ATTESTATION_INCLUSION_DELAY
attestation.custody_bitfield = deepcopy(attestation.aggregation_bitfield)
sign_attestation(state, attestation)
yield from run_attestation_processing(state, attestation, False)
@spec_state_test
def test_empty_aggregation_bitfield(state):
attestation = get_valid_attestation(state)
attestation = get_valid_attestation(state, signed=False)
state.slot += spec.MIN_ATTESTATION_INCLUSION_DELAY
attestation.aggregation_bitfield = b'\x00' * len(attestation.aggregation_bitfield)
sign_attestation(state, attestation)
yield from run_attestation_processing(state, attestation, False)

View File

@ -3,14 +3,15 @@ from eth2spec.phase0.spec import (
get_beacon_proposer_index,
process_attester_slashing,
)
from eth2spec.test.helpers import (
from eth2spec.test.context import spec_state_test, expect_assertion_error, always_bls
from eth2spec.test.helpers.attestations import sign_indexed_attestation
from eth2spec.test.helpers.attester_slashings import get_valid_attester_slashing
from eth2spec.test.helpers.block import apply_empty_block
from eth2spec.test.helpers.state import (
get_balance,
get_valid_attester_slashing,
next_epoch,
)
from eth2spec.test.context import spec_state_test, expect_assertion_error
def run_attester_slashing_processing(state, attester_slashing, valid=True):
"""
@ -45,24 +46,22 @@ def run_attester_slashing_processing(state, attester_slashing, valid=True):
assert slashed_validator.exit_epoch < spec.FAR_FUTURE_EPOCH
assert slashed_validator.withdrawable_epoch < spec.FAR_FUTURE_EPOCH
# lost whistleblower reward
assert (
get_balance(state, slashed_index) <
pre_slashed_balance
)
# gained whistleblower reward
assert (
get_balance(state, proposer_index) >
pre_proposer_balance
)
if slashed_index != proposer_index:
# lost whistleblower reward
assert get_balance(state, slashed_index) < pre_slashed_balance
# gained whistleblower reward
assert get_balance(state, proposer_index) > pre_proposer_balance
else:
# gained rewards for all slashings, which may include others. And only lost that of themselves.
# Netto at least 0, if more people where slashed, a balance increase.
assert get_balance(state, slashed_index) >= pre_slashed_balance
yield 'post', state
@spec_state_test
def test_success_double(state):
attester_slashing = get_valid_attester_slashing(state)
attester_slashing = get_valid_attester_slashing(state, signed_1=True, signed_2=True)
yield from run_attester_slashing_processing(state, attester_slashing)
@ -70,37 +69,64 @@ def test_success_double(state):
@spec_state_test
def test_success_surround(state):
next_epoch(state)
apply_empty_block(state)
state.current_justified_epoch += 1
attester_slashing = get_valid_attester_slashing(state)
attester_slashing = get_valid_attester_slashing(state, signed_1=False, signed_2=True)
# set attestion1 to surround attestation 2
attester_slashing.attestation_1.data.source_epoch = attester_slashing.attestation_2.data.source_epoch - 1
attester_slashing.attestation_1.data.target_epoch = attester_slashing.attestation_2.data.target_epoch + 1
sign_indexed_attestation(state, attester_slashing.attestation_1)
yield from run_attester_slashing_processing(state, attester_slashing)
@always_bls
@spec_state_test
def test_invalid_sig_1(state):
attester_slashing = get_valid_attester_slashing(state, signed_1=False, signed_2=True)
yield from run_attester_slashing_processing(state, attester_slashing, False)
@always_bls
@spec_state_test
def test_invalid_sig_2(state):
attester_slashing = get_valid_attester_slashing(state, signed_1=True, signed_2=False)
yield from run_attester_slashing_processing(state, attester_slashing, False)
@always_bls
@spec_state_test
def test_invalid_sig_1_and_2(state):
attester_slashing = get_valid_attester_slashing(state, signed_1=False, signed_2=False)
yield from run_attester_slashing_processing(state, attester_slashing, False)
@spec_state_test
def test_same_data(state):
attester_slashing = get_valid_attester_slashing(state)
attester_slashing = get_valid_attester_slashing(state, signed_1=False, signed_2=True)
attester_slashing.attestation_1.data = attester_slashing.attestation_2.data
sign_indexed_attestation(state, attester_slashing.attestation_1)
yield from run_attester_slashing_processing(state, attester_slashing, False)
@spec_state_test
def test_no_double_or_surround(state):
attester_slashing = get_valid_attester_slashing(state)
attester_slashing = get_valid_attester_slashing(state, signed_1=False, signed_2=True)
attester_slashing.attestation_1.data.target_epoch += 1
sign_indexed_attestation(state, attester_slashing.attestation_1)
yield from run_attester_slashing_processing(state, attester_slashing, False)
@spec_state_test
def test_participants_already_slashed(state):
attester_slashing = get_valid_attester_slashing(state)
attester_slashing = get_valid_attester_slashing(state, signed_1=True, signed_2=True)
# set all indices to slashed
attestation_1 = attester_slashing.attestation_1
@ -113,10 +139,11 @@ def test_participants_already_slashed(state):
@spec_state_test
def test_custody_bit_0_and_1(state):
attester_slashing = get_valid_attester_slashing(state)
attester_slashing = get_valid_attester_slashing(state, signed_1=False, signed_2=True)
attester_slashing.attestation_1.custody_bit_1_indices = (
attester_slashing.attestation_1.custody_bit_0_indices
)
sign_indexed_attestation(state, attester_slashing.attestation_1)
yield from run_attester_slashing_processing(state, attester_slashing, False)

View File

@ -6,12 +6,12 @@ from eth2spec.phase0.spec import (
advance_slot,
process_block_header,
)
from eth2spec.test.helpers import (
from eth2spec.test.context import spec_state_test, expect_assertion_error, always_bls
from eth2spec.test.helpers.block import (
build_empty_block_for_next_slot,
next_slot,
sign_block
)
from eth2spec.test.context import spec_state_test, expect_assertion_error
from eth2spec.test.helpers.state import next_slot
def prepare_state_for_header_processing(state):
@ -42,23 +42,32 @@ def run_block_header_processing(state, block, valid=True):
@spec_state_test
def test_success(state):
block = build_empty_block_for_next_slot(state)
def test_success_block_header(state):
block = build_empty_block_for_next_slot(state, signed=True)
yield from run_block_header_processing(state, block)
@always_bls
@spec_state_test
def test_invalid_slot(state):
block = build_empty_block_for_next_slot(state)
def test_invalid_sig_block_header(state):
block = build_empty_block_for_next_slot(state, signed=False)
yield from run_block_header_processing(state, block, valid=False)
@spec_state_test
def test_invalid_slot_block_header(state):
block = build_empty_block_for_next_slot(state, signed=False)
block.slot = state.slot + 2 # invalid slot
sign_block(state, block)
yield from run_block_header_processing(state, block, valid=False)
@spec_state_test
def test_invalid_previous_block_root(state):
block = build_empty_block_for_next_slot(state)
block = build_empty_block_for_next_slot(state, signed=False)
block.previous_block_root = b'\12' * 32 # invalid prev root
sign_block(state, block)
yield from run_block_header_processing(state, block, valid=False)
@ -73,6 +82,6 @@ def test_proposer_slashed(state):
# set proposer to slashed
state.validator_registry[proposer_index].slashed = True
block = build_empty_block_for_next_slot(state)
block = build_empty_block_for_next_slot(state, signed=True)
yield from run_block_header_processing(state, block, valid=False)

View File

@ -1,21 +1,12 @@
import eth2spec.phase0.spec as spec
from eth2spec.phase0.spec import (
ZERO_HASH,
process_deposit,
)
from eth2spec.test.helpers import (
get_balance,
build_deposit,
prepare_state_and_deposit,
privkeys,
pubkeys,
)
from eth2spec.test.context import spec_state_test, expect_assertion_error
from eth2spec.phase0.spec import process_deposit
from eth2spec.test.context import spec_state_test, expect_assertion_error, always_bls
from eth2spec.test.helpers.deposits import prepare_state_and_deposit, sign_deposit_data
from eth2spec.test.helpers.state import get_balance
from eth2spec.test.helpers.keys import privkeys
def run_deposit_processing(state, deposit, validator_index, valid=True):
def run_deposit_processing(state, deposit, validator_index, valid=True, effective=True):
"""
Run ``process_deposit``, yielding:
- pre-state ('pre')
@ -43,47 +34,76 @@ def run_deposit_processing(state, deposit, validator_index, valid=True):
yield 'post', state
if validator_index < pre_validator_count:
# top-up
if not effective:
assert len(state.validator_registry) == pre_validator_count
assert len(state.balances) == pre_validator_count
if validator_index < pre_validator_count:
assert get_balance(state, validator_index) == pre_balance
else:
# new validator
assert len(state.validator_registry) == pre_validator_count + 1
assert len(state.balances) == pre_validator_count + 1
if validator_index < pre_validator_count:
# top-up
assert len(state.validator_registry) == pre_validator_count
assert len(state.balances) == pre_validator_count
else:
# new validator
assert len(state.validator_registry) == pre_validator_count + 1
assert len(state.balances) == pre_validator_count + 1
assert get_balance(state, validator_index) == pre_balance + deposit.data.amount
assert state.deposit_index == state.latest_eth1_data.deposit_count
assert get_balance(state, validator_index) == pre_balance + deposit.data.amount
@spec_state_test
def test_success(state):
def test_new_deposit(state):
# fresh deposit = next validator index = validator appended to registry
validator_index = len(state.validator_registry)
amount = spec.MAX_EFFECTIVE_BALANCE
deposit = prepare_state_and_deposit(state, validator_index, amount)
deposit = prepare_state_and_deposit(state, validator_index, amount, signed=True)
yield from run_deposit_processing(state, deposit, validator_index)
@always_bls
@spec_state_test
def test_invalid_sig_new_deposit(state):
# fresh deposit = next validator index = validator appended to registry
validator_index = len(state.validator_registry)
amount = spec.MAX_EFFECTIVE_BALANCE
deposit = prepare_state_and_deposit(state, validator_index, amount, signed=False)
yield from run_deposit_processing(state, deposit, validator_index, valid=True, effective=False)
@spec_state_test
def test_success_top_up(state):
validator_index = 0
amount = spec.MAX_EFFECTIVE_BALANCE // 4
deposit = prepare_state_and_deposit(state, validator_index, amount)
deposit = prepare_state_and_deposit(state, validator_index, amount, signed=True)
yield from run_deposit_processing(state, deposit, validator_index)
@always_bls
@spec_state_test
def test_invalid_sig_top_up(state):
validator_index = 0
amount = spec.MAX_EFFECTIVE_BALANCE // 4
deposit = prepare_state_and_deposit(state, validator_index, amount, signed=False)
# invalid signatures, in top-ups, are allowed!
yield from run_deposit_processing(state, deposit, validator_index, valid=True, effective=True)
@spec_state_test
def test_wrong_index(state):
validator_index = len(state.validator_registry)
amount = spec.MAX_EFFECTIVE_BALANCE
deposit = prepare_state_and_deposit(state, validator_index, amount)
deposit = prepare_state_and_deposit(state, validator_index, amount, signed=False)
# mess up deposit_index
deposit.index = state.deposit_index + 1
sign_deposit_data(state, deposit.data, privkeys[validator_index])
yield from run_deposit_processing(state, deposit, validator_index, valid=False)
@ -94,9 +114,11 @@ def test_wrong_index(state):
def test_bad_merkle_proof(state):
validator_index = len(state.validator_registry)
amount = spec.MAX_EFFECTIVE_BALANCE
deposit = prepare_state_and_deposit(state, validator_index, amount)
deposit = prepare_state_and_deposit(state, validator_index, amount, signed=False)
# mess up merkle branch
deposit.proof[-1] = spec.ZERO_HASH
sign_deposit_data(state, deposit.data, privkeys[validator_index])
yield from run_deposit_processing(state, deposit, validator_index, valid=False)

View File

@ -3,12 +3,11 @@ from eth2spec.phase0.spec import (
get_current_epoch,
process_proposer_slashing,
)
from eth2spec.test.helpers import (
get_balance,
get_valid_proposer_slashing,
)
from eth2spec.test.context import spec_state_test, expect_assertion_error
from eth2spec.test.context import spec_state_test, expect_assertion_error, always_bls
from eth2spec.test.helpers.block_header import sign_block_header
from eth2spec.test.helpers.keys import privkeys
from eth2spec.test.helpers.proposer_slashings import get_valid_proposer_slashing
from eth2spec.test.helpers.state import get_balance
def run_proposer_slashing_processing(state, proposer_slashing, valid=True):
@ -48,14 +47,35 @@ def run_proposer_slashing_processing(state, proposer_slashing, valid=True):
@spec_state_test
def test_success(state):
proposer_slashing = get_valid_proposer_slashing(state)
proposer_slashing = get_valid_proposer_slashing(state, signed_1=True, signed_2=True)
yield from run_proposer_slashing_processing(state, proposer_slashing)
@always_bls
@spec_state_test
def test_invalid_sig_1(state):
proposer_slashing = get_valid_proposer_slashing(state, signed_1=False, signed_2=True)
yield from run_proposer_slashing_processing(state, proposer_slashing, False)
@always_bls
@spec_state_test
def test_invalid_sig_2(state):
proposer_slashing = get_valid_proposer_slashing(state, signed_1=True, signed_2=False)
yield from run_proposer_slashing_processing(state, proposer_slashing, False)
@always_bls
@spec_state_test
def test_invalid_sig_1_and_2(state):
proposer_slashing = get_valid_proposer_slashing(state, signed_1=False, signed_2=False)
yield from run_proposer_slashing_processing(state, proposer_slashing, False)
@spec_state_test
def test_invalid_proposer_index(state):
proposer_slashing = get_valid_proposer_slashing(state)
proposer_slashing = get_valid_proposer_slashing(state, signed_1=True, signed_2=True)
# Index just too high (by 1)
proposer_slashing.proposer_index = len(state.validator_registry)
@ -64,17 +84,18 @@ def test_invalid_proposer_index(state):
@spec_state_test
def test_epochs_are_different(state):
proposer_slashing = get_valid_proposer_slashing(state)
proposer_slashing = get_valid_proposer_slashing(state, signed_1=True, signed_2=False)
# set slots to be in different epochs
proposer_slashing.header_2.slot += spec.SLOTS_PER_EPOCH
sign_block_header(state, proposer_slashing.header_2, privkeys[proposer_slashing.proposer_index])
yield from run_proposer_slashing_processing(state, proposer_slashing, False)
@spec_state_test
def test_headers_are_same(state):
proposer_slashing = get_valid_proposer_slashing(state)
proposer_slashing = get_valid_proposer_slashing(state, signed_1=True, signed_2=False)
# set headers to be the same
proposer_slashing.header_2 = proposer_slashing.header_1
@ -84,7 +105,7 @@ def test_headers_are_same(state):
@spec_state_test
def test_proposer_is_not_activated(state):
proposer_slashing = get_valid_proposer_slashing(state)
proposer_slashing = get_valid_proposer_slashing(state, signed_1=True, signed_2=True)
# set proposer to be not active yet
state.validator_registry[proposer_slashing.proposer_index].activation_epoch = get_current_epoch(state) + 1
@ -94,7 +115,7 @@ def test_proposer_is_not_activated(state):
@spec_state_test
def test_proposer_is_slashed(state):
proposer_slashing = get_valid_proposer_slashing(state)
proposer_slashing = get_valid_proposer_slashing(state, signed_1=True, signed_2=True)
# set proposer to slashed
state.validator_registry[proposer_slashing.proposer_index].slashed = True
@ -104,8 +125,10 @@ def test_proposer_is_slashed(state):
@spec_state_test
def test_proposer_is_withdrawn(state):
proposer_slashing = get_valid_proposer_slashing(state)
proposer_slashing = get_valid_proposer_slashing(state, signed_1=True, signed_2=True)
# move 1 epoch into future, to allow for past withdrawable epoch
state.slot += spec.SLOTS_PER_EPOCH
# set proposer withdrawable_epoch in past
current_epoch = get_current_epoch(state)
proposer_index = proposer_slashing.proposer_index

View File

@ -1,17 +1,14 @@
import eth2spec.phase0.spec as spec
from eth2spec.phase0.spec import (
get_active_validator_indices,
get_beacon_proposer_index,
get_current_epoch,
process_transfer,
)
from eth2spec.test.helpers import (
get_valid_transfer,
next_epoch,
)
from eth2spec.test.context import spec_state_test, expect_assertion_error
from eth2spec.test.context import spec_state_test, expect_assertion_error, always_bls
from eth2spec.test.helpers.state import next_epoch
from eth2spec.test.helpers.block import apply_empty_block
from eth2spec.test.helpers.transfers import get_valid_transfer
def run_transfer_processing(state, transfer, valid=True):
@ -48,7 +45,7 @@ def run_transfer_processing(state, transfer, valid=True):
@spec_state_test
def test_success_non_activated(state):
transfer = get_valid_transfer(state)
transfer = get_valid_transfer(state, signed=True)
# un-activate so validator can transfer
state.validator_registry[transfer.sender].activation_eligibility_epoch = spec.FAR_FUTURE_EPOCH
@ -58,8 +55,9 @@ def test_success_non_activated(state):
@spec_state_test
def test_success_withdrawable(state):
next_epoch(state)
apply_empty_block(state)
transfer = get_valid_transfer(state)
transfer = get_valid_transfer(state, signed=True)
# withdrawable_epoch in past so can transfer
state.validator_registry[transfer.sender].withdrawable_epoch = get_current_epoch(state) - 1
@ -71,7 +69,7 @@ def test_success_withdrawable(state):
def test_success_active_above_max_effective(state):
sender_index = get_active_validator_indices(state, get_current_epoch(state))[-1]
state.balances[sender_index] = spec.MAX_EFFECTIVE_BALANCE + 1
transfer = get_valid_transfer(state, sender_index=sender_index, amount=1, fee=0)
transfer = get_valid_transfer(state, sender_index=sender_index, amount=1, fee=0, signed=True)
yield from run_transfer_processing(state, transfer)
@ -80,24 +78,34 @@ def test_success_active_above_max_effective(state):
def test_success_active_above_max_effective_fee(state):
sender_index = get_active_validator_indices(state, get_current_epoch(state))[-1]
state.balances[sender_index] = spec.MAX_EFFECTIVE_BALANCE + 1
transfer = get_valid_transfer(state, sender_index=sender_index, amount=0, fee=1)
transfer = get_valid_transfer(state, sender_index=sender_index, amount=0, fee=1, signed=True)
yield from run_transfer_processing(state, transfer)
@always_bls
@spec_state_test
def test_invalid_signature(state):
transfer = get_valid_transfer(state, signed=False)
# un-activate so validator can transfer
state.validator_registry[transfer.sender].activation_eligibility_epoch = spec.FAR_FUTURE_EPOCH
yield from run_transfer_processing(state, transfer, False)
@spec_state_test
def test_active_but_transfer_past_effective_balance(state):
sender_index = get_active_validator_indices(state, get_current_epoch(state))[-1]
amount = spec.MAX_EFFECTIVE_BALANCE // 32
state.balances[sender_index] = spec.MAX_EFFECTIVE_BALANCE
transfer = get_valid_transfer(state, sender_index=sender_index, amount=amount, fee=0)
transfer = get_valid_transfer(state, sender_index=sender_index, amount=amount, fee=0, signed=True)
yield from run_transfer_processing(state, transfer, False)
@spec_state_test
def test_incorrect_slot(state):
transfer = get_valid_transfer(state, slot=state.slot+1)
transfer = get_valid_transfer(state, slot=state.slot + 1, signed=True)
# un-activate so validator can transfer
state.validator_registry[transfer.sender].activation_epoch = spec.FAR_FUTURE_EPOCH
@ -108,7 +116,7 @@ def test_incorrect_slot(state):
def test_insufficient_balance_for_fee(state):
sender_index = get_active_validator_indices(state, get_current_epoch(state))[-1]
state.balances[sender_index] = spec.MAX_EFFECTIVE_BALANCE
transfer = get_valid_transfer(state, sender_index=sender_index, amount=0, fee=1)
transfer = get_valid_transfer(state, sender_index=sender_index, amount=0, fee=1, signed=True)
# un-activate so validator can transfer
state.validator_registry[transfer.sender].activation_epoch = spec.FAR_FUTURE_EPOCH
@ -120,7 +128,7 @@ def test_insufficient_balance_for_fee(state):
def test_insufficient_balance(state):
sender_index = get_active_validator_indices(state, get_current_epoch(state))[-1]
state.balances[sender_index] = spec.MAX_EFFECTIVE_BALANCE
transfer = get_valid_transfer(state, sender_index=sender_index, amount=1, fee=0)
transfer = get_valid_transfer(state, sender_index=sender_index, amount=1, fee=0, signed=True)
# un-activate so validator can transfer
state.validator_registry[transfer.sender].activation_epoch = spec.FAR_FUTURE_EPOCH
@ -132,7 +140,7 @@ def test_insufficient_balance(state):
def test_no_dust_sender(state):
sender_index = get_active_validator_indices(state, get_current_epoch(state))[-1]
balance = state.balances[sender_index]
transfer = get_valid_transfer(state, sender_index=sender_index, amount=balance - spec.MIN_DEPOSIT_AMOUNT + 1, fee=0)
transfer = get_valid_transfer(state, sender_index=sender_index, amount=balance - spec.MIN_DEPOSIT_AMOUNT + 1, fee=0, signed=True)
# un-activate so validator can transfer
state.validator_registry[transfer.sender].activation_epoch = spec.FAR_FUTURE_EPOCH
@ -144,7 +152,7 @@ def test_no_dust_sender(state):
def test_no_dust_recipient(state):
sender_index = get_active_validator_indices(state, get_current_epoch(state))[-1]
state.balances[sender_index] = spec.MAX_EFFECTIVE_BALANCE + 1
transfer = get_valid_transfer(state, sender_index=sender_index, amount=1, fee=0)
transfer = get_valid_transfer(state, sender_index=sender_index, amount=1, fee=0, signed=True)
state.balances[transfer.recipient] = 0
# un-activate so validator can transfer
@ -155,7 +163,7 @@ def test_no_dust_recipient(state):
@spec_state_test
def test_invalid_pubkey(state):
transfer = get_valid_transfer(state)
transfer = get_valid_transfer(state, signed=True)
state.validator_registry[transfer.sender].withdrawal_credentials = spec.ZERO_HASH
# un-activate so validator can transfer

View File

@ -1,17 +1,13 @@
import eth2spec.phase0.spec as spec
from eth2spec.phase0.spec import (
get_active_validator_indices,
get_churn_limit,
get_current_epoch,
process_voluntary_exit,
)
from eth2spec.test.helpers import (
build_voluntary_exit,
pubkey_to_privkey,
)
from eth2spec.test.context import spec_state_test, expect_assertion_error
from eth2spec.test.context import spec_state_test, expect_assertion_error, always_bls
from eth2spec.test.helpers.keys import pubkey_to_privkey
from eth2spec.test.helpers.voluntary_exits import build_voluntary_exit, sign_voluntary_exit
def run_voluntary_exit_processing(state, voluntary_exit, valid=True):
@ -51,16 +47,26 @@ def test_success(state):
validator_index = get_active_validator_indices(state, current_epoch)[0]
privkey = pubkey_to_privkey[state.validator_registry[validator_index].pubkey]
voluntary_exit = build_voluntary_exit(
state,
current_epoch,
validator_index,
privkey,
)
voluntary_exit = build_voluntary_exit(state, current_epoch, validator_index, privkey, signed=True)
yield from run_voluntary_exit_processing(state, voluntary_exit)
@always_bls
@spec_state_test
def test_invalid_signature(state):
# move state forward PERSISTENT_COMMITTEE_PERIOD epochs to allow for exit
state.slot += spec.PERSISTENT_COMMITTEE_PERIOD * spec.SLOTS_PER_EPOCH
current_epoch = get_current_epoch(state)
validator_index = get_active_validator_indices(state, current_epoch)[0]
privkey = pubkey_to_privkey[state.validator_registry[validator_index].pubkey]
voluntary_exit = build_voluntary_exit(state, current_epoch, validator_index, privkey, signed=False)
yield from run_voluntary_exit_processing(state, voluntary_exit, False)
@spec_state_test
def test_success_exit_queue(state):
# move state forward PERSISTENT_COMMITTEE_PERIOD epochs to allow for exit
@ -80,6 +86,7 @@ def test_success_exit_queue(state):
current_epoch,
index,
privkey,
signed=True,
))
# Now run all the exits
@ -96,6 +103,7 @@ def test_success_exit_queue(state):
current_epoch,
validator_index,
privkey,
signed=True,
)
# This is the interesting part of the test: on a pre-state with a full exit queue,
@ -122,8 +130,10 @@ def test_validator_exit_in_future(state):
current_epoch,
validator_index,
privkey,
signed=False,
)
voluntary_exit.epoch += 1
sign_voluntary_exit(state, voluntary_exit, privkey)
yield from run_voluntary_exit_processing(state, voluntary_exit, False)
@ -142,8 +152,10 @@ def test_validator_invalid_validator_index(state):
current_epoch,
validator_index,
privkey,
signed=False,
)
voluntary_exit.validator_index = len(state.validator_registry)
sign_voluntary_exit(state, voluntary_exit, privkey)
yield from run_voluntary_exit_processing(state, voluntary_exit, False)
@ -162,6 +174,7 @@ def test_validator_not_active(state):
current_epoch,
validator_index,
privkey,
signed=True,
)
yield from run_voluntary_exit_processing(state, voluntary_exit, False)
@ -184,6 +197,7 @@ def test_validator_already_exited(state):
current_epoch,
validator_index,
privkey,
signed=True,
)
yield from run_voluntary_exit_processing(state, voluntary_exit, False)
@ -200,6 +214,7 @@ def test_validator_not_active_long_enough(state):
current_epoch,
validator_index,
privkey,
signed=True,
)
assert (

View File

@ -1,16 +1,27 @@
from eth2spec.phase0 import spec
from eth2spec.utils import bls
from .helpers import create_genesis_state
from .helpers.genesis import create_genesis_state
from .utils import spectest, with_args
from .utils import spectest, with_args, with_tags
# Provides a genesis state as first argument to the function decorated with this
with_state = with_args(lambda: [create_genesis_state(spec.SLOTS_PER_EPOCH * 8, list())])
with_state = with_args(lambda: [create_genesis_state(spec.SLOTS_PER_EPOCH * 8)])
# BLS is turned off by default *for performance purposes during TESTING*.
# The runner of the test can indicate the preferred setting (test generators prefer BLS to be ON).
# - Some tests are marked as BLS-requiring, and ignore this setting.
# (tests that express differences caused by BLS, e.g. invalid signatures being rejected)
# - Some other tests are marked as BLS-ignoring, and ignore this setting.
# (tests that are heavily performance impacted / require unsigned state transitions)
# - Most tests respect the BLS setting.
DEFAULT_BLS_ACTIVE = False
# shorthand for decorating @with_state @spectest()
def spec_state_test(fn):
return with_state(spectest()(fn))
return with_state(bls_switch(spectest()(fn)))
def expect_assertion_error(fn):
@ -25,3 +36,47 @@ def expect_assertion_error(fn):
pass
if bad:
raise AssertionError('expected an assertion error, but got none.')
# Tags a test to be ignoring BLS for it to pass.
bls_ignored = with_tags({'bls_ignored': True})
def never_bls(fn):
"""
Decorator to apply on ``bls_switch`` decorator to force BLS de-activation. Useful to mark tests as BLS-ignorant.
"""
def entry(*args, **kw):
# override bls setting
kw['bls_active'] = False
return fn(*args, **kw)
return bls_ignored(entry)
# Tags a test to be requiring BLS for it to pass.
bls_required = with_tags({'bls_required': True})
def always_bls(fn):
"""
Decorator to apply on ``bls_switch`` decorator to force BLS activation. Useful to mark tests as BLS-dependent.
"""
def entry(*args, **kw):
# override bls setting
kw['bls_active'] = True
return fn(*args, **kw)
return bls_required(entry)
def bls_switch(fn):
"""
Decorator to make a function execute with BLS ON, or BLS off.
Based on an optional bool argument ``bls_active``, passed to the function at runtime.
"""
def entry(*args, **kw):
old_state = bls.bls_active
bls.bls_active = kw.pop('bls_active', DEFAULT_BLS_ACTIVE)
out = fn(*args, **kw)
bls.bls_active = old_state
return out
return entry

View File

@ -1,25 +1,27 @@
from copy import deepcopy
import eth2spec.phase0.spec as spec
from eth2spec.phase0.state_transition import (
state_transition,
)
from eth2spec.phase0.spec import (
cache_state,
get_crosslink_deltas,
process_crosslinks,
)
from eth2spec.test.helpers import (
from eth2spec.phase0.state_transition import (
state_transition,
)
from eth2spec.test.context import spec_state_test
from eth2spec.test.helpers.state import (
next_epoch,
next_slot
)
from eth2spec.test.helpers.block import apply_empty_block, sign_block
from eth2spec.test.helpers.attestations import (
add_attestation_to_state,
build_empty_block_for_next_slot,
fill_aggregate_attestation,
get_crosslink_committee,
get_valid_attestation,
next_epoch,
next_slot,
)
from eth2spec.test.context import spec_state_test
def run_process_crosslinks(state, valid=True):
@ -31,8 +33,9 @@ def run_process_crosslinks(state, valid=True):
"""
# transition state to slot before state transition
slot = state.slot + (spec.SLOTS_PER_EPOCH - state.slot % spec.SLOTS_PER_EPOCH) - 1
block = build_empty_block_for_next_slot(state)
block = build_empty_block_for_next_slot(state, signed=False)
block.slot = slot
sign_block(state, block)
state_transition(state, block)
# cache state before epoch transition
@ -55,7 +58,7 @@ def test_no_attestations(state):
def test_single_crosslink_update_from_current_epoch(state):
next_epoch(state)
attestation = get_valid_attestation(state)
attestation = get_valid_attestation(state, signed=True)
fill_aggregate_attestation(state, attestation)
add_attestation_to_state(state, attestation, state.slot + spec.MIN_ATTESTATION_INCLUSION_DELAY)
@ -75,7 +78,7 @@ def test_single_crosslink_update_from_current_epoch(state):
def test_single_crosslink_update_from_previous_epoch(state):
next_epoch(state)
attestation = get_valid_attestation(state)
attestation = get_valid_attestation(state, signed=True)
fill_aggregate_attestation(state, attestation)
add_attestation_to_state(state, attestation, state.slot + spec.SLOTS_PER_EPOCH)
@ -103,7 +106,7 @@ def test_double_late_crosslink(state):
next_epoch(state)
state.slot += 4
attestation_1 = get_valid_attestation(state)
attestation_1 = get_valid_attestation(state, signed=True)
fill_aggregate_attestation(state, attestation_1)
# add attestation_1 in the next epoch
@ -111,10 +114,12 @@ def test_double_late_crosslink(state):
add_attestation_to_state(state, attestation_1, state.slot + 1)
for slot in range(spec.SLOTS_PER_EPOCH):
attestation_2 = get_valid_attestation(state)
attestation_2 = get_valid_attestation(state, signed=True)
if attestation_2.data.shard == attestation_1.data.shard:
break
next_slot(state)
apply_empty_block(state)
fill_aggregate_attestation(state, attestation_2)
# add attestation_2 in the next epoch after attestation_1 has
@ -126,7 +131,7 @@ def test_double_late_crosslink(state):
assert len(state.current_epoch_attestations) == 0
crosslink_deltas = get_crosslink_deltas(state)
yield from run_process_crosslinks(state)
shard = attestation_2.data.shard

View File

@ -4,10 +4,7 @@ from eth2spec.phase0.spec import (
get_current_epoch,
is_active_validator,
)
from eth2spec.test.helpers import (
next_epoch,
)
from eth2spec.test.helpers.state import next_epoch
from eth2spec.test.context import spec_state_test

View File

@ -1,445 +0,0 @@
from copy import deepcopy
from py_ecc import bls
from eth2spec.phase0.state_transition import (
state_transition,
)
import eth2spec.phase0.spec as spec
from eth2spec.utils.minimal_ssz import signing_root
from eth2spec.phase0.spec import (
# constants
ZERO_HASH,
# SSZ
Attestation,
AttestationData,
AttestationDataAndCustodyBit,
AttesterSlashing,
BeaconBlock,
BeaconBlockHeader,
Deposit,
DepositData,
Eth1Data,
ProposerSlashing,
Transfer,
VoluntaryExit,
# functions
convert_to_indexed,
get_active_validator_indices,
get_attesting_indices,
get_block_root,
get_block_root_at_slot,
get_crosslink_committee,
get_current_epoch,
get_domain,
get_epoch_start_slot,
get_genesis_beacon_state,
get_previous_epoch,
get_shard_delta,
hash_tree_root,
slot_to_epoch,
verify_merkle_branch,
hash,
)
from eth2spec.utils.merkle_minimal import (
calc_merkle_tree_from_leaves,
get_merkle_proof,
get_merkle_root,
)
privkeys = [i + 1 for i in range(1024)]
pubkeys = [bls.privtopub(privkey) for privkey in privkeys]
pubkey_to_privkey = {pubkey: privkey for privkey, pubkey in zip(privkeys, pubkeys)}
def get_balance(state, index):
return state.balances[index]
def set_bitfield_bit(bitfield, i):
"""
Set the bit in ``bitfield`` at position ``i`` to ``1``.
"""
byte_index = i // 8
bit_index = i % 8
return (
bitfield[:byte_index] +
bytes([bitfield[byte_index] | (1 << bit_index)]) +
bitfield[byte_index+1:]
)
def create_mock_genesis_validator_deposits(num_validators, deposit_data_leaves=None):
if not deposit_data_leaves:
deposit_data_leaves = []
signature = b'\x33' * 96
deposit_data_list = []
for i in range(num_validators):
pubkey = pubkeys[i]
deposit_data = DepositData(
pubkey=pubkey,
# insecurely use pubkey as withdrawal key as well
withdrawal_credentials=spec.BLS_WITHDRAWAL_PREFIX_BYTE + hash(pubkey)[1:],
amount=spec.MAX_EFFECTIVE_BALANCE,
signature=signature,
)
item = deposit_data.hash_tree_root()
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=i))
assert verify_merkle_branch(item, proof, spec.DEPOSIT_CONTRACT_TREE_DEPTH, i, root)
deposit_data_list.append(deposit_data)
genesis_validator_deposits = []
for i in range(num_validators):
genesis_validator_deposits.append(Deposit(
proof=list(get_merkle_proof(tree, item_index=i)),
index=i,
data=deposit_data_list[i]
))
return genesis_validator_deposits, root
def create_genesis_state(num_validators, deposit_data_leaves=None):
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,
),
)
def build_empty_block_for_next_slot(state):
empty_block = BeaconBlock()
empty_block.slot = state.slot + 1
empty_block.body.eth1_data.deposit_count = state.deposit_index
previous_block_header = deepcopy(state.latest_block_header)
if previous_block_header.state_root == spec.ZERO_HASH:
previous_block_header.state_root = state.hash_tree_root()
empty_block.previous_block_root = signing_root(previous_block_header)
return empty_block
def build_deposit_data(state, pubkey, privkey, amount):
deposit_data = DepositData(
pubkey=pubkey,
# insecurely use pubkey as withdrawal key as well
withdrawal_credentials=spec.BLS_WITHDRAWAL_PREFIX_BYTE + hash(pubkey)[1:],
amount=amount,
)
signature = bls.sign(
message_hash=signing_root(deposit_data),
privkey=privkey,
domain=get_domain(
state,
spec.DOMAIN_DEPOSIT,
)
)
deposit_data.signature = signature
return deposit_data
def build_attestation_data(state, slot, shard):
assert state.slot >= slot
if slot == state.slot:
block_root = build_empty_block_for_next_slot(state).previous_block_root
else:
block_root = get_block_root_at_slot(state, slot)
current_epoch_start_slot = get_epoch_start_slot(get_current_epoch(state))
if slot < current_epoch_start_slot:
epoch_boundary_root = get_block_root(state, get_previous_epoch(state))
elif slot == current_epoch_start_slot:
epoch_boundary_root = block_root
else:
epoch_boundary_root = get_block_root(state, get_current_epoch(state))
if slot < current_epoch_start_slot:
justified_epoch = state.previous_justified_epoch
justified_block_root = state.previous_justified_root
else:
justified_epoch = state.current_justified_epoch
justified_block_root = state.current_justified_root
crosslinks = state.current_crosslinks if slot_to_epoch(slot) == get_current_epoch(state) else state.previous_crosslinks
return AttestationData(
shard=shard,
beacon_block_root=block_root,
source_epoch=justified_epoch,
source_root=justified_block_root,
target_epoch=slot_to_epoch(slot),
target_root=epoch_boundary_root,
crosslink_data_root=spec.ZERO_HASH,
previous_crosslink_root=hash_tree_root(crosslinks[shard]),
)
def build_voluntary_exit(state, epoch, validator_index, privkey):
voluntary_exit = VoluntaryExit(
epoch=epoch,
validator_index=validator_index,
)
voluntary_exit.signature = bls.sign(
message_hash=signing_root(voluntary_exit),
privkey=privkey,
domain=get_domain(
state=state,
domain_type=spec.DOMAIN_VOLUNTARY_EXIT,
message_epoch=epoch,
)
)
return voluntary_exit
def build_deposit(state,
deposit_data_leaves,
pubkey,
privkey,
amount):
deposit_data = build_deposit_data(state, pubkey, privkey, amount)
item = deposit_data.hash_tree_root()
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,
data=deposit_data,
)
return deposit, root, deposit_data_leaves
def get_valid_proposer_slashing(state):
current_epoch = get_current_epoch(state)
validator_index = get_active_validator_indices(state, current_epoch)[-1]
privkey = pubkey_to_privkey[state.validator_registry[validator_index].pubkey]
slot = state.slot
header_1 = BeaconBlockHeader(
slot=slot,
previous_block_root=ZERO_HASH,
state_root=ZERO_HASH,
block_body_root=ZERO_HASH,
)
header_2 = deepcopy(header_1)
header_2.previous_block_root = b'\x02' * 32
header_2.slot = slot + 1
domain = get_domain(
state=state,
domain_type=spec.DOMAIN_BEACON_PROPOSER,
)
header_1.signature = bls.sign(
message_hash=signing_root(header_1),
privkey=privkey,
domain=domain,
)
header_2.signature = bls.sign(
message_hash=signing_root(header_2),
privkey=privkey,
domain=domain,
)
return ProposerSlashing(
proposer_index=validator_index,
header_1=header_1,
header_2=header_2,
)
def get_valid_attester_slashing(state):
attestation_1 = get_valid_attestation(state)
attestation_2 = deepcopy(attestation_1)
attestation_2.data.target_root = b'\x01' * 32
return AttesterSlashing(
attestation_1=convert_to_indexed(state, attestation_1),
attestation_2=convert_to_indexed(state, attestation_2),
)
def get_valid_attestation(state, slot=None):
if slot is None:
slot = state.slot
if slot_to_epoch(slot) == get_current_epoch(state):
shard = (state.latest_start_shard + slot) % spec.SLOTS_PER_EPOCH
else:
previous_shard_delta = get_shard_delta(state, get_previous_epoch(state))
shard = (state.latest_start_shard - previous_shard_delta + slot) % spec.SHARD_COUNT
attestation_data = build_attestation_data(state, slot, shard)
crosslink_committee = get_crosslink_committee(state, attestation_data.target_epoch, attestation_data.shard)
committee_size = len(crosslink_committee)
bitfield_length = (committee_size + 7) // 8
aggregation_bitfield = b'\xC0' + b'\x00' * (bitfield_length - 1)
custody_bitfield = b'\x00' * bitfield_length
attestation = Attestation(
aggregation_bitfield=aggregation_bitfield,
data=attestation_data,
custody_bitfield=custody_bitfield,
)
participants = get_attesting_indices(
state,
attestation.data,
attestation.aggregation_bitfield,
)
assert len(participants) == 2
signatures = []
for validator_index in participants:
privkey = privkeys[validator_index]
signatures.append(
get_attestation_signature(
state,
attestation.data,
privkey
)
)
attestation.aggregation_signature = bls.aggregate_signatures(signatures)
return attestation
def get_valid_transfer(state, slot=None, sender_index=None, amount=None, fee=None):
if slot is None:
slot = state.slot
current_epoch = get_current_epoch(state)
if sender_index is None:
sender_index = get_active_validator_indices(state, current_epoch)[-1]
recipient_index = get_active_validator_indices(state, current_epoch)[0]
transfer_pubkey = pubkeys[-1]
transfer_privkey = privkeys[-1]
if fee is None:
fee = get_balance(state, sender_index) // 32
if amount is None:
amount = get_balance(state, sender_index) - fee
transfer = Transfer(
sender=sender_index,
recipient=recipient_index,
amount=amount,
fee=fee,
slot=slot,
pubkey=transfer_pubkey,
signature=ZERO_HASH,
)
transfer.signature = bls.sign(
message_hash=signing_root(transfer),
privkey=transfer_privkey,
domain=get_domain(
state=state,
domain_type=spec.DOMAIN_TRANSFER,
message_epoch=get_current_epoch(state),
)
)
# ensure withdrawal_credentials reproducable
state.validator_registry[transfer.sender].withdrawal_credentials = (
spec.BLS_WITHDRAWAL_PREFIX_BYTE + spec.hash(transfer.pubkey)[1:]
)
return transfer
def get_attestation_signature(state, attestation_data, privkey, custody_bit=0b0):
message_hash = AttestationDataAndCustodyBit(
data=attestation_data,
custody_bit=custody_bit,
).hash_tree_root()
return bls.sign(
message_hash=message_hash,
privkey=privkey,
domain=get_domain(
state=state,
domain_type=spec.DOMAIN_ATTESTATION,
message_epoch=attestation_data.target_epoch,
)
)
def fill_aggregate_attestation(state, attestation):
crosslink_committee = get_crosslink_committee(state, attestation.data.target_epoch, attestation.data.shard)
for i in range(len(crosslink_committee)):
attestation.aggregation_bitfield = set_bitfield_bit(attestation.aggregation_bitfield, i)
def add_attestation_to_state(state, attestation, slot):
block = build_empty_block_for_next_slot(state)
block.slot = slot
block.body.attestations.append(attestation)
state_transition(state, block)
def next_slot(state):
"""
Transition to the next slot via an empty block.
Return the empty block that triggered the transition.
"""
block = build_empty_block_for_next_slot(state)
state_transition(state, block)
return block
def next_epoch(state):
"""
Transition to the start slot of the next epoch via an empty block.
Return the empty block that triggered the transition.
"""
block = build_empty_block_for_next_slot(state)
block.slot += spec.SLOTS_PER_EPOCH - (state.slot % spec.SLOTS_PER_EPOCH)
state_transition(state, block)
return block
def get_state_root(state, slot) -> bytes:
"""
Return the state root at a recent ``slot``.
"""
assert slot < state.slot <= slot + spec.SLOTS_PER_HISTORICAL_ROOT
return state.latest_state_roots[slot % spec.SLOTS_PER_HISTORICAL_ROOT]
def prepare_state_and_deposit(state, validator_index, amount):
"""
Prepare the state for the deposit, and create a deposit for the given validator, depositing the given amount.
"""
pre_validator_count = len(state.validator_registry)
# fill previous deposits with zero-hash
deposit_data_leaves = [ZERO_HASH] * pre_validator_count
pubkey = pubkeys[validator_index]
privkey = privkeys[validator_index]
deposit, root, deposit_data_leaves = build_deposit(
state,
deposit_data_leaves,
pubkey,
privkey,
amount,
)
state.latest_eth1_data.deposit_root = root
state.latest_eth1_data.deposit_count = len(deposit_data_leaves)
return deposit

View File

@ -0,0 +1,146 @@
from typing import List
# Access constants from spec pkg reference.
import eth2spec.phase0.spec as spec
from eth2spec.phase0.spec import (
Attestation,
AttestationData,
AttestationDataAndCustodyBit,
get_epoch_start_slot, get_block_root, get_current_epoch, get_previous_epoch, slot_to_epoch,
get_crosslink_committee, get_domain, IndexedAttestation, get_attesting_indices, BeaconState, get_block_root_at_slot,
get_epoch_start_shard, get_epoch_committee_count)
from eth2spec.phase0.state_transition import (
state_transition, state_transition_to
)
from eth2spec.test.helpers.bitfields import set_bitfield_bit
from eth2spec.test.helpers.block import build_empty_block_for_next_slot, sign_block
from eth2spec.test.helpers.keys import privkeys
from eth2spec.utils.bls import bls_sign, bls_aggregate_signatures
from eth2spec.utils.minimal_ssz import hash_tree_root
def build_attestation_data(state, slot, shard):
assert state.slot >= slot
if slot == state.slot:
block_root = build_empty_block_for_next_slot(state).previous_block_root
else:
block_root = get_block_root_at_slot(state, slot)
current_epoch_start_slot = get_epoch_start_slot(get_current_epoch(state))
if slot < current_epoch_start_slot:
epoch_boundary_root = get_block_root(state, get_previous_epoch(state))
elif slot == current_epoch_start_slot:
epoch_boundary_root = block_root
else:
epoch_boundary_root = get_block_root(state, get_current_epoch(state))
if slot < current_epoch_start_slot:
justified_epoch = state.previous_justified_epoch
justified_block_root = state.previous_justified_root
else:
justified_epoch = state.current_justified_epoch
justified_block_root = state.current_justified_root
crosslinks = state.current_crosslinks if slot_to_epoch(slot) == get_current_epoch(
state) else state.previous_crosslinks
return AttestationData(
shard=shard,
beacon_block_root=block_root,
source_epoch=justified_epoch,
source_root=justified_block_root,
target_epoch=slot_to_epoch(slot),
target_root=epoch_boundary_root,
crosslink_data_root=spec.ZERO_HASH,
previous_crosslink_root=hash_tree_root(crosslinks[shard]),
)
def get_valid_attestation(state, slot=None, signed=False):
if slot is None:
slot = state.slot
epoch = slot_to_epoch(slot)
epoch_start_shard = get_epoch_start_shard(state, epoch)
committees_per_slot = get_epoch_committee_count(state, epoch) // spec.SLOTS_PER_EPOCH
shard = (epoch_start_shard + committees_per_slot * (slot % spec.SLOTS_PER_EPOCH)) % spec.SHARD_COUNT
attestation_data = build_attestation_data(state, slot, shard)
crosslink_committee = get_crosslink_committee(state, attestation_data.target_epoch, attestation_data.shard)
committee_size = len(crosslink_committee)
bitfield_length = (committee_size + 7) // 8
aggregation_bitfield = b'\x00' * bitfield_length
custody_bitfield = b'\x00' * bitfield_length
attestation = Attestation(
aggregation_bitfield=aggregation_bitfield,
data=attestation_data,
custody_bitfield=custody_bitfield,
)
fill_aggregate_attestation(state, attestation)
if signed:
sign_attestation(state, attestation)
return attestation
def sign_aggregate_attestation(state: BeaconState, data: AttestationData, participants: List[int]):
signatures = []
for validator_index in participants:
privkey = privkeys[validator_index]
signatures.append(
get_attestation_signature(
state,
data,
privkey
)
)
return bls_aggregate_signatures(signatures)
def sign_indexed_attestation(state, indexed_attestation: IndexedAttestation):
participants = indexed_attestation.custody_bit_0_indices + indexed_attestation.custody_bit_1_indices
indexed_attestation.signature = sign_aggregate_attestation(state, indexed_attestation.data, participants)
def sign_attestation(state, attestation: Attestation):
participants = get_attesting_indices(
state,
attestation.data,
attestation.aggregation_bitfield,
)
attestation.signature = sign_aggregate_attestation(state, attestation.data, participants)
def get_attestation_signature(state, attestation_data, privkey, custody_bit=0b0):
message_hash = AttestationDataAndCustodyBit(
data=attestation_data,
custody_bit=custody_bit,
).hash_tree_root()
return bls_sign(
message_hash=message_hash,
privkey=privkey,
domain=get_domain(
state=state,
domain_type=spec.DOMAIN_ATTESTATION,
message_epoch=attestation_data.target_epoch,
)
)
def fill_aggregate_attestation(state, attestation):
crosslink_committee = get_crosslink_committee(state, attestation.data.target_epoch, attestation.data.shard)
for i in range(len(crosslink_committee)):
attestation.aggregation_bitfield = set_bitfield_bit(attestation.aggregation_bitfield, i)
def add_attestation_to_state(state, attestation, slot):
block = build_empty_block_for_next_slot(state, signed=False)
block.slot = slot
block.body.attestations.append(attestation)
state_transition_to(state, block.slot)
sign_block(state, block)
state_transition(state, block)

View File

@ -0,0 +1,19 @@
from copy import deepcopy
from eth2spec.phase0.spec import AttesterSlashing, convert_to_indexed
from eth2spec.test.helpers.attestations import get_valid_attestation, sign_attestation
def get_valid_attester_slashing(state, signed_1=False, signed_2=False):
attestation_1 = get_valid_attestation(state, signed=signed_1)
attestation_2 = deepcopy(attestation_1)
attestation_2.data.target_root = b'\x01' * 32
if signed_2:
sign_attestation(state, attestation_2)
return AttesterSlashing(
attestation_1=convert_to_indexed(state, attestation_1),
attestation_2=convert_to_indexed(state, attestation_2),
)

View File

@ -0,0 +1,11 @@
def set_bitfield_bit(bitfield, i):
"""
Set the bit in ``bitfield`` at position ``i`` to ``1``.
"""
byte_index = i // 8
bit_index = i % 8
return (
bitfield[:byte_index] +
bytes([bitfield[byte_index] | (1 << bit_index)]) +
bitfield[byte_index + 1:]
)

View File

@ -0,0 +1,77 @@
from copy import deepcopy
from eth2spec.phase0 import spec
from eth2spec.phase0.spec import get_beacon_proposer_index, slot_to_epoch, get_domain, BeaconBlock
from eth2spec.phase0.state_transition import state_transition, state_transition_to
from eth2spec.test.helpers.keys import privkeys
from eth2spec.utils.bls import bls_sign, only_with_bls
from eth2spec.utils.minimal_ssz import signing_root, hash_tree_root
# Fully ignore the function if BLS is off, beacon-proposer index calculation is slow.
@only_with_bls()
def sign_block(state, block, proposer_index=None):
assert state.slot <= block.slot
if proposer_index is None:
if block.slot == state.slot:
proposer_index = get_beacon_proposer_index(state)
else:
if slot_to_epoch(state.slot) + 1 > slot_to_epoch(block.slot):
print("warning: block slot far away, and no proposer index manually given."
" Signing block is slow due to transition for proposer index calculation.")
# use stub state to get proposer index of future slot
stub_state = deepcopy(state)
state_transition_to(stub_state, block.slot)
proposer_index = get_beacon_proposer_index(stub_state)
privkey = privkeys[proposer_index]
block.body.randao_reveal = bls_sign(
privkey=privkey,
message_hash=hash_tree_root(slot_to_epoch(block.slot)),
domain=get_domain(
state,
message_epoch=slot_to_epoch(block.slot),
domain_type=spec.DOMAIN_RANDAO,
)
)
block.signature = bls_sign(
message_hash=signing_root(block),
privkey=privkey,
domain=get_domain(
state,
spec.DOMAIN_BEACON_PROPOSER,
slot_to_epoch(block.slot)))
def apply_empty_block(state):
"""
Transition via an empty block (on current slot, assuming no block has been applied yet).
:return: the empty block that triggered the transition.
"""
block = build_empty_block(state, signed=True)
state_transition(state, block)
return block
def build_empty_block(state, slot=None, signed=False):
if slot is None:
slot = state.slot
empty_block = BeaconBlock()
empty_block.slot = slot
empty_block.body.eth1_data.deposit_count = state.deposit_index
previous_block_header = deepcopy(state.latest_block_header)
if previous_block_header.state_root == spec.ZERO_HASH:
previous_block_header.state_root = state.hash_tree_root()
empty_block.previous_block_root = signing_root(previous_block_header)
if signed:
sign_block(state, empty_block)
return empty_block
def build_empty_block_for_next_slot(state, signed=False):
return build_empty_block(state, state.slot + 1, signed=signed)

View File

@ -0,0 +1,18 @@
# Access constants from spec pkg reference.
import eth2spec.phase0.spec as spec
from eth2spec.phase0.spec import get_domain
from eth2spec.utils.bls import bls_sign
from eth2spec.utils.minimal_ssz import signing_root
def sign_block_header(state, header, privkey):
domain = get_domain(
state=state,
domain_type=spec.DOMAIN_BEACON_PROPOSER,
)
header.signature = bls_sign(
message_hash=signing_root(header),
privkey=privkey,
domain=domain,
)

View File

@ -0,0 +1,81 @@
# Access constants from spec pkg reference.
import eth2spec.phase0.spec as spec
from eth2spec.phase0.spec import get_domain, DepositData, verify_merkle_branch, Deposit, ZERO_HASH
from eth2spec.test.helpers.keys import pubkeys, privkeys
from eth2spec.utils.bls import bls_sign
from eth2spec.utils.merkle_minimal import calc_merkle_tree_from_leaves, get_merkle_root, get_merkle_proof
from eth2spec.utils.minimal_ssz import signing_root
def build_deposit_data(state, pubkey, privkey, amount, signed=False):
deposit_data = DepositData(
pubkey=pubkey,
# insecurely use pubkey as withdrawal key as well
withdrawal_credentials=spec.BLS_WITHDRAWAL_PREFIX_BYTE + spec.hash(pubkey)[1:],
amount=amount,
)
if signed:
sign_deposit_data(state, deposit_data, privkey)
return deposit_data
def sign_deposit_data(state, deposit_data, privkey):
signature = bls_sign(
message_hash=signing_root(deposit_data),
privkey=privkey,
domain=get_domain(
state,
spec.DOMAIN_DEPOSIT,
)
)
deposit_data.signature = signature
def build_deposit(state,
deposit_data_leaves,
pubkey,
privkey,
amount,
signed):
deposit_data = build_deposit_data(state, pubkey, privkey, amount, signed)
item = deposit_data.hash_tree_root()
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,
data=deposit_data,
)
return deposit, root, deposit_data_leaves
def prepare_state_and_deposit(state, validator_index, amount, signed=False):
"""
Prepare the state for the deposit, and create a deposit for the given validator, depositing the given amount.
"""
pre_validator_count = len(state.validator_registry)
# fill previous deposits with zero-hash
deposit_data_leaves = [ZERO_HASH] * pre_validator_count
pubkey = pubkeys[validator_index]
privkey = privkeys[validator_index]
deposit, root, deposit_data_leaves = build_deposit(
state,
deposit_data_leaves,
pubkey,
privkey,
amount,
signed
)
state.latest_eth1_data.deposit_root = root
state.latest_eth1_data.deposit_count = len(deposit_data_leaves)
return deposit

View File

@ -0,0 +1,51 @@
# Access constants from spec pkg reference.
import eth2spec.phase0.spec as spec
from eth2spec.phase0.spec import Eth1Data, ZERO_HASH, get_active_validator_indices
from eth2spec.test.helpers.keys import pubkeys
from eth2spec.utils.minimal_ssz import hash_tree_root
def build_mock_validator(i: int, balance: int):
pubkey = pubkeys[i]
# insecurely use pubkey as withdrawal key as well
withdrawal_credentials = spec.BLS_WITHDRAWAL_PREFIX_BYTE + spec.hash(pubkey)[1:]
return spec.Validator(
pubkey=pubkeys[i],
withdrawal_credentials=withdrawal_credentials,
activation_eligibility_epoch=spec.FAR_FUTURE_EPOCH,
activation_epoch=spec.FAR_FUTURE_EPOCH,
exit_epoch=spec.FAR_FUTURE_EPOCH,
withdrawable_epoch=spec.FAR_FUTURE_EPOCH,
effective_balance=min(balance - balance % spec.EFFECTIVE_BALANCE_INCREMENT, spec.MAX_EFFECTIVE_BALANCE)
)
def create_genesis_state(num_validators):
deposit_root = b'\x42' * 32
state = spec.BeaconState(
genesis_time=0,
deposit_index=num_validators,
latest_eth1_data=Eth1Data(
deposit_root=deposit_root,
deposit_count=num_validators,
block_hash=ZERO_HASH,
))
# We "hack" in the initial validators,
# as it is much faster than creating and processing genesis deposits for every single test case.
state.balances = [spec.MAX_EFFECTIVE_BALANCE] * num_validators
state.validator_registry = [build_mock_validator(i, state.balances[i]) for i in range(num_validators)]
# Process genesis activations
for validator in state.validator_registry:
if validator.effective_balance >= spec.MAX_EFFECTIVE_BALANCE:
validator.activation_eligibility_epoch = spec.GENESIS_EPOCH
validator.activation_epoch = spec.GENESIS_EPOCH
genesis_active_index_root = hash_tree_root(get_active_validator_indices(state, spec.GENESIS_EPOCH))
for index in range(spec.LATEST_ACTIVE_INDEX_ROOTS_LENGTH):
state.latest_active_index_roots[index] = genesis_active_index_root
return state

View File

@ -0,0 +1,6 @@
from py_ecc import bls
from eth2spec.phase0 import spec
privkeys = [i + 1 for i in range(spec.SLOTS_PER_EPOCH * 16)]
pubkeys = [bls.privtopub(privkey) for privkey in privkeys]
pubkey_to_privkey = {pubkey: privkey for privkey, pubkey in zip(privkeys, pubkeys)}

View File

@ -0,0 +1,35 @@
from copy import deepcopy
from eth2spec.phase0.spec import (
get_current_epoch, get_active_validator_indices, BeaconBlockHeader, ProposerSlashing
)
from eth2spec.test.helpers.block_header import sign_block_header
from eth2spec.test.helpers.keys import pubkey_to_privkey
def get_valid_proposer_slashing(state, signed_1=False, signed_2=False):
current_epoch = get_current_epoch(state)
validator_index = get_active_validator_indices(state, current_epoch)[-1]
privkey = pubkey_to_privkey[state.validator_registry[validator_index].pubkey]
slot = state.slot
header_1 = BeaconBlockHeader(
slot=slot,
previous_block_root=b'\x33' * 32,
state_root=b'\x44' * 32,
block_body_root=b'\x55' * 32,
)
header_2 = deepcopy(header_1)
header_2.previous_block_root = b'\x99' * 32
header_2.slot = slot + 1
if signed_1:
sign_block_header(state, header_1, privkey)
if signed_2:
sign_block_header(state, header_2, privkey)
return ProposerSlashing(
proposer_index=validator_index,
header_1=header_1,
header_2=header_2,
)

View File

@ -0,0 +1,31 @@
# Access constants from spec pkg reference.
import eth2spec.phase0.spec as spec
from eth2spec.phase0.state_transition import state_transition_to
def get_balance(state, index):
return state.balances[index]
def next_slot(state):
"""
Transition to the next slot.
"""
state_transition_to(state, state.slot + 1)
def next_epoch(state):
"""
Transition to the start slot of the next epoch
"""
slot = state.slot + spec.SLOTS_PER_EPOCH - (state.slot % spec.SLOTS_PER_EPOCH)
state_transition_to(state, slot)
def get_state_root(state, slot) -> bytes:
"""
Return the state root at a recent ``slot``.
"""
assert slot < state.slot <= slot + spec.SLOTS_PER_HISTORICAL_ROOT
return state.latest_state_roots[slot % spec.SLOTS_PER_HISTORICAL_ROOT]

View File

@ -0,0 +1,55 @@
# Access constants from spec pkg reference.
import eth2spec.phase0.spec as spec
from eth2spec.phase0.spec import get_current_epoch, get_active_validator_indices, Transfer, get_domain
from eth2spec.test.helpers.keys import pubkeys, privkeys
from eth2spec.test.helpers.state import get_balance
from eth2spec.utils.bls import bls_sign
from eth2spec.utils.minimal_ssz import signing_root
def get_valid_transfer(state, slot=None, sender_index=None, amount=None, fee=None, signed=False):
if slot is None:
slot = state.slot
current_epoch = get_current_epoch(state)
if sender_index is None:
sender_index = get_active_validator_indices(state, current_epoch)[-1]
recipient_index = get_active_validator_indices(state, current_epoch)[0]
transfer_pubkey = pubkeys[-1]
transfer_privkey = privkeys[-1]
if fee is None:
fee = get_balance(state, sender_index) // 32
if amount is None:
amount = get_balance(state, sender_index) - fee
transfer = Transfer(
sender=sender_index,
recipient=recipient_index,
amount=amount,
fee=fee,
slot=slot,
pubkey=transfer_pubkey,
)
if signed:
sign_transfer(state, transfer, transfer_privkey)
# ensure withdrawal_credentials reproducible
state.validator_registry[transfer.sender].withdrawal_credentials = (
spec.BLS_WITHDRAWAL_PREFIX_BYTE + spec.hash(transfer.pubkey)[1:]
)
return transfer
def sign_transfer(state, transfer, privkey):
transfer.signature = bls_sign(
message_hash=signing_root(transfer),
privkey=privkey,
domain=get_domain(
state=state,
domain_type=spec.DOMAIN_TRANSFER,
message_epoch=get_current_epoch(state),
)
)
return transfer

View File

@ -0,0 +1,28 @@
# Access constants from spec pkg reference.
import eth2spec.phase0.spec as spec
from eth2spec.phase0.spec import VoluntaryExit, get_domain
from eth2spec.utils.bls import bls_sign
from eth2spec.utils.minimal_ssz import signing_root
def build_voluntary_exit(state, epoch, validator_index, privkey, signed=False):
voluntary_exit = VoluntaryExit(
epoch=epoch,
validator_index=validator_index,
)
if signed:
sign_voluntary_exit(state, voluntary_exit, privkey)
return voluntary_exit
def sign_voluntary_exit(state, voluntary_exit, privkey):
voluntary_exit.signature = bls_sign(
message_hash=signing_root(voluntary_exit),
privkey=privkey,
domain=get_domain(
state=state,
domain_type=spec.DOMAIN_VOLUNTARY_EXIT,
message_epoch=voluntary_exit.epoch,
)
)

View File

@ -1,21 +1,18 @@
from copy import deepcopy
import eth2spec.phase0.spec as spec
from eth2spec.phase0.state_transition import (
state_transition,
)
from .helpers import (
build_empty_block_for_next_slot,
fill_aggregate_attestation,
from .context import spec_state_test, never_bls
from .helpers.state import next_epoch
from .helpers.block import build_empty_block_for_next_slot, apply_empty_block
from .helpers.attestations import (
get_current_epoch,
get_epoch_start_slot,
get_valid_attestation,
next_epoch,
)
from .context import spec_state_test
def check_finality(state,
prev_state,
@ -55,13 +52,11 @@ def next_epoch_with_attestations(state,
slot_to_attest = post_state.slot - spec.MIN_ATTESTATION_INCLUSION_DELAY + 1
if slot_to_attest >= get_epoch_start_slot(get_current_epoch(post_state)):
cur_attestation = get_valid_attestation(post_state, slot_to_attest)
fill_aggregate_attestation(post_state, cur_attestation)
block.body.attestations.append(cur_attestation)
if fill_prev_epoch:
slot_to_attest = post_state.slot - spec.SLOTS_PER_EPOCH + 1
prev_attestation = get_valid_attestation(post_state, slot_to_attest)
fill_aggregate_attestation(post_state, prev_attestation)
block.body.attestations.append(prev_attestation)
state_transition(post_state, block)
@ -70,6 +65,7 @@ def next_epoch_with_attestations(state,
return state, blocks, post_state
@never_bls
@spec_state_test
def test_finality_rule_4(state):
yield 'pre', state
@ -97,11 +93,14 @@ def test_finality_rule_4(state):
yield 'post', state
@never_bls
@spec_state_test
def test_finality_rule_1(state):
# get past first two epochs that finality does not run on
next_epoch(state)
apply_empty_block(state)
next_epoch(state)
apply_empty_block(state)
yield 'pre', state
@ -124,11 +123,14 @@ def test_finality_rule_1(state):
yield 'post', state
@never_bls
@spec_state_test
def test_finality_rule_2(state):
# get past first two epochs that finality does not run on
next_epoch(state)
apply_empty_block(state)
next_epoch(state)
apply_empty_block(state)
yield 'pre', state
@ -153,6 +155,7 @@ def test_finality_rule_2(state):
yield 'post', state
@never_bls
@spec_state_test
def test_finality_rule_3(state):
"""
@ -161,7 +164,9 @@ def test_finality_rule_3(state):
"""
# get past first two epochs that finality does not run on
next_epoch(state)
apply_empty_block(state)
next_epoch(state)
apply_empty_block(state)
yield 'pre', state

View File

@ -1,7 +1,7 @@
from copy import deepcopy
from py_ecc import bls
import eth2spec.phase0.spec as spec
from eth2spec.utils.bls import bls_sign
from eth2spec.utils.minimal_ssz import signing_root
from eth2spec.phase0.spec import (
@ -19,20 +19,22 @@ from eth2spec.phase0.spec import (
from eth2spec.phase0.state_transition import (
state_transition,
)
from .helpers import (
from .helpers.state import (
get_balance,
build_empty_block_for_next_slot,
get_state_root,
get_valid_attestation,
get_valid_attester_slashing,
get_valid_proposer_slashing,
get_valid_transfer,
prepare_state_and_deposit,
get_state_root
)
from .helpers.transfers import get_valid_transfer
from .helpers.block import build_empty_block_for_next_slot, sign_block
from .helpers.keys import (
privkeys,
pubkeys,
)
from .helpers.attester_slashings import get_valid_attester_slashing
from .helpers.proposer_slashings import get_valid_proposer_slashing
from .helpers.attestations import get_valid_attestation
from .helpers.deposits import prepare_state_and_deposit
from .context import spec_state_test
from .context import spec_state_test, never_bls
@spec_state_test
@ -49,6 +51,7 @@ def test_slot_transition(state):
assert get_state_root(state, pre_slot) == pre_root
@never_bls
@spec_state_test
def test_empty_block_transition(state):
pre_slot = state.slot
@ -56,7 +59,7 @@ def test_empty_block_transition(state):
yield 'pre', state
block = build_empty_block_for_next_slot(state)
block = build_empty_block_for_next_slot(state, signed=True)
yield 'blocks', [block], [spec.BeaconBlock]
state_transition(state, block)
@ -66,13 +69,15 @@ def test_empty_block_transition(state):
assert get_block_root_at_slot(state, pre_slot) == block.previous_block_root
@never_bls
@spec_state_test
def test_skipped_slots(state):
pre_slot = state.slot
yield 'pre', state
block = build_empty_block_for_next_slot(state)
block = build_empty_block_for_next_slot(state, signed=False)
block.slot += 3
sign_block(state, block)
yield 'blocks', [block], [spec.BeaconBlock]
state_transition(state, block)
@ -88,8 +93,9 @@ def test_empty_epoch_transition(state):
pre_slot = state.slot
yield 'pre', state
block = build_empty_block_for_next_slot(state)
block = build_empty_block_for_next_slot(state, signed=False)
block.slot += spec.SLOTS_PER_EPOCH
sign_block(state, block)
yield 'blocks', [block], [spec.BeaconBlock]
state_transition(state, block)
@ -100,30 +106,31 @@ def test_empty_epoch_transition(state):
assert get_block_root_at_slot(state, slot) == block.previous_block_root
@spec_state_test
def test_empty_epoch_transition_not_finalizing(state):
# copy for later balance lookups.
pre_state = deepcopy(state)
yield 'pre', state
block = build_empty_block_for_next_slot(state)
block.slot += spec.SLOTS_PER_EPOCH * 5
yield 'blocks', [block], [spec.BeaconBlock]
state_transition(state, block)
yield 'post', state
assert state.slot == block.slot
assert state.finalized_epoch < get_current_epoch(state) - 4
for index in range(len(state.validator_registry)):
assert get_balance(state, index) < get_balance(pre_state, index)
# @spec_state_test
# def test_empty_epoch_transition_not_finalizing(state):
# # copy for later balance lookups.
# pre_state = deepcopy(state)
# yield 'pre', state
#
# block = build_empty_block_for_next_slot(state, signed=False)
# block.slot += spec.SLOTS_PER_EPOCH * 5
# sign_block(state, block, proposer_index=0)
# yield 'blocks', [block], [spec.BeaconBlock]
#
# state_transition(state, block)
# yield 'post', state
#
# assert state.slot == block.slot
# assert state.finalized_epoch < get_current_epoch(state) - 4
# for index in range(len(state.validator_registry)):
# assert get_balance(state, index) < get_balance(pre_state, index)
@spec_state_test
def test_proposer_slashing(state):
# copy for later balance lookups.
pre_state = deepcopy(state)
proposer_slashing = get_valid_proposer_slashing(state)
proposer_slashing = get_valid_proposer_slashing(state, signed_1=True, signed_2=True)
validator_index = proposer_slashing.proposer_index
assert not state.validator_registry[validator_index].slashed
@ -133,8 +140,9 @@ def test_proposer_slashing(state):
#
# Add to state via block transition
#
block = build_empty_block_for_next_slot(state)
block = build_empty_block_for_next_slot(state, signed=False)
block.body.proposer_slashings.append(proposer_slashing)
sign_block(state, block)
yield 'blocks', [block], [spec.BeaconBlock]
state_transition(state, block)
@ -154,8 +162,9 @@ def test_attester_slashing(state):
# copy for later balance lookups.
pre_state = deepcopy(state)
attester_slashing = get_valid_attester_slashing(state)
validator_index = attester_slashing.attestation_1.custody_bit_0_indices[0]
attester_slashing = get_valid_attester_slashing(state, signed_1=True, signed_2=True)
validator_index = (attester_slashing.attestation_1.custody_bit_0_indices +
attester_slashing.attestation_1.custody_bit_1_indices)[0]
assert not state.validator_registry[validator_index].slashed
@ -164,8 +173,9 @@ def test_attester_slashing(state):
#
# Add to state via block transition
#
block = build_empty_block_for_next_slot(state)
block = build_empty_block_for_next_slot(state, signed=False)
block.body.attester_slashings.append(attester_slashing)
sign_block(state, block)
yield 'blocks', [block], [spec.BeaconBlock]
state_transition(state, block)
@ -195,12 +205,13 @@ def test_deposit_in_block(state):
validator_index = len(state.validator_registry)
amount = spec.MAX_EFFECTIVE_BALANCE
deposit = prepare_state_and_deposit(state, validator_index, amount)
deposit = prepare_state_and_deposit(state, validator_index, amount, signed=True)
yield 'pre', state
block = build_empty_block_for_next_slot(state)
block = build_empty_block_for_next_slot(state, signed=False)
block.body.deposits.append(deposit)
sign_block(state, block)
yield 'blocks', [block], [spec.BeaconBlock]
@ -225,8 +236,9 @@ def test_deposit_top_up(state):
yield 'pre', state
block = build_empty_block_for_next_slot(state)
block = build_empty_block_for_next_slot(state, signed=False)
block.body.deposits.append(deposit)
sign_block(state, block)
yield 'blocks', [block], [spec.BeaconBlock]
@ -244,23 +256,24 @@ def test_attestation(state):
yield 'pre', state
attestation = get_valid_attestation(state)
attestation = get_valid_attestation(state, signed=True)
# Add to state via block transition
pre_current_attestations_len = len(state.current_epoch_attestations)
attestation_block = build_empty_block_for_next_slot(state)
attestation_block = build_empty_block_for_next_slot(state, signed=False)
attestation_block.slot += spec.MIN_ATTESTATION_INCLUSION_DELAY
attestation_block.body.attestations.append(attestation)
sign_block(state, attestation_block)
state_transition(state, attestation_block)
assert len(state.current_epoch_attestations) == pre_current_attestations_len + 1
# Epoch transition should move to previous_epoch_attestations
pre_current_attestations_root = spec.hash_tree_root(state.current_epoch_attestations)
epoch_block = build_empty_block_for_next_slot(state)
epoch_block = build_empty_block_for_next_slot(state, signed=False)
epoch_block.slot += spec.SLOTS_PER_EPOCH
sign_block(state, epoch_block)
state_transition(state, epoch_block)
yield 'blocks', [attestation_block, epoch_block], [spec.BeaconBlock]
@ -286,7 +299,7 @@ def test_voluntary_exit(state):
epoch=get_current_epoch(state),
validator_index=validator_index,
)
voluntary_exit.signature = bls.sign(
voluntary_exit.signature = bls_sign(
message_hash=signing_root(voluntary_exit),
privkey=privkeys[validator_index],
domain=get_domain(
@ -296,15 +309,17 @@ def test_voluntary_exit(state):
)
# Add to state via block transition
initiate_exit_block = build_empty_block_for_next_slot(state)
initiate_exit_block = build_empty_block_for_next_slot(state, signed=False)
initiate_exit_block.body.voluntary_exits.append(voluntary_exit)
sign_block(state, initiate_exit_block)
state_transition(state, initiate_exit_block)
assert state.validator_registry[validator_index].exit_epoch < spec.FAR_FUTURE_EPOCH
# Process within epoch transition
exit_block = build_empty_block_for_next_slot(state)
exit_block = build_empty_block_for_next_slot(state, signed=False)
exit_block.slot += spec.SLOTS_PER_EPOCH
sign_block(state, exit_block)
state_transition(state, exit_block)
yield 'blocks', [initiate_exit_block, exit_block], [spec.BeaconBlock]
@ -321,7 +336,7 @@ def test_transfer(state):
sender_index = get_active_validator_indices(state, get_current_epoch(state))[-1]
amount = get_balance(state, sender_index)
transfer = get_valid_transfer(state, state.slot + 1, sender_index, amount)
transfer = get_valid_transfer(state, state.slot + 1, sender_index, amount, signed=True)
recipient_index = transfer.recipient
pre_transfer_recipient_balance = get_balance(state, recipient_index)
@ -331,8 +346,9 @@ def test_transfer(state):
yield 'pre', state
# Add to state via block transition
block = build_empty_block_for_next_slot(state)
block = build_empty_block_for_next_slot(state, signed=False)
block.body.transfers.append(transfer)
sign_block(state, block)
yield 'blocks', [block], [spec.BeaconBlock]
@ -358,8 +374,9 @@ def test_balance_driven_status_transitions(state):
yield 'pre', state
# trigger epoch transition
block = build_empty_block_for_next_slot(state)
block = build_empty_block_for_next_slot(state, signed=False)
block.slot += spec.SLOTS_PER_EPOCH
sign_block(state, block)
state_transition(state, block)
yield 'blocks', [block], [spec.BeaconBlock]
@ -375,7 +392,7 @@ def test_historical_batch(state):
yield 'pre', state
block = build_empty_block_for_next_slot(state)
block = build_empty_block_for_next_slot(state, signed=True)
state_transition(state, block)
yield 'blocks', [block], [spec.BeaconBlock]
@ -386,28 +403,28 @@ def test_historical_batch(state):
assert len(state.historical_roots) == pre_historical_roots_len + 1
@spec_state_test
def test_eth1_data_votes(state):
yield 'pre', state
expected_votes = 0
assert len(state.eth1_data_votes) == expected_votes
blocks = []
for _ in range(spec.SLOTS_PER_ETH1_VOTING_PERIOD - 1):
block = build_empty_block_for_next_slot(state)
state_transition(state, block)
expected_votes += 1
assert len(state.eth1_data_votes) == expected_votes
blocks.append(block)
block = build_empty_block_for_next_slot(state)
blocks.append(block)
state_transition(state, block)
yield 'blocks', [block], [spec.BeaconBlock]
yield 'post', state
assert state.slot % spec.SLOTS_PER_ETH1_VOTING_PERIOD == 0
assert len(state.eth1_data_votes) == 1
# @spec_state_test
# def test_eth1_data_votes(state):
# yield 'pre', state
#
# expected_votes = 0
# assert len(state.eth1_data_votes) == expected_votes
#
# blocks = []
# for _ in range(spec.SLOTS_PER_ETH1_VOTING_PERIOD - 1):
# block = build_empty_block_for_next_slot(state, signed=False)
# state_transition(state, block)
# expected_votes += 1
# assert len(state.eth1_data_votes) == expected_votes
# blocks.append(block)
#
# block = build_empty_block_for_next_slot(state, signed=False)
# blocks.append(block)
#
# state_transition(state, block)
#
# yield 'blocks', [block], [spec.BeaconBlock]
# yield 'post', state
#
# assert state.slot % spec.SLOTS_PER_ETH1_VOTING_PERIOD == 0
# assert len(state.eth1_data_votes) == 1

View File

@ -1,3 +1,4 @@
from typing import Dict, Any, Callable, Iterable
from eth2spec.debug.encode import encode
@ -40,10 +41,34 @@ def spectest(description: str = None):
return runner
def with_args(create_args):
def with_tags(tags: Dict[str, Any]):
"""
Decorator factory, adds tags (key, value) pairs to the output of the function.
Useful to build test-vector annotations with.
This decorator is applied after the ``spectest`` decorator is applied.
:param tags: dict of tags
:return: Decorator.
"""
def runner(fn):
def entry(*args, **kw):
fn_out = fn(*args, **kw)
# do not add tags if the function is not returning a dict at all (i.e. not in generator mode)
if fn_out is None:
return fn_out
return {**tags, **fn_out}
return entry
return runner
def with_args(create_args: Callable[[], Iterable[Any]]):
"""
Decorator factory, adds given extra arguments to the decorated function.
:param create_args: function to create arguments with.
:return: Decorator.
"""
def runner(fn):
# this wraps the function, to hide that the function actually yielding data.
def entry(*args, **kw):
return fn(*(create_args() + list(args)), **kw)
return fn(*(list(create_args()) + list(args)), **kw)
return entry
return runner

View File

@ -0,0 +1,46 @@
from py_ecc import bls
# Flag to make BLS active or not. Used for testing, do not ignore BLS in production unless you know what you are doing.
bls_active = True
STUB_SIGNATURE = b'\x11' * 96
STUB_PUBKEY = b'\x22' * 48
def only_with_bls(alt_return=None):
"""
Decorator factory to make a function only run when BLS is active. Otherwise return the default.
"""
def runner(fn):
def entry(*args, **kw):
if bls_active:
return fn(*args, **kw)
else:
return alt_return
return entry
return runner
@only_with_bls(alt_return=True)
def bls_verify(pubkey, message_hash, signature, domain):
return bls.verify(message_hash=message_hash, pubkey=pubkey, signature=signature, domain=domain)
@only_with_bls(alt_return=True)
def bls_verify_multiple(pubkeys, message_hashes, signature, domain):
return bls.verify_multiple(pubkeys, message_hashes, signature, domain)
@only_with_bls(alt_return=STUB_PUBKEY)
def bls_aggregate_pubkeys(pubkeys):
return bls.aggregate_pubkeys(pubkeys)
@only_with_bls(alt_return=STUB_SIGNATURE)
def bls_aggregate_signatures(signatures):
return bls.aggregate_signatures(signatures)
@only_with_bls(alt_return=STUB_SIGNATURE)
def bls_sign(message_hash, privkey, domain):
return bls.sign(message_hash=message_hash, privkey=privkey, domain=domain)

View File

@ -1,12 +0,0 @@
def bls_verify(pubkey, message_hash, signature, domain):
return True
def bls_verify_multiple(pubkeys, message_hashes, signature, domain):
return True
def bls_aggregate_pubkeys(pubkeys):
return b'\x42' * 96