Update to spec v0.8.3 (#3355)

* Ignore latest messages in fork choice prior to latest justified

* Make sure Compact Committee Roots isn't changed by process_final_updates

* WIP add attestation bitfields length to match committee length

* Begin work on updating spec tests to 0.8.2

* WIP set up for new spec test structure

* Fix slashings

* Get mainnet tests mostly passing for attestations and attester slashings

* Fix process attestation test

* Undo change

* Complete spec tests for all operations
Still need sanity block tests

* Fix BLS sigs

* Reduce amount of reused code in core/blocks/spectests/

* Fix tests

* Update block sanity tests to 0.8.2

* Update epoch spec tests to 0.8.2

* Clean up all tests and fix shuffling/epoch tests

* WIP update bls tests to 0.8.2

* WIP update bls tests to 0.8.3

* Finish BLS spectest update to 0.8.3

* Fix shuffling spec tests

* Fix more tests

* Update proto ssz spec tests to 0.8.3

* Attempt to fix PrevEpochFFGDataMismatches test

* Goimports

* Fix documentation

* fix test

* Use custom general spec tests

* Reduce code footprint

* Remove unneeded minimal skip

* Fix for comments

* Fix for comments

* Fix test

* Small fixes

* Cleanup block spec tests a bit

* Undo change

* fix validator

* Fix validator tests

* Run gazelle

* Fix error output for epoch spec tests
This commit is contained in:
Ivan Martinez
2019-09-08 15:41:52 -04:00
committed by Preston Van Loon
parent d94522510f
commit 5e939378d0
103 changed files with 1671 additions and 2412 deletions

View File

@@ -92,8 +92,12 @@ func (s *Store) GenesisStore(
// Spec pseudocode definition:
// def get_ancestor(store: Store, root: Hash, slot: Slot) -> Hash:
// block = store.blocks[root]
// assert block.slot >= slot
// return root if block.slot == slot else get_ancestor(store, block.parent_root, slot)
// if block.slot > slot:
// return get_ancestor(store, block.parent_root, slot)
// elif block.slot == slot:
// return root
// else:
// return Bytes32() # root is older than queried slot: no results.
func (s *Store) ancestor(ctx context.Context, root []byte, slot uint64) ([]byte, error) {
ctx, span := trace.StartSpan(ctx, "forkchoice.ancestor")
defer span.End()

View File

@@ -525,9 +525,15 @@ func ProcessAttestationsNoVerify(
// Process ``Attestation`` operation.
// """
// data = attestation.data
// assert data.crosslink.shard < SHARD_COUNT
// assert data.target.epoch in (get_previous_epoch(state), get_current_epoch(state))
//
// attestation_slot = get_attestation_data_slot(state, data)
// assert attestation_slot + MIN_ATTESTATION_INCLUSION_DELAY <= state.slot <= attestation_slot + SLOTS_PER_EPOCH
//
// committee = get_crosslink_committee(state, data.target.epoch, data.crosslink.shard)
// assert len(attestation.aggregation_bits) == len(attestation.custody_bits) == len(committee)
//
// pending_attestation = PendingAttestation(
// data=data,
// aggregation_bitfield=attestation.aggregation_bitfield,
@@ -535,23 +541,23 @@ func ProcessAttestationsNoVerify(
// proposer_index=get_beacon_proposer_index(state),
// )
//
// assert data.target_epoch in (get_previous_epoch(state), get_current_epoch(state))
// if data.target_epoch == get_current_epoch(state):
// ffg_data = (state.current_justified_epoch, state.current_justified_root, get_current_epoch(state))
// parent_crosslink = state.current_crosslinks[data.crosslink.shard]
// state.current_epoch_attestations.append(pending_attestation)
// assert data.source == state.current_justified_checkpoint
// parent_crosslink = state.current_crosslinks[data.crosslink.shard]
// state.current_epoch_attestations.append(pending_attestation)
// else:
// ffg_data = (state.previous_justified_epoch, state.previous_justified_root, get_previous_epoch(state))
// parent_crosslink = state.previous_crosslinks[data.crosslink.shard]
// state.previous_epoch_attestations.append(pending_attestation)
// assert data.source == state.previous_justified_checkpoint
// parent_crosslink = state.previous_crosslinks[data.crosslink.shard]
// state.previous_epoch_attestations.append(pending_attestation)
//
// # Check FFG data, crosslink data, and signature
// assert ffg_data == (data.source_epoch, data.source_root, data.target_epoch)
// assert data.crosslink.start_epoch == parent_crosslink.end_epoch
// assert data.crosslink.end_epoch == min(data.target_epoch, parent_crosslink.end_epoch + MAX_EPOCHS_PER_CROSSLINK)
// # Check crosslink against expected parent crosslink
// assert data.crosslink.parent_root == hash_tree_root(parent_crosslink)
// assert data.crosslink.start_epoch == parent_crosslink.end_epoch
// assert data.crosslink.end_epoch == min(data.target.epoch, parent_crosslink.end_epoch + MAX_EPOCHS_PER_CROSSLINK)
// assert data.crosslink.data_root == Bytes32() # [to be removed in phase 1]
// validate_indexed_attestation(state, convert_to_indexed(state, attestation))
//
// # Check signature
// assert is_valid_indexed_attestation(state, get_indexed_attestation(state, attestation))
func ProcessAttestation(beaconState *pb.BeaconState, att *ethpb.Attestation) (*pb.BeaconState, error) {
beaconState, err := ProcessAttestationNoVerify(beaconState, att)
if err != nil {
@@ -564,6 +570,24 @@ func ProcessAttestation(beaconState *pb.BeaconState, att *ethpb.Attestation) (*p
// method is used to validate attestations whose signatures have already been verified.
func ProcessAttestationNoVerify(beaconState *pb.BeaconState, att *ethpb.Attestation) (*pb.BeaconState, error) {
data := att.Data
if data.Crosslink.Shard > params.BeaconConfig().ShardCount {
return nil, fmt.Errorf(
"expected crosslink shard %d to be less than SHARD_COUNT %d",
data.Crosslink.Shard,
params.BeaconConfig().ShardCount,
)
}
if data.Target.Epoch != helpers.PrevEpoch(beaconState) && data.Target.Epoch != helpers.CurrentEpoch(beaconState) {
return nil, fmt.Errorf(
"expected target epoch (%d) to be the previous epoch (%d) or the current epoch (%d)",
data.Target.Epoch,
helpers.PrevEpoch(beaconState),
helpers.CurrentEpoch(beaconState),
)
}
attestationSlot, err := helpers.AttestationDataSlot(beaconState, data)
if err != nil {
return nil, errors.Wrap(err, "could not get attestation slot")
@@ -586,6 +610,11 @@ func ProcessAttestationNoVerify(beaconState *pb.BeaconState, att *ethpb.Attestat
params.BeaconConfig().SlotsPerEpoch,
)
}
if err := helpers.VerifyAttestationBitfieldLengths(beaconState, att); err != nil {
return nil, errors.Wrap(err, "could not verify attestation bitfields")
}
proposerIndex, err := helpers.BeaconProposerIndex(beaconState)
if err != nil {
return nil, err
@@ -597,15 +626,6 @@ func ProcessAttestationNoVerify(beaconState *pb.BeaconState, att *ethpb.Attestat
ProposerIndex: proposerIndex,
}
if !(data.Target.Epoch == helpers.PrevEpoch(beaconState) || data.Target.Epoch == helpers.CurrentEpoch(beaconState)) {
return nil, fmt.Errorf(
"expected target epoch %d == %d or %d",
data.Target.Epoch,
helpers.PrevEpoch(beaconState),
helpers.CurrentEpoch(beaconState),
)
}
var ffgSourceEpoch uint64
var ffgSourceRoot []byte
var ffgTargetEpoch uint64
@@ -664,6 +684,7 @@ func ProcessAttestationNoVerify(beaconState *pb.BeaconState, att *ethpb.Attestat
data.Crosslink.ParentRoot,
)
}
// To be removed in Phase 1
if !bytes.Equal(data.Crosslink.DataRoot, params.BeaconConfig().ZeroHash[:]) {
return nil, fmt.Errorf("expected data root %#x == ZERO_HASH", data.Crosslink.DataRoot)

View File

@@ -906,20 +906,20 @@ func TestProcessAttestations_NeitherCurrentNorPrevEpoch(t *testing.T) {
helpers.ClearActiveCountCache()
helpers.ClearStartShardCache()
attestations := []*ethpb.Attestation{
{
Data: &ethpb.AttestationData{
Source: &ethpb.Checkpoint{Epoch: 0},
Target: &ethpb.Checkpoint{Epoch: 0},
Crosslink: &ethpb.Crosslink{
Shard: 0,
},
att := &ethpb.Attestation{
Data: &ethpb.AttestationData{
Source: &ethpb.Checkpoint{Epoch: 0, Root: []byte("hello-world")},
Target: &ethpb.Checkpoint{Epoch: 0},
Crosslink: &ethpb.Crosslink{
Shard: 0,
StartEpoch: 0,
},
},
}
block := &ethpb.BeaconBlock{
Body: &ethpb.BeaconBlockBody{
Attestations: attestations,
Attestations: []*ethpb.Attestation{att},
},
}
deposits, _ := testutil.SetupInitialDeposits(t, 100)
@@ -929,10 +929,17 @@ func TestProcessAttestations_NeitherCurrentNorPrevEpoch(t *testing.T) {
}
helpers.ClearAllCaches()
beaconState.Slot += params.BeaconConfig().SlotsPerEpoch*4 + params.BeaconConfig().MinAttestationInclusionDelay
beaconState.PreviousCrosslinks = []*ethpb.Crosslink{
{
Shard: 0,
},
}
beaconState.PreviousJustifiedCheckpoint.Root = []byte("hello-world")
beaconState.PreviousEpochAttestations = []*pb.PendingAttestation{}
want := fmt.Sprintf(
"expected target epoch %d == %d or %d",
attestations[0].Data.Target.Epoch,
"expected target epoch (%d) to be the previous epoch (%d) or the current epoch (%d)",
att.Data.Target.Epoch,
helpers.PrevEpoch(beaconState),
helpers.CurrentEpoch(beaconState),
)
@@ -944,15 +951,20 @@ func TestProcessAttestations_NeitherCurrentNorPrevEpoch(t *testing.T) {
func TestProcessAttestations_CurrentEpochFFGDataMismatches(t *testing.T) {
helpers.ClearAllCaches()
aggBits := bitfield.NewBitlist(1)
custodyBits := bitfield.NewBitlist(1)
attestations := []*ethpb.Attestation{
{
Data: &ethpb.AttestationData{
Target: &ethpb.Checkpoint{Epoch: 0},
Source: &ethpb.Checkpoint{Epoch: 1},
Crosslink: &ethpb.Crosslink{
Shard: 0,
Shard: 0,
StartEpoch: 0,
},
},
AggregationBits: aggBits,
CustodyBits: custodyBits,
},
}
block := &ethpb.BeaconBlock{
@@ -999,15 +1011,26 @@ func TestProcessAttestations_CurrentEpochFFGDataMismatches(t *testing.T) {
func TestProcessAttestations_PrevEpochFFGDataMismatches(t *testing.T) {
helpers.ClearAllCaches()
deposits, _ := testutil.SetupInitialDeposits(t, 100)
beaconState, err := state.GenesisBeaconState(deposits, uint64(0), &ethpb.Eth1Data{})
if err != nil {
t.Fatal(err)
}
aggBits := bitfield.NewBitlist(1)
aggBits.SetBitAt(0, true)
custodyBits := bitfield.NewBitlist(1)
attestations := []*ethpb.Attestation{
{
Data: &ethpb.AttestationData{
Source: &ethpb.Checkpoint{Epoch: 1},
Target: &ethpb.Checkpoint{Epoch: 0},
Target: &ethpb.Checkpoint{Epoch: 1},
Crosslink: &ethpb.Crosslink{
Shard: 0,
},
},
AggregationBits: aggBits,
CustodyBits: custodyBits,
},
}
block := &ethpb.BeaconBlock{
@@ -1015,12 +1038,8 @@ func TestProcessAttestations_PrevEpochFFGDataMismatches(t *testing.T) {
Attestations: attestations,
},
}
deposits, _ := testutil.SetupInitialDeposits(t, 100)
beaconState, err := state.GenesisBeaconState(deposits, uint64(0), &ethpb.Eth1Data{})
if err != nil {
t.Fatal(err)
}
helpers.ClearAllCaches()
beaconState.Slot += params.BeaconConfig().SlotsPerEpoch + params.BeaconConfig().MinAttestationInclusionDelay
beaconState.PreviousCrosslinks = []*ethpb.Crosslink{
{
@@ -1038,13 +1057,15 @@ func TestProcessAttestations_PrevEpochFFGDataMismatches(t *testing.T) {
if _, err := blocks.ProcessAttestations(beaconState, block.Body); !strings.Contains(err.Error(), want) {
t.Errorf("Expected %s, received %v", want, err)
}
helpers.ClearAllCaches()
block.Body.Attestations[0].Data.Source.Epoch = helpers.PrevEpoch(beaconState)
block.Body.Attestations[0].Data.Target.Epoch = helpers.CurrentEpoch(beaconState)
block.Body.Attestations[0].Data.Source.Root = []byte{}
want = fmt.Sprintf(
"expected source root %#x, received %#x",
beaconState.PreviousJustifiedCheckpoint.Root,
beaconState.CurrentJustifiedCheckpoint.Root,
attestations[0].Data.Source.Root,
)
if _, err := blocks.ProcessAttestations(beaconState, block.Body); !strings.Contains(err.Error(), want) {
@@ -1055,6 +1076,9 @@ func TestProcessAttestations_PrevEpochFFGDataMismatches(t *testing.T) {
func TestProcessAttestations_CrosslinkMismatches(t *testing.T) {
helpers.ClearAllCaches()
aggBits := bitfield.NewBitlist(1)
aggBits.SetBitAt(0, true)
custodyBits := bitfield.NewBitlist(1)
attestations := []*ethpb.Attestation{
{
Data: &ethpb.AttestationData{
@@ -1064,6 +1088,8 @@ func TestProcessAttestations_CrosslinkMismatches(t *testing.T) {
Shard: 0,
},
},
AggregationBits: aggBits,
CustodyBits: custodyBits,
},
}
block := &ethpb.BeaconBlock{
@@ -1108,14 +1134,16 @@ func TestProcessAttestations_CrosslinkMismatches(t *testing.T) {
}
}
func TestProcessAttestations_OK(t *testing.T) {
func TestProcessAttestations_InvalidAggregationBitsLength(t *testing.T) {
helpers.ClearAllCaches()
deposits, privKeys := testutil.SetupInitialDeposits(t, 100)
deposits, _ := testutil.SetupInitialDeposits(t, 100)
beaconState, err := state.GenesisBeaconState(deposits, uint64(0), &ethpb.Eth1Data{})
if err != nil {
t.Fatal(err)
}
aggBits := bitfield.NewBitlist(2)
custodyBits := bitfield.NewBitlist(2)
att := &ethpb.Attestation{
Data: &ethpb.AttestationData{
Source: &ethpb.Checkpoint{Epoch: 0, Root: []byte("hello-world")},
@@ -1125,30 +1153,10 @@ func TestProcessAttestations_OK(t *testing.T) {
StartEpoch: 0,
},
},
AggregationBits: bitfield.Bitlist{0xC0, 0xC0, 0xC0, 0xC0, 0x01},
CustodyBits: bitfield.Bitlist{0x00, 0x00, 0x00, 0x00, 0x01},
AggregationBits: aggBits,
CustodyBits: custodyBits,
}
attestingIndices, err := helpers.AttestingIndices(beaconState, att.Data, att.AggregationBits)
if err != nil {
t.Error(err)
}
domain := helpers.Domain(beaconState, 0, params.BeaconConfig().DomainAttestation)
sigs := make([]*bls.Signature, len(attestingIndices))
for i, indice := range attestingIndices {
dataAndCustodyBit := &pb.AttestationDataAndCustodyBit{
Data: att.Data,
CustodyBit: false,
}
hashTreeRoot, err := ssz.HashTreeRoot(dataAndCustodyBit)
if err != nil {
t.Error(err)
}
sig := privKeys[indice].Sign(hashTreeRoot[:], domain)
sigs[i] = sig
}
att.Signature = bls.AggregateSignatures(sigs).Marshal()[:]
block := &ethpb.BeaconBlock{
Body: &ethpb.BeaconBlockBody{
Attestations: []*ethpb.Attestation{att},
@@ -1172,6 +1180,80 @@ func TestProcessAttestations_OK(t *testing.T) {
block.Body.Attestations[0].Data.Crosslink.ParentRoot = encoded[:]
block.Body.Attestations[0].Data.Crosslink.DataRoot = params.BeaconConfig().ZeroHash[:]
expected := "failed to verify aggregation bitfield: wanted participants bitfield length 1, got: 2"
_, err = blocks.ProcessAttestations(beaconState, block.Body)
if !strings.Contains(err.Error(), expected) {
t.Errorf("Expected error checking aggregation and custody bit length, received: %v", err)
}
}
func TestProcessAttestations_OK(t *testing.T) {
helpers.ClearAllCaches()
deposits, privKeys := testutil.SetupInitialDeposits(t, 100)
beaconState, err := state.GenesisBeaconState(deposits, uint64(0), &ethpb.Eth1Data{})
if err != nil {
t.Fatal(err)
}
aggBits := bitfield.NewBitlist(1)
aggBits.SetBitAt(0, true)
custodyBits := bitfield.NewBitlist(1)
att := &ethpb.Attestation{
Data: &ethpb.AttestationData{
Source: &ethpb.Checkpoint{Epoch: 0, Root: []byte("hello-world")},
Target: &ethpb.Checkpoint{Epoch: 0, Root: []byte("hello-world")},
Crosslink: &ethpb.Crosslink{
Shard: 0,
StartEpoch: 0,
},
},
AggregationBits: aggBits,
CustodyBits: custodyBits,
}
beaconState.CurrentCrosslinks = []*ethpb.Crosslink{
{
Shard: 0,
StartEpoch: 0,
},
}
beaconState.CurrentJustifiedCheckpoint.Root = []byte("hello-world")
beaconState.CurrentEpochAttestations = []*pb.PendingAttestation{}
encoded, err := ssz.HashTreeRoot(beaconState.CurrentCrosslinks[0])
if err != nil {
t.Fatal(err)
}
att.Data.Crosslink.ParentRoot = encoded[:]
att.Data.Crosslink.DataRoot = params.BeaconConfig().ZeroHash[:]
attestingIndices, err := helpers.AttestingIndices(beaconState, att.Data, att.AggregationBits)
if err != nil {
t.Error(err)
}
dataAndCustodyBit := &pb.AttestationDataAndCustodyBit{
Data: att.Data,
CustodyBit: false,
}
hashTreeRoot, err := ssz.HashTreeRoot(dataAndCustodyBit)
if err != nil {
t.Error(err)
}
domain := helpers.Domain(beaconState, 0, params.BeaconConfig().DomainAttestation)
sigs := make([]*bls.Signature, len(attestingIndices))
for i, indice := range attestingIndices {
sig := privKeys[indice].Sign(hashTreeRoot[:], domain)
sigs[i] = sig
}
att.Signature = bls.AggregateSignatures(sigs).Marshal()[:]
block := &ethpb.BeaconBlock{
Body: &ethpb.BeaconBlockBody{
Attestations: []*ethpb.Attestation{att},
},
}
beaconState.Slot += params.BeaconConfig().MinAttestationInclusionDelay
if _, err := blocks.ProcessAttestations(beaconState, block.Body); err != nil {
t.Errorf("Unexpected error: %v", err)
}
@@ -1186,6 +1268,9 @@ func TestProcessAttestationsNoVerify_OK(t *testing.T) {
t.Fatal(err)
}
aggBits := bitfield.NewBitlist(1)
aggBits.SetBitAt(1, true)
custodyBits := bitfield.NewBitlist(1)
att := &ethpb.Attestation{
Data: &ethpb.AttestationData{
Source: &ethpb.Checkpoint{Epoch: 0, Root: []byte("hello-world")},
@@ -1195,8 +1280,8 @@ func TestProcessAttestationsNoVerify_OK(t *testing.T) {
StartEpoch: 0,
},
},
AggregationBits: bitfield.Bitlist{0xC0, 0xC0, 0xC0, 0xC0, 0x01},
CustodyBits: bitfield.Bitlist{0x00, 0x00, 0x00, 0x00, 0x01},
AggregationBits: aggBits,
CustodyBits: custodyBits,
}
zeroSig := [96]byte{}

View File

@@ -2,19 +2,9 @@ load("@io_bazel_rules_go//go:def.bzl", "go_library", "go_test")
go_library(
name = "go_default_library",
testonly = True,
srcs = [
"attestation_test.yaml.go",
"block_operations.yaml.go",
"blocks_mainnet.yaml.go",
"blocks_minimal.yaml.go",
],
srcs = ["block_processing_test.yaml.go"],
importpath = "github.com/prysmaticlabs/prysm/beacon-chain/core/blocks/spectest",
visibility = ["//beacon-chain:__subpackages__"],
deps = [
"//proto/beacon/p2p/v1:go_default_library",
"//proto/eth/v1alpha1:go_default_library",
],
)
test_suite(
@@ -34,7 +24,7 @@ go_test(
exclude = ["*_minimal_test.go"],
),
data = glob(["*.yaml"]) + [
"@eth2_spec_tests//:test_data",
"@eth2_spec_tests_mainnet//:test_data",
],
embed = [":go_default_library"],
shard_count = 4,
@@ -44,10 +34,12 @@ go_test(
"//beacon-chain/core/helpers:go_default_library",
"//beacon-chain/core/state:go_default_library",
"//beacon-chain/core/state/stateutils:go_default_library",
"//proto/beacon/p2p/v1:go_default_library",
"//proto/eth/v1alpha1:go_default_library",
"//shared/params/spectest:go_default_library",
"//shared/testutil:go_default_library",
"@com_github_gogo_protobuf//proto:go_default_library",
"@com_github_prysmaticlabs_go_ssz//:go_default_library",
"@in_gopkg_d4l3k_messagediff_v1//:go_default_library",
"@io_bazel_rules_go//go/tools/bazel:go_default_library",
],
@@ -61,7 +53,7 @@ go_test(
exclude = ["*_mainnet_test.go"],
),
data = glob(["*.yaml"]) + [
"@eth2_spec_tests//:test_data",
"@eth2_spec_tests_minimal//:test_data",
],
embed = [":go_default_library"],
tags = ["spectest"],
@@ -70,10 +62,12 @@ go_test(
"//beacon-chain/core/helpers:go_default_library",
"//beacon-chain/core/state:go_default_library",
"//beacon-chain/core/state/stateutils:go_default_library",
"//proto/beacon/p2p/v1:go_default_library",
"//proto/eth/v1alpha1:go_default_library",
"//shared/params/spectest:go_default_library",
"//shared/testutil:go_default_library",
"@com_github_gogo_protobuf//proto:go_default_library",
"@com_github_prysmaticlabs_go_ssz//:go_default_library",
"@in_gopkg_d4l3k_messagediff_v1//:go_default_library",
"@io_bazel_rules_go//go/tools/bazel:go_default_library",
],

View File

@@ -5,5 +5,5 @@ import (
)
func TestAttestationMainnet(t *testing.T) {
runAttestationTest(t, "attestation_mainnet.yaml")
runAttestationTest(t, "mainnet")
}

View File

@@ -5,5 +5,5 @@ import (
)
func TestAttestationMinimal(t *testing.T) {
runAttestationTest(t, "attestation_minimal.yaml")
runAttestationTest(t, "minimal")
}

View File

@@ -1,78 +1,36 @@
package spectest
import (
"io/ioutil"
"reflect"
"path"
"testing"
"github.com/bazelbuild/rules_go/go/tools/bazel"
"github.com/gogo/protobuf/proto"
"github.com/prysmaticlabs/go-ssz"
"github.com/prysmaticlabs/prysm/beacon-chain/core/blocks"
"github.com/prysmaticlabs/prysm/beacon-chain/core/helpers"
ethpb "github.com/prysmaticlabs/prysm/proto/eth/v1alpha1"
"github.com/prysmaticlabs/prysm/shared/params/spectest"
"github.com/prysmaticlabs/prysm/shared/testutil"
"gopkg.in/d4l3k/messagediff.v1"
)
func runAttestationTest(t *testing.T, filename string) {
filepath, err := bazel.Runfile("tests/operations/attestation/" + filename)
if err != nil {
t.Fatal(err)
}
file, err := ioutil.ReadFile(filepath)
if err != nil {
t.Fatalf("Failed to read file: %v", err)
}
test := &AttestationTest{}
if err := testutil.UnmarshalYaml(file, test); err != nil {
t.Fatalf("Failed to unmarshal: %v", err)
}
if err := spectest.SetConfig(test.Config); err != nil {
func runAttestationTest(t *testing.T, config string) {
if err := spectest.SetConfig(config); err != nil {
t.Fatal(err)
}
if len(test.TestCases) == 0 {
t.Fatal("No tests!")
}
for _, tt := range test.TestCases {
t.Run(tt.Description, func(t *testing.T) {
helpers.ClearAllCaches()
body := &ethpb.BeaconBlockBody{
Attestations: []*ethpb.Attestation{
tt.Attestation,
},
}
post, err := blocks.ProcessAttestations(tt.Pre, body)
if !reflect.ValueOf(tt.Post).IsValid() {
// Note: This doesn't test anything worthwhile. It essentially tests
// that *any* error has occurred, not any specific error.
if err == nil {
t.Fatal("did not fail when expected")
}
return
}
// Note: This doesn't test anything worthwhile. It essentially tests
// that *any* error has occurred, not any specific error.
if tt.Post == nil {
if err == nil {
t.Fatal("Did not fail when expected")
}
t.Logf("Expected failure; failure reason = %v", err)
return
} else if err != nil {
testFolders, testsFolderPath := testutil.TestFolders(t, config, "operations/attestation/pyspec_tests")
for _, folder := range testFolders {
t.Run(folder.Name(), func(t *testing.T) {
folderPath := path.Join(testsFolderPath, folder.Name())
attestationFile, err := testutil.BazelFileBytes(folderPath, "attestation.ssz")
if err != nil {
t.Fatal(err)
}
if !proto.Equal(post, tt.Post) {
diff, _ := messagediff.PrettyDiff(post, tt.Post)
t.Log(diff)
t.Fatal("Post state does not match expected")
att := &ethpb.Attestation{}
if err := ssz.Unmarshal(attestationFile, att); err != nil {
t.Fatalf("Failed to unmarshal: %v", err)
}
body := &ethpb.BeaconBlockBody{Attestations: []*ethpb.Attestation{att}}
testutil.RunBlockOperationTest(t, folderPath, body, blocks.ProcessAttestations)
})
}
}

View File

@@ -1,26 +0,0 @@
// Code generated by yaml_to_go. DO NOT EDIT.
// source: attestation_minimal.yaml
package spectest
import (
pb "github.com/prysmaticlabs/prysm/proto/beacon/p2p/v1"
ethpb "github.com/prysmaticlabs/prysm/proto/eth/v1alpha1"
)
type AttestationTest struct {
Title string `json:"title"`
Summary string `json:"summary"`
ForksTimeline string `json:"forks_timeline"`
Forks []string `json:"forks"`
Config string `json:"config"`
Runner string `json:"runner"`
Handler string `json:"handler"`
TestCases []struct {
Description string `json:"description"`
Pre *pb.BeaconState `json:"pre"`
Attestation *ethpb.Attestation `json:"attestation"`
Post *pb.BeaconState `json:"post"`
BlsSetting uint64 `json:"bls_setting,omitempty"`
} `json:"test_cases"`
}

View File

@@ -2,14 +2,8 @@ package spectest
import (
"testing"
"github.com/bazelbuild/rules_go/go/tools/bazel"
)
func TestAttesterSlashingMainnet(t *testing.T) {
filepath, err := bazel.Runfile(attesterSlashingPrefix + "attester_slashing_mainnet.yaml")
if err != nil {
t.Fatal(err)
}
runAttesterSlashingTest(t, filepath)
runAttesterSlashingTest(t, "mainnet")
}

View File

@@ -2,14 +2,8 @@ package spectest
import (
"testing"
"github.com/bazelbuild/rules_go/go/tools/bazel"
)
func TestAttesterSlashingMinimal(t *testing.T) {
filepath, err := bazel.Runfile(attesterSlashingPrefix + "attester_slashing_minimal.yaml")
if err != nil {
t.Fatal(err)
}
runAttesterSlashingTest(t, filepath)
runAttesterSlashingTest(t, "minimal")
}

View File

@@ -1,63 +1,36 @@
package spectest
import (
"io/ioutil"
"path"
"testing"
"github.com/gogo/protobuf/proto"
"github.com/prysmaticlabs/go-ssz"
"github.com/prysmaticlabs/prysm/beacon-chain/core/blocks"
"github.com/prysmaticlabs/prysm/beacon-chain/core/helpers"
ethpb "github.com/prysmaticlabs/prysm/proto/eth/v1alpha1"
"github.com/prysmaticlabs/prysm/shared/params/spectest"
"github.com/prysmaticlabs/prysm/shared/testutil"
"gopkg.in/d4l3k/messagediff.v1"
)
const attesterSlashingPrefix = "tests/operations/attester_slashing/"
func runAttesterSlashingTest(t *testing.T, filename string) {
file, err := ioutil.ReadFile(filename)
if err != nil {
t.Fatalf("Could not load file %v", err)
}
test := &BlockOperationTest{}
if err := testutil.UnmarshalYaml(file, test); err != nil {
t.Fatalf("Failed to Unmarshal: %v", err)
}
if err := spectest.SetConfig(test.Config); err != nil {
func runAttesterSlashingTest(t *testing.T, config string) {
if err := spectest.SetConfig(config); err != nil {
t.Fatal(err)
}
if len(test.TestCases) == 0 {
t.Fatal("No tests!")
}
for _, tt := range test.TestCases {
t.Run(tt.Description, func(t *testing.T) {
helpers.ClearAllCaches()
body := &ethpb.BeaconBlockBody{AttesterSlashings: []*ethpb.AttesterSlashing{tt.AttesterSlashing}}
postState, err := blocks.ProcessAttesterSlashings(tt.Pre, body)
// Note: This doesn't test anything worthwhile. It essentially tests
// that *any* error has occurred, not any specific error.
if tt.Post == nil {
if err == nil {
t.Fatal("Did not fail when expected")
}
return
}
testFolders, testsFolderPath := testutil.TestFolders(t, config, "operations/attester_slashing/pyspec_tests")
for _, folder := range testFolders {
t.Run(folder.Name(), func(t *testing.T) {
folderPath := path.Join(testsFolderPath, folder.Name())
attSlashingFile, err := testutil.BazelFileBytes(folderPath, "attester_slashing.ssz")
if err != nil {
t.Fatal(err)
}
if !proto.Equal(postState, tt.Post) {
diff, _ := messagediff.PrettyDiff(postState, tt.Post)
t.Log(diff)
t.Fatal("Post state does not match expected")
attSlashing := &ethpb.AttesterSlashing{}
if err := ssz.Unmarshal(attSlashingFile, attSlashing); err != nil {
t.Fatalf("Failed to unmarshal: %v", err)
}
body := &ethpb.BeaconBlockBody{AttesterSlashings: []*ethpb.AttesterSlashing{attSlashing}}
testutil.RunBlockOperationTest(t, folderPath, body, blocks.ProcessAttesterSlashings)
})
}
}

View File

@@ -2,14 +2,8 @@ package spectest
import (
"testing"
"github.com/bazelbuild/rules_go/go/tools/bazel"
)
func TestBlockHeaderMainnet(t *testing.T) {
filepath, err := bazel.Runfile(blkHeaderPrefix + "block_header_mainnet.yaml")
if err != nil {
t.Fatal(err)
}
runBlockHeaderTest(t, filepath)
runBlockHeaderTest(t, "mainnet")
}

View File

@@ -2,14 +2,8 @@ package spectest
import (
"testing"
"github.com/bazelbuild/rules_go/go/tools/bazel"
)
func TestBlockHeaderMinimal(t *testing.T) {
filepath, err := bazel.Runfile(blkHeaderPrefix + "block_header_minimal.yaml")
if err != nil {
t.Fatal(err)
}
runBlockHeaderTest(t, filepath)
runBlockHeaderTest(t, "minimal")
}

View File

@@ -2,63 +2,87 @@ package spectest
import (
"io/ioutil"
"path"
"strings"
"testing"
"github.com/bazelbuild/rules_go/go/tools/bazel"
"github.com/gogo/protobuf/proto"
"github.com/prysmaticlabs/go-ssz"
"github.com/prysmaticlabs/prysm/beacon-chain/core/blocks"
"github.com/prysmaticlabs/prysm/beacon-chain/core/helpers"
pb "github.com/prysmaticlabs/prysm/proto/beacon/p2p/v1"
ethpb "github.com/prysmaticlabs/prysm/proto/eth/v1alpha1"
"github.com/prysmaticlabs/prysm/shared/params/spectest"
"github.com/prysmaticlabs/prysm/shared/testutil"
"gopkg.in/d4l3k/messagediff.v1"
)
const blkHeaderPrefix = "tests/operations/block_header/"
// Block header test is actually a full block processing test. Not sure why it
// was named "block_header". The note in the test format readme says "Note that
// block_header is not strictly an operation (and is a full Block), but
// processed in the same manner, and hence included here."
func runBlockHeaderTest(t *testing.T, filename string) {
file, err := ioutil.ReadFile(filename)
if err != nil {
t.Fatalf("Failed to read file: %v", err)
}
test := &BlockOperationTest{}
if err := testutil.UnmarshalYaml(file, test); err != nil {
t.Fatalf("Failed to unmarshal: %v", err)
}
if err := spectest.SetConfig(test.Config); err != nil {
func runBlockHeaderTest(t *testing.T, config string) {
if err := spectest.SetConfig(config); err != nil {
t.Fatal(err)
}
if len(test.TestCases) == 0 {
t.Fatal("No tests!")
}
for _, tt := range test.TestCases {
t.Run(tt.Description, func(t *testing.T) {
testFolders, testsFolderPath := testutil.TestFolders(t, config, "operations/block_header/pyspec_tests")
for _, folder := range testFolders {
t.Run(folder.Name(), func(t *testing.T) {
helpers.ClearAllCaches()
post, err := blocks.ProcessBlockHeader(tt.Pre, tt.Block)
if tt.Post == nil {
// Note: This doesn't test anything worthwhile. It essentially tests
// that *any* error has occurred, not any specific error.
if err == nil {
t.Fatal("did not fail when expected")
}
return
}
blockFile, err := testutil.BazelFileBytes(testsFolderPath, folder.Name(), "block.ssz")
if err != nil {
t.Fatal(err)
}
block := &ethpb.BeaconBlock{}
if err := ssz.Unmarshal(blockFile, block); err != nil {
t.Fatalf("Failed to unmarshal: %v", err)
}
if !proto.Equal(post, tt.Post) {
diff, _ := messagediff.PrettyDiff(post, tt.Post)
t.Log(diff)
t.Fatal("Post state does not match expected")
preBeaconStateFile, err := testutil.BazelFileBytes(testsFolderPath, folder.Name(), "pre.ssz")
if err != nil {
t.Fatal(err)
}
preBeaconState := &pb.BeaconState{}
if err := ssz.Unmarshal(preBeaconStateFile, preBeaconState); err != nil {
t.Fatalf("Failed to unmarshal: %v", err)
}
// If the post.ssz is not present, it means the test should fail on our end.
postSSZFilepath, err := bazel.Runfile(path.Join(testsFolderPath, folder.Name(), "post.ssz"))
postSSZExists := true
if err != nil && strings.Contains(err.Error(), "could not locate file") {
postSSZExists = false
} else if err != nil {
t.Fatal(err)
}
beaconState, err := blocks.ProcessBlockHeader(preBeaconState, block)
if postSSZExists {
if err != nil {
t.Fatalf("Unexpected error: %v", err)
}
postBeaconStateFile, err := ioutil.ReadFile(postSSZFilepath)
if err != nil {
t.Fatal(err)
}
postBeaconState := &pb.BeaconState{}
if err := ssz.Unmarshal(postBeaconStateFile, postBeaconState); err != nil {
t.Fatalf("Failed to unmarshal: %v", err)
}
if !proto.Equal(beaconState, postBeaconState) {
diff, _ := messagediff.PrettyDiff(beaconState, postBeaconState)
t.Log(diff)
t.Fatal("Post state does not match expected")
}
} else {
// Note: This doesn't test anything worthwhile. It essentially tests
// that *any* error has occurred, not any specific error.
if err == nil {
t.Fatal("Did not fail when expected")
}
t.Logf("Expected failure; failure reason = %v", err)
return
}
})
}

View File

@@ -1,31 +0,0 @@
// Code generated by yaml_to_go. DO NOT EDIT.
// source: voluntary_exit_minimal.yaml
package spectest
import (
pb "github.com/prysmaticlabs/prysm/proto/beacon/p2p/v1"
ethpb "github.com/prysmaticlabs/prysm/proto/eth/v1alpha1"
)
type BlockOperationTest struct {
Title string `json:"title"`
Summary string `json:"summary"`
ForksTimeline string `json:"forks_timeline"`
Forks []string `json:"forks"`
Config string `json:"config"`
Runner string `json:"runner"`
Handler string `json:"handler"`
TestCases []struct {
BlsSetting uint64 `json:"bls_setting,omitempty"`
Description string `json:"description"`
Pre *pb.BeaconState `json:"pre"`
VoluntaryExit *ethpb.VoluntaryExit `json:"voluntary_exit"`
ProposerSlashing *ethpb.ProposerSlashing `json:"proposer_slashing"`
AttesterSlashing *ethpb.AttesterSlashing `json:"attester_slashing"`
Deposit *ethpb.Deposit `json:"deposit"`
Transfer *ethpb.Transfer `json:"transfer"`
Block *ethpb.BeaconBlock `json:"block"`
Post *pb.BeaconState `json:"post"`
} `json:"test_cases"`
}

View File

@@ -5,5 +5,5 @@ import (
)
func TestBlockProcessingMainnetYaml(t *testing.T) {
runBlockProcessingTest(t, "sanity_blocks_mainnet.yaml")
runBlockProcessingTest(t, "mainnet")
}

View File

@@ -5,7 +5,5 @@ import (
)
func TestBlockProcessingMinimalYaml(t *testing.T) {
t.Skip("This test suite requires --define ssz=minimal to be provided and there isn't a great way to do that without breaking //... See https://github.com/prysmaticlabs/prysm/issues/3066")
runBlockProcessingTest(t, "sanity_blocks_minimal.yaml")
runBlockProcessingTest(t, "minimal")
}

View File

@@ -2,67 +2,103 @@ package spectest
import (
"context"
"fmt"
"io/ioutil"
"path"
"strings"
"testing"
"github.com/bazelbuild/rules_go/go/tools/bazel"
"github.com/gogo/protobuf/proto"
"github.com/prysmaticlabs/prysm/beacon-chain/core/blocks"
"github.com/prysmaticlabs/go-ssz"
"github.com/prysmaticlabs/prysm/beacon-chain/core/helpers"
"github.com/prysmaticlabs/prysm/beacon-chain/core/state"
pb "github.com/prysmaticlabs/prysm/proto/beacon/p2p/v1"
ethpb "github.com/prysmaticlabs/prysm/proto/eth/v1alpha1"
"github.com/prysmaticlabs/prysm/shared/params/spectest"
"github.com/prysmaticlabs/prysm/shared/testutil"
"gopkg.in/d4l3k/messagediff.v1"
)
func runBlockProcessingTest(t *testing.T, filename string) {
filepath, err := bazel.Runfile("tests/sanity/blocks/" + filename)
if err != nil {
func runBlockProcessingTest(t *testing.T, config string) {
if err := spectest.SetConfig(config); err != nil {
t.Fatal(err)
}
file, err := ioutil.ReadFile(filepath)
if err != nil {
t.Fatalf("Could not load file %v", err)
}
s := &BlocksMainnet{}
if err := testutil.UnmarshalYaml(file, s); err != nil {
t.Fatalf("Failed to Unmarshal: %v", err)
}
if err := spectest.SetConfig(s.Config); err != nil {
t.Fatalf("Could not set config: %v", err)
}
if len(s.TestCases) == 0 {
t.Fatal("No tests!")
}
for _, tt := range s.TestCases {
t.Run(tt.Description, func(t *testing.T) {
ctx := context.Background()
testFolders, testsFolderPath := testutil.TestFolders(t, config, "sanity/blocks/pyspec_tests")
for _, folder := range testFolders {
t.Run(folder.Name(), func(t *testing.T) {
helpers.ClearAllCaches()
blocks.ClearEth1DataVoteCache()
s := tt.Pre
for _, b := range tt.Blocks {
tt.Pre, err = state.ExecuteStateTransition(ctx, tt.Pre, b)
if tt.Post == nil {
if err == nil {
t.Fatal("Transition did not fail despite being invalid")
}
continue
}
if err != nil {
t.Fatalf("Transition failed with block at slot %d: %v", b.Slot, err)
}
preBeaconStateFile, err := testutil.BazelFileBytes(testsFolderPath, folder.Name(), "pre.ssz")
if err != nil {
t.Fatal(err)
}
if tt.Post != nil {
if !proto.Equal(s, tt.Post) {
diff, _ := messagediff.PrettyDiff(s, tt.Post)
beaconState := &pb.BeaconState{}
if err := ssz.Unmarshal(preBeaconStateFile, beaconState); err != nil {
t.Fatalf("Failed to unmarshal: %v", err)
}
file, err := testutil.BazelFileBytes(testsFolderPath, folder.Name(), "meta.yaml")
if err != nil {
t.Fatal(err)
}
metaYaml := &SanityConfig{}
if err := testutil.UnmarshalYaml(file, metaYaml); err != nil {
t.Fatalf("Failed to Unmarshal: %v", err)
}
var transitionError error
for i := 0; i < metaYaml.BlocksCount; i++ {
filename := fmt.Sprintf("blocks_%d.ssz", i)
blockFile, err := testutil.BazelFileBytes(testsFolderPath, folder.Name(), filename)
if err != nil {
t.Fatal(err)
}
block := &ethpb.BeaconBlock{}
if err := ssz.Unmarshal(blockFile, block); err != nil {
t.Fatalf("Failed to unmarshal: %v", err)
}
beaconState, transitionError = state.ExecuteStateTransition(context.Background(), beaconState, block)
}
// If the post.ssz is not present, it means the test should fail on our end.
postSSZFilepath, readError := bazel.Runfile(path.Join(testsFolderPath, folder.Name(), "post.ssz"))
postSSZExists := true
if readError != nil && strings.Contains(readError.Error(), "could not locate file") {
postSSZExists = false
} else if readError != nil {
t.Fatal(readError)
}
if postSSZExists {
if transitionError != nil {
t.Fatalf("Unexpected error: %v", transitionError)
}
postBeaconStateFile, err := ioutil.ReadFile(postSSZFilepath)
if err != nil {
t.Fatal(err)
}
postBeaconState := &pb.BeaconState{}
if err := ssz.Unmarshal(postBeaconStateFile, postBeaconState); err != nil {
t.Fatalf("Failed to unmarshal: %v", err)
}
if !proto.Equal(beaconState, postBeaconState) {
diff, _ := messagediff.PrettyDiff(beaconState, postBeaconState)
t.Log(diff)
t.Fatal("Post state does not match expected")
}
} else {
// Note: This doesn't test anything worthwhile. It essentially tests
// that *any* error has occurred, not any specific error.
if transitionError == nil {
t.Fatal("Did not fail when expected")
}
t.Logf("Expected failure; failure reason = %v", transitionError)
return
}
})
}

View File

@@ -0,0 +1,6 @@
package spectest
// SanityConfig --
type SanityConfig struct {
BlocksCount int `json:"blocks_count"`
}

View File

@@ -1,25 +0,0 @@
// Code generated by yaml_to_go. DO NOT EDIT.
// source: sanity_blocks_mainnet.yaml
package spectest
import (
pb "github.com/prysmaticlabs/prysm/proto/beacon/p2p/v1"
ethpb "github.com/prysmaticlabs/prysm/proto/eth/v1alpha1"
)
type BlocksMainnet struct {
Title string `json:"title"`
Summary string `json:"summary"`
ForksTimeline string `json:"forks_timeline"`
Forks []string `json:"forks"`
Config string `json:"config"`
Runner string `json:"runner"`
Handler string `json:"handler"`
TestCases []struct {
Description string `json:"description"`
Pre *pb.BeaconState `json:"pre"`
Blocks []*ethpb.BeaconBlock `json:"blocks"`
Post *pb.BeaconState `json:"post"`
} `json:"test_cases"`
}

View File

@@ -1,25 +0,0 @@
// Code generated by yaml_to_go. DO NOT EDIT.
// source: sanity_blocks_minimal.yaml
package spectest
import (
pb "github.com/prysmaticlabs/prysm/proto/beacon/p2p/v1"
ethpb "github.com/prysmaticlabs/prysm/proto/eth/v1alpha1"
)
type BlocksMinimal struct {
Title string `json:"title"`
Summary string `json:"summary"`
ForksTimeline string `json:"forks_timeline"`
Forks []string `json:"forks"`
Config string `json:"config"`
Runner string `json:"runner"`
Handler string `json:"handler"`
TestCases []struct {
Description string `json:"description"`
Pre *pb.BeaconState `json:"pre"`
Blocks []*ethpb.BeaconBlock `json:"blocks"`
Post *pb.BeaconState `json:"post"`
} `json:"test_cases"`
}

View File

@@ -2,14 +2,8 @@ package spectest
import (
"testing"
"github.com/bazelbuild/rules_go/go/tools/bazel"
)
func TestDepositMainnetYaml(t *testing.T) {
filepath, err := bazel.Runfile(depositPrefix + "deposit_mainnet.yaml")
if err != nil {
t.Fatal(err)
}
runDepositTest(t, filepath)
runDepositTest(t, "mainnet")
}

View File

@@ -2,14 +2,8 @@ package spectest
import (
"testing"
"github.com/bazelbuild/rules_go/go/tools/bazel"
)
func TestDepositMinimalYaml(t *testing.T) {
filepath, err := bazel.Runfile(depositPrefix + "deposit_minimal.yaml")
if err != nil {
t.Fatal(err)
}
runDepositTest(t, filepath)
runDepositTest(t, "minimal")
}

View File

@@ -1,58 +1,36 @@
package spectest
import (
"io/ioutil"
"reflect"
"path"
"testing"
"github.com/prysmaticlabs/go-ssz"
"github.com/prysmaticlabs/prysm/beacon-chain/core/blocks"
"github.com/prysmaticlabs/prysm/beacon-chain/core/helpers"
"github.com/prysmaticlabs/prysm/beacon-chain/core/state/stateutils"
ethpb "github.com/prysmaticlabs/prysm/proto/eth/v1alpha1"
"github.com/prysmaticlabs/prysm/shared/params/spectest"
"github.com/prysmaticlabs/prysm/shared/testutil"
)
const depositPrefix = "tests/operations/deposit/"
func runDepositTest(t *testing.T, filename string) {
file, err := ioutil.ReadFile(filename)
if err != nil {
t.Fatalf("Could not load file %v", err)
}
test := &BlockOperationTest{}
if err := testutil.UnmarshalYaml(file, test); err != nil {
t.Fatalf("Failed to Unmarshal: %v", err)
}
if err := spectest.SetConfig(test.Config); err != nil {
func runDepositTest(t *testing.T, config string) {
if err := spectest.SetConfig(config); err != nil {
t.Fatal(err)
}
if len(test.TestCases) == 0 {
t.Fatal("No tests!")
}
for _, tt := range test.TestCases {
helpers.ClearAllCaches()
t.Run(tt.Description, func(t *testing.T) {
valMap := stateutils.ValidatorIndexMap(tt.Pre)
post, err := blocks.ProcessDeposit(tt.Pre, tt.Deposit, valMap)
// Note: This doesn't test anything worthwhile. It essentially tests
// that *any* error has occurred, not any specific error.
if tt.Post == nil {
if err == nil {
t.Fatal("Did not fail when expected")
}
return
}
testFolders, testsFolderPath := testutil.TestFolders(t, config, "operations/deposit/pyspec_tests")
for _, folder := range testFolders {
t.Run(folder.Name(), func(t *testing.T) {
folderPath := path.Join(testsFolderPath, folder.Name())
depositFile, err := testutil.BazelFileBytes(folderPath, "deposit.ssz")
if err != nil {
t.Fatal(err)
}
if !reflect.DeepEqual(post, tt.Post) {
t.Error("Post state does not match expected")
deposit := &ethpb.Deposit{}
if err := ssz.Unmarshal(depositFile, deposit); err != nil {
t.Fatalf("Failed to unmarshal: %v", err)
}
body := &ethpb.BeaconBlockBody{Deposits: []*ethpb.Deposit{deposit}}
testutil.RunBlockOperationTest(t, folderPath, body, blocks.ProcessDeposits)
})
}
}

View File

@@ -2,14 +2,8 @@ package spectest
import (
"testing"
"github.com/bazelbuild/rules_go/go/tools/bazel"
)
func TestProposerSlashingMainnet(t *testing.T) {
filepath, err := bazel.Runfile(proposerSlashingPrefix + "proposer_slashing_mainnet.yaml")
if err != nil {
t.Fatal(err)
}
runProposerSlashingTest(t, filepath)
runProposerSlashingTest(t, "mainnet")
}

View File

@@ -2,14 +2,8 @@ package spectest
import (
"testing"
"github.com/bazelbuild/rules_go/go/tools/bazel"
)
func TestProposerSlashingMinimal(t *testing.T) {
filepath, err := bazel.Runfile(proposerSlashingPrefix + "proposer_slashing_minimal.yaml")
if err != nil {
t.Fatal(err)
}
runProposerSlashingTest(t, filepath)
runProposerSlashingTest(t, "minimal")
}

View File

@@ -1,63 +1,36 @@
package spectest
import (
"io/ioutil"
"path"
"testing"
"github.com/gogo/protobuf/proto"
"github.com/prysmaticlabs/go-ssz"
"github.com/prysmaticlabs/prysm/beacon-chain/core/blocks"
"github.com/prysmaticlabs/prysm/beacon-chain/core/helpers"
ethpb "github.com/prysmaticlabs/prysm/proto/eth/v1alpha1"
"github.com/prysmaticlabs/prysm/shared/params/spectest"
"github.com/prysmaticlabs/prysm/shared/testutil"
"gopkg.in/d4l3k/messagediff.v1"
)
const proposerSlashingPrefix = "tests/operations/proposer_slashing/"
func runProposerSlashingTest(t *testing.T, filename string) {
file, err := ioutil.ReadFile(filename)
if err != nil {
t.Fatalf("Could not load file %v", err)
}
test := &BlockOperationTest{}
if err := testutil.UnmarshalYaml(file, test); err != nil {
t.Fatalf("Failed to Unmarshal: %v", err)
}
if err := spectest.SetConfig(test.Config); err != nil {
func runProposerSlashingTest(t *testing.T, config string) {
if err := spectest.SetConfig(config); err != nil {
t.Fatal(err)
}
if len(test.TestCases) == 0 {
t.Fatal("No tests!")
}
for _, tt := range test.TestCases {
t.Run(tt.Description, func(t *testing.T) {
helpers.ClearAllCaches()
body := &ethpb.BeaconBlockBody{ProposerSlashings: []*ethpb.ProposerSlashing{tt.ProposerSlashing}}
postState, err := blocks.ProcessProposerSlashings(tt.Pre, body)
// Note: This doesn't test anything worthwhile. It essentially tests
// that *any* error has occurred, not any specific error.
if tt.Post == nil {
if err == nil {
t.Fatal("Did not fail when expected")
}
return
}
testFolders, testsFolderPath := testutil.TestFolders(t, config, "operations/proposer_slashing/pyspec_tests")
for _, folder := range testFolders {
t.Run(folder.Name(), func(t *testing.T) {
folderPath := path.Join(testsFolderPath, folder.Name())
proposerSlashingFile, err := testutil.BazelFileBytes(folderPath, "proposer_slashing.ssz")
if err != nil {
t.Fatal(err)
}
if !proto.Equal(postState, tt.Post) {
diff, _ := messagediff.PrettyDiff(postState, tt.Post)
t.Log(diff)
t.Fatal("Post state does not match expected")
proposerSlashing := &ethpb.ProposerSlashing{}
if err := ssz.Unmarshal(proposerSlashingFile, proposerSlashing); err != nil {
t.Fatalf("Failed to unmarshal: %v", err)
}
body := &ethpb.BeaconBlockBody{ProposerSlashings: []*ethpb.ProposerSlashing{proposerSlashing}}
testutil.RunBlockOperationTest(t, folderPath, body, blocks.ProcessProposerSlashings)
})
}
}

View File

@@ -1,16 +0,0 @@
package spectest
import (
"testing"
"github.com/bazelbuild/rules_go/go/tools/bazel"
)
func TestTransferMainnet(t *testing.T) {
t.Skip("Transfer tests are disabled. See https://github.com/ethereum/eth2.0-specs/pull/1238#issuecomment-507054595")
filepath, err := bazel.Runfile(transferPrefix + "transfer_mainnet.yaml")
if err != nil {
t.Fatal(err)
}
runTransferTest(t, filepath)
}

View File

@@ -1,16 +0,0 @@
package spectest
import (
"testing"
"github.com/bazelbuild/rules_go/go/tools/bazel"
)
func TestTransferMinimal(t *testing.T) {
t.Skip("Transfer tests are disabled. See https://github.com/ethereum/eth2.0-specs/pull/1238#issuecomment-507054595")
filepath, err := bazel.Runfile(transferPrefix + "transfer_minimal.yaml")
if err != nil {
t.Fatal(err)
}
runTransferTest(t, filepath)
}

View File

@@ -1,63 +0,0 @@
package spectest
import (
"io/ioutil"
"testing"
"github.com/gogo/protobuf/proto"
"github.com/prysmaticlabs/prysm/beacon-chain/core/blocks"
"github.com/prysmaticlabs/prysm/beacon-chain/core/helpers"
ethpb "github.com/prysmaticlabs/prysm/proto/eth/v1alpha1"
"github.com/prysmaticlabs/prysm/shared/params/spectest"
"github.com/prysmaticlabs/prysm/shared/testutil"
"gopkg.in/d4l3k/messagediff.v1"
)
const transferPrefix = "tests/operations/transfer/"
func runTransferTest(t *testing.T, filename string) {
file, err := ioutil.ReadFile(filename)
if err != nil {
t.Fatalf("Could not load file %v", err)
}
test := &BlockOperationTest{}
if err := testutil.UnmarshalYaml(file, test); err != nil {
t.Fatalf("Failed to Unmarshal: %v", err)
}
if err := spectest.SetConfig(test.Config); err != nil {
t.Fatal(err)
}
if len(test.TestCases) == 0 {
t.Fatal("No tests!")
}
for _, tt := range test.TestCases {
t.Run(tt.Description, func(t *testing.T) {
helpers.ClearAllCaches()
body := &ethpb.BeaconBlockBody{Transfers: []*ethpb.Transfer{tt.Transfer}}
postState, err := blocks.ProcessTransfers(tt.Pre, body)
// Note: This doesn't test anything worthwhile. It essentially tests
// that *any* error has occurred, not any specific error.
if tt.Post == nil {
if err == nil {
t.Fatal("Did not fail when expected")
}
return
}
if err != nil {
t.Fatal(err)
}
if !proto.Equal(postState, tt.Post) {
diff, _ := messagediff.PrettyDiff(postState, tt.Post)
t.Log(diff)
t.Fatal("Post state does not match expected")
}
})
}
}

View File

@@ -2,14 +2,8 @@ package spectest
import (
"testing"
"github.com/bazelbuild/rules_go/go/tools/bazel"
)
func TestVoluntaryExitMainnet(t *testing.T) {
filepath, err := bazel.Runfile(exitPrefix + "voluntary_exit_mainnet.yaml")
if err != nil {
t.Fatal(err)
}
runVoluntaryExitTest(t, filepath)
runVoluntaryExitTest(t, "mainnet")
}

View File

@@ -2,14 +2,8 @@ package spectest
import (
"testing"
"github.com/bazelbuild/rules_go/go/tools/bazel"
)
func TestVoluntaryExitMinimal(t *testing.T) {
filepath, err := bazel.Runfile(exitPrefix + "voluntary_exit_mainnet.yaml")
if err != nil {
t.Fatal(err)
}
runVoluntaryExitTest(t, filepath)
runVoluntaryExitTest(t, "minimal")
}

View File

@@ -1,63 +1,36 @@
package spectest
import (
"io/ioutil"
"path"
"testing"
"github.com/gogo/protobuf/proto"
"github.com/prysmaticlabs/go-ssz"
"github.com/prysmaticlabs/prysm/beacon-chain/core/blocks"
"github.com/prysmaticlabs/prysm/beacon-chain/core/helpers"
ethpb "github.com/prysmaticlabs/prysm/proto/eth/v1alpha1"
"github.com/prysmaticlabs/prysm/shared/params/spectest"
"github.com/prysmaticlabs/prysm/shared/testutil"
"gopkg.in/d4l3k/messagediff.v1"
)
const exitPrefix = "tests/operations/voluntary_exit/"
func runVoluntaryExitTest(t *testing.T, filename string) {
file, err := ioutil.ReadFile(filename)
if err != nil {
t.Fatalf("Could not load file %v", err)
}
test := &BlockOperationTest{}
if err := testutil.UnmarshalYaml(file, test); err != nil {
t.Fatalf("Failed to Unmarshal: %v", err)
}
if err := spectest.SetConfig(test.Config); err != nil {
func runVoluntaryExitTest(t *testing.T, config string) {
if err := spectest.SetConfig(config); err != nil {
t.Fatal(err)
}
if len(test.TestCases) == 0 {
t.Fatal("No tests!")
}
for _, tt := range test.TestCases {
t.Run(tt.Description, func(t *testing.T) {
helpers.ClearAllCaches()
body := &ethpb.BeaconBlockBody{VoluntaryExits: []*ethpb.VoluntaryExit{tt.VoluntaryExit}}
postState, err := blocks.ProcessVoluntaryExits(tt.Pre, body)
// Note: This doesn't test anything worthwhile. It essentially tests
// that *any* error has occurred, not any specific error.
if tt.Post == nil {
if err == nil {
t.Fatal("Did not fail when expected")
}
return
}
testFolders, testsFolderPath := testutil.TestFolders(t, config, "operations/voluntary_exit/pyspec_tests")
for _, folder := range testFolders {
t.Run(folder.Name(), func(t *testing.T) {
folderPath := path.Join(testsFolderPath, folder.Name())
exitFile, err := testutil.BazelFileBytes(folderPath, "voluntary_exit.ssz")
if err != nil {
t.Fatal(err)
}
if !proto.Equal(postState, tt.Post) {
diff, _ := messagediff.PrettyDiff(postState, tt.Post)
t.Log(diff)
t.Fatal("Post state does not match expected")
voluntaryExit := &ethpb.VoluntaryExit{}
if err := ssz.Unmarshal(exitFile, voluntaryExit); err != nil {
t.Fatalf("Failed to unmarshal: %v", err)
}
body := &ethpb.BeaconBlockBody{VoluntaryExits: []*ethpb.VoluntaryExit{voluntaryExit}}
testutil.RunBlockOperationTest(t, folderPath, body, blocks.ProcessVoluntaryExits)
})
}
}

View File

@@ -46,7 +46,7 @@ type MatchedAttestations struct {
// def get_matching_head_attestations(state: BeaconState, epoch: Epoch) -> List[PendingAttestation]:
// return [
// a for a in get_matching_source_attestations(state, epoch)
// if a.data.beacon_block_root == get_block_root_at_slot(state, a.data.slot)
// if a.data.beacon_block_root == get_block_root_at_slot(state, get_attestation_data_slot(state, a.data))
// ]
func MatchAttestations(state *pb.BeaconState, epoch uint64) (*MatchedAttestations, error) {
currentEpoch := helpers.CurrentEpoch(state)
@@ -443,8 +443,6 @@ func ProcessSlashings(state *pb.BeaconState) (*pb.BeaconState, error) {
// HALF_INCREMENT = EFFECTIVE_BALANCE_INCREMENT // 2
// if balance < validator.effective_balance or validator.effective_balance + 3 * HALF_INCREMENT < balance:
// validator.effective_balance = min(balance - balance % EFFECTIVE_BALANCE_INCREMENT, MAX_EFFECTIVE_BALANCE)
// # Update start shard
// state.start_shard = Shard((state.start_shard + get_shard_delta(state, current_epoch)) % SHARD_COUNT)
// # Set active index root
// index_epoch = Epoch(next_epoch + ACTIVATION_EXIT_DELAY)
// index_root_position = index_epoch % EPOCHS_PER_HISTORICAL_VECTOR
@@ -461,6 +459,8 @@ func ProcessSlashings(state *pb.BeaconState) (*pb.BeaconState, error) {
// if next_epoch % (SLOTS_PER_HISTORICAL_ROOT // SLOTS_PER_EPOCH) == 0:
// historical_batch = HistoricalBatch(block_roots=state.block_roots, state_roots=state.state_roots)
// state.historical_roots.append(hash_tree_root(historical_batch))
// # Update start shard
// state.start_shard = Shard((state.start_shard + get_shard_delta(state, current_epoch)) % SHARD_COUNT)
// # Rotate current/previous epoch attestations
// state.previous_epoch_attestations = state.current_epoch_attestations
// state.current_epoch_attestations = []
@@ -485,14 +485,6 @@ func ProcessFinalUpdates(state *pb.BeaconState) (*pb.BeaconState, error) {
}
}
// Update start shard.
delta, err := helpers.ShardDelta(state, currentEpoch)
if err != nil {
return nil, errors.Wrap(err, "could not get shard delta")
}
state.StartShard = (state.StartShard + delta) %
params.BeaconConfig().ShardCount
// Set active index root.
// index_epoch = Epoch(next_epoch + ACTIVATION_EXIT_DELAY)
// index_root_position = index_epoch % EPOCHS_PER_HISTORICAL_VECTOR
@@ -540,6 +532,13 @@ func ProcessFinalUpdates(state *pb.BeaconState) (*pb.BeaconState, error) {
state.HistoricalRoots = append(state.HistoricalRoots, batchRoot[:])
}
// Update start shard.
delta, err := helpers.ShardDelta(state, currentEpoch)
if err != nil {
return nil, errors.Wrap(err, "could not get shard delta")
}
state.StartShard = (state.StartShard + delta) % params.BeaconConfig().ShardCount
// Rotate current and previous epoch attestations.
state.PreviousEpochAttestations = state.CurrentEpochAttestations
state.CurrentEpochAttestations = []*pb.PendingAttestation{}

View File

@@ -1,12 +1,4 @@
load("@io_bazel_rules_go//go:def.bzl", "go_library", "go_test")
go_library(
name = "go_default_library",
srcs = ["epoch_processing_test.yaml.go"],
importpath = "github.com/prysmaticlabs/prysm/beacon-chain/core/epoch/spectest",
visibility = ["//beacon-chain:__subpackages__"],
deps = ["//proto/beacon/p2p/v1:go_default_library"],
)
load("@io_bazel_rules_go//go:def.bzl", "go_test")
test_suite(
name = "go_default_test",
@@ -25,9 +17,8 @@ go_test(
exclude = ["*_minimal_test.go"],
),
data = [
"@eth2_spec_tests//:test_data",
"@eth2_spec_tests_mainnet//:test_data",
],
embed = [":go_default_library"],
shard_count = 4,
tags = [
"spectest",
@@ -39,6 +30,7 @@ go_test(
"//shared/params/spectest:go_default_library",
"//shared/testutil:go_default_library",
"@com_github_gogo_protobuf//proto:go_default_library",
"@com_github_prysmaticlabs_go_ssz//:go_default_library",
"@in_gopkg_d4l3k_messagediff_v1//:go_default_library",
"@io_bazel_rules_go//go/tools/bazel:go_default_library",
],
@@ -52,9 +44,8 @@ go_test(
exclude = ["*_mainnet_test.go"],
),
data = [
"@eth2_spec_tests//:test_data",
"@eth2_spec_tests_minimal//:test_data",
],
embed = [":go_default_library"],
tags = [
"spectest",
],

View File

@@ -2,16 +2,8 @@ package spectest
import (
"testing"
"github.com/bazelbuild/rules_go/go/tools/bazel"
"github.com/prysmaticlabs/prysm/beacon-chain/core/helpers"
)
func TestCrosslinksProcessingMainnet(t *testing.T) {
helpers.ClearAllCaches()
filepath, err := bazel.Runfile(crosslinkPrefix + "crosslinks_mainnet.yaml")
if err != nil {
t.Fatal(err)
}
runCrosslinkProcessingTests(t, filepath)
runCrosslinkProcessingTests(t, "mainnet")
}

View File

@@ -2,14 +2,8 @@ package spectest
import (
"testing"
"github.com/bazelbuild/rules_go/go/tools/bazel"
)
func TestCrosslinksProcessingMinimal(t *testing.T) {
filepath, err := bazel.Runfile(crosslinkPrefix + "crosslinks_minimal.yaml")
if err != nil {
t.Fatal(err)
}
runCrosslinkProcessingTests(t, filepath)
runCrosslinkProcessingTests(t, "minimal")
}

View File

@@ -1,47 +1,33 @@
package spectest
import (
"io/ioutil"
"reflect"
"path"
"testing"
"github.com/prysmaticlabs/prysm/beacon-chain/core/epoch"
pb "github.com/prysmaticlabs/prysm/proto/beacon/p2p/v1"
"github.com/prysmaticlabs/prysm/shared/params/spectest"
"github.com/prysmaticlabs/prysm/shared/testutil"
)
const crosslinkPrefix = "tests/epoch_processing/crosslinks/"
func runCrosslinkProcessingTests(t *testing.T, filename string) {
file, err := ioutil.ReadFile(filename)
if err != nil {
t.Fatalf("Could not load file %v", err)
}
s := &EpochProcessingTest{}
if err := testutil.UnmarshalYaml(file, s); err != nil {
t.Fatalf("Failed to Unmarshal: %v", err)
}
if err := spectest.SetConfig(s.Config); err != nil {
func runCrosslinkProcessingTests(t *testing.T, config string) {
if err := spectest.SetConfig(config); err != nil {
t.Fatal(err)
}
if len(s.TestCases) == 0 {
t.Fatal("No tests!")
}
for _, tt := range s.TestCases {
t.Run(tt.Description, func(t *testing.T) {
postState, err := epoch.ProcessCrosslinks(tt.Pre)
if err != nil {
t.Fatal(err)
}
if !reflect.DeepEqual(postState, tt.Post) {
t.Error("Did not get expected state")
}
testFolders, testsFolderPath := testutil.TestFolders(t, config, "epoch_processing/crosslinks/pyspec_tests")
for _, folder := range testFolders {
t.Run(folder.Name(), func(t *testing.T) {
folderPath := path.Join(testsFolderPath, folder.Name())
testutil.RunEpochOperationTest(t, folderPath, processCrosslinksWrapper)
})
}
}
func processCrosslinksWrapper(t *testing.T, state *pb.BeaconState) (*pb.BeaconState, error) {
state, err := epoch.ProcessCrosslinks(state)
if err != nil {
t.Fatalf("could not process crosslinks: %v", err)
}
return state, nil
}

View File

@@ -1,19 +0,0 @@
// Code generated by yaml_to_go. DO NOT EDIT.
package spectest
import pb "github.com/prysmaticlabs/prysm/proto/beacon/p2p/v1"
type EpochProcessingTest struct {
Title string `json:"title"`
Summary string `json:"summary"`
ForksTimeline string `json:"forks_timeline"`
Forks []string `json:"forks"`
Config string `json:"config"`
Runner string `json:"runner"`
Handler string `json:"handler"`
TestCases []struct {
Description string `json:"description"`
Pre *pb.BeaconState `json:"pre"`
Post *pb.BeaconState `json:"post"`
} `json:"test_cases"`
}

View File

@@ -2,14 +2,8 @@ package spectest
import (
"testing"
"github.com/bazelbuild/rules_go/go/tools/bazel"
)
func TestFinalUpdatesMainnet(t *testing.T) {
filepath, err := bazel.Runfile(finalUpdatesPrefix + "final_updates_mainnet.yaml")
if err != nil {
t.Fatal(err)
}
runFinalUpdatesTests(t, filepath)
runFinalUpdatesTests(t, "mainnet")
}

View File

@@ -2,14 +2,8 @@ package spectest
import (
"testing"
"github.com/bazelbuild/rules_go/go/tools/bazel"
)
func TestFinalUpdatesMinimal(t *testing.T) {
filepath, err := bazel.Runfile(finalUpdatesPrefix + "final_updates_minimal.yaml")
if err != nil {
t.Fatal(err)
}
runFinalUpdatesTests(t, filepath)
runFinalUpdatesTests(t, "minimal")
}

View File

@@ -1,54 +1,33 @@
package spectest
import (
"io/ioutil"
"reflect"
"path"
"testing"
"github.com/prysmaticlabs/prysm/beacon-chain/core/epoch"
"github.com/prysmaticlabs/prysm/beacon-chain/core/helpers"
pb "github.com/prysmaticlabs/prysm/proto/beacon/p2p/v1"
"github.com/prysmaticlabs/prysm/shared/params/spectest"
"github.com/prysmaticlabs/prysm/shared/testutil"
"gopkg.in/d4l3k/messagediff.v1"
)
const finalUpdatesPrefix = "tests/epoch_processing/final_updates/"
func runFinalUpdatesTests(t *testing.T, filename string) {
file, err := ioutil.ReadFile(filename)
if err != nil {
t.Fatalf("Could not load file %v", err)
}
s := &EpochProcessingTest{}
if err := testutil.UnmarshalYaml(file, s); err != nil {
t.Fatalf("Failed to Unmarshal: %v", err)
}
if err := spectest.SetConfig(s.Config); err != nil {
func runFinalUpdatesTests(t *testing.T, config string) {
if err := spectest.SetConfig(config); err != nil {
t.Fatal(err)
}
if len(s.TestCases) == 0 {
t.Fatal("No tests!")
}
for _, tt := range s.TestCases {
t.Run(tt.Description, func(t *testing.T) {
helpers.ClearAllCaches()
var postState *pb.BeaconState
postState, err = epoch.ProcessFinalUpdates(tt.Pre)
if err != nil {
t.Fatal(err)
}
if !reflect.DeepEqual(postState, tt.Post) {
t.Error("Did not get expected state")
diff, _ := messagediff.PrettyDiff(tt.Post, postState)
t.Log(diff)
}
testFolders, testsFolderPath := testutil.TestFolders(t, config, "epoch_processing/final_updates/pyspec_tests")
for _, folder := range testFolders {
t.Run(folder.Name(), func(t *testing.T) {
folderPath := path.Join(testsFolderPath, folder.Name())
testutil.RunEpochOperationTest(t, folderPath, processFinalUpdatesWrapper)
})
}
}
func processFinalUpdatesWrapper(t *testing.T, state *pb.BeaconState) (*pb.BeaconState, error) {
state, err := epoch.ProcessFinalUpdates(state)
if err != nil {
t.Fatalf("could not process final updates: %v", err)
}
return state, nil
}

View File

@@ -2,14 +2,8 @@ package spectest
import (
"testing"
"github.com/bazelbuild/rules_go/go/tools/bazel"
)
func TestJustificationAndFinalizationMainnet(t *testing.T) {
filepath, err := bazel.Runfile(justificationAndFinalizationPrefix + "justification_and_finalization_mainnet.yaml")
if err != nil {
t.Fatal(err)
}
runJustificationAndFinalizationTests(t, filepath)
runJustificationAndFinalizationTests(t, "mainnet")
}

View File

@@ -2,15 +2,8 @@ package spectest
import (
"testing"
"github.com/bazelbuild/rules_go/go/tools/bazel"
)
func TestJustificationAndFinalizationMinimal(t *testing.T) {
t.Skip("This test suite requires --define ssz=minimal to be provided and there isn't a great way to do that without breaking //... See https://github.com/prysmaticlabs/prysm/issues/3066")
filepath, err := bazel.Runfile(justificationAndFinalizationPrefix + "justification_and_finalization_minimal.yaml")
if err != nil {
t.Fatal(err)
}
runJustificationAndFinalizationTests(t, filepath)
runJustificationAndFinalizationTests(t, "minimal")
}

View File

@@ -1,102 +1,55 @@
package spectest
import (
"fmt"
"io/ioutil"
"reflect"
"path"
"testing"
"github.com/gogo/protobuf/proto"
"github.com/prysmaticlabs/prysm/beacon-chain/core/epoch"
"github.com/prysmaticlabs/prysm/beacon-chain/core/helpers"
pb "github.com/prysmaticlabs/prysm/proto/beacon/p2p/v1"
"github.com/prysmaticlabs/prysm/shared/params/spectest"
"github.com/prysmaticlabs/prysm/shared/testutil"
"gopkg.in/d4l3k/messagediff.v1"
)
const justificationAndFinalizationPrefix = "tests/epoch_processing/justification_and_finalization/"
func runJustificationAndFinalizationTests(t *testing.T, config string) {
if err := spectest.SetConfig(config); err != nil {
t.Fatal(err)
}
testPath := "epoch_processing/justification_and_finalization/pyspec_tests"
testFolders, testsFolderPath := testutil.TestFolders(t, config, testPath)
for _, folder := range testFolders {
t.Run(folder.Name(), func(t *testing.T) {
folderPath := path.Join(testsFolderPath, folder.Name())
testutil.RunEpochOperationTest(t, folderPath, processJustificationAndFinalizationWrapper)
})
}
}
// This is a subset of state.ProcessEpoch. The spec test defines input data for
// `justification_and_finalization` only.
func processJustificationAndFinalizationWrapper(state *pb.BeaconState) (*pb.BeaconState, error) {
helpers.ClearAllCaches()
// This process mutates the state, so we'll make a copy in order to print debug before/after.
state = proto.Clone(state).(*pb.BeaconState)
func processJustificationAndFinalizationWrapper(t *testing.T, state *pb.BeaconState) (*pb.BeaconState, error) {
prevEpochAtts, err := epoch.MatchAttestations(state, helpers.PrevEpoch(state))
if err != nil {
return nil, fmt.Errorf("could not get target atts prev epoch %d: %v",
helpers.PrevEpoch(state), err)
t.Fatalf("could not get target atts prev epoch %d: %v", helpers.PrevEpoch(state), err)
}
currentEpochAtts, err := epoch.MatchAttestations(state, helpers.CurrentEpoch(state))
if err != nil {
return nil, fmt.Errorf("could not get target atts current epoch %d: %v",
helpers.CurrentEpoch(state), err)
t.Fatalf("could not get target atts current epoch %d: %v", helpers.CurrentEpoch(state), err)
}
prevEpochAttestedBalance, err := epoch.AttestingBalance(state, prevEpochAtts.Target)
if err != nil {
return nil, fmt.Errorf("could not get attesting balance prev epoch: %v", err)
t.Fatalf("could not get attesting balance prev epoch: %v", err)
}
currentEpochAttestedBalance, err := epoch.AttestingBalance(state, currentEpochAtts.Target)
if err != nil {
return nil, fmt.Errorf("could not get attesting balance current epoch: %v", err)
t.Fatalf("could not get attesting balance current epoch: %v", err)
}
state, err = epoch.ProcessJustificationAndFinalization(state, prevEpochAttestedBalance, currentEpochAttestedBalance)
if err != nil {
return nil, fmt.Errorf("could not process justification: %v", err)
t.Fatalf("could not process justification: %v", err)
}
return state, nil
}
func runJustificationAndFinalizationTests(t *testing.T, filename string) {
file, err := ioutil.ReadFile(filename)
if err != nil {
t.Fatalf("Could not load file %v", err)
}
s := &EpochProcessingTest{}
if err := testutil.UnmarshalYaml(file, s); err != nil {
t.Fatalf("Failed to Unmarshal: %v", err)
}
if err := spectest.SetConfig(s.Config); err != nil {
t.Fatal(err)
}
if len(s.TestCases) == 0 {
t.Fatal("No tests!")
}
for _, tt := range s.TestCases {
t.Run(tt.Description, func(t *testing.T) {
preState := &pb.BeaconState{}
if err := testutil.ConvertToPb(tt.Pre, preState); err != nil {
t.Fatal(err)
}
postState, err := processJustificationAndFinalizationWrapper(preState)
if err != nil {
t.Fatal(err)
}
expectedPostState := &pb.BeaconState{}
if err := testutil.ConvertToPb(tt.Post, expectedPostState); err != nil {
t.Fatal(err)
}
if postState.JustificationBits[0] != expectedPostState.JustificationBits[0] {
t.Errorf("Justification bits mismatch. PreState.JustificationBits=%v. PostState.JustificationBits=%v. Expected=%v", preState.JustificationBits, postState.JustificationBits, expectedPostState.JustificationBits)
}
if !reflect.DeepEqual(postState, expectedPostState) {
diff, _ := messagediff.PrettyDiff(postState, expectedPostState)
t.Log(diff)
t.Error("Did not get expected state")
}
})
}
}

View File

@@ -2,14 +2,8 @@ package spectest
import (
"testing"
"github.com/bazelbuild/rules_go/go/tools/bazel"
)
func TestRegistryProcessingMainnet(t *testing.T) {
filepath, err := bazel.Runfile(registryUpdatesPrefix + "registry_updates_mainnet.yaml")
if err != nil {
t.Fatal(err)
}
runRegisteryProcessingTests(t, filepath)
func TestRegistryUpdatesMainnet(t *testing.T) {
runRegistryUpdatesTests(t, "mainnet")
}

View File

@@ -2,14 +2,8 @@ package spectest
import (
"testing"
"github.com/bazelbuild/rules_go/go/tools/bazel"
)
func TestRegistryProcessingMinimal(t *testing.T) {
filepath, err := bazel.Runfile(registryUpdatesPrefix + "registry_updates_minimal.yaml")
if err != nil {
t.Fatal(err)
}
runRegisteryProcessingTests(t, filepath)
func TestRegistryUpdatesMinimal(t *testing.T) {
runRegistryUpdatesTests(t, "minimal")
}

View File

@@ -1,46 +1,33 @@
package spectest
import (
"io/ioutil"
"reflect"
"path"
"testing"
"github.com/prysmaticlabs/prysm/beacon-chain/core/epoch"
pb "github.com/prysmaticlabs/prysm/proto/beacon/p2p/v1"
"github.com/prysmaticlabs/prysm/shared/params/spectest"
"github.com/prysmaticlabs/prysm/shared/testutil"
)
const registryUpdatesPrefix = "tests/epoch_processing/registry_updates/"
func runRegisteryProcessingTests(t *testing.T, filename string) {
file, err := ioutil.ReadFile(filename)
if err != nil {
t.Fatalf("Could not load file %v", err)
}
s := &EpochProcessingTest{}
if err := testutil.UnmarshalYaml(file, s); err != nil {
t.Fatalf("Failed to Unmarshal: %v", err)
}
if err := spectest.SetConfig(s.Config); err != nil {
func runRegistryUpdatesTests(t *testing.T, config string) {
if err := spectest.SetConfig(config); err != nil {
t.Fatal(err)
}
if len(s.TestCases) == 0 {
t.Fatal("No tests!")
}
for _, tt := range s.TestCases {
t.Run(tt.Description, func(t *testing.T) {
postState, err := epoch.ProcessRegistryUpdates(tt.Pre)
if err != nil {
t.Fatal(err)
}
if !reflect.DeepEqual(postState, tt.Post) {
t.Error("Did not get expected state")
}
testFolders, testsFolderPath := testutil.TestFolders(t, config, "epoch_processing/registry_updates/pyspec_tests")
for _, folder := range testFolders {
t.Run(folder.Name(), func(t *testing.T) {
folderPath := path.Join(testsFolderPath, folder.Name())
testutil.RunEpochOperationTest(t, folderPath, processRegistryUpdatesWrapper)
})
}
}
func processRegistryUpdatesWrapper(t *testing.T, state *pb.BeaconState) (*pb.BeaconState, error) {
state, err := epoch.ProcessRegistryUpdates(state)
if err != nil {
t.Fatalf("could not process registry updates: %v", err)
}
return state, nil
}

View File

@@ -2,14 +2,8 @@ package spectest
import (
"testing"
"github.com/bazelbuild/rules_go/go/tools/bazel"
)
func TestSlashingsMainnet(t *testing.T) {
filepath, err := bazel.Runfile(slashingsPrefix + "slashings_mainnet.yaml")
if err != nil {
t.Fatal(err)
}
runSlashingsTests(t, filepath)
runSlashingsTests(t, "mainnet")
}

View File

@@ -2,14 +2,8 @@ package spectest
import (
"testing"
"github.com/bazelbuild/rules_go/go/tools/bazel"
)
func TestSlashingsMinimal(t *testing.T) {
filepath, err := bazel.Runfile(slashingsPrefix + "slashings_minimal.yaml")
if err != nil {
t.Fatal(err)
}
runSlashingsTests(t, filepath)
runSlashingsTests(t, "minimal")
}

View File

@@ -1,48 +1,33 @@
package spectest
import (
"io/ioutil"
"reflect"
"path"
"testing"
"github.com/prysmaticlabs/prysm/beacon-chain/core/epoch"
"github.com/prysmaticlabs/prysm/beacon-chain/core/helpers"
pb "github.com/prysmaticlabs/prysm/proto/beacon/p2p/v1"
"github.com/prysmaticlabs/prysm/shared/params/spectest"
"github.com/prysmaticlabs/prysm/shared/testutil"
)
const slashingsPrefix = "tests/epoch_processing/slashings/"
func runSlashingsTests(t *testing.T, filename string) {
file, err := ioutil.ReadFile(filename)
if err != nil {
t.Fatalf("Could not load file %v", err)
}
s := &EpochProcessingTest{}
if err := testutil.UnmarshalYaml(file, s); err != nil {
t.Fatalf("Failed to Unmarshal: %v", err)
}
if err := spectest.SetConfig(s.Config); err != nil {
func runSlashingsTests(t *testing.T, config string) {
if err := spectest.SetConfig(config); err != nil {
t.Fatal(err)
}
if len(s.TestCases) == 0 {
t.Fatal("No tests!")
}
for _, tt := range s.TestCases {
t.Run(tt.Description, func(t *testing.T) {
helpers.ClearAllCaches()
postState, err := epoch.ProcessSlashings(tt.Pre)
if err != nil {
t.Fatal(err)
}
if !reflect.DeepEqual(postState, tt.Post) {
t.Error("Did not get expected state")
}
testFolders, testsFolderPath := testutil.TestFolders(t, config, "epoch_processing/slashings/pyspec_tests")
for _, folder := range testFolders {
t.Run(folder.Name(), func(t *testing.T) {
folderPath := path.Join(testsFolderPath, folder.Name())
testutil.RunEpochOperationTest(t, folderPath, processSlashingsWrapper)
})
}
}
func processSlashingsWrapper(t *testing.T, state *pb.BeaconState) (*pb.BeaconState, error) {
state, err := epoch.ProcessSlashings(state)
if err != nil {
t.Fatalf("could not process slashings: %v", err)
}
return state, nil
}

View File

@@ -17,7 +17,7 @@ import (
// assert slot < state.slot <= slot + SLOTS_PER_HISTORICAL_ROOT
// return state.block_roots[slot % SLOTS_PER_HISTORICAL_ROOT]
func BlockRootAtSlot(state *pb.BeaconState, slot uint64) ([]byte, error) {
if !(slot < state.Slot && state.Slot <= slot+params.BeaconConfig().SlotsPerHistoricalRoot) {
if slot >= state.Slot || state.Slot > slot+params.BeaconConfig().SlotsPerHistoricalRoot {
return []byte{}, errors.New("slot out of bounds")
}
return state.BlockRoots[slot%params.BeaconConfig().SlotsPerHistoricalRoot], nil

View File

@@ -175,6 +175,17 @@ func AttestingIndices(state *pb.BeaconState, data *ethpb.AttestationData, bf bit
return indices, nil
}
// VerifyBitfieldLength verifies that a bitfield length matches the given committee size.
func VerifyBitfieldLength(bf bitfield.Bitfield, committeeSize uint64) error {
if bf.Len() != committeeSize {
return fmt.Errorf(
"wanted participants bitfield length %d, got: %d",
committeeSize,
bf.Len())
}
return nil
}
// CommitteeAssignment is used to query committee assignment from
// current and previous epoch.
//
@@ -346,6 +357,27 @@ func StartShard(state *pb.BeaconState, epoch uint64) (uint64, error) {
return startShard, nil
}
// VerifyAttestationBitfieldLengths verifies that an attestations aggregation and custody bitfields are
// a valid length matching the size of the committee.
func VerifyAttestationBitfieldLengths(bState *pb.BeaconState, att *ethpb.Attestation) error {
committee, err := CrosslinkCommittee(bState, att.Data.Target.Epoch, att.Data.Crosslink.Shard)
if err != nil {
return errors.Wrap(err, "could not retrieve crosslink committees")
}
if committee == nil {
return errors.New("no committee exist for shard in the attestation")
}
if err := VerifyBitfieldLength(att.AggregationBits, uint64(len(committee))); err != nil {
return errors.Wrap(err, "failed to verify aggregation bitfield")
}
if err := VerifyBitfieldLength(att.CustodyBits, uint64(len(committee))); err != nil {
return errors.Wrap(err, "failed to verify custody bitfield")
}
return nil
}
// CompactCommitteesRoot returns the index root of a given epoch.
//
// Spec pseudocode definition:

View File

@@ -3,6 +3,7 @@ package helpers
import (
"fmt"
"reflect"
"strings"
"testing"
"github.com/prysmaticlabs/go-bitfield"
@@ -318,6 +319,20 @@ func TestAttestationParticipants_EmptyBitfield(t *testing.T) {
}
}
func TestVerifyBitfieldLength_OK(t *testing.T) {
bf := bitfield.Bitlist{0xFF, 0x01}
committeeSize := uint64(8)
if err := VerifyBitfieldLength(bf, committeeSize); err != nil {
t.Errorf("bitfield is not validated when it was supposed to be: %v", err)
}
bf = bitfield.Bitlist{0xFF, 0x07}
committeeSize = 10
if err := VerifyBitfieldLength(bf, committeeSize); err != nil {
t.Errorf("bitfield is not validated when it was supposed to be: %v", err)
}
}
func TestCommitteeAssignment_CanRetrieve(t *testing.T) {
// Initialize test with 128 validators, each slot and each shard gets 2 validators.
validators := make([]*ethpb.Validator, 2*params.BeaconConfig().SlotsPerEpoch)
@@ -572,6 +587,139 @@ func TestEpochStartShard_MixedActivationValidators(t *testing.T) {
}
}
func TestVerifyAttestationBitfieldLengths_OK(t *testing.T) {
if params.BeaconConfig().SlotsPerEpoch != 64 {
t.Errorf("SlotsPerEpoch should be 64 for these tests to pass")
}
validators := make([]*ethpb.Validator, 2*params.BeaconConfig().SlotsPerEpoch)
activeRoots := make([][]byte, params.BeaconConfig().EpochsPerHistoricalVector)
for i := 0; i < len(validators); i++ {
validators[i] = &ethpb.Validator{
ExitEpoch: params.BeaconConfig().FarFutureEpoch,
}
activeRoots[i] = []byte{'A'}
}
state := &pb.BeaconState{
Validators: validators,
ActiveIndexRoots: activeRoots,
RandaoMixes: activeRoots,
}
tests := []struct {
attestation *ethpb.Attestation
stateSlot uint64
invalidCustodyBits bool
verificationFailure bool
}{
{
attestation: &ethpb.Attestation{
AggregationBits: bitfield.Bitlist{0x05},
CustodyBits: bitfield.Bitlist{0x05},
Data: &ethpb.AttestationData{
Crosslink: &ethpb.Crosslink{
Shard: 5,
},
Target: &ethpb.Checkpoint{},
},
},
stateSlot: 5,
},
{
attestation: &ethpb.Attestation{
AggregationBits: bitfield.Bitlist{0x06},
CustodyBits: bitfield.Bitlist{0x06},
Data: &ethpb.AttestationData{
Crosslink: &ethpb.Crosslink{
Shard: 10,
},
Target: &ethpb.Checkpoint{},
},
},
stateSlot: 10,
},
{
attestation: &ethpb.Attestation{
AggregationBits: bitfield.Bitlist{0x06},
CustodyBits: bitfield.Bitlist{0x06},
Data: &ethpb.AttestationData{
Crosslink: &ethpb.Crosslink{
Shard: 20,
},
Target: &ethpb.Checkpoint{},
},
},
stateSlot: 20,
},
{
attestation: &ethpb.Attestation{
AggregationBits: bitfield.Bitlist{0x06},
CustodyBits: bitfield.Bitlist{0x10},
Data: &ethpb.AttestationData{
Crosslink: &ethpb.Crosslink{
Shard: 20,
},
Target: &ethpb.Checkpoint{},
},
},
stateSlot: 20,
verificationFailure: true,
invalidCustodyBits: true,
},
{
attestation: &ethpb.Attestation{
AggregationBits: bitfield.Bitlist{0xFF, 0xC0, 0x01},
CustodyBits: bitfield.Bitlist{0xFF, 0xC0, 0x01},
Data: &ethpb.AttestationData{
Crosslink: &ethpb.Crosslink{
Shard: 5,
},
Target: &ethpb.Checkpoint{},
},
},
stateSlot: 5,
verificationFailure: true,
},
{
attestation: &ethpb.Attestation{
AggregationBits: bitfield.Bitlist{0xFF, 0x01},
CustodyBits: bitfield.Bitlist{0xFF, 0x01},
Data: &ethpb.AttestationData{
Crosslink: &ethpb.Crosslink{
Shard: 20,
},
Target: &ethpb.Checkpoint{},
},
},
stateSlot: 20,
verificationFailure: true,
},
}
for i, tt := range tests {
ClearAllCaches()
state.Slot = tt.stateSlot
err := VerifyAttestationBitfieldLengths(state, tt.attestation)
if tt.verificationFailure {
if tt.invalidCustodyBits {
if !strings.Contains(err.Error(), "custody bitfield") {
t.Errorf("%d expected custody bits to fail: %v", i, err)
}
}
if err == nil {
t.Error("verification succeeded when it was supposed to fail")
}
continue
}
if err != nil {
t.Errorf("%d Failed to verify bitfield: %v", i, err)
continue
}
}
}
func TestCompactCommitteesRoot_OK(t *testing.T) {
ClearAllCaches()
// Create 10 committees

View File

@@ -12,15 +12,16 @@ go_test(
size = "small",
srcs = ["shuffle_yaml_test.go"],
data = [
"@eth2_spec_tests//:test_data",
"@eth2_spec_tests_mainnet//:test_data",
"@eth2_spec_tests_minimal//:test_data",
],
embed = [":go_default_library"],
tags = ["spectest"],
deps = [
"//beacon-chain/core/helpers:go_default_library",
"//shared/params/spectest:go_default_library",
"//shared/testutil:go_default_library",
"@com_github_ethereum_go_ethereum//common:go_default_library",
"@com_github_go_yaml_yaml//:go_default_library",
"@io_bazel_rules_go//go/tools/bazel:go_default_library",
],
)

View File

@@ -1,20 +1,8 @@
package spectest
// ShuffleTest --
type ShuffleTest struct {
Title string `yaml:"title"`
Summary string `yaml:"summary"`
ForksTimeline string `yaml:"forks_timeline"`
Forks []string `yaml:"forks"`
Config string `yaml:"config"`
Runner string `yaml:"runner"`
Handler string `yaml:"handler"`
TestCases []*ShuffleTestCase `yaml:"test_cases"`
}
// ShuffleTestCase --
type ShuffleTestCase struct {
Seed string `yaml:"seed"`
Count uint64 `yaml:"count"`
Shuffled []uint64 `yaml:"shuffled"`
Seed string `yaml:"seed"`
Count uint64 `yaml:"count"`
Mapping []uint64 `yaml:"mapping"`
}

View File

@@ -1,68 +1,56 @@
package spectest
import (
"encoding/base64"
"encoding/hex"
"fmt"
"io/ioutil"
"path"
"reflect"
"testing"
"github.com/bazelbuild/rules_go/go/tools/bazel"
"github.com/ethereum/go-ethereum/common"
"github.com/go-yaml/yaml"
"github.com/prysmaticlabs/prysm/beacon-chain/core/helpers"
"github.com/prysmaticlabs/prysm/shared/params/spectest"
"github.com/prysmaticlabs/prysm/shared/testutil"
)
const shufflePrefix = "tests/shuffling/core/"
func TestShufflingMinimal(t *testing.T) {
helpers.ClearAllCaches()
filepath, err := bazel.Runfile(shufflePrefix + "shuffling_minimal.yaml")
if err != nil {
t.Fatal(err)
}
runShuffleTests(t, filepath)
runShuffleTests(t, "minimal")
}
func TestShufflingMainnet(t *testing.T) {
helpers.ClearAllCaches()
filepath, err := bazel.Runfile(shufflePrefix + "shuffling_full.yaml")
if err != nil {
t.Fatal(err)
}
runShuffleTests(t, filepath)
runShuffleTests(t, "mainnet")
}
func runShuffleTests(t *testing.T, filepath string) {
file, err := ioutil.ReadFile(filepath)
if err != nil {
t.Fatalf("could not read YAML tests directory: %v", err)
}
shuffleTest := &ShuffleTest{}
if err := yaml.Unmarshal(file, shuffleTest); err != nil {
t.Fatalf("could not unmarshal YAML file into test struct: %v", err)
}
if err := spectest.SetConfig(shuffleTest.Config); err != nil {
func runShuffleTests(t *testing.T, config string) {
helpers.ClearAllCaches()
if err := spectest.SetConfig(config); err != nil {
t.Fatal(err)
}
t.Logf("Title: %v", shuffleTest.Title)
t.Logf("Summary: %v", shuffleTest.Summary)
t.Logf("Fork: %v", shuffleTest.Forks)
t.Logf("Config: %v", shuffleTest.Config)
for _, testCase := range shuffleTest.TestCases {
if err := runShuffleTest(testCase); err != nil {
t.Fatalf("shuffle test failed: %v", err)
}
}
testFolders, testsFolderPath := testutil.TestFolders(t, config, "shuffling/core/shuffle")
for _, folder := range testFolders {
t.Run(folder.Name(), func(t *testing.T) {
testCaseFile, err := testutil.BazelFileBytes(path.Join(testsFolderPath, folder.Name(), "mapping.yaml"))
if err != nil {
t.Fatalf("could not read YAML tests directory: %v", err)
}
testCase := &ShuffleTestCase{}
if err := yaml.Unmarshal(testCaseFile, testCase); err != nil {
t.Fatalf("could not unmarshal YAML file into test struct: %v", err)
}
if err := runShuffleTest(testCase); err != nil {
t.Fatalf("shuffle test failed: %v", err)
}
})
}
}
// RunShuffleTest uses validator set specified from a YAML file, runs the validator shuffle
// algorithm, then compare the output with the expected output from the YAML file.
func runShuffleTest(testCase *ShuffleTestCase) error {
baseSeed, err := base64.StdEncoding.DecodeString(testCase.Seed)
baseSeed, err := hex.DecodeString(testCase.Seed[2:])
if err != nil {
return err
}
@@ -80,8 +68,8 @@ func runShuffleTest(testCase *ShuffleTestCase) error {
}
shuffledList[i] = si
}
if !reflect.DeepEqual(shuffledList, testCase.Shuffled) {
return fmt.Errorf("shuffle result error: expected %v, actual %v", testCase.Shuffled, shuffledList)
if !reflect.DeepEqual(shuffledList, testCase.Mapping) {
return fmt.Errorf("shuffle result error: expected %v, actual %v", testCase.Mapping, shuffledList)
}
return nil
}

View File

@@ -1,19 +1,4 @@
load("@io_bazel_rules_go//go:def.bzl", "go_library", "go_test")
go_library(
name = "go_default_library",
srcs = [
"genesis_initialization.yaml.go",
"genesis_validity.yaml.go",
"sanity_slots_test.yaml.go",
],
importpath = "github.com/prysmaticlabs/prysm/beacon-chain/core/state/spectest",
visibility = ["//beacon-chain:__subpackages__"],
deps = [
"//proto/beacon/p2p/v1:go_default_library",
"//proto/eth/v1alpha1:go_default_library",
],
)
load("@io_bazel_rules_go//go:def.bzl", "go_test")
test_suite(
name = "go_default_test",
@@ -32,14 +17,14 @@ go_test(
exclude = ["*_minimal_test.go"],
),
data = [
"@eth2_spec_tests//:test_data",
"@eth2_spec_tests_mainnet//:test_data",
],
embed = [":go_default_library"],
shard_count = 2,
tags = ["spectest"],
deps = [
"//beacon-chain/core/helpers:go_default_library",
"//beacon-chain/core/state:go_default_library",
"//proto/beacon/p2p/v1:go_default_library",
"//proto/eth/v1alpha1:go_default_library",
"//shared/params:go_default_library",
"//shared/params/spectest:go_default_library",
@@ -59,13 +44,13 @@ go_test(
exclude = ["*_mainnet_test.go"],
),
data = [
"@eth2_spec_tests//:test_data",
"@eth2_spec_tests_minimal//:test_data",
],
embed = [":go_default_library"],
tags = ["spectest"],
deps = [
"//beacon-chain/core/helpers:go_default_library",
"//beacon-chain/core/state:go_default_library",
"//proto/beacon/p2p/v1:go_default_library",
"//proto/eth/v1alpha1:go_default_library",
"//shared/params:go_default_library",
"//shared/params/spectest:go_default_library",

View File

@@ -1,26 +0,0 @@
// Code generated by yaml_to_go. DO NOT EDIT.
// source: genesis_initialization_minimal.yaml
package spectest
import (
pb "github.com/prysmaticlabs/prysm/proto/beacon/p2p/v1"
ethpb "github.com/prysmaticlabs/prysm/proto/eth/v1alpha1"
)
type GenesisInitializationTest struct {
Title string `json:"title"`
Summary string `json:"summary"`
ForksTimeline string `json:"forks_timeline"`
Forks []string `json:"forks"`
Config string `json:"config"`
Runner string `json:"runner"`
Handler string `json:"handler"`
TestCases []struct {
Description string `json:"description"`
Eth1BlockHash []byte `json:"eth1_block_hash"`
Eth1Timestamp uint64 `json:"eth1_timestamp"`
Deposits []*ethpb.Deposit `json:"deposits"`
State *pb.BeaconState `json:"state"`
} `json:"test_cases"`
}

View File

@@ -1,70 +0,0 @@
package spectest
import (
"io/ioutil"
"testing"
"github.com/bazelbuild/rules_go/go/tools/bazel"
"github.com/gogo/protobuf/proto"
"github.com/prysmaticlabs/go-ssz"
"github.com/prysmaticlabs/prysm/beacon-chain/core/helpers"
"github.com/prysmaticlabs/prysm/beacon-chain/core/state"
ethpb "github.com/prysmaticlabs/prysm/proto/eth/v1alpha1"
"github.com/prysmaticlabs/prysm/shared/params"
"github.com/prysmaticlabs/prysm/shared/params/spectest"
"github.com/prysmaticlabs/prysm/shared/testutil"
)
func TestGenesisInitializationMinimal(t *testing.T) {
t.Skip("This test suite requires --define ssz=minimal to be provided and there isn't a great way to do that without breaking //... See https://github.com/prysmaticlabs/prysm/issues/3066")
filepath, err := bazel.Runfile("tests/genesis/initialization/genesis_initialization_minimal.yaml")
if err != nil {
t.Fatal(err)
}
file, err := ioutil.ReadFile(filepath)
if err != nil {
t.Fatalf("Could not load file %v", err)
}
s := &GenesisInitializationTest{}
if err := testutil.UnmarshalYaml(file, s); err != nil {
t.Fatalf("Failed to Unmarshal: %v", err)
}
if err := spectest.SetConfig(s.Config); err != nil {
t.Fatal(err)
}
if len(s.TestCases) == 0 {
t.Fatal("No tests!")
}
for _, tt := range s.TestCases {
t.Run(tt.Description, func(t *testing.T) {
helpers.ClearAllCaches()
deposits := tt.Deposits
dataLeaves := make([]*ethpb.Deposit_Data, len(deposits))
for i := range deposits {
dataLeaves[i] = deposits[i].Data
}
depositRoot, err := ssz.HashTreeRootWithCapacity(dataLeaves, 1<<params.BeaconConfig().DepositContractTreeDepth)
if err != nil {
t.Fatal(err)
}
eth1Data := &ethpb.Eth1Data{
DepositRoot: depositRoot[:],
DepositCount: uint64(len(deposits)),
BlockHash: tt.Eth1BlockHash,
}
genesisState, err := state.GenesisBeaconState(deposits, tt.Eth1Timestamp, eth1Data)
if err != nil {
t.Fatal(err)
}
if !proto.Equal(genesisState, tt.State) {
t.Error("States are not equal")
}
})
}
}

View File

@@ -1,21 +0,0 @@
// Code generated by yaml_to_go. DO NOT EDIT.
// source: genesis_initialization_minimal.yaml
package spectest
import pb "github.com/prysmaticlabs/prysm/proto/beacon/p2p/v1"
type GenesisValidityTest struct {
Title string `json:"title"`
Summary string `json:"summary"`
ForksTimeline string `json:"forks_timeline"`
Forks []string `json:"forks"`
Config string `json:"config"`
Runner string `json:"runner"`
Handler string `json:"handler"`
TestCases []struct {
Description string `json:"description"`
Genesis *pb.BeaconState `json:"genesis"`
IsValid bool `json:"is_valid"`
} `json:"test_cases"`
}

View File

@@ -1,53 +0,0 @@
package spectest
import (
"io/ioutil"
"testing"
"github.com/bazelbuild/rules_go/go/tools/bazel"
"github.com/prysmaticlabs/prysm/beacon-chain/core/helpers"
"github.com/prysmaticlabs/prysm/beacon-chain/core/state"
"github.com/prysmaticlabs/prysm/shared/params/spectest"
"github.com/prysmaticlabs/prysm/shared/testutil"
)
func TestGenesisValidityMinimal(t *testing.T) {
filepath, err := bazel.Runfile("tests/genesis/validity/genesis_validity_minimal.yaml")
if err != nil {
t.Fatal(err)
}
file, err := ioutil.ReadFile(filepath)
if err != nil {
t.Fatalf("Could not load file %v", err)
}
s := &GenesisValidityTest{}
if err := testutil.UnmarshalYaml(file, s); err != nil {
t.Fatalf("Failed to Unmarshal: %v", err)
}
if err := spectest.SetConfig(s.Config); err != nil {
t.Fatal(err)
}
for _, tt := range s.TestCases {
t.Run(tt.Description, func(t *testing.T) {
helpers.ClearAllCaches()
genesisState := tt.Genesis
validatorCount, err := helpers.ActiveValidatorCount(genesisState, 0)
if err != nil {
t.Fatalf("Could not get active validator count: %v", err)
}
isValid := state.IsValidGenesisState(validatorCount, genesisState.GenesisTime)
if isValid != tt.IsValid {
t.Fatalf(
"Genesis state does not have expected validity. Expected to be valid: %d, %d. %t %t",
tt.Genesis.GenesisTime,
validatorCount,
isValid,
tt.IsValid,
)
}
})
}
}

View File

@@ -1,22 +0,0 @@
// Code generated by yaml_to_go. DO NOT EDIT.
// source: sanity_slots_minimal.yaml
package spectest
import pb "github.com/prysmaticlabs/prysm/proto/beacon/p2p/v1"
type SanitySlotsTest struct {
Title string `json:"title"`
Summary string `json:"summary"`
ForksTimeline string `json:"forks_timeline"`
Forks []string `json:"forks"`
Config string `json:"config"`
Runner string `json:"runner"`
Handler string `json:"handler"`
TestCases []struct {
Description string `json:"description"`
Pre *pb.BeaconState `json:"pre"`
Slots uint64 `json:"slots"`
Post *pb.BeaconState `json:"post"`
} `json:"test_cases"`
}

View File

@@ -5,5 +5,5 @@ import (
)
func TestSlotProcessingMainnet(t *testing.T) {
runSlotProcessingTests(t, "sanity_slots_mainnet.yaml")
runSlotProcessingTests(t, "mainnet")
}

View File

@@ -5,6 +5,5 @@ import (
)
func TestSlotProcessingMinimal(t *testing.T) {
t.Skip("This test suite requires --define ssz=minimal to be provided and there isn't a great way to do that without breaking //... See https://github.com/prysmaticlabs/prysm/issues/3066")
runSlotProcessingTests(t, "sanity_slots_minimal.yaml")
runSlotProcessingTests(t, "minimal")
}

View File

@@ -2,53 +2,65 @@ package spectest
import (
"context"
"io/ioutil"
"strconv"
"testing"
"github.com/bazelbuild/rules_go/go/tools/bazel"
"github.com/gogo/protobuf/proto"
"github.com/prysmaticlabs/go-ssz"
"github.com/prysmaticlabs/prysm/beacon-chain/core/helpers"
"github.com/prysmaticlabs/prysm/beacon-chain/core/state"
pb "github.com/prysmaticlabs/prysm/proto/beacon/p2p/v1"
"github.com/prysmaticlabs/prysm/shared/params/spectest"
"github.com/prysmaticlabs/prysm/shared/testutil"
"gopkg.in/d4l3k/messagediff.v1"
)
const slotProcessingPrefix = "tests/sanity/slots/"
func runSlotProcessingTests(t *testing.T, filename string) {
filepath, err := bazel.Runfile(slotProcessingPrefix + filename)
if err != nil {
t.Fatal(err)
}
file, err := ioutil.ReadFile(filepath)
if err != nil {
t.Fatalf("Could not load file %v", err)
}
s := &SanitySlotsTest{}
if err := testutil.UnmarshalYaml(file, s); err != nil {
t.Fatalf("Failed to Unmarshal: %v", err)
}
if err := spectest.SetConfig(s.Config); err != nil {
func runSlotProcessingTests(t *testing.T, config string) {
if err := spectest.SetConfig(config); err != nil {
t.Fatal(err)
}
if len(s.TestCases) == 0 {
t.Fatal("No tests!")
}
testFolders, testsFolderPath := testutil.TestFolders(t, config, "sanity/slots/pyspec_tests")
for _, tt := range s.TestCases {
t.Run(tt.Description, func(t *testing.T) {
postState, err := state.ProcessSlots(context.Background(), tt.Pre, tt.Pre.Slot+tt.Slots)
for _, folder := range testFolders {
t.Run(folder.Name(), func(t *testing.T) {
helpers.ClearAllCaches()
preBeaconStateFile, err := testutil.BazelFileBytes(testsFolderPath, folder.Name(), "pre.ssz")
if err != nil {
t.Fatal(err)
}
beaconState := &pb.BeaconState{}
if err := ssz.Unmarshal(preBeaconStateFile, beaconState); err != nil {
t.Fatalf("Failed to unmarshal: %v", err)
}
file, err := testutil.BazelFileBytes(testsFolderPath, folder.Name(), "slots.yaml")
if err != nil {
t.Fatal(err)
}
fileStr := string(file)
slotsCount, err := strconv.Atoi(fileStr[:len(fileStr)-5])
if err != nil {
t.Fatal(err)
}
if !proto.Equal(postState, tt.Post) {
diff, _ := messagediff.PrettyDiff(postState, tt.Post)
postBeaconStateFile, err := testutil.BazelFileBytes(testsFolderPath, folder.Name(), "post.ssz")
if err != nil {
t.Fatal(err)
}
postBeaconState := &pb.BeaconState{}
if err := ssz.Unmarshal(postBeaconStateFile, postBeaconState); err != nil {
t.Fatalf("Failed to unmarshal: %v", err)
}
postState, err := state.ProcessSlots(context.Background(), beaconState, beaconState.Slot+uint64(slotsCount))
if err != nil {
t.Fatal(err)
}
if !proto.Equal(postState, postBeaconState) {
diff, _ := messagediff.PrettyDiff(beaconState, postBeaconState)
t.Log(diff)
_ = diff
t.Fatal("Post state does not match expected")
}
})

View File

@@ -453,6 +453,19 @@ func TestProcessBlock_PassesProcessingConditions(t *testing.T) {
BodyRoot: bodyRoot[:],
}
beaconState.Slashings = make([]uint64, params.BeaconConfig().EpochsPerSlashingsVector)
beaconState.CurrentCrosslinks = []*ethpb.Crosslink{
{
Shard: 0,
StartEpoch: helpers.SlotToEpoch(beaconState.Slot),
DataRoot: []byte{1},
},
}
beaconState.CurrentJustifiedCheckpoint.Root = []byte("hello-world")
beaconState.CurrentEpochAttestations = []*pb.PendingAttestation{}
encoded, err := ssz.HashTreeRoot(beaconState.CurrentCrosslinks[0])
if err != nil {
t.Fatal(err)
}
proposerSlashIdx := uint64(3)
slotsPerEpoch := params.BeaconConfig().SlotsPerEpoch
@@ -553,11 +566,10 @@ func TestProcessBlock_PassesProcessingConditions(t *testing.T) {
blockRoots = append(blockRoots, []byte{byte(i)})
}
beaconState.BlockRoots = blockRoots
beaconState.CurrentCrosslinks = []*ethpb.Crosslink{
{
DataRoot: []byte{1},
},
}
aggBits := bitfield.NewBitlist(1)
aggBits.SetBitAt(1, true)
custodyBits := bitfield.NewBitlist(1)
blockAtt := &ethpb.Attestation{
Data: &ethpb.AttestationData{
Target: &ethpb.Checkpoint{Epoch: helpers.SlotToEpoch(beaconState.Slot)},
@@ -566,27 +578,29 @@ func TestProcessBlock_PassesProcessingConditions(t *testing.T) {
Root: []byte("hello-world"),
},
Crosslink: &ethpb.Crosslink{
Shard: 0,
EndEpoch: 64,
Shard: 0,
EndEpoch: 64,
DataRoot: params.BeaconConfig().ZeroHash[:],
ParentRoot: encoded[:],
},
},
AggregationBits: bitfield.Bitlist{0xC0, 0xC0, 0xC0, 0xC0, 0x01},
CustodyBits: bitfield.Bitlist{0x00, 0x00, 0x00, 0x00, 0x01},
AggregationBits: aggBits,
CustodyBits: custodyBits,
}
attestingIndices, err := helpers.AttestingIndices(beaconState, blockAtt.Data, blockAtt.AggregationBits)
if err != nil {
t.Error(err)
}
dataAndCustodyBit = &pb.AttestationDataAndCustodyBit{
Data: blockAtt.Data,
CustodyBit: false,
}
hashTreeRoot, err = ssz.HashTreeRoot(dataAndCustodyBit)
if err != nil {
t.Error(err)
}
sigs := make([]*bls.Signature, len(attestingIndices))
for i, indice := range attestingIndices {
dataAndCustodyBit := &pb.AttestationDataAndCustodyBit{
Data: blockAtt.Data,
CustodyBit: false,
}
hashTreeRoot, err := ssz.HashTreeRoot(dataAndCustodyBit)
if err != nil {
t.Error(err)
}
sig := privKeys[indice].Sign(hashTreeRoot[:], domain)
sigs[i] = sig
}
@@ -607,18 +621,6 @@ func TestProcessBlock_PassesProcessingConditions(t *testing.T) {
if err != nil {
t.Fatal(err)
}
beaconState.CurrentCrosslinks = []*ethpb.Crosslink{
{
Shard: 0,
StartEpoch: helpers.SlotToEpoch(beaconState.Slot),
},
}
beaconState.CurrentJustifiedCheckpoint.Root = []byte("hello-world")
beaconState.CurrentEpochAttestations = []*pb.PendingAttestation{}
encoded, err := ssz.HashTreeRoot(beaconState.CurrentCrosslinks[0])
if err != nil {
t.Fatal(err)
}
randaoReveal, err := testutil.CreateRandaoReveal(beaconState, currentEpoch, privKeys)
if err != nil {
@@ -639,8 +641,6 @@ func TestProcessBlock_PassesProcessingConditions(t *testing.T) {
},
},
}
block.Body.Attestations[0].Data.Crosslink.ParentRoot = encoded[:]
block.Body.Attestations[0].Data.Crosslink.DataRoot = params.BeaconConfig().ZeroHash[:]
block, err = testutil.SignBlock(beaconState, block, privKeys)
if err != nil {

View File

@@ -196,6 +196,20 @@ func TestPendingAttestations_FiltersWithinInclusionDelay(t *testing.T) {
t.Fatal(err)
}
currentEpoch := helpers.CurrentEpoch(beaconState)
activeCount, err := helpers.ActiveValidatorCount(beaconState, currentEpoch)
if err != nil {
t.Error(err)
}
committeeCount, err := helpers.CommitteeCount(beaconState, currentEpoch)
if err != nil {
t.Error(err)
}
aggBits := bitfield.NewBitlist(activeCount / committeeCount)
for i := uint64(0); i < aggBits.Len(); i++ {
aggBits.SetBitAt(i, true)
}
custodyBits := bitfield.NewBitlist(activeCount / committeeCount)
att := &ethpb.Attestation{
Data: &ethpb.AttestationData{
Crosslink: &ethpb.Crosslink{
@@ -205,15 +219,22 @@ func TestPendingAttestations_FiltersWithinInclusionDelay(t *testing.T) {
Source: &ethpb.Checkpoint{},
Target: &ethpb.Checkpoint{},
},
AggregationBits: bitfield.Bitlist{0xC0, 0xC0, 0xC0, 0xC0, 0x01},
CustodyBits: []byte{0x00, 0x00, 0x00, 0x00},
AggregationBits: aggBits,
CustodyBits: custodyBits,
}
attestingIndices, err := helpers.AttestingIndices(beaconState, att.Data, att.AggregationBits)
if err != nil {
t.Error(err)
}
currentEpoch := helpers.CurrentEpoch(beaconState)
dataAndCustodyBit := &pbp2p.AttestationDataAndCustodyBit{
Data: att.Data,
CustodyBit: false,
}
hashTreeRoot, err := ssz.HashTreeRoot(dataAndCustodyBit)
if err != nil {
t.Error(err)
}
domain := helpers.Domain(beaconState, currentEpoch, params.BeaconConfig().DomainAttestation)
sigs := make([]*bls.Signature, len(attestingIndices))
for i, indice := range attestingIndices {
@@ -221,14 +242,6 @@ func TestPendingAttestations_FiltersWithinInclusionDelay(t *testing.T) {
if err != nil {
t.Error(err)
}
dataAndCustodyBit := &pbp2p.AttestationDataAndCustodyBit{
Data: att.Data,
CustodyBit: false,
}
hashTreeRoot, err := ssz.HashTreeRoot(dataAndCustodyBit)
if err != nil {
t.Error(err)
}
beaconState.Validators[indice].PublicKey = priv.PublicKey().Marshal()[:]
sigs[i] = priv.Sign(hashTreeRoot[:], domain)
}
@@ -310,14 +323,30 @@ func TestPendingAttestations_FiltersExpiredAttestations(t *testing.T) {
LatestBlockHeader: &ethpb.BeaconBlockHeader{StateRoot: []byte{}},
}
currentEpoch := helpers.CurrentEpoch(beaconState)
activeCount, err := helpers.ActiveValidatorCount(beaconState, currentEpoch)
if err != nil {
t.Error(err)
}
committeeCount, err := helpers.CommitteeCount(beaconState, currentEpoch)
if err != nil {
t.Error(err)
}
aggBits := bitfield.NewBitlist(activeCount / committeeCount)
for i := uint64(0); i < aggBits.Len(); i++ {
aggBits.SetBitAt(i, true)
}
custodyBits := bitfield.NewBitlist(activeCount / committeeCount)
att := &ethpb.Attestation{
Data: &ethpb.AttestationData{
Target: &ethpb.Checkpoint{Epoch: 10},
Source: &ethpb.Checkpoint{Epoch: expectedEpoch},
Crosslink: &ethpb.Crosslink{EndEpoch: 10, DataRoot: params.BeaconConfig().ZeroHash[:], ParentRoot: encoded[:]},
},
AggregationBits: bitfield.Bitlist{0xC0, 0xC0, 0xC0, 0xC0, 0x01},
AggregationBits: aggBits,
CustodyBits: custodyBits,
}
attestingIndices, err := helpers.AttestingIndices(beaconState, att.Data, att.AggregationBits)
if err != nil {
t.Error(err)
@@ -349,38 +378,60 @@ func TestPendingAttestations_FiltersExpiredAttestations(t *testing.T) {
opService := &mockOperationService{
pendingAttestations: []*ethpb.Attestation{
//Expired attestations
{Data: &ethpb.AttestationData{
Target: &ethpb.Checkpoint{Epoch: 10},
Source: &ethpb.Checkpoint{Epoch: expectedEpoch},
Crosslink: &ethpb.Crosslink{DataRoot: params.BeaconConfig().ZeroHash[:]},
}},
{Data: &ethpb.AttestationData{
Target: &ethpb.Checkpoint{Epoch: 10},
Source: &ethpb.Checkpoint{Epoch: expectedEpoch},
Crosslink: &ethpb.Crosslink{DataRoot: params.BeaconConfig().ZeroHash[:]},
}},
{Data: &ethpb.AttestationData{
Target: &ethpb.Checkpoint{Epoch: 10},
Source: &ethpb.Checkpoint{Epoch: expectedEpoch},
Crosslink: &ethpb.Crosslink{DataRoot: params.BeaconConfig().ZeroHash[:]},
}},
{Data: &ethpb.AttestationData{
Target: &ethpb.Checkpoint{Epoch: 10},
Source: &ethpb.Checkpoint{Epoch: expectedEpoch},
Crosslink: &ethpb.Crosslink{DataRoot: params.BeaconConfig().ZeroHash[:]},
}},
{Data: &ethpb.AttestationData{
Target: &ethpb.Checkpoint{Epoch: 10},
Source: &ethpb.Checkpoint{Epoch: expectedEpoch},
Crosslink: &ethpb.Crosslink{DataRoot: params.BeaconConfig().ZeroHash[:]},
}},
{
Data: &ethpb.AttestationData{
Target: &ethpb.Checkpoint{Epoch: 10},
Source: &ethpb.Checkpoint{Epoch: expectedEpoch},
Crosslink: &ethpb.Crosslink{DataRoot: params.BeaconConfig().ZeroHash[:]},
},
AggregationBits: aggBits,
CustodyBits: custodyBits,
},
{
Data: &ethpb.AttestationData{
Target: &ethpb.Checkpoint{Epoch: 10},
Source: &ethpb.Checkpoint{Epoch: expectedEpoch},
Crosslink: &ethpb.Crosslink{DataRoot: params.BeaconConfig().ZeroHash[:]},
},
AggregationBits: aggBits,
CustodyBits: custodyBits,
},
{
Data: &ethpb.AttestationData{
Target: &ethpb.Checkpoint{Epoch: 10},
Source: &ethpb.Checkpoint{Epoch: expectedEpoch},
Crosslink: &ethpb.Crosslink{DataRoot: params.BeaconConfig().ZeroHash[:]},
},
AggregationBits: aggBits,
CustodyBits: custodyBits,
},
{
Data: &ethpb.AttestationData{
Target: &ethpb.Checkpoint{Epoch: 10},
Source: &ethpb.Checkpoint{Epoch: expectedEpoch},
Crosslink: &ethpb.Crosslink{DataRoot: params.BeaconConfig().ZeroHash[:]},
},
AggregationBits: aggBits,
CustodyBits: custodyBits,
},
{
Data: &ethpb.AttestationData{
Target: &ethpb.Checkpoint{Epoch: 10},
Source: &ethpb.Checkpoint{Epoch: expectedEpoch},
Crosslink: &ethpb.Crosslink{DataRoot: params.BeaconConfig().ZeroHash[:]},
},
AggregationBits: aggBits,
CustodyBits: custodyBits},
// Non-expired attestation with incorrect justified epoch
{Data: &ethpb.AttestationData{
Target: &ethpb.Checkpoint{Epoch: 10},
Source: &ethpb.Checkpoint{Epoch: expectedEpoch - 1},
Crosslink: &ethpb.Crosslink{DataRoot: params.BeaconConfig().ZeroHash[:]},
}},
{
Data: &ethpb.AttestationData{
Target: &ethpb.Checkpoint{Epoch: 10},
Source: &ethpb.Checkpoint{Epoch: expectedEpoch - 1},
Crosslink: &ethpb.Crosslink{DataRoot: params.BeaconConfig().ZeroHash[:]},
},
AggregationBits: aggBits,
CustodyBits: custodyBits,
},
// Non-expired attestations with correct justified epoch
att,
att2,
@@ -421,7 +472,8 @@ func TestPendingAttestations_FiltersExpiredAttestations(t *testing.T) {
Source: &ethpb.Checkpoint{Epoch: expectedEpoch},
Crosslink: &ethpb.Crosslink{EndEpoch: 10, DataRoot: params.BeaconConfig().ZeroHash[:], ParentRoot: encoded[:]},
},
AggregationBits: bitfield.Bitlist{0xC0, 0xC0, 0xC0, 0xC0, 0x01},
AggregationBits: aggBits,
CustodyBits: custodyBits,
Signature: aggregateSig,
},
{
@@ -430,7 +482,8 @@ func TestPendingAttestations_FiltersExpiredAttestations(t *testing.T) {
Source: &ethpb.Checkpoint{Epoch: expectedEpoch},
Crosslink: &ethpb.Crosslink{EndEpoch: 10, DataRoot: params.BeaconConfig().ZeroHash[:], ParentRoot: encoded[:]},
},
AggregationBits: bitfield.Bitlist{0xC0, 0xC0, 0xC0, 0xC0, 0x01},
AggregationBits: aggBits,
CustodyBits: custodyBits,
Signature: aggregateSig,
},
{
@@ -439,7 +492,8 @@ func TestPendingAttestations_FiltersExpiredAttestations(t *testing.T) {
Source: &ethpb.Checkpoint{Epoch: expectedEpoch},
Crosslink: &ethpb.Crosslink{EndEpoch: 10, DataRoot: params.BeaconConfig().ZeroHash[:], ParentRoot: encoded[:]},
},
AggregationBits: bitfield.Bitlist{0xC0, 0xC0, 0xC0, 0xC0, 0x01},
AggregationBits: aggBits,
CustodyBits: custodyBits,
Signature: aggregateSig,
},
}