Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

chore(state-transition): flipped transaction context attributes logic #2451

Merged
merged 20 commits into from
Feb 4, 2025
Merged
Show file tree
Hide file tree
Changes from 16 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
73 changes: 35 additions & 38 deletions beacon/blockchain/finalize_block.go
Original file line number Diff line number Diff line change
Expand Up @@ -151,45 +151,42 @@ func (s *Service) executeStateTransition(
) (transition.ValidatorUpdates, error) {
startTime := time.Now()
defer s.metrics.measureStateTransitionDuration(startTime)
valUpdates, err := s.stateProcessor.Transition(
&transition.Context{
Context: ctx,

MeterGas: true,

// We set `OptimisticEngine` to true since this is called during
// FinalizeBlock. We want to assume the payload is valid. If it
// ends up not being valid later, the node will simply AppHash,
// which is completely fine. This means we were syncing from a
// bad peer, and we would likely AppHash anyways.
OptimisticEngine: true,

// When we are NOT synced to the tip, process proposal
// does NOT get called and thus we must ensure that
// NewPayload is called to get the execution
// client the payload.
//
// When we are synced to the tip, we can skip the
// NewPayload call since we already gave our execution client
// the payload in process proposal.
//
// In both cases the payload was already accepted by a majority
// of validators in their process proposal call and thus
// the "verification aspect" of this NewPayload call is
// actually irrelevant at this point.
SkipPayloadVerification: false,

// We skip randao validation in FinalizeBlock since either
// 1. we validated it during ProcessProposal at the head of the chain OR
// 2. we are bootstrapping and implicitly trust that the randao was validated by
// the super majority during ProcessProposal of the given block height.
SkipValidateRandao: true,

ProposerAddress: blk.GetProposerAddress(),
ConsensusTime: blk.GetConsensusTime(),
},

// Notes about context attributes:
// - `OptimisticEngine`: set to true since this is called during
// FinalizeBlock. We want to assume the payload is valid. If it
// ends up not being valid later, the node will simply AppHash,
// which is completely fine. This means we were syncing from a
// bad peer, and we would likely AppHash anyways.
// - VerifyPayload: set to true. When we are NOT synced to the tip,
// process proposal does NOT get called and thus we must ensure that
// NewPayload is called to get the execution client the payload.
// When we are synced to the tip, we can skip the
// NewPayload call since we already gave our execution client
// the payload in process proposal.
// In both cases the payload was already accepted by a majority
// of validators in their process proposal call and thus
// the "verification aspect" of this NewPayload call is
// actually irrelevant at this point.
// VerifyRandao: set to false. We skip randao validation in FinalizeBlock
// since either
// 1. we validated it during ProcessProposal at the head of the chain OR
// 2. we are bootstrapping and implicitly trust that the randao was validated by
// the super majority during ProcessProposal of the given block height.
txCtx := transition.NewTransitionCtx(
ctx,
blk.GetConsensusTime(),
blk.GetProposerAddress(),
).
WithVerifyPayload(true).
WithVerifyRandao(false).
WithVerifyResult(false).
WithMeterGas(true).
WithOptimisticEngine(true)

return s.stateProcessor.Transition(
txCtx,
st,
blk.GetBeaconBlock(),
)
return valUpdates, err
}
29 changes: 14 additions & 15 deletions beacon/blockchain/process_proposal.go
Original file line number Diff line number Diff line change
Expand Up @@ -322,22 +322,21 @@ func (s *Service) verifyStateRoot(
) error {
startTime := time.Now()
defer s.metrics.measureStateRootVerificationTime(startTime)
_, err := s.stateProcessor.Transition(
// We run with a non-optimistic engine here to ensure
// that the proposer does not try to push through a bad block.
&transition.Context{
Context: ctx,
MeterGas: false,
OptimisticEngine: false,
SkipPayloadVerification: false,
SkipValidateResult: false,
SkipValidateRandao: false,
ProposerAddress: proposerAddress,
ConsensusTime: consensusTime,
},
st, blk,
)

// We run with a non-optimistic engine here to ensure
// that the proposer does not try to push through a bad block.
txCtx := transition.NewTransitionCtx(
ctx,
consensusTime,
proposerAddress,
).
WithVerifyPayload(true).
WithVerifyRandao(true).
WithVerifyResult(true).
WithMeterGas(false).
WithOptimisticEngine(false)

_, err := s.stateProcessor.Transition(txCtx, st, blk)
return err
}

Expand Down
5 changes: 2 additions & 3 deletions beacon/blockchain/service.go
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,6 @@ import (
"github.com/berachain/beacon-kit/execution/deposit"
"github.com/berachain/beacon-kit/log"
"github.com/berachain/beacon-kit/primitives/math"
"github.com/berachain/beacon-kit/primitives/transition"
)

// Service is the blockchain service.
Expand Down Expand Up @@ -59,7 +58,7 @@ type Service struct {
// localBuilder is a local builder for constructing new beacon states.
localBuilder LocalBuilder
// stateProcessor is the state processor for beacon blocks and states.
stateProcessor StateProcessor[*transition.Context]
stateProcessor StateProcessor
// metrics is the metrics for the service.
metrics *chainMetrics
// optimisticPayloadBuilds is a flag used when the optimistic payload
Expand All @@ -79,7 +78,7 @@ func NewService(
chainSpec chain.Spec,
executionEngine ExecutionEngine,
localBuilder LocalBuilder,
stateProcessor StateProcessor[*transition.Context],
stateProcessor StateProcessor,
telemetrySink TelemetrySink,
optimisticPayloadBuilds bool,
) *Service {
Expand Down
6 changes: 2 additions & 4 deletions beacon/blockchain/types.go
Original file line number Diff line number Diff line change
Expand Up @@ -138,9 +138,7 @@ type ReadOnlyBeaconState[

// StateProcessor defines the interface for processing various state transitions
// in the beacon chain.
type StateProcessor[
ContextT any,
] interface {
type StateProcessor interface {
// InitializePreminedBeaconStateFromEth1 initializes the premined beacon
// state
// from the eth1 deposits.
Expand All @@ -156,7 +154,7 @@ type StateProcessor[
) (transition.ValidatorUpdates, error)
// Transition processes the state transition for a given block.
Transition(
ContextT,
transition.ReadOnlyContext,
*statedb.StateDB,
*ctypes.BeaconBlock,
) (transition.ValidatorUpdates, error)
Expand Down
32 changes: 16 additions & 16 deletions beacon/validator/block_builder.go
Original file line number Diff line number Diff line change
Expand Up @@ -369,22 +369,22 @@ func (s *Service) computeStateRoot(
) (common.Root, error) {
startTime := time.Now()
defer s.metrics.measureStateRootComputationTime(startTime)
if _, err := s.stateProcessor.Transition(
// TODO: We should think about how having optimistic
// engine enabled here would affect the proposer when
// the payload in their block has come from a remote builder.
&transition.Context{
Context: ctx,
MeterGas: false,
OptimisticEngine: true,
SkipPayloadVerification: true,
SkipValidateResult: true,
SkipValidateRandao: true,
ProposerAddress: proposerAddress,
ConsensusTime: consensusTime,
},
st, blk,
); err != nil {

// TODO: We should think about how having optimistic
// engine enabled here would affect the proposer when
// the payload in their block has come from a remote builder.
txCtx := transition.NewTransitionCtx(
ctx,
consensusTime,
proposerAddress,
).
WithVerifyPayload(false).
WithVerifyRandao(false).
WithVerifyResult(false).
WithMeterGas(false).
WithOptimisticEngine(true)

if _, err := s.stateProcessor.Transition(txCtx, st, blk); err != nil {
return common.Root{}, err
}

Expand Down
5 changes: 2 additions & 3 deletions beacon/validator/service.go
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,6 @@ import (
"github.com/berachain/beacon-kit/chain"
"github.com/berachain/beacon-kit/log"
"github.com/berachain/beacon-kit/primitives/crypto"
"github.com/berachain/beacon-kit/primitives/transition"
)

// Service is responsible for building beacon blocks and sidecars.
Expand All @@ -44,7 +43,7 @@ type Service struct {
// sb is the beacon state backend.
sb StorageBackend
// stateProcessor is responsible for processing the state.
stateProcessor StateProcessor[*transition.Context]
stateProcessor StateProcessor
// localPayloadBuilder represents the local block builder, this builder
// is connected to this nodes execution client via the EngineAPI.
// Building blocks are done by submitting forkchoice updates through.
Expand All @@ -60,7 +59,7 @@ func NewService(
logger log.Logger,
chainSpec chain.Spec,
sb StorageBackend,
stateProcessor StateProcessor[*transition.Context],
stateProcessor StateProcessor,
signer crypto.BLSSigner,
blobFactory BlobFactory,
localPayloadBuilder PayloadBuilder,
Expand Down
6 changes: 2 additions & 4 deletions beacon/validator/types.go
Original file line number Diff line number Diff line change
Expand Up @@ -171,16 +171,14 @@ type SlotData interface {
}

// StateProcessor defines the interface for processing the state.
type StateProcessor[
ContextT any,
] interface {
type StateProcessor interface {
// ProcessSlot processes the slot.
ProcessSlots(
st *statedb.StateDB, slot math.Slot,
) (transition.ValidatorUpdates, error)
// Transition performs the core state transition.
Transition(
ctx ContextT,
ctx transition.ReadOnlyContext,
st *statedb.StateDB,
blk *ctypes.BeaconBlock,
) (transition.ValidatorUpdates, error)
Expand Down
2 changes: 1 addition & 1 deletion cmd/beacond/types.go
Original file line number Diff line number Diff line change
Expand Up @@ -77,7 +77,7 @@ type (
SidecarFactory = dablob.SidecarFactory

// StateProcessor is the type alias for the state processor interface.
StateProcessor = core.StateProcessor[*Context]
StateProcessor = core.StateProcessor

// StorageBackend is the type alias for the storage backend interface.
StorageBackend = storage.Backend
Expand Down
2 changes: 1 addition & 1 deletion node-core/components/api.go
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,7 @@ type NodeAPIBackendInput struct {
depinject.In

ChainSpec chain.Spec
StateProcessor StateProcessor[*Context]
StateProcessor StateProcessor
StorageBackend *storage.Backend
}

Expand Down
2 changes: 1 addition & 1 deletion node-core/components/chain_service.go
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,7 @@ type ChainServiceInput struct {
LocalBuilder LocalBuilder
Logger *phuslu.Logger
Signer crypto.BLSSigner
StateProcessor StateProcessor[*Context]
StateProcessor StateProcessor
StorageBackend *storage.Backend
BlobProcessor BlobProcessor
TelemetrySink *metrics.TelemetrySink
Expand Down
39 changes: 2 additions & 37 deletions node-core/components/interfaces.go
Original file line number Diff line number Diff line change
Expand Up @@ -203,39 +203,6 @@ type (
) (*v1.ProcessProposalResponse, error)
}

// // Context defines an interface for managing state transition context.
// Context[T any] interface {
// context.Context
// // Wrap returns a new context with the given context.
// Wrap(context.Context) T
// // OptimisticEngine sets the optimistic engine flag to true.
// OptimisticEngine() T
// // SkipPayloadVerification sets the skip payload verification flag to
// // true.
// SkipPayloadVerification() T
// // SkipValidateRandao sets the skip validate randao flag to true.
// SkipValidateRandao() T
// // SkipValidateResult sets the skip validate result flag to true.
// SkipValidateResult() T
// // GetOptimisticEngine returns whether to optimistically assume the
// // execution client has the correct state when certain errors are
// // returned
// // by the execution engine.
// GetOptimisticEngine() bool
// // GetSkipPayloadVerification returns whether to skip verifying the
// // payload
// // if
// // it already exists on the execution client.
// GetSkipPayloadVerification() bool
// // GetSkipValidateRandao returns whether to skip validating the RANDAO
// // reveal.
// GetSkipValidateRandao() bool
// // GetSkipValidateResult returns whether to validate the result of the
// // state
// // transition.
// GetSkipValidateResult() bool
// }

// Deposit is the interface for a deposit.
Deposit[
T any,
Expand Down Expand Up @@ -348,9 +315,7 @@ type (
// }.

// StateProcessor defines the interface for processing the state.
StateProcessor[
ContextT any,
] interface {
StateProcessor interface {
// InitializePreminedBeaconStateFromEth1 initializes the premined beacon
// state
// from the eth1 deposits.
Expand All @@ -366,7 +331,7 @@ type (
) (transition.ValidatorUpdates, error)
// Transition performs the core state transition.
Transition(
ctx ContextT,
ctx transition.ReadOnlyContext,
st *statedb.StateDB,
blk *ctypes.BeaconBlock,
) (transition.ValidatorUpdates, error)
Expand Down
4 changes: 2 additions & 2 deletions node-core/components/state_processor.go
Original file line number Diff line number Diff line change
Expand Up @@ -45,8 +45,8 @@ type StateProcessorInput struct {

// ProvideStateProcessor provides the state processor to the depinject
// framework.
func ProvideStateProcessor(in StateProcessorInput) *core.StateProcessor[*Context] {
return core.NewStateProcessor[*Context](
func ProvideStateProcessor(in StateProcessorInput) *core.StateProcessor {
return core.NewStateProcessor(
in.Logger.With("service", "state-processor"),
in.ChainSpec,
in.ExecutionEngine,
Expand Down
2 changes: 1 addition & 1 deletion node-core/components/validator_service.go
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,7 @@ type ValidatorServiceInput struct {
ChainSpec chain.Spec
LocalBuilder LocalBuilder
Logger *phuslu.Logger
StateProcessor StateProcessor[*Context]
StateProcessor StateProcessor
StorageBackend *storage.Backend
Signer crypto.BLSSigner
SidecarFactory SidecarFactory
Expand Down
Loading
Loading