diff --git a/WORKSPACE b/WORKSPACE index e9427d99d882..3634b1194673 100644 --- a/WORKSPACE +++ b/WORKSPACE @@ -140,7 +140,7 @@ filegroup( visibility = ["//visibility:public"], ) """, - sha256 = "d297d5df03d1a635450cdb6d746e585485529ce13f121fffc375ad12470ae32f", + sha256 = "56847989737e816ab7d23f3bb2422347dfa81271bae81a94de512c01461fab25", url = "https://github.com/prysmaticlabs/eth2.0-spec-tests/releases/download/v0.7.1/base64_encoded_archive.tar.gz", ) diff --git a/beacon-chain/core/blocks/block_operations.go b/beacon-chain/core/blocks/block_operations.go index 8df4a8f8beee..caef0c0d8b74 100644 --- a/beacon-chain/core/blocks/block_operations.go +++ b/beacon-chain/core/blocks/block_operations.go @@ -103,6 +103,7 @@ func ProcessBlockHeader( if beaconState.Slot != block.Slot { return nil, fmt.Errorf("state slot: %d is different then block slot: %d", beaconState.Slot, block.Slot) } + parentRoot, err := ssz.SigningRoot(beaconState.LatestBlockHeader) if err != nil { return nil, err diff --git a/beacon-chain/core/epoch/epoch_processing.go b/beacon-chain/core/epoch/epoch_processing.go index 2c85c7e5101f..8cb6665289ff 100644 --- a/beacon-chain/core/epoch/epoch_processing.go +++ b/beacon-chain/core/epoch/epoch_processing.go @@ -940,6 +940,7 @@ func crosslinkDelta(state *pb.BeaconState) ([]uint64, []uint64, error) { } } } + return rewards, penalties, nil } diff --git a/beacon-chain/core/state/spectest/BUILD.bazel b/beacon-chain/core/state/spectest/BUILD.bazel new file mode 100644 index 000000000000..b274f0ef32c5 --- /dev/null +++ b/beacon-chain/core/state/spectest/BUILD.bazel @@ -0,0 +1,27 @@ +load("@io_bazel_rules_go//go:def.bzl", "go_library", "go_test") + +go_library( + name = "go_default_library", + srcs = ["sanity_slots_test.yaml.go"], + importpath = "github.com/prysmaticlabs/prysm/beacon-chain/core/state/spectest", + visibility = ["//beacon-chain:__subpackages__"], +) + +go_test( + name = "go_default_test", + srcs = ["slot_processing_test.go"], + data = [ + "@eth2_spec_tests//:test_data", + ], + embed = [":go_default_library"], + tags = ["spectest"], + deps = [ + "//beacon-chain/core/state:go_default_library", + "//proto/beacon/p2p/v1:go_default_library", + "//shared/params/spectest:go_default_library", + "//shared/testutil:go_default_library", + "@com_github_ghodss_yaml//:go_default_library", + "@com_github_prysmaticlabs_go_ssz//:go_default_library", + "@io_bazel_rules_go//go/tools/bazel:go_default_library", + ], +) diff --git a/beacon-chain/core/state/spectest/sanity_slots_test.yaml.go b/beacon-chain/core/state/spectest/sanity_slots_test.yaml.go new file mode 100644 index 000000000000..ecf4a4ff4d03 --- /dev/null +++ b/beacon-chain/core/state/spectest/sanity_slots_test.yaml.go @@ -0,0 +1,146 @@ +// Code generated by yaml_to_go. DO NOT EDIT. +// source: sanity_slots_minimal.yaml + +package spectest + +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 struct { + Slot uint64 `json:"slot"` + GenesisTime uint64 `json:"genesis_time"` + Fork struct { + PreviousVersion []byte `json:"previous_version"` + CurrentVersion []byte `json:"current_version"` + Epoch uint64 `json:"epoch"` + } `json:"fork"` + ValidatorRegistry []struct { + Pubkey []byte `json:"pubkey" ssz:"size=48"` + WithdrawalCredentials []byte `json:"withdrawal_credentials" ssz:"size=32"` + ActivationEligibilityEpoch uint64 `json:"activation_eligibility_epoch"` + ActivationEpoch uint64 `json:"activation_epoch"` + ExitEpoch uint64 `json:"exit_epoch"` + WithdrawableEpoch uint64 `json:"withdrawable_epoch"` + Slashed bool `json:"slashed"` + EffectiveBalance uint64 `json:"effective_balance"` + } `json:"validator_registry"` + Balances []uint64 `json:"balances"` + LatestRandaoMixes [][]byte `json:"latest_randao_mixes"` + LatestStartShard uint64 `json:"latest_start_shard"` + PreviousEpochAttestations []interface{} `json:"previous_epoch_attestations"` + CurrentEpochAttestations []interface{} `json:"current_epoch_attestations"` + PreviousJustifiedEpoch uint64 `json:"previous_justified_epoch"` + CurrentJustifiedEpoch uint64 `json:"current_justified_epoch"` + PreviousJustifiedRoot []byte `json:"previous_justified_root" ssz:"size=32"` + CurrentJustifiedRoot []byte `json:"current_justified_root" ssz:"size=32"` + JustificationBitfield uint64 `json:"justification_bitfield"` + FinalizedEpoch uint64 `json:"finalized_epoch"` + FinalizedRoot []byte `json:"finalized_root" ssz:"size=32"` + CurrentCrosslinks []struct { + Shard uint64 `json:"shard"` + StartEpoch uint64 `json:"start_epoch"` + EndEpoch uint64 `json:"end_epoch"` + ParentRoot []byte `json:"parent_root" ssz:"size=32"` + DataRoot []byte `json:"data_root" ssz:"size=32"` + } `json:"current_crosslinks"` + PreviousCrosslinks []struct { + Shard uint64 `json:"shard"` + StartEpoch uint64 `json:"start_epoch"` + EndEpoch uint64 `json:"end_epoch"` + ParentRoot []byte `json:"parent_root" ssz:"size=32"` + DataRoot []byte `json:"data_root" ssz:"size=32"` + } `json:"previous_crosslinks"` + LatestBlockRoots [][]byte `json:"latest_block_roots"` + LatestStateRoots [][]byte `json:"latest_state_roots"` + LatestActiveIndexRoots [][]byte `json:"latest_active_index_roots"` + LatestSlashedBalances []uint64 `json:"latest_slashed_balances"` + LatestBlockHeader struct { + Slot uint64 `json:"slot"` + ParentRoot []byte `json:"parent_root" ssz:"size=32"` + StateRoot []byte `json:"state_root" ssz:"size=32"` + BodyRoot []byte `json:"body_root" ssz:"size=32"` + Signature []byte `json:"signature" ssz:"size=96"` + } `json:"latest_block_header"` + HistoricalRoots []interface{} `json:"historical_roots"` + LatestEth1Data struct { + DepositRoot []byte `json:"deposit_root" ssz:"size=32"` + DepositCount uint64 `json:"deposit_count"` + BlockHash []byte `json:"block_hash" ssz:"size=32"` + } `json:"latest_eth1_data"` + Eth1DataVotes []interface{} `json:"eth1_data_votes"` + DepositIndex uint64 `json:"deposit_index"` + } `json:"pre"` + Slots uint64 `json:"slots"` + Post struct { + Slot uint64 `json:"slot"` + GenesisTime uint64 `json:"genesis_time"` + Fork struct { + PreviousVersion []byte `json:"previous_version"` + CurrentVersion []byte `json:"current_version"` + Epoch uint64 `json:"epoch"` + } `json:"fork"` + ValidatorRegistry []struct { + Pubkey []byte `json:"pubkey" ssz:"size=48"` + WithdrawalCredentials []byte `json:"withdrawal_credentials" ssz:"size=32"` + ActivationEligibilityEpoch uint64 `json:"activation_eligibility_epoch"` + ActivationEpoch uint64 `json:"activation_epoch"` + ExitEpoch uint64 `json:"exit_epoch"` + WithdrawableEpoch uint64 `json:"withdrawable_epoch"` + Slashed bool `json:"slashed"` + EffectiveBalance uint64 `json:"effective_balance"` + } `json:"validator_registry"` + Balances []uint64 `json:"balances"` + LatestRandaoMixes [][]byte `json:"latest_randao_mixes"` + LatestStartShard uint64 `json:"latest_start_shard"` + PreviousEpochAttestations []interface{} `json:"previous_epoch_attestations"` + CurrentEpochAttestations []interface{} `json:"current_epoch_attestations"` + PreviousJustifiedEpoch uint64 `json:"previous_justified_epoch"` + CurrentJustifiedEpoch uint64 `json:"current_justified_epoch"` + PreviousJustifiedRoot []byte `json:"previous_justified_root" ssz:"size=32"` + CurrentJustifiedRoot []byte `json:"current_justified_root" ssz:"size=32"` + JustificationBitfield uint64 `json:"justification_bitfield"` + FinalizedEpoch uint64 `json:"finalized_epoch"` + FinalizedRoot []byte `json:"finalized_root" ssz:"size=32"` + CurrentCrosslinks []struct { + Shard uint64 `json:"shard"` + StartEpoch uint64 `json:"start_epoch"` + EndEpoch uint64 `json:"end_epoch"` + ParentRoot []byte `json:"parent_root" ssz:"size=32"` + DataRoot []byte `json:"data_root" ssz:"size=32"` + } `json:"current_crosslinks"` + PreviousCrosslinks []struct { + Shard uint64 `json:"shard"` + StartEpoch uint64 `json:"start_epoch"` + EndEpoch uint64 `json:"end_epoch"` + ParentRoot []byte `json:"parent_root" ssz:"size=32"` + DataRoot []byte `json:"data_root" ssz:"size=32"` + } `json:"previous_crosslinks"` + LatestBlockRoots [][]byte `json:"latest_block_roots"` + LatestStateRoots [][]byte `json:"latest_state_roots"` + LatestActiveIndexRoots [][]byte `json:"latest_active_index_roots"` + LatestSlashedBalances []uint64 `json:"latest_slashed_balances"` + LatestBlockHeader struct { + Slot uint64 `json:"slot"` + ParentRoot []byte `json:"parent_root" ssz:"size=32"` + StateRoot []byte `json:"state_root" ssz:"size=32"` + BodyRoot []byte `json:"body_root" ssz:"size=32"` + Signature []byte `json:"signature" ssz:"size=96"` + } `json:"latest_block_header"` + HistoricalRoots []interface{} `json:"historical_roots"` + LatestEth1Data struct { + DepositRoot []byte `json:"deposit_root" ssz:"size=32"` + DepositCount uint64 `json:"deposit_count"` + BlockHash []byte `json:"block_hash" ssz:"size=32"` + } `json:"latest_eth1_data"` + Eth1DataVotes []interface{} `json:"eth1_data_votes"` + DepositIndex uint64 `json:"deposit_index"` + } `json:"post"` + } `json:"test_cases"` +} diff --git a/beacon-chain/core/state/spectest/slot_processing_test.go b/beacon-chain/core/state/spectest/slot_processing_test.go new file mode 100644 index 000000000000..2e8652d71d74 --- /dev/null +++ b/beacon-chain/core/state/spectest/slot_processing_test.go @@ -0,0 +1,68 @@ +package spectest + +import ( + "context" + "io/ioutil" + "testing" + + "github.com/bazelbuild/rules_go/go/tools/bazel" + "github.com/ghodss/yaml" + "github.com/prysmaticlabs/go-ssz" + "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" +) + +func TestSlotProcessingMainnet(t *testing.T) { + filepath, err := bazel.Runfile("/eth2_spec_tests/tests/sanity/slots/sanity_slots_mainnet.yaml") + 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 := yaml.Unmarshal(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) { + preState := &pb.BeaconState{} + if err := testutil.ConvertToPb(tt.Pre, preState); err != nil { + t.Fatal(err) + } + + var postState *pb.BeaconState + + postState, err = state.ProcessSlots(context.Background(), preState, preState.Slot+tt.Slots) + if err != nil { + t.Fatal(err) + } + + expectedPostState := &pb.BeaconState{} + if err := testutil.ConvertToPb(tt.Post, expectedPostState); err != nil { + t.Fatal(err) + } + + expected, err := ssz.HashTreeRoot(expectedPostState) + if err != nil { + t.Fatal(err) + } + received, err := ssz.HashTreeRoot(postState) + if err != nil { + t.Fatal(err) + } + if expected != received { + t.Fatal("post state does not match") + } + }) + } +} diff --git a/beacon-chain/core/state/transition.go b/beacon-chain/core/state/transition.go index 0f10ce4110d1..44a5e5a91d82 100644 --- a/beacon-chain/core/state/transition.go +++ b/beacon-chain/core/state/transition.go @@ -78,6 +78,20 @@ func ExecuteStateTransition( // ProcessSlot happens every slot and focuses on the slot counter and block roots record updates. // It happens regardless if there's an incoming block or not. +// Spec pseudocode definition: +// +// def process_slot(state: BeaconState) -> None: +// # Cache state root +// previous_state_root = hash_tree_root(state) +// state.state_roots[state.slot % SLOTS_PER_HISTORICAL_ROOT] = previous_state_root +// +// # Cache latest block header state root +// if state.latest_block_header.state_root == ZERO_HASH: +// state.latest_block_header.state_root = previous_state_root +// +// # Cache block root +// previous_block_root = signing_root(state.latest_block_header) +// state.block_roots[state.slot % SLOTS_PER_HISTORICAL_ROOT] = previous_block_root func ProcessSlot(ctx context.Context, state *pb.BeaconState) (*pb.BeaconState, error) { ctx, span := trace.StartSpan(ctx, "beacon-chain.ChainService.state.ProcessSlot") defer span.End() @@ -85,6 +99,7 @@ func ProcessSlot(ctx context.Context, state *pb.BeaconState) (*pb.BeaconState, e if err != nil { return nil, fmt.Errorf("could not tree hash prev state root: %v", err) } + state.LatestStateRoots[state.Slot%params.BeaconConfig().SlotsPerHistoricalRoot] = prevStateRoot[:] zeroHash := params.BeaconConfig().ZeroHash @@ -92,7 +107,8 @@ func ProcessSlot(ctx context.Context, state *pb.BeaconState) (*pb.BeaconState, e if bytes.Equal(state.LatestBlockHeader.StateRoot, zeroHash[:]) { state.LatestBlockHeader.StateRoot = prevStateRoot[:] } - prevBlockRoot, err := ssz.HashTreeRoot(state.LatestBlockHeader) + + prevBlockRoot, err := ssz.SigningRoot(state.LatestBlockHeader) if err != nil { return nil, fmt.Errorf("could not determine prev block root: %v", err) }