Update Slot Processing and State Transition v0.6 (#2664)

* edit state transition to add slot processing logic, reorder logic

* fix build

* lint

* tests passing

* spacing

* tests pass

* imports

* passing tests
This commit is contained in:
Raul Jordan
2019-05-21 19:56:40 -04:00
committed by nisdas
parent 5c1410b224
commit ebff47bde1
25 changed files with 137 additions and 319 deletions

View File

@@ -11,13 +11,11 @@ go_library(
deps = [
"//beacon-chain/cache:go_default_library",
"//beacon-chain/core/helpers:go_default_library",
"//beacon-chain/core/state:go_default_library",
"//beacon-chain/db:go_default_library",
"//proto/beacon/p2p/v1:go_default_library",
"//shared/bitutil:go_default_library",
"//shared/bytesutil:go_default_library",
"//shared/event:go_default_library",
"//shared/hashutil:go_default_library",
"//shared/messagehandler:go_default_library",
"//shared/params:go_default_library",
"@com_github_gogo_protobuf//proto:go_default_library",

View File

@@ -10,13 +10,11 @@ import (
"github.com/gogo/protobuf/proto"
"github.com/prysmaticlabs/prysm/beacon-chain/cache"
"github.com/prysmaticlabs/prysm/beacon-chain/core/helpers"
"github.com/prysmaticlabs/prysm/beacon-chain/core/state"
"github.com/prysmaticlabs/prysm/beacon-chain/db"
pb "github.com/prysmaticlabs/prysm/proto/beacon/p2p/v1"
"github.com/prysmaticlabs/prysm/shared/bitutil"
"github.com/prysmaticlabs/prysm/shared/bytesutil"
"github.com/prysmaticlabs/prysm/shared/event"
"github.com/prysmaticlabs/prysm/shared/hashutil"
handler "github.com/prysmaticlabs/prysm/shared/messagehandler"
"github.com/prysmaticlabs/prysm/shared/params"
"github.com/sirupsen/logrus"
@@ -164,15 +162,7 @@ func (a *Service) UpdateLatestAttestation(ctx context.Context, attestation *pb.A
if err != nil {
return err
}
head, err := a.beaconDB.ChainHead()
if err != nil {
return err
}
headRoot, err := hashutil.HashBeaconBlock(head)
if err != nil {
return err
}
return a.updateAttestation(ctx, headRoot, beaconState, attestation)
return a.updateAttestation(beaconState, attestation)
}
// BatchUpdateLatestAttestation updates multiple attestations and adds them into the attestation store
@@ -188,19 +178,11 @@ func (a *Service) BatchUpdateLatestAttestation(ctx context.Context, attestations
if err != nil {
return err
}
head, err := a.beaconDB.ChainHead()
if err != nil {
return err
}
headRoot, err := hashutil.HashBeaconBlock(head)
if err != nil {
return err
}
attestations = a.sortAttestations(attestations)
for _, attestation := range attestations {
if err := a.updateAttestation(ctx, headRoot, beaconState, attestation); err != nil {
if err := a.updateAttestation(beaconState, attestation); err != nil {
return err
}
}
@@ -216,22 +198,9 @@ func (a *Service) InsertAttestationIntoStore(pubkey [48]byte, att *pb.Attestatio
a.store.m[pubkey] = att
}
func (a *Service) updateAttestation(ctx context.Context, headRoot [32]byte, beaconState *pb.BeaconState,
attestation *pb.Attestation) error {
func (a *Service) updateAttestation(beaconState *pb.BeaconState, attestation *pb.Attestation) error {
totalAttestationSeen.Inc()
slot := attestation.Data.Slot
var err error
for beaconState.Slot < slot {
beaconState, err = state.ExecuteStateTransition(
ctx, beaconState, nil /* block */, headRoot, &state.TransitionConfig{},
)
if err != nil {
return fmt.Errorf("could not execute head transition: %v", err)
}
}
committee, err := helpers.CrosslinkCommitteeAtEpoch(beaconState, helpers.CurrentEpoch(beaconState), attestation.Data.Shard)
if err != nil {
return err

View File

@@ -35,7 +35,7 @@ type BlockReceiver interface {
// to beacon blocks and generating a new beacon state from the Ethereum 2.0 core primitives.
type BlockProcessor interface {
VerifyBlockValidity(ctx context.Context, block *pb.BeaconBlock, beaconState *pb.BeaconState) error
ApplyBlockStateTransition(ctx context.Context, block *pb.BeaconBlock, beaconState *pb.BeaconState) (*pb.BeaconState, error)
AdvanceState(ctx context.Context, beaconState *pb.BeaconState, block *pb.BeaconBlock) (*pb.BeaconState, error)
CleanupBlockOperations(ctx context.Context, block *pb.BeaconBlock) error
}
@@ -95,7 +95,7 @@ func (c *ChainService) ReceiveBlock(ctx context.Context, block *pb.BeaconBlock)
"Executing state transition")
// We then apply the block state transition accordingly to obtain the resulting beacon state.
beaconState, err = c.ApplyBlockStateTransition(ctx, block, beaconState)
beaconState, err = c.AdvanceState(ctx, beaconState, block)
if err != nil {
switch err.(type) {
case *BlockFailedProcessingErr:
@@ -139,52 +139,6 @@ func (c *ChainService) ReceiveBlock(ctx context.Context, block *pb.BeaconBlock)
return beaconState, nil
}
// ApplyBlockStateTransition runs the Ethereum 2.0 state transition function
// to produce a new beacon state and also accounts for skip slots occurring.
//
// def apply_block_state_transition(block):
// # process skipped slots
// while (state.slot < block.slot - 1):
// state = slot_state_transition(state, block=None)
//
// # process slot with block
// state = slot_state_transition(state, block)
//
// # check state root
// if block.state_root == hash(state):
// return state, error
// else:
// return nil, error # or throw or whatever
//
func (c *ChainService) ApplyBlockStateTransition(
ctx context.Context, block *pb.BeaconBlock, beaconState *pb.BeaconState,
) (*pb.BeaconState, error) {
// Retrieve the last processed beacon block's hash root.
headRoot, err := c.ChainHeadRoot()
if err != nil {
return beaconState, fmt.Errorf("could not retrieve chain head root: %v", err)
}
// Check for skipped slots.
numSkippedSlots := 0
for beaconState.Slot < block.Slot-1 {
beaconState, err = c.runStateTransition(ctx, headRoot, nil, beaconState)
if err != nil {
return beaconState, err
}
numSkippedSlots++
}
if numSkippedSlots > 0 {
log.Warnf("Processed %d skipped slots", numSkippedSlots)
}
beaconState, err = c.runStateTransition(ctx, headRoot, block, beaconState)
if err != nil {
return beaconState, err
}
return beaconState, nil
}
// VerifyBlockValidity cross-checks the block against the pre-processing conditions from
// Ethereum 2.0, namely:
// The parent block with root block.parent_root has been processed and accepted.
@@ -255,20 +209,18 @@ func (c *ChainService) CleanupBlockOperations(ctx context.Context, block *pb.Bea
return nil
}
// runStateTransition executes the Ethereum 2.0 core state transition for the beacon chain and
// AdvanceState executes the Ethereum 2.0 core state transition for the beacon chain and
// updates important checkpoints and local persistent data during epoch transitions. It serves as a wrapper
// around the more low-level, core state transition function primitive.
func (c *ChainService) runStateTransition(
func (c *ChainService) AdvanceState(
ctx context.Context,
headRoot [32]byte,
block *pb.BeaconBlock,
beaconState *pb.BeaconState,
block *pb.BeaconBlock,
) (*pb.BeaconState, error) {
newState, err := state.ExecuteStateTransition(
ctx,
beaconState,
block,
headRoot,
&state.TransitionConfig{
VerifySignatures: false, // We disable signature verification for now.
Logging: true, // We enable logging in this state transition call.

View File

@@ -39,7 +39,7 @@ func initBlockStateRoot(t *testing.T, block *pb.BeaconBlock, chainService *Chain
}
saveLatestBlock := beaconState.LatestBlock
computedState, err := chainService.ApplyBlockStateTransition(context.Background(), block, beaconState)
computedState, err := chainService.AdvanceState(context.Background(), beaconState, block)
if err != nil {
t.Fatalf("could not apply block state transition: %v", err)
}
@@ -115,6 +115,10 @@ func TestReceiveBlock_ProcessCorrectly(t *testing.T) {
if err != nil {
t.Fatalf("Can't generate genesis state: %v", err)
}
beaconState.LatestStateRoots = make([][]byte, params.BeaconConfig().SlotsPerHistoricalRoot)
beaconState.LatestBlockHeader = &pb.BeaconBlockHeader{
StateRoot: []byte{},
}
stateRoot, err := hashutil.HashProto(beaconState)
if err != nil {
t.Fatalf("Could not tree hash state: %v", err)
@@ -186,8 +190,9 @@ func TestReceiveBlock_UsesParentBlockState(t *testing.T) {
if err != nil {
t.Fatalf("Can't generate genesis state: %v", err)
}
if err := chainService.beaconDB.SaveHistoricalState(ctx, beaconState); err != nil {
t.Fatal(err)
beaconState.LatestStateRoots = make([][]byte, params.BeaconConfig().SlotsPerHistoricalRoot)
beaconState.LatestBlockHeader = &pb.BeaconBlockHeader{
StateRoot: []byte{},
}
stateRoot, err := hashutil.HashProto(beaconState)
if err != nil {
@@ -241,6 +246,10 @@ func TestReceiveBlock_DeletesBadBlock(t *testing.T) {
if err != nil {
t.Fatalf("Can't generate genesis state: %v", err)
}
beaconState.LatestStateRoots = make([][]byte, params.BeaconConfig().SlotsPerHistoricalRoot)
beaconState.LatestBlockHeader = &pb.BeaconBlockHeader{
StateRoot: []byte{},
}
stateRoot, err := hashutil.HashProto(beaconState)
if err != nil {
t.Fatalf("Could not tree hash state: %v", err)
@@ -324,7 +333,12 @@ func TestReceiveBlock_CheckBlockStateRoot_GoodState(t *testing.T) {
if err != nil {
t.Fatalf("Can't generate genesis state: %v", err)
}
if err := chainService.beaconDB.SaveHistoricalState(ctx, beaconState); err != nil {
beaconState.LatestStateRoots = make([][]byte, params.BeaconConfig().SlotsPerHistoricalRoot)
beaconState.LatestBlockHeader = &pb.BeaconBlockHeader{
StateRoot: []byte{},
}
parentHash, genesisBlock := setupGenesisBlock(t, chainService)
if err := chainService.beaconDB.SaveHistoricalState(ctx, beaconState, parentHash); err != nil {
t.Fatal(err)
}
parentHash, genesisBlock := setupGenesisBlock(t, chainService)
@@ -370,7 +384,12 @@ func TestReceiveBlock_CheckBlockStateRoot_BadState(t *testing.T) {
if err != nil {
t.Fatalf("Can't generate genesis state: %v", err)
}
if err := chainService.beaconDB.SaveHistoricalState(ctx, beaconState); err != nil {
beaconState.LatestStateRoots = make([][]byte, params.BeaconConfig().SlotsPerHistoricalRoot)
beaconState.LatestBlockHeader = &pb.BeaconBlockHeader{
StateRoot: []byte{},
}
parentHash, genesisBlock := setupGenesisBlock(t, chainService)
if err := chainService.beaconDB.SaveHistoricalState(ctx, beaconState, parentHash); err != nil {
t.Fatal(err)
}
parentHash, genesisBlock := setupGenesisBlock(t, chainService)
@@ -419,6 +438,10 @@ func TestReceiveBlock_RemovesPendingDeposits(t *testing.T) {
if err != nil {
t.Fatalf("Can't generate genesis state: %v", err)
}
beaconState.LatestStateRoots = make([][]byte, params.BeaconConfig().SlotsPerHistoricalRoot)
beaconState.LatestBlockHeader = &pb.BeaconBlockHeader{
StateRoot: []byte{},
}
if err := chainService.beaconDB.SaveJustifiedState(beaconState); err != nil {
t.Fatal(err)
}
@@ -585,6 +608,10 @@ func TestReceiveBlock_OnChainSplit(t *testing.T) {
if err != nil {
t.Fatalf("Can't generate genesis state: %v", err)
}
beaconState.LatestStateRoots = make([][]byte, params.BeaconConfig().SlotsPerHistoricalRoot)
beaconState.LatestBlockHeader = &pb.BeaconBlockHeader{
StateRoot: []byte{},
}
stateRoot, err := hashutil.HashProto(beaconState)
if err != nil {
t.Fatalf("Could not tree hash state: %v", err)
@@ -718,6 +745,10 @@ func TestIsBlockReadyForProcessing_ValidBlock(t *testing.T) {
if err != nil {
t.Fatalf("Can't get genesis state: %v", err)
}
beaconState.LatestStateRoots = make([][]byte, params.BeaconConfig().SlotsPerHistoricalRoot)
beaconState.LatestBlockHeader = &pb.BeaconBlockHeader{
StateRoot: []byte{},
}
block := &pb.BeaconBlock{
ParentBlockRoot: []byte{'a'},
}

View File

@@ -42,6 +42,10 @@ func TestApplyForkChoice_ChainSplitReorg(t *testing.T) {
if err != nil {
t.Fatalf("Can't generate genesis state: %v", err)
}
justifiedState.LatestStateRoots = make([][]byte, params.BeaconConfig().SlotsPerHistoricalRoot)
justifiedState.LatestBlockHeader = &pb.BeaconBlockHeader{
StateRoot: []byte{},
}
chainService := setupBeaconChain(t, beaconDB, nil)
@@ -68,7 +72,7 @@ func TestApplyForkChoice_ChainSplitReorg(t *testing.T) {
canonicalBlockIndices := []int{1, 3, 5}
postState := proto.Clone(justifiedState).(*pb.BeaconState)
for _, canonicalIndex := range canonicalBlockIndices {
postState, err = chainService.ApplyBlockStateTransition(ctx, blocks[canonicalIndex], postState)
postState, err = chainService.AdvanceState(ctx, postState, blocks[canonicalIndex])
if err != nil {
t.Fatal(err)
}
@@ -97,7 +101,7 @@ func TestApplyForkChoice_ChainSplitReorg(t *testing.T) {
forkedBlockIndices := []int{2, 4}
forkState := proto.Clone(justifiedState).(*pb.BeaconState)
for _, forkIndex := range forkedBlockIndices {
forkState, err = chainService.ApplyBlockStateTransition(ctx, blocks[forkIndex], forkState)
forkState, err = chainService.AdvanceState(ctx, forkState, blocks[forkIndex])
if err != nil {
t.Fatal(err)
}

View File

@@ -81,7 +81,6 @@ func GenerateStateFromBlock(ctx context.Context, db *db.BeaconDB, slot uint64) (
log.Infof("Recompute state starting last finalized slot %d and ending slot %d",
fState.Slot-params.BeaconConfig().GenesisSlot, slot-params.BeaconConfig().GenesisSlot)
postState := fState
root := fRoot
// this recomputes state up to the last available block.
// ex: 1A - 2B (finalized) - 3C - 4 - 5 - 6C - 7 - 8 (C is the last block).
// input slot 8, this recomputes state to slot 6.
@@ -96,7 +95,6 @@ func GenerateStateFromBlock(ctx context.Context, db *db.BeaconDB, slot uint64) (
ctx,
postState,
nil,
root,
&state.TransitionConfig{
VerifySignatures: false,
Logging: false,
@@ -110,7 +108,6 @@ func GenerateStateFromBlock(ctx context.Context, db *db.BeaconDB, slot uint64) (
ctx,
postState,
block,
root,
&state.TransitionConfig{
VerifySignatures: false,
Logging: false,
@@ -119,11 +116,6 @@ func GenerateStateFromBlock(ctx context.Context, db *db.BeaconDB, slot uint64) (
if err != nil {
return nil, fmt.Errorf("could not execute state transition %v", err)
}
root, err = hashutil.HashBeaconBlock(block)
if err != nil {
return nil, fmt.Errorf("unable to get block root %v", err)
}
}
// this recomputes state from last block to last slot if there's skipp slots after.
@@ -134,7 +126,6 @@ func GenerateStateFromBlock(ctx context.Context, db *db.BeaconDB, slot uint64) (
ctx,
postState,
nil,
root,
&state.TransitionConfig{
VerifySignatures: false,
Logging: false,

View File

@@ -128,13 +128,6 @@ func TestGenerateState_WithNilBlocksOK(t *testing.T) {
slotsWithNil := uint64(10)
// Run the chain for 10 slots with nil blocks.
for i := uint64(0); i < slotsWithNil; i++ {
if err := b.GenerateNilBlockAndAdvanceChain(); err != nil {
t.Fatalf("Could not generate block and transition state successfully %v for slot %d", err, b.State().Slot+1)
}
}
for i := uint64(0); i < slotLimit-slotsWithNil; i++ {
if err := b.GenerateBlockAndAdvanceChain(&backend.SimulatedObjects{}, privKeys); err != nil {
t.Fatalf("Could not generate block and transition state successfully %v for slot %d", err, b.State().Slot+1)

View File

@@ -107,7 +107,6 @@ func (sb *SimulatedBackend) GenerateBlockAndAdvanceChain(objects *SimulatedObjec
context.Background(),
sb.state,
newBlock,
prevBlockRoot,
state.DefaultConfig(),
)
if err != nil {
@@ -124,23 +123,6 @@ func (sb *SimulatedBackend) GenerateBlockAndAdvanceChain(objects *SimulatedObjec
return nil
}
// GenerateNilBlockAndAdvanceChain would trigger a state transition with a nil block.
func (sb *SimulatedBackend) GenerateNilBlockAndAdvanceChain() error {
prevBlockRoot := sb.prevBlockRoots[len(sb.prevBlockRoots)-1]
newState, err := state.ExecuteStateTransition(
context.Background(),
sb.state,
nil,
prevBlockRoot,
state.DefaultConfig(),
)
if err != nil {
return fmt.Errorf("could not execute state transition: %v", err)
}
sb.state = newState
return nil
}
// Shutdown closes the db associated with the simulated backend.
func (sb *SimulatedBackend) Shutdown() error {
return sb.beaconDB.Close()
@@ -223,13 +205,9 @@ func (sb *SimulatedBackend) RunStateTransitionTest(testCase *StateTestCase) erro
averageTimesPerTransition := []time.Duration{}
startSlot := params.BeaconConfig().GenesisSlot
for i := startSlot; i < startSlot+testCase.Config.NumSlots; i++ {
// If the slot is marked as skipped in the configuration options,
// we simply run the state transition with a nil block argument.
if sliceutil.IsInUint64(i, testCase.Config.SkipSlots) {
if err := sb.GenerateNilBlockAndAdvanceChain(); err != nil {
return fmt.Errorf("could not advance the chain with a nil block %v", err)
}
continue
}
@@ -279,6 +257,10 @@ func (sb *SimulatedBackend) setupBeaconStateAndGenesisBlock(initialDeposits []*p
if err != nil {
return fmt.Errorf("could not initialize simulated beacon state: %v", err)
}
sb.state.LatestStateRoots = make([][]byte, params.BeaconConfig().SlotsPerHistoricalRoot)
sb.state.LatestBlockHeader = &pb.BeaconBlockHeader{
StateRoot: []byte{},
}
sb.historicalDeposits = initialDeposits
// We do not expect hashing initial beacon state and genesis block to

View File

@@ -55,31 +55,4 @@ func TestGenerateBlockAndAdvanceChain_IncreasesSlot(t *testing.T) {
if backend.state.Slot != params.BeaconConfig().GenesisSlot+uint64(slotLimit) {
t.Errorf("Unequal state slot and expected slot %d %d", backend.state.Slot, slotLimit)
}
}
func TestGenerateNilBlockAndAdvanceChain_IncreasesSlot(t *testing.T) {
backend, err := NewSimulatedBackend()
if err != nil {
t.Fatalf("Could not create a new simulated backedn %v", err)
}
if _, err := backend.SetupBackend(100); err != nil {
t.Fatalf("Could not set up backend %v", err)
}
defer backend.Shutdown()
defer db.TeardownDB(backend.beaconDB)
slotLimit := params.BeaconConfig().SlotsPerEpoch + uint64(1)
for i := uint64(0); i < slotLimit; i++ {
if err := backend.GenerateNilBlockAndAdvanceChain(); err != nil {
t.Fatalf("Could not generate block and transition state successfully %v for slot %d", err, backend.state.Slot+1)
}
}
if backend.state.Slot != params.BeaconConfig().GenesisSlot+uint64(slotLimit) {
t.Errorf("Unequal state slot and expected slot %d %d", backend.state.Slot, slotLimit)
}
}

View File

@@ -9,6 +9,8 @@ import (
"encoding/binary"
"errors"
"fmt"
"sort"
"github.com/gogo/protobuf/proto"
"github.com/prysmaticlabs/prysm/beacon-chain/core/helpers"
"github.com/prysmaticlabs/prysm/beacon-chain/core/validators"
@@ -19,7 +21,6 @@ import (
"github.com/prysmaticlabs/prysm/shared/params"
"github.com/prysmaticlabs/prysm/shared/sliceutil"
"github.com/prysmaticlabs/prysm/shared/ssz"
"sort"
)
// MatchedAttestations is an object that contains the correctly

View File

@@ -18,6 +18,7 @@ go_library(
"//shared/bytesutil:go_default_library",
"//shared/hashutil:go_default_library",
"//shared/params:go_default_library",
"//shared/ssz:go_default_library",
"@com_github_sirupsen_logrus//:go_default_library",
"@io_opencensus_go//trace:go_default_library",
],

View File

@@ -4,6 +4,7 @@
package state
import (
"bytes"
"context"
"fmt"
@@ -13,6 +14,7 @@ import (
"github.com/prysmaticlabs/prysm/shared/bytesutil"
"github.com/prysmaticlabs/prysm/shared/hashutil"
"github.com/prysmaticlabs/prysm/shared/params"
"github.com/prysmaticlabs/prysm/shared/ssz"
"github.com/sirupsen/logrus"
"go.opencensus.io/trace"
)
@@ -38,26 +40,39 @@ func DefaultConfig() *TransitionConfig {
// ExecuteStateTransition defines the procedure for a state transition function.
// Spec pseudocode definition:
// We now define the state transition function. At a high level the state transition is made up of three parts:
// - The per-slot transitions, which happens at the start of every slot.
// - The per-block transitions, which happens at every block.
// - The per-epoch transitions, which happens at the end of the last slot of every epoch (i.e. (state.slot + 1) % SLOTS_PER_EPOCH == 0).
// The per-slot transitions focus on the slot counter and block roots records updates.
// The per-block transitions focus on verifying aggregate signatures and saving temporary records relating to the per-block activity in the state.
// The per-epoch transitions focus on the validator registry, including adjusting balances and activating and exiting validators,
// as well as processing crosslinks and managing block justification/finalization.
// - The per-slot transitions focuses on increasing the slot number and recording recent block headers.
// - The per-epoch transitions focuses on the validator registry, adjusting balances, and finalizing slots.
// - The per-block transitions focuses on verifying block operations, verifying attestations, and signatures.
func ExecuteStateTransition(
ctx context.Context,
state *pb.BeaconState,
block *pb.BeaconBlock,
headRoot [32]byte,
config *TransitionConfig,
) (*pb.BeaconState, error) {
if ctx.Err() != nil {
return nil, ctx.Err()
}
ctx, span := trace.StartSpan(ctx, "beacon-chain.ChainService.StateTransition")
defer span.End()
var err error
// Execute per slot transition.
state = ProcessSlot(ctx, state, headRoot)
if state.Slot >= block.Slot {
return nil, fmt.Errorf("expected state.slot %d < block.slot %d", state.Slot, block.Slot)
}
for state.Slot < block.Slot {
state, err = ProcessSlot(ctx, state)
if err != nil {
return nil, fmt.Errorf("could not process slot: %v", err)
}
if e.CanProcessEpoch(state) {
state, err = ProcessEpoch(ctx, state)
if err != nil {
return nil, fmt.Errorf("could not process epoch: %v", err)
}
}
state.Slot++
}
// Execute per block transition.
if block != nil {
@@ -66,33 +81,33 @@ func ExecuteStateTransition(
return nil, fmt.Errorf("could not process block: %v", err)
}
}
// Execute per epoch transition.
if e.CanProcessEpoch(state) {
state, err = ProcessEpoch(ctx, state, block, config)
}
if err != nil {
return nil, fmt.Errorf("could not process epoch: %v", err)
}
// TODO(#2307): Validate state root.
return state, nil
}
// 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:
// Set state.slot += 1
// Let previous_block_root be the hash_tree_root of the previous beacon block processed in the chain
// Set state.latest_block_roots[(state.slot - 1) % LATEST_BLOCK_ROOTS_LENGTH] = previous_block_root
// If state.slot % LATEST_BLOCK_ROOTS_LENGTH == 0
// append merkle_root(state.latest_block_roots) to state.batched_block_roots
func ProcessSlot(ctx context.Context, state *pb.BeaconState, headRoot [32]byte) *pb.BeaconState {
func ProcessSlot(ctx context.Context, state *pb.BeaconState) (*pb.BeaconState, error) {
ctx, span := trace.StartSpan(ctx, "beacon-chain.ChainService.state.ProcessSlot")
defer span.End()
state.Slot++
state = b.ProcessBlockRoots(state, headRoot)
return state
prevStateRoot, err := ssz.TreeHash(state)
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
// Cache latest block header state root.
if bytes.Equal(state.LatestBlockHeader.StateRoot, zeroHash[:]) {
state.LatestBlockHeader.StateRoot = prevStateRoot[:]
}
prevBlockRoot, err := ssz.SigningRoot(state.LatestBlockHeader)
if err != nil {
return nil, fmt.Errorf("could not determine prev block root: %v", err)
}
// Cache the block root.
state.LatestBlockRoots[state.Slot%params.BeaconConfig().SlotsPerHistoricalRoot] = prevBlockRoot[:]
return state, nil
}
// ProcessBlock creates a new, modified beacon state by applying block operation
@@ -104,7 +119,6 @@ func ProcessBlock(
block *pb.BeaconBlock,
config *TransitionConfig,
) (*pb.BeaconState, error) {
ctx, span := trace.StartSpan(ctx, "beacon-chain.ChainService.state.ProcessBlock")
defer span.End()
@@ -113,24 +127,6 @@ func ProcessBlock(
return nil, fmt.Errorf("could not hash block: %v", err)
}
// Below are the processing steps to verify every block.
// Verify block slot.
if block.Slot != state.Slot {
return nil, fmt.Errorf(
"block.slot != state.slot, block.slot = %d, state.slot = %d",
block.Slot-params.BeaconConfig().GenesisSlot,
state.Slot-params.BeaconConfig().GenesisSlot,
)
}
// Verify block signature.
if config.VerifySignatures {
// TODO(#781): Verify Proposer Signature.
if err := b.VerifyProposerSignature(block); err != nil {
return nil, fmt.Errorf("could not verify proposer signature: %v", err)
}
}
// Save latest block.
state.LatestBlock = block
@@ -139,24 +135,20 @@ func ProcessBlock(
if err != nil {
return nil, fmt.Errorf("could not verify and process randao: %v", err)
}
// Process ETH1 data.
state = b.ProcessEth1DataInBlock(state, block)
state, err = b.ProcessAttesterSlashings(state, block, config.VerifySignatures)
if err != nil {
return nil, fmt.Errorf("could not verify block attester slashings: %v", err)
}
state, err = b.ProcessProposerSlashings(state, block, config.VerifySignatures)
if err != nil {
return nil, fmt.Errorf("could not verify block proposer slashings: %v", err)
}
state, err = b.ProcessBlockAttestations(state, block, config.VerifySignatures)
if err != nil {
return nil, fmt.Errorf("could not process block attestations: %v", err)
}
state, err = b.ProcessValidatorDeposits(state, block, config.VerifySignatures)
if err != nil {
return nil, fmt.Errorf("could not process block validator deposits: %v", err)
@@ -165,6 +157,10 @@ func ProcessBlock(
if err != nil {
return nil, fmt.Errorf("could not process validator exits: %v", err)
}
state, err = b.ProcessTransfers(state, block, config.VerifySignatures)
if err != nil {
return nil, fmt.Errorf("could not process block transfers: %v", err)
}
if config.Logging {
log.WithField("blockRoot", fmt.Sprintf("%#x", bytesutil.Trunc(r[:]))).Debugf("Verified block slot == state slot")
@@ -182,12 +178,10 @@ func ProcessBlock(
// ProcessEpoch describes the per epoch operations that are performed on the
// beacon state.
//
func ProcessEpoch(ctx context.Context, state *pb.BeaconState, _ *pb.BeaconBlock, _ *TransitionConfig) (*pb.BeaconState, error) {
func ProcessEpoch(ctx context.Context, state *pb.BeaconState) (*pb.BeaconState, error) {
ctx, span := trace.StartSpan(ctx, "beacon-chain.ChainService.state.ProcessEpoch")
defer span.End()
// TODO(#2307): Implement process epoch based on 0.6.
return state, nil
}

View File

@@ -61,19 +61,15 @@ func createRandaoReveal(t *testing.T, beaconState *pb.BeaconState, privKeys []*b
return epochSignature.Marshal()
}
func TestProcessBlock_IncorrectSlot(t *testing.T) {
func TestExecuteStateTransition_IncorrectSlot(t *testing.T) {
beaconState := &pb.BeaconState{
Slot: params.BeaconConfig().GenesisSlot + 5,
}
block := &pb.BeaconBlock{
Slot: params.BeaconConfig().GenesisSlot + 4,
}
want := fmt.Sprintf(
"block.slot != state.slot, block.slot = %d, state.slot = %d",
4,
5,
)
if _, err := state.ProcessBlock(context.Background(), beaconState, block, state.DefaultConfig()); !strings.Contains(err.Error(), want) {
want := "expected state.slot"
if _, err := state.ExecuteStateTransition(context.Background(), beaconState, block, state.DefaultConfig()); !strings.Contains(err.Error(), want) {
t.Errorf("Expected %s, received %v", want, err)
}
}
@@ -452,7 +448,7 @@ func TestProcessEpoch_PassesProcessingConditions(t *testing.T) {
params.BeaconConfig().LatestSlashedExitLength),
}
_, err := state.ProcessEpoch(context.Background(), newState, &pb.BeaconBlock{}, state.DefaultConfig())
_, err := state.ProcessEpoch(context.Background(), newState)
if err != nil {
t.Errorf("Expected epoch transition to pass processing conditions: %v", err)
}
@@ -516,7 +512,7 @@ func TestProcessEpoch_PreventsRegistryUpdateOnNilBlock(t *testing.T) {
FinalizedEpoch: params.BeaconConfig().GenesisEpoch + 1,
}
newState, err := state.ProcessEpoch(context.Background(), newState, nil, state.DefaultConfig())
newState, err := state.ProcessEpoch(context.Background(), newState)
if err != nil {
t.Errorf("Expected epoch transition to pass processing conditions: %v", err)
}
@@ -587,7 +583,7 @@ func TestProcessEpoch_InactiveConditions(t *testing.T) {
params.BeaconConfig().LatestSlashedExitLength),
}
_, err := state.ProcessEpoch(context.Background(), newState, &pb.BeaconBlock{}, state.DefaultConfig())
_, err := state.ProcessEpoch(context.Background(), newState)
if err != nil {
t.Errorf("Expected epoch transition to pass processing conditions: %v", err)
}
@@ -608,7 +604,7 @@ func TestProcessEpoch_CantGetBoundaryAttestation(t *testing.T) {
0,
newState.Slot-params.BeaconConfig().GenesisSlot,
)
if _, err := state.ProcessEpoch(context.Background(), newState, &pb.BeaconBlock{}, state.DefaultConfig()); !strings.Contains(err.Error(), want) {
if _, err := state.ProcessEpoch(context.Background(), newState); !strings.Contains(err.Error(), want) {
t.Errorf("Expected: %s, received: %v", want, err)
}
}
@@ -643,7 +639,7 @@ func TestProcessEpoch_CantGetCurrentValidatorIndices(t *testing.T) {
wanted := fmt.Sprintf("could not process justification and finalization of state: slot %d is not within expected range of %d to %d",
64, 0, 64)
if _, err := state.ProcessEpoch(context.Background(), newState, &pb.BeaconBlock{}, state.DefaultConfig()); !strings.Contains(err.Error(), wanted) {
if _, err := state.ProcessEpoch(context.Background(), newState); !strings.Contains(err.Error(), wanted) {
t.Errorf("Expected: %s, received: %v", wanted, err)
}
}

View File

@@ -6,7 +6,6 @@ import (
"github.com/prysmaticlabs/prysm/beacon-chain/core/blocks"
"github.com/prysmaticlabs/prysm/beacon-chain/core/helpers"
"github.com/prysmaticlabs/prysm/beacon-chain/core/state"
"github.com/prysmaticlabs/prysm/beacon-chain/db"
pbp2p "github.com/prysmaticlabs/prysm/proto/beacon/p2p/v1"
pb "github.com/prysmaticlabs/prysm/proto/beacon/rpc/v1"
@@ -57,15 +56,6 @@ func (as *AttesterServer) AttestationDataAtSlot(ctx context.Context, req *pb.Att
return nil, fmt.Errorf("could not fetch head state: %v", err)
}
for headState.Slot < req.Slot {
headState, err = state.ExecuteStateTransition(
ctx, headState, nil /* block */, headRoot, state.DefaultConfig(),
)
if err != nil {
return nil, fmt.Errorf("could not execute head transition: %v", err)
}
}
// Fetch the epoch boundary root = hash_tree_root(epoch_boundary)
// where epoch_boundary is the block at the most recent epoch boundary in the
// chain defined by head -- i.e. the BeaconBlock where block.slot == get_epoch_start_slot(head.slot).

View File

@@ -36,23 +36,6 @@ func (ps *ProposerServer) ProposerIndex(ctx context.Context, req *pb.ProposerInd
if err != nil {
return nil, fmt.Errorf("could not get beacon state: %v", err)
}
head, err := ps.beaconDB.ChainHead()
if err != nil {
return nil, fmt.Errorf("could not get chain head: %v", err)
}
headRoot, err := hashutil.HashBeaconBlock(head)
if err != nil {
return nil, fmt.Errorf("could not hash block: %v", err)
}
for beaconState.Slot < req.SlotNumber {
beaconState, err = state.ExecuteStateTransition(
ctx, beaconState, nil /* block */, headRoot, state.DefaultConfig(),
)
if err != nil {
return nil, fmt.Errorf("could not execute head transition: %v", err)
}
}
beaconState.Slot = req.SlotNumber
proposerIndex, err := helpers.BeaconProposerIndex(beaconState)
if err != nil {
@@ -106,23 +89,6 @@ func (ps *ProposerServer) PendingAttestations(ctx context.Context, req *pb.Pendi
if err != nil {
return nil, fmt.Errorf("could not retrieve pending attestations from operations service: %v", err)
}
head, err := ps.beaconDB.ChainHead()
if err != nil {
return nil, fmt.Errorf("failed to retrieve chain head: %v", err)
}
blockRoot, err := hashutil.HashBeaconBlock(head)
if err != nil {
return nil, fmt.Errorf("could not hash beacon block: %v", err)
}
for beaconState.Slot < req.ProposalBlockSlot-1 {
beaconState, err = state.ExecuteStateTransition(
ctx, beaconState, nil /* block */, blockRoot, &state.TransitionConfig{},
)
if err != nil {
return nil, fmt.Errorf("could not execute head transition: %v", err)
}
}
beaconState.Slot++
var attsReadyForInclusion []*pbp2p.Attestation
@@ -161,25 +127,10 @@ func (ps *ProposerServer) ComputeStateRoot(ctx context.Context, req *pbp2p.Beaco
return nil, fmt.Errorf("could not get beacon state: %v", err)
}
parentHash := bytesutil.ToBytes32(req.ParentBlockRoot)
// Check for skipped slots.
for beaconState.Slot < req.Slot-1 {
beaconState, err = state.ExecuteStateTransition(
ctx,
beaconState,
nil,
parentHash,
state.DefaultConfig(),
)
if err != nil {
return nil, fmt.Errorf("could not execute state transition %v", err)
}
}
beaconState, err = state.ExecuteStateTransition(
ctx,
beaconState,
req,
parentHash,
state.DefaultConfig(),
)
if err != nil {

View File

@@ -110,7 +110,10 @@ func TestComputeStateRoot_OK(t *testing.T) {
if err != nil {
t.Fatalf("Could not instantiate genesis state: %v", err)
}
beaconState.LatestStateRoots = make([][]byte, params.BeaconConfig().SlotsPerHistoricalRoot)
beaconState.LatestBlockHeader = &pbp2p.BeaconBlockHeader{
StateRoot: []byte{},
}
beaconState.Slot = 10
if err := db.UpdateChainHead(ctx, genesis, beaconState); err != nil {

View File

@@ -8,11 +8,11 @@ import (
"time"
"github.com/prysmaticlabs/prysm/beacon-chain/core/helpers"
"github.com/prysmaticlabs/prysm/beacon-chain/core/state"
"github.com/prysmaticlabs/prysm/beacon-chain/core/state/stateutils"
"github.com/prysmaticlabs/prysm/beacon-chain/db"
pbp2p "github.com/prysmaticlabs/prysm/proto/beacon/p2p/v1"
pb "github.com/prysmaticlabs/prysm/proto/beacon/rpc/v1"
"github.com/prysmaticlabs/prysm/shared/hashutil"
"github.com/prysmaticlabs/prysm/shared/bytesutil"
"github.com/prysmaticlabs/prysm/shared/params"
)
@@ -132,23 +132,6 @@ func (vs *ValidatorServer) CommitteeAssignment(
if err != nil {
return nil, fmt.Errorf("could not fetch beacon state: %v", err)
}
chainHead, err := vs.beaconDB.ChainHead()
if err != nil {
return nil, fmt.Errorf("could not get chain head: %v", err)
}
headRoot, err := hashutil.HashBeaconBlock(chainHead)
if err != nil {
return nil, fmt.Errorf("could not hash block: %v", err)
}
for beaconState.Slot < req.EpochStart {
beaconState, err = state.ExecuteStateTransition(
ctx, beaconState, nil /* block */, headRoot, state.DefaultConfig(),
)
if err != nil {
return nil, fmt.Errorf("could not execute head transition: %v", err)
}
}
var assignments []*pb.CommitteeAssignmentResponse_CommitteeAssignment
activeKeys := vs.filterActivePublicKeys(beaconState, req.PublicKeys)

View File

@@ -221,7 +221,7 @@ func (s *InitialSync) exitInitialSync(ctx context.Context, block *pb.BeaconBlock
}); err != nil {
return fmt.Errorf("failed to save attestation target: %v", err)
}
state, err = s.chainService.ApplyBlockStateTransition(ctx, block, state)
state, err = s.chainService.AdvanceState(ctx, state, block)
if err != nil {
switch err.(type) {
case *blockchain.BlockFailedProcessingErr:

View File

@@ -67,8 +67,8 @@ func (ms *mockChainService) ReceiveBlock(ctx context.Context, block *pb.BeaconBl
return &pb.BeaconState{}, nil
}
func (ms *mockChainService) ApplyBlockStateTransition(
ctx context.Context, block *pb.BeaconBlock, beaconState *pb.BeaconState,
func (ms *mockChainService) AdvanceState(
ctx context.Context, beaconState *pb.BeaconState, block *pb.BeaconBlock,
) (*pb.BeaconState, error) {
return &pb.BeaconState{}, nil
}

View File

@@ -167,7 +167,7 @@ func (s *InitialSync) validateAndSaveNextBlock(ctx context.Context, block *pb.Be
}); err != nil {
return fmt.Errorf("could not to save attestation target: %v", err)
}
state, err = s.chainService.ApplyBlockStateTransition(ctx, block, state)
state, err = s.chainService.AdvanceState(ctx, state, block)
if err != nil {
return fmt.Errorf("could not apply block state transition: %v", err)
}

View File

@@ -76,7 +76,9 @@ func (ms *mockChainService) ReceiveBlock(ctx context.Context, block *pb.BeaconBl
return &pb.BeaconState{}, nil
}
func (ms *mockChainService) ApplyBlockStateTransition(ctx context.Context, block *pb.BeaconBlock, beaconState *pb.BeaconState) (*pb.BeaconState, error) {
func (ms *mockChainService) AdvanceState(
ctx context.Context, beaconState *pb.BeaconState, block *pb.BeaconBlock,
) (*pb.BeaconState, error) {
return &pb.BeaconState{}, nil
}

View File

@@ -5,9 +5,10 @@ package ethereum_beacon_p2p_v1
import (
fmt "fmt"
proto "github.com/gogo/protobuf/proto"
io "io"
math "math"
proto "github.com/gogo/protobuf/proto"
)
// Reference imports to suppress errors if they are not otherwise used.

View File

@@ -5,10 +5,11 @@ package ethereum_beacon_p2p_v1
import (
fmt "fmt"
proto "github.com/gogo/protobuf/proto"
_ "github.com/prysmaticlabs/prysm/proto/common"
io "io"
math "math"
proto "github.com/gogo/protobuf/proto"
_ "github.com/prysmaticlabs/prysm/proto/common"
)
// Reference imports to suppress errors if they are not otherwise used.

View File

@@ -7,12 +7,13 @@ import (
context "context"
encoding_binary "encoding/binary"
fmt "fmt"
io "io"
math "math"
proto "github.com/gogo/protobuf/proto"
types "github.com/gogo/protobuf/types"
v1 "github.com/prysmaticlabs/prysm/proto/beacon/p2p/v1"
grpc "google.golang.org/grpc"
io "io"
math "math"
)
// Reference imports to suppress errors if they are not otherwise used.

View File

@@ -5,9 +5,10 @@ package ethereum_sharding_p2p_v1
import (
fmt "fmt"
proto "github.com/gogo/protobuf/proto"
io "io"
math "math"
proto "github.com/gogo/protobuf/proto"
)
// Reference imports to suppress errors if they are not otherwise used.