protocol

package
v0.34.0-crescendo-prev... Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Mar 28, 2024 License: AGPL-3.0 Imports: 14 Imported by: 55

Documentation

Index

Constants

This section is empty.

Variables

View Source
var (
	// ErrNoPreviousEpoch is a sentinel error returned when a previous epoch is
	// queried from a snapshot within the first epoch after the root block.
	ErrNoPreviousEpoch = fmt.Errorf("no previous epoch exists")

	// ErrNextEpochNotSetup is a sentinel error returned when the next epoch
	// has not been set up yet.
	ErrNextEpochNotSetup = fmt.Errorf("next epoch has not yet been set up")

	// ErrNextEpochNotCommitted is a sentinel error returned when the next epoch
	// has not been committed and information is queried that is only accessible
	// in the EpochCommitted phase.
	ErrNextEpochNotCommitted = fmt.Errorf("queried info from EpochCommit event before it was emitted")

	// ErrEpochTransitionNotFinalized is a sentinel returned when a query is made
	// for a block at an epoch boundary which has not yet been finalized.
	ErrEpochTransitionNotFinalized = fmt.Errorf("cannot query block at un-finalized epoch transition")

	// ErrSealingSegmentBelowRootBlock is a sentinel error returned for queries
	// for a sealing segment below the root block (local history cutoff).
	ErrSealingSegmentBelowRootBlock = fmt.Errorf("cannot construct sealing segment beyond locally known history")

	// ErrClusterNotFound is a sentinel error returns for queries for a cluster
	ErrClusterNotFound = fmt.Errorf("could not find cluster")

	// ErrMultipleSealsForSameHeight indicates that an (unordered) slice of seals
	// contains two or more seals for the same block height (possibilities include
	// duplicated seals or seals for different blocks at the same height).
	ErrMultipleSealsForSameHeight = fmt.Errorf("multiple seals for same block height")

	// ErrDiscontinuousSeals indicates that an (unordered) slice of seals skips at least one block height.
	ErrDiscontinuousSeals = fmt.Errorf("seals have discontinuity, i.e. they skip some block heights")
)

Functions

func CheckNodeStatusAt added in v0.17.0

func CheckNodeStatusAt(snapshot Snapshot, id flow.Identifier, checks ...flow.IdentityFilter[flow.Identity]) (bool, error)

CheckNodeStatusAt returns whether the node with the given ID is a valid identity at the given state snapshot, and satisfies all checks. Expected errors during normal operations:

  • state.ErrUnknownSnapshotReference if snapshot references an unknown block

All other errors are unexpected and potential symptoms of internal state corruption.

func DKGPhaseViews added in v0.20.0

func DKGPhaseViews(epoch Epoch) (phase1FinalView uint64, phase2FinalView uint64, phase3FinalView uint64, err error)

DKGPhaseViews returns the DKG final phase views for an epoch. Error returns: * protocol.ErrNoPreviousEpoch - if the epoch represents a previous epoch which does not exist. * protocol.ErrNextEpochNotSetup - if the epoch represents a next epoch which has not been set up. * protocol.ErrNextEpochNotCommitted - if the epoch has not been committed. * state.ErrUnknownSnapshotReference - if the epoch is queried from an unresolvable snapshot.

func DefaultEpochCommitSafetyThreshold added in v0.29.0

func DefaultEpochCommitSafetyThreshold(chain flow.ChainID) (uint64, error)

DefaultEpochCommitSafetyThreshold returns the default epoch commit safety threshold for each chain ID. Greater threshold values are generally safer, but require longer epochs and longer EpochCommit phases. See Params for more details on this value.

func FindGuarantors added in v0.26.1

func FindGuarantors(state State, guarantee *flow.CollectionGuarantee) ([]flow.Identifier, error)

FindGuarantors decodes the signer indices from the guarantee, and finds the guarantor identifiers from protocol state Expected Error returns during normal operations:

  • signature.InvalidSignerIndicesError if `signerIndices` does not encode a valid set of collection guarantors
  • state.ErrUnknownSnapshotReference if guarantee references an unknown block
  • protocol.ErrNextEpochNotCommitted if epoch has not been committed yet
  • protocol.ErrClusterNotFound if cluster is not found by the given chainID

func GetDKGParticipantKeys added in v0.17.0

func GetDKGParticipantKeys(dkg DKG, participants flow.IdentitySkeletonList) ([]crypto.PublicKey, error)

GetDKGParticipantKeys retrieves the canonically ordered list of DKG participant keys from the DKG. All errors indicate inconsistent or invalid inputs. No errors are expected during normal operation.

func IsIdentityNotFound

func IsIdentityNotFound(err error) bool

func IsInvalidBlockTimestampError added in v0.20.0

func IsInvalidBlockTimestampError(err error) bool

func IsInvalidServiceEventError added in v0.23.2

func IsInvalidServiceEventError(err error) bool

func IsNodeAuthorizedAt added in v0.25.0

func IsNodeAuthorizedAt(snapshot Snapshot, id flow.Identifier) (bool, error)

IsNodeAuthorizedAt returns whether the node with the given ID is a valid un-ejected network participant as of the given state snapshot.

func IsNodeAuthorizedWithRoleAt added in v0.25.0

func IsNodeAuthorizedWithRoleAt(snapshot Snapshot, id flow.Identifier, role flow.Role) (bool, error)

IsNodeAuthorizedWithRoleAt returns whether the node with the given ID is a valid un-ejected network participant with the specified role as of the given state snapshot. Expected errors during normal operations:

  • state.ErrUnknownSnapshotReference if snapshot references an unknown block

All other errors are unexpected and potential symptoms of internal state corruption.

func IsSporkRootSnapshot added in v0.23.9

func IsSporkRootSnapshot(snapshot Snapshot) (bool, error)

IsSporkRootSnapshot returns whether the given snapshot is the state snapshot representing the initial state for a spork.

func IsUnfinalizedSealingSegmentError added in v0.30.0

func IsUnfinalizedSealingSegmentError(err error) bool

IsUnfinalizedSealingSegmentError returns true if err is of type UnfinalizedSealingSegmentError

func IsValidEpochCommit added in v0.33.30

func IsValidEpochCommit(commit *flow.EpochCommit, setup *flow.EpochSetup) error

IsValidEpochCommit checks whether an epoch commit service event is intrinsically valid. Assumes the input flow.EpochSetup event has already been validated. Expected errors during normal operations: * protocol.InvalidServiceEventError if the EpochCommit is invalid

func IsValidEpochSetup added in v0.33.30

func IsValidEpochSetup(setup *flow.EpochSetup, verifyNetworkAddress bool) error

IsValidEpochSetup checks whether an `EpochSetup` event is syntactically correct. The boolean parameter `verifyNetworkAddress` controls, whether we want to permit nodes to share a networking address. This is a side-effect-free function. Any error return indicates that the EpochSetup event is not compliant with protocol rules.

func IsValidExtendingEpochCommit added in v0.33.30

func IsValidExtendingEpochCommit(extendingCommit *flow.EpochCommit, protocolStateEntry *flow.ProtocolStateEntry, nextEpochSetupEvent *flow.EpochSetup) error

IsValidExtendingEpochCommit checks whether an EpochCommit service event being added to the state is valid. In addition to intrinsic validity, we also check that it is valid w.r.t. the previous epoch setup event, and the current epoch status. CAUTION: This function assumes that all inputs besides extendingCommit are already validated. Expected errors during normal operations: * protocol.InvalidServiceEventError if the input service event is invalid to extend the currently active epoch

func IsValidExtendingEpochSetup added in v0.33.30

func IsValidExtendingEpochSetup(extendingSetup *flow.EpochSetup, protocolStateEntry *flow.ProtocolStateEntry, currentEpochSetupEvent *flow.EpochSetup) error

IsValidExtendingEpochSetup checks whether an EpochSetup service event being added to the state is valid. In addition to intrinsic validity, we also check that it is valid w.r.t. the previous epoch setup event, and the current epoch status. CAUTION: This function assumes that all inputs besides extendingCommit are already validated. Expected errors during normal operations: * protocol.InvalidServiceEventError if the input service event is invalid to extend the currently active epoch status

func NewInvalidBlockTimestamp added in v0.20.0

func NewInvalidBlockTimestamp(msg string, args ...interface{}) error

func NewInvalidServiceEventErrorf added in v0.29.0

func NewInvalidServiceEventErrorf(msg string, args ...interface{}) error

NewInvalidServiceEventErrorf returns an invalid service event error. Since all invalid service events indicate an invalid extension, the service event error is wrapped in the invalid extension error at construction.

func NewUnfinalizedSealingSegmentErrorf added in v0.30.0

func NewUnfinalizedSealingSegmentErrorf(msg string, args ...interface{}) error

func OrderedSeals added in v0.29.0

func OrderedSeals(blockSeals []*flow.Seal, headers storage.Headers) ([]*flow.Seal, error)

OrderedSeals returns the seals in the input payload in ascending height order. The Flow protocol has a variety of validity rules for `payload`. While we do not verify payload validity in this function, the implementation is optimized for valid payloads, where the heights of the sealed blocks form a continuous integer sequence (no gaps). Per convention ['Vacuous Truth'], an empty set of seals is considered to be ordered. Hence, if `payload.Seals` is empty, we return (nil, nil). Expected Error returns during normal operations:

  • ErrMultipleSealsForSameHeight in case there are seals repeatedly sealing block at the same height
  • ErrDiscontinuousSeals in case there are height-gaps in the sealed blocks
  • storage.ErrNotFound if any of the seals references an unknown block

func PreviousEpochExists added in v0.29.0

func PreviousEpochExists(snap Snapshot) (bool, error)

PreviousEpochExists returns whether the previous epoch exists w.r.t. the given state snapshot. No errors are expected during normal operation.

func ToDKGParticipantLookup added in v0.15.0

func ToDKGParticipantLookup(dkg DKG, participants flow.IdentitySkeletonList) (map[flow.Identifier]flow.DKGParticipant, error)

ToDKGParticipantLookup computes the nodeID -> DKGParticipant lookup for a DKG instance. The participants must exactly match the DKG instance configuration. All errors indicate inconsistent or invalid inputs. No errors are expected during normal operation.

func ToEpochCommit added in v0.15.0

func ToEpochCommit(epoch Epoch) (*flow.EpochCommit, error)

ToEpochCommit converts an Epoch interface instance to the underlying concrete epoch commit service event. The epoch must have been committed. Error returns: * protocol.ErrNoPreviousEpoch - if the epoch represents a previous epoch which does not exist. * protocol.ErrNextEpochNotSetup - if the epoch represents a next epoch which has not been set up. * protocol.ErrNextEpochNotCommitted - if the epoch has not been committed. * state.ErrUnknownSnapshotReference - if the epoch is queried from an unresolvable snapshot.

func ToEpochSetup added in v0.15.0

func ToEpochSetup(epoch Epoch) (*flow.EpochSetup, error)

ToEpochSetup converts an Epoch interface instance to the underlying concrete epoch setup service event. The input must be a valid, set up epoch. Error returns: * protocol.ErrNoPreviousEpoch - if the epoch represents a previous epoch which does not exist. * protocol.ErrNextEpochNotSetup - if the epoch represents a next epoch which has not been set up. * state.ErrUnknownSnapshotReference - if the epoch is queried from an unresolvable snapshot.

Types

type BlockTimer added in v0.20.0

type BlockTimer interface {
	// Build generates a timestamp based on definition of valid timestamp.
	Build(parentTimestamp time.Time) time.Time
	// Validate checks validity of a block's time stamp.
	// Error returns
	//  * `model.InvalidBlockTimestampError` if time stamp is invalid.
	//  * all other errors are unexpected and potentially symptoms of internal implementation bugs or state corruption (fatal).
	Validate(parentTimestamp, currentTimestamp time.Time) error
}

BlockTimer constructs and validates block timestamps.

type Cluster

type Cluster interface {

	// Index returns the index for this cluster.
	Index() uint

	// ChainID returns chain ID for the cluster's chain.
	ChainID() flow.ChainID

	// EpochCounter returns the epoch counter for this cluster.
	EpochCounter() uint64

	// Members returns the IdentitySkeletons of the cluster members in canonical order.
	// This represents the cluster composition at the time the cluster was specified by the epoch smart
	// contract (hence, we return IdentitySkeletons as opposed to full identities).
	Members() flow.IdentitySkeletonList

	// RootBlock returns the root block for this cluster.
	RootBlock() *cluster.Block

	// RootQC returns the quorum certificate for this cluster.
	RootQC() *flow.QuorumCertificate
}

Cluster represents the detailed information for a particular cluster, for a given epoch. This information represents the INITIAL state of the cluster, as defined by the Epoch Preparation Protocol. It DOES NOT take into account state changes over the course of the epoch (ie. slashing).

type Consumer

type Consumer interface {
	// BlockFinalized is called when a block is finalized.
	// Formally, this callback is informationally idempotent. I.e. the consumer
	// of this callback must handle repeated calls for the same block.
	BlockFinalized(block *flow.Header)

	// BlockProcessable is called when a correct block is encountered that is
	// ready to be processed (i.e. it is connected to the finalized chain and
	// its source of randomness is available).
	// BlockProcessable provides the block and a certifying QC. BlockProcessable is never emitted
	// for the root block, as the root block is always processable.
	// Formally, this callback is informationally idempotent. I.e. the consumer
	// of this callback must handle repeated calls for the same block.
	BlockProcessable(block *flow.Header, certifyingQC *flow.QuorumCertificate)

	// EpochTransition is called when we transition to a new epoch. This is
	// equivalent to the beginning of the new epoch's staking phase and the end
	// of the previous epoch's epoch committed phase.
	//
	// The block parameter is the first block of the new epoch.
	//
	// NOTE: Only called once the transition has been finalized.
	EpochTransition(newEpochCounter uint64, first *flow.Header)

	// EpochSetupPhaseStarted is called when we begin the epoch setup phase for
	// the current epoch. This is equivalent to the end of the epoch staking
	// phase for the current epoch.
	//
	// Referencing the diagram below, the event is emitted when block b is finalized.
	// The block parameter is the first block of the epoch setup phase (block b).
	//
	// |<-- Epoch N ------------------------------------------------->|
	// |<-- StakingPhase -->|<-- SetupPhase -->|<-- CommittedPhase -->|
	//                    ^--- block A - this block's execution result contains an EpochSetup event
	//                      ^--- block b - contains seal for block A, first block of Setup phase
	//                         ^--- block c - finalizes block b, triggers EpochSetupPhaseStarted event
	//
	// NOTE: Only called once the phase transition has been finalized.
	EpochSetupPhaseStarted(currentEpochCounter uint64, first *flow.Header)

	// EpochCommittedPhaseStarted is called when we begin the epoch committed phase
	// for the current epoch. This is equivalent to the end of the epoch setup
	// phase for the current epoch.
	//
	// Referencing the diagram below, the event is emitted when block e is finalized.
	// The block parameter is the first block of the epoch committed phase (block e).
	//
	// |<-- Epoch N ------------------------------------------------->|
	// |<-- StakingPhase -->|<-- SetupPhase -->|<-- CommittedPhase -->|
	//                                       ^--- block D - this block's execution result contains an EpochCommit event
	//                                         ^--- block e - contains seal for block D, first block of Committed phase
	//                                            ^--- block f - finalizes block e, triggers EpochCommittedPhaseStarted event
	//
	// NOTE: Only called once the phase transition has been finalized.
	EpochCommittedPhaseStarted(currentEpochCounter uint64, first *flow.Header)

	// EpochEmergencyFallbackTriggered is called when epoch fallback mode [EFM] is triggered.
	// Since EFM is a permanent, spork-scoped state, this event is triggered only once.
	// After this event is triggered, no further epoch transitions will occur,
	// no further epoch phase transitions will occur, and no further epoch-related
	// related protocol events (the events defined in this interface) will be emitted.
	EpochEmergencyFallbackTriggered()
}

Consumer defines a set of events that occur within the protocol state, that can be propagated to other components via an implementation of this interface. Collectively, these are referred to as "Protocol Events".

Protocol events are delivered immediately after the database transaction committing the corresponding state change completes successfully. This means that events are delivered exactly once, while the system is running. Events may not be delivered during crashes and restarts, but any missed events are guaranteed to be reflected in the Protocol State upon restarting. Components consuming protocol events which cannot tolerate missed events must implement initialization logic which accounts for any missed events.

EXAMPLE: Suppose block A is finalized at height 100. If the BlockFinalized(A) event is dropped due to a crash, then when the node restarts, the latest finalized block in the Protocol State is guaranteed to be A.

CAUTION: Protocol event subscriber callbacks are invoked synchronously in the critical path of protocol state mutations. Most subscribers should immediately spawn a goroutine to handle the notification to avoid blocking protocol state progression, especially for frequent protocol events (eg. BlockFinalized).

NOTE: the epoch-related callbacks are only called once the fork containing the relevant event has been finalized.

type DKG

type DKG interface {

	// Size is the number of members in the DKG.
	Size() uint

	// GroupKey is the group public key.
	GroupKey() crypto.PublicKey

	// Index returns the index for the given node.
	// Error Returns:
	// * protocol.IdentityNotFoundError if nodeID is not a valid DKG participant.
	Index(nodeID flow.Identifier) (uint, error)

	// KeyShare returns the public key share for the given node.
	// Error Returns:
	// * protocol.IdentityNotFoundError if nodeID is not a valid DKG participant.
	KeyShare(nodeID flow.Identifier) (crypto.PublicKey, error)
}

DKG represents the result of running the distributed key generation procedure for the random beacon.

type DynamicProtocolState added in v0.35.4

type DynamicProtocolState interface {
	InitialProtocolState

	// InvalidEpochTransitionAttempted denotes whether an invalid epoch state transition was attempted
	// on the fork ending this block. Once the first block where this flag is true is finalized, epoch
	// fallback mode is triggered.
	// TODO for 'leaving Epoch Fallback via special service event': at the moment, this is a one-way transition and requires a spork to recover - need to revisit for sporkless EFM recovery
	InvalidEpochTransitionAttempted() bool
	// PreviousEpochExists returns true if a previous epoch exists. This is true for all epoch
	// except those immediately following a spork.
	PreviousEpochExists() bool
	// EpochPhase returns the epoch phase for the current epoch.
	EpochPhase() flow.EpochPhase

	// Identities returns identities (in canonical ordering) that can participate in the current or previous
	// or next epochs. Let P be the set of identities in the previous epoch, C be the set of identities in
	// the current epoch, and N be the set of identities in the next epoch.
	// The set of authorized identities this function returns is different depending on epoch state:
	// EpochStaking phase:
	//   - nodes in C with status `flow.EpochParticipationStatusActive`
	//   - nodes in P-C with status `flow.EpochParticipationStatusLeaving`
	// EpochSetup/EpochCommitted phase:
	//   - nodes in C with status `flow.EpochParticipationStatusActive`
	//   - nodes in N-C with status `flow.EpochParticipationStatusJoining`
	Identities() flow.IdentityList
	// GlobalParams returns params that are same for all nodes in the network.
	GlobalParams() GlobalParams
}

DynamicProtocolState extends the InitialProtocolState with data that can change from block to block. It can be used to access the identity table at given block.

type Epoch

type Epoch interface {

	// Counter returns the Epoch's counter.
	// Error returns:
	// * protocol.ErrNoPreviousEpoch - if the epoch represents a previous epoch which does not exist.
	// * protocol.ErrNextEpochNotSetup - if the epoch represents a next epoch which has not been set up.
	// * state.ErrUnknownSnapshotReference - if the epoch is queried from an unresolvable snapshot.
	Counter() (uint64, error)

	// FirstView returns the first view of this epoch.
	// Error returns:
	// * protocol.ErrNoPreviousEpoch - if the epoch represents a previous epoch which does not exist.
	// * protocol.ErrNextEpochNotSetup - if the epoch represents a next epoch which has not been set up.
	// * state.ErrUnknownSnapshotReference - if the epoch is queried from an unresolvable snapshot.
	FirstView() (uint64, error)

	// DKGPhase1FinalView returns the final view of DKG phase 1
	// Error returns:
	// * protocol.ErrNoPreviousEpoch - if the epoch represents a previous epoch which does not exist.
	// * protocol.ErrNextEpochNotSetup - if the epoch represents a next epoch which has not been set up.
	// * state.ErrUnknownSnapshotReference - if the epoch is queried from an unresolvable snapshot.
	DKGPhase1FinalView() (uint64, error)

	// DKGPhase2FinalView returns the final view of DKG phase 2
	// Error returns:
	// * protocol.ErrNoPreviousEpoch - if the epoch represents a previous epoch which does not exist.
	// * protocol.ErrNextEpochNotSetup - if the epoch represents a next epoch which has not been set up.
	// * state.ErrUnknownSnapshotReference - if the epoch is queried from an unresolvable snapshot.
	DKGPhase2FinalView() (uint64, error)

	// DKGPhase3FinalView returns the final view of DKG phase 3
	// Error returns:
	// * protocol.ErrNoPreviousEpoch - if the epoch represents a previous epoch which does not exist.
	// * protocol.ErrNextEpochNotSetup - if the epoch represents a next epoch which has not been set up.
	// * state.ErrUnknownSnapshotReference - if the epoch is queried from an unresolvable snapshot.
	DKGPhase3FinalView() (uint64, error)

	// FinalView returns the largest view number which still belongs to this epoch.
	// Error returns:
	// * protocol.ErrNoPreviousEpoch - if the epoch represents a previous epoch which does not exist.
	// * protocol.ErrNextEpochNotSetup - if the epoch represents a next epoch which has not been set up.
	// * state.ErrUnknownSnapshotReference - if the epoch is queried from an unresolvable snapshot.
	FinalView() (uint64, error)

	// TargetDuration returns the desired real-world duration for this epoch, in seconds.
	// This target is specified by the FlowEpoch smart contract along the TargetEndTime in
	// the EpochSetup event and used by the Cruise Control system to moderate the block rate.
	// Error returns:
	// * protocol.ErrNoPreviousEpoch - if the epoch represents a previous epoch which does not exist.
	// * protocol.ErrNextEpochNotSetup - if the epoch represents a next epoch which has not been set up.
	// * state.ErrUnknownSnapshotReference - if the epoch is queried from an unresolvable snapshot.
	TargetDuration() (uint64, error)

	// TargetEndTime returns the desired real-world end time for this epoch, represented as
	// Unix Time (in units of seconds). This target is specified by the FlowEpoch smart contract in
	// the EpochSetup event and used by the Cruise Control system to moderate the block rate.
	// Error returns:
	// * protocol.ErrNoPreviousEpoch - if the epoch represents a previous epoch which does not exist.
	// * protocol.ErrNextEpochNotSetup - if the epoch represents a next epoch which has not been set up.
	// * state.ErrUnknownSnapshotReference - if the epoch is queried from an unresolvable snapshot.
	TargetEndTime() (uint64, error)

	// RandomSource returns the underlying random source of this epoch.
	// This source is currently generated by an on-chain contract using the
	// UnsafeRandom() Cadence function.
	// Error returns:
	// * protocol.ErrNoPreviousEpoch - if the epoch represents a previous epoch which does not exist.
	// * protocol.ErrNextEpochNotSetup - if the epoch represents a next epoch which has not been set up.
	// * state.ErrUnknownSnapshotReference - if the epoch is queried from an unresolvable snapshot.
	RandomSource() ([]byte, error)

	// InitialIdentities returns the identities for this epoch as they were
	// specified in the EpochSetup service event.
	// Error returns:
	// * protocol.ErrNoPreviousEpoch - if the epoch represents a previous epoch which does not exist.
	// * protocol.ErrNextEpochNotSetup - if the epoch represents a next epoch which has not been set up.
	// * state.ErrUnknownSnapshotReference - if the epoch is queried from an unresolvable snapshot.
	InitialIdentities() (flow.IdentitySkeletonList, error)

	// Clustering returns the cluster assignment for this epoch.
	// Error returns:
	// * protocol.ErrNoPreviousEpoch - if the epoch represents a previous epoch which does not exist.
	// * protocol.ErrNextEpochNotSetup - if the epoch represents a next epoch which has not been set up.
	// * state.ErrUnknownSnapshotReference - if the epoch is queried from an unresolvable snapshot.
	Clustering() (flow.ClusterList, error)

	// Cluster returns the detailed cluster information for the cluster with the
	// given index, in this epoch.
	// Error returns:
	// * protocol.ErrNoPreviousEpoch - if the epoch represents a previous epoch which does not exist.
	// * protocol.ErrNextEpochNotSetup - if the epoch represents a next epoch which has not been set up.
	// * state.ErrUnknownSnapshotReference - if the epoch is queried from an unresolvable snapshot.
	// * protocol.ErrClusterNotFound - if no cluster has the given index (index > len(clusters))
	Cluster(index uint) (Cluster, error)

	// ClusterByChainID returns the detailed cluster information for the cluster with
	// the given chain ID, in this epoch
	// Error returns:
	// * protocol.ErrNoPreviousEpoch - if the epoch represents a previous epoch which does not exist.
	// * protocol.ErrNextEpochNotSetup - if the epoch represents a next epoch which has not been set up.
	// * state.ErrUnknownSnapshotReference - if the epoch is queried from an unresolvable snapshot.
	// * protocol.ErrNextEpochNotCommitted - if epoch has not been committed yet
	// * protocol.ErrClusterNotFound - if cluster is not found by the given chainID
	ClusterByChainID(chainID flow.ChainID) (Cluster, error)

	// DKG returns the result of the distributed key generation procedure.
	// Error returns:
	// * protocol.ErrNoPreviousEpoch - if the epoch represents a previous epoch which does not exist.
	// * protocol.ErrNextEpochNotSetup - if the epoch represents a next epoch which has not been set up.
	// * protocol.ErrNextEpochNotCommitted if epoch has not been committed yet
	// * state.ErrUnknownSnapshotReference - if the epoch is queried from an unresolvable snapshot.
	DKG() (DKG, error)

	// FirstHeight returns the height of the first block of the epoch.
	// The first block of an epoch E is defined as the block B with the lowest
	// height so that: B.View >= E.FirstView
	// The first block of an epoch is not defined until it is finalized, so this
	// value is only guaranteed to be defined for `Current` epochs of finalized snapshots.
	// Error returns:
	// * protocol.ErrNoPreviousEpoch - if the epoch represents a previous epoch which does not exist.
	// * protocol.ErrNextEpochNotSetup - if the epoch represents a next epoch which has not been set up.
	// * protocol.ErrNextEpochNotCommitted if epoch has not been committed yet
	// * protocol.ErrEpochTransitionNotFinalized - if the first block of the epoch has not been finalized yet.
	// * state.ErrUnknownSnapshotReference - if the epoch is queried from an unresolvable snapshot.
	FirstHeight() (uint64, error)

	// FinalHeight returns the height of the final block of the epoch.
	// The final block of an epoch E is defined as the parent of the first
	// block in epoch E+1 (see definition from FirstHeight).
	// The final block of an epoch is not defined until its child is finalized,
	// so this value is only guaranteed to be defined for `Previous` epochs of finalized snapshots.
	// Error returns:
	// * protocol.ErrNoPreviousEpoch - if the epoch represents a previous epoch which does not exist.
	// * protocol.ErrNextEpochNotSetup - if the epoch represents a next epoch which has not been set up.
	// * protocol.ErrNextEpochNotCommitted - if epoch has not been committed yet
	// * protocol.ErrEpochTransitionNotFinalized - if the first block of the next epoch has not been finalized yet.
	// * state.ErrUnknownSnapshotReference - if the epoch is queried from an unresolvable snapshot.
	FinalHeight() (uint64, error)
}

Epoch contains the information specific to a certain Epoch (defined by the epoch Counter). Note that the Epoch preparation can differ along different forks, since the emission of service events is fork-dependent. Therefore, an epoch exists RELATIVE to the snapshot from which it was queried.

CAUTION: Clients must ensure to query epochs only for finalized blocks to ensure they query finalized epoch information.

An Epoch instance is constant and reports the identical information even if progress is made later and more information becomes available in subsequent blocks.

Methods error if epoch preparation has not progressed far enough for this information to be determined by a finalized block.

TODO Epoch / Snapshot API Structure: Currently Epoch and Snapshot APIs are structured to allow chained queries to be used without error checking at each call where errors might occur. Instead, errors are cached in the resulting struct (eg. invalid.Epoch) until the query chain ends with a function which can return an error. This has some negative effects:

  1. Cached intermediary errors result in more complex error handling a) each final call of the chained query needs to handle all intermediary errors, every time b) intermediary errors must be handled by dependencies on the final call of the query chain (eg. conversion functions)
  2. The error caching pattern encourages potentially dangerous snapshot query patterns

See https://github.com/dapperlabs/flow-go/issues/6368 for details and proposal

type EpochQuery

type EpochQuery interface {

	// Current returns the current epoch as of this snapshot. All valid snapshots
	// have a current epoch.
	Current() Epoch

	// Next returns the next epoch as of this snapshot. Valid snapshots must
	// have a next epoch available after the transition to epoch setup phase.
	Next() Epoch

	// Previous returns the previous epoch as of this snapshot. Valid snapshots
	// must have a previous epoch for all epochs except that immediately after
	// the root block - in other words, if a previous epoch exists, implementations
	// must arrange to expose it here.
	//
	// Returns ErrNoPreviousEpoch in the case that this method is queried w.r.t.
	// a snapshot from the first epoch after the root block.
	Previous() Epoch
}

EpochQuery defines the different ways to query for epoch information given a Snapshot. It only exists to simplify the main Snapshot interface.

type FollowerState added in v0.30.0

type FollowerState interface {
	State

	// ExtendCertified introduces the block with the given ID into the persistent
	// protocol state without modifying the current finalized state. It allows us
	// to execute fork-aware queries against the known protocol state. The caller
	// must pass a QC for candidate block to prove that the candidate block has
	// been certified, and it's safe to add it to the protocol state. The QC
	// cannot be nil and must certify candidate block:
	//   candidate.View == qc.View && candidate.BlockID == qc.BlockID
	// The `candidate` block and its QC _must be valid_ (otherwise, the state will
	// be corrupted). ExtendCertified inserts any given block, as long as its
	// parent is already in the protocol state. Also orphaned blocks are excepted.
	// No errors are expected during normal operations.
	ExtendCertified(ctx context.Context, candidate *flow.Block, qc *flow.QuorumCertificate) error

	// Finalize finalizes the block with the given hash.
	// At this level, we can only finalize one block at a time. This implies
	// that the parent of the pending block that is to be finalized has
	// to be the last finalized block.
	// It modifies the persistent immutable protocol state accordingly and
	// forwards the pointer to the latest finalized state.
	// No errors are expected during normal operations.
	Finalize(ctx context.Context, blockID flow.Identifier) error
}

FollowerState is a mutable protocol state used by nodes following main consensus (ie. non-consensus nodes). All blocks must have a certifying QC when being added to the state to guarantee they are valid, so there is a one-block lag between block production and incorporation into the FollowerState. However, since all blocks are certified upon insertion, they are immediately processable by other components.

type GlobalParams added in v0.23.2

type GlobalParams interface {

	// ChainID returns the chain ID for the current Flow network. The chain ID
	// uniquely identifies a Flow network in perpetuity across epochs and sporks.
	ChainID() flow.ChainID

	// SporkID returns the unique identifier for this network within the current spork.
	// This ID is determined at the beginning of a spork during bootstrapping and is
	// part of the root protocol state snapshot.
	SporkID() flow.Identifier

	// SporkRootBlockHeight returns the height of the spork's root block.
	// This value is determined at the beginning of a spork during bootstrapping.
	// If node uses a sealing segment for bootstrapping then this value will be carried over
	// as part of snapshot.
	SporkRootBlockHeight() uint64

	// ProtocolVersion returns the protocol version, the major software version
	// of the protocol software.
	ProtocolVersion() uint

	// EpochCommitSafetyThreshold [t] defines a deadline for sealing the EpochCommit
	// service event near the end of each epoch - the "epoch commitment deadline".
	// Given a safety threshold t, the deadline for an epoch with final view f is:
	//   Epoch Commitment Deadline: d=f-t
	//
	//                     Epoch Commitment Deadline
	//   EPOCH N           ↓                 EPOCH N+1
	//   ...---------------|---------------| |-----...
	//   view:             d<·····t·······>f
	//
	// DEFINITION:
	// This deadline is used to determine when to trigger epoch emergency fallback mode.
	// Epoch Emergency Fallback mode is triggered when the EpochCommit service event
	// fails to be sealed.
	//
	// Example: A service event is emitted in block A. The seal for A is included in C.
	// A<-B(RA)<-C(SA)<-...<-R
	//
	// A service event S is considered sealed w.r.t. a reference block R if:
	// * S was emitted during execution of some block A, s.t. A is an ancestor of R
	// * The seal for block A was included in some block C, s.t C is an ancestor of R
	//
	// When we finalize the first block B with B.View >= d:
	//  - HAPPY PATH: If an EpochCommit service event has been sealed w.r.t. B, no action is taken.
	//  - FALLBACK PATH: If no EpochCommit service event has been sealed w.r.t. B,
	//    Epoch Fallback Mode [EFM] is triggered.
	//
	// CONTEXT:
	// The epoch commitment deadline exists to ensure that all nodes agree on
	// whether Epoch Fallback Mode is triggered for a particular epoch, before
	// the epoch actually ends. In particular, all nodes will agree about EFM
	// being triggered (or not) if at least one block with view in [d, f] is
	// finalized - in other words, we require at least one block being finalized
	// after the epoch commitment deadline, and before the next epoch begins.
	//
	// It should be noted that we are employing a heuristic here, which succeeds with
	// overwhelming probability of nearly 1. However, theoretically it is possible that
	// no blocks are finalized within t views. In this edge case, the nodes would have not
	// detected the epoch commit phase failing and the protocol would just halt at the end
	// of the epoch. However, we emphasize that this is extremely unlikely, because the
	// probability of randomly selecting t faulty leaders in sequence decays to zero
	// exponentially with increasing t. Furthermore, failing to finalize blocks for a
	// noticeable period entails halting block sealing, which would trigger human
	// intervention on much smaller time scales than t views.
	// Therefore, t should be chosen such that it takes more than 30mins to pass t views
	// under happy path operation. Significant larger values are ok, but t views equalling
	// 30 mins should be seen as a lower bound.
	//
	// When selecting a threshold value, ensure:
	//  * The deadline is after the end of the DKG, with enough buffer between
	//    the two that the EpochCommit event is overwhelmingly likely to be emitted
	//    before the deadline, if it is emitted at all.
	//  * The buffer between the deadline and the final view of the epoch is large
	//    enough that the network is overwhelming likely to finalize at least one
	//    block with a view in this range
	//
	EpochCommitSafetyThreshold() uint64
}

GlobalParams represents protocol state parameters that do not vary between instances. Any nodes running in the same spork, on the same network (same chain ID) must have the same global params.

type IdentityNotFoundError added in v0.13.0

type IdentityNotFoundError struct {
	NodeID flow.Identifier
}

func (IdentityNotFoundError) Error added in v0.13.0

func (e IdentityNotFoundError) Error() string

type InitialProtocolState added in v0.35.4

type InitialProtocolState interface {
	// Epoch returns counter of epoch.
	Epoch() uint64
	// Clustering returns initial clustering from epoch setup.
	// No errors are expected during normal operations.
	Clustering() (flow.ClusterList, error)
	// EpochSetup returns original epoch setup event that was used to initialize the protocol state.
	EpochSetup() *flow.EpochSetup
	// EpochCommit returns original epoch commit event that was used to update the protocol state.
	EpochCommit() *flow.EpochCommit
	// DKG returns information about DKG that was obtained from EpochCommit event.
	// No errors are expected during normal operations.
	DKG() (DKG, error)
	// Entry Returns low-level protocol state entry that was used to initialize this object.
	// It shouldn't be used by high-level logic, it is useful for some cases such as bootstrapping.
	// Prefer using other methods to access protocol state.
	Entry() *flow.RichProtocolStateEntry
}

InitialProtocolState returns constant data for given epoch. This interface can be only obtained for epochs that have progressed to epoch commit event.

type InstanceParams added in v0.23.2

type InstanceParams interface {

	// FinalizedRoot returns the finalized root header of the current protocol state. This will be
	// the head of the protocol state snapshot used to bootstrap this state and
	// may differ from node to node for the same protocol state.
	FinalizedRoot() *flow.Header

	// SealedRoot returns the sealed root block. If it's different from FinalizedRoot() block,
	// it means the node is bootstrapped from mid-spork.
	SealedRoot() *flow.Header

	// Seal returns the root block seal of the current protocol state. This is the seal for the
	// `SealedRoot` block that was used to bootstrap this state. It may differ from node to node.
	Seal() *flow.Seal

	// EpochFallbackTriggered returns whether Epoch Fallback Mode [EFM] has been triggered.
	// EFM is a permanent, spork-scoped state which is triggered when the next
	// epoch fails to be committed in the allocated time. Once EFM is triggered,
	// it will remain in effect until the next spork.
	// TODO for 'leaving Epoch Fallback via special service event'
	// No errors are expected during normal operation.
	EpochFallbackTriggered() (bool, error)
}

InstanceParams represents protocol state parameters that vary between instances. For example, two nodes both running in the same spork on Flow Mainnet may have different instance params.

type InvalidBlockTimestampError added in v0.20.0

type InvalidBlockTimestampError struct {
	// contains filtered or unexported fields
}

func (InvalidBlockTimestampError) Error added in v0.20.0

func (InvalidBlockTimestampError) Unwrap added in v0.20.0

func (e InvalidBlockTimestampError) Unwrap() error

type InvalidServiceEventError added in v0.23.2

type InvalidServiceEventError struct {
	// contains filtered or unexported fields
}

InvalidServiceEventError indicates an invalid service event was processed.

func (InvalidServiceEventError) Unwrap added in v0.23.2

func (e InvalidServiceEventError) Unwrap() error

type MutableProtocolState added in v0.33.30

type MutableProtocolState interface {
	ProtocolState

	// Mutator instantiates a `StateMutator` based on the previous protocol state.
	// Has to be called for each block to evolve the protocol state.
	// Expected errors during normal operations:
	//  * `storage.ErrNotFound` if no protocol state for parent block is known.
	Mutator(candidateView uint64, parentID flow.Identifier) (StateMutator, error)
}

type Params

type Params interface {
	InstanceParams
	GlobalParams
}

Params are parameters of the protocol state, divided into parameters of this specific instance of the state (varies from node to node) and global parameters of the state.

type ParticipantState added in v0.30.0

type ParticipantState interface {
	FollowerState

	// Extend introduces the block with the given ID into the persistent
	// protocol state without modifying the current finalized state. It allows
	// us to execute fork-aware queries against ambiguous protocol state, while
	// still checking that the given block is a valid extension of the protocol state.
	// The candidate block must have passed HotStuff validation before being passed to Extend.
	// Expected errors during normal operations:
	//  * state.OutdatedExtensionError if the candidate block is outdated (e.g. orphaned)
	//  * state.InvalidExtensionError if the candidate block is invalid
	Extend(ctx context.Context, candidate *flow.Block) error
}

ParticipantState is a mutable protocol state used by active consensus participants (consensus nodes). All blocks are validated in full, including payload validation, prior to insertion. Only valid blocks are inserted.

type ProtocolState added in v0.33.30

type ProtocolState interface {

	// AtBlockID returns protocol state at block ID.
	// The resulting protocol state is returned AFTER applying updates that are contained in block.
	// Can be queried for any block that has been added to the block tree.
	// Returns:
	// - (DynamicProtocolState, nil) - if there is a protocol state associated with given block ID.
	// - (nil, storage.ErrNotFound) - if there is no protocol state associated with given block ID.
	// - (nil, exception) - any other error should be treated as exception.
	AtBlockID(blockID flow.Identifier) (DynamicProtocolState, error)

	// GlobalParams returns params that are the same for all nodes in the network.
	GlobalParams() GlobalParams
}

ProtocolState is the read-only interface for protocol state, it allows to query information on a per-block and per-epoch basis.

type Snapshot

type Snapshot interface {

	// Head returns the latest block at the selected point of the protocol state
	// history. It can represent either a finalized or ambiguous block,
	// depending on our selection criteria. Either way, it's the block on which
	// we should build the next block in the context of the selected state.
	// TODO document error returns
	Head() (*flow.Header, error)

	// QuorumCertificate returns a valid quorum certificate for the header at
	// this snapshot, if one exists.
	// Expected error returns:
	//   - storage.ErrNotFound is returned if the QC is unknown.
	//   - state.ErrUnknownSnapshotReference if the snapshot reference block is unknown
	// All other errors should be treated as exceptions.
	QuorumCertificate() (*flow.QuorumCertificate, error)

	// Identities returns a list of identities at the selected point of the
	// protocol state history. At the beginning of an epoch, this list includes
	// identities from the previous epoch that are un-staking during the current
	// epoch. At the end of an epoch, this includes identities scheduled to join
	// in the next epoch but are not active yet.
	//
	// Identities are guaranteed to be returned in canonical order (flow.Canonical[flow.Identity]).
	//
	// It allows us to provide optional upfront filters which can be used by the
	// implementation to speed up database lookups.
	// TODO document error returns
	Identities(selector flow.IdentityFilter[flow.Identity]) (flow.IdentityList, error)

	// Identity attempts to retrieve the node with the given identifier at the
	// selected point of the protocol state history. It will error if it doesn't exist.
	// TODO document error returns
	Identity(nodeID flow.Identifier) (*flow.Identity, error)

	// SealedResult returns the most recent included seal as of this block and
	// the corresponding execution result. The seal may have been included in a
	// parent block, if this block is empty. If this block contains multiple
	// seals, this returns the seal for the block with the greatest height.
	// TODO document error returns
	SealedResult() (*flow.ExecutionResult, *flow.Seal, error)

	// Commit returns the state commitment of the most recently included seal
	// as of this block. It represents the sealed state.
	// TODO document error returns
	Commit() (flow.StateCommitment, error)

	// SealingSegment returns the chain segment such that the highest block
	// is this snapshot's reference block and the lowest block
	// is the most recently sealed block as of this snapshot (ie. the block
	// referenced by LatestSeal). The segment is in ascending height order.
	//
	// TAIL <- B1 <- ... <- BN <- HEAD
	//
	// NOTE 1: TAIL is not always sealed by HEAD. In the case that the head of
	// the snapshot contains no seals, TAIL must be sealed by the first ancestor
	// of HEAD which contains any seal.
	//
	// NOTE 2: In the special case of a root snapshot generated for a spork,
	// the sealing segment has exactly one block (the root block for the spork).
	// For all other snapshots, the sealing segment contains at least 2 blocks.
	//
	// NOTE 3: It is often the case that a block inside the segment will contain
	// an execution receipt in its payload that references an execution result
	// missing from the payload. These missing execution results are stored on the
	// flow.SealingSegment.ExecutionResults field.
	// Expected errors during normal operations:
	//  - protocol.ErrSealingSegmentBelowRootBlock if sealing segment would stretch beyond the node's local history cut-off
	//  - protocol.UnfinalizedSealingSegmentError if sealing segment would contain unfinalized blocks (including orphaned blocks)
	//  - state.ErrUnknownSnapshotReference if the snapshot reference block is unknown
	SealingSegment() (*flow.SealingSegment, error)

	// Descendants returns the IDs of all descendants of the Head block.
	// The IDs are ordered such that parents are included before their children.
	// Since all blocks are fully validated before being inserted to the state,
	// all returned blocks are validated.
	// No errors are expected under normal operation.
	Descendants() ([]flow.Identifier, error)

	// RandomSource returns the source of randomness _for_ the snapshot's Head block.
	// Note that the source of randomness for a block `H`, is contained in the
	// QuorumCertificate [QC] for block `H` (QCs for H are distributed as part of child
	// blocks, timeout messages or timeout certificates). While there might be different
	// QCs for block H, they all yield exactly the same source of randomness (feature of
	// threshold signatures used here). Therefore, it is a possibility that there is no
	// QC known (yet) for the head block.
	// NOTE: not to be confused with the epoch source of randomness!
	// Expected error returns:
	//  - storage.ErrNotFound is returned if the QC is unknown.
	//  - state.ErrUnknownSnapshotReference if the snapshot reference block is unknown
	// All other errors should be treated as exceptions.
	RandomSource() ([]byte, error)

	// Phase returns the epoch phase for the current epoch, as of the Head block.
	// TODO document error returns
	Phase() (flow.EpochPhase, error)

	// Epochs returns a query object enabling querying detailed information about
	// various epochs.
	//
	// For epochs that are in the future w.r.t. the Head block, some of Epoch's
	// methods may return errors, since the Epoch Preparation Protocol may be
	// in-progress and incomplete for the epoch.
	// Returns invalid.Epoch with state.ErrUnknownSnapshotReference if snapshot reference block is unknown.
	Epochs() EpochQuery

	// Params returns global parameters of the state this snapshot is taken from.
	// Returns invalid.Params with state.ErrUnknownSnapshotReference if snapshot reference block is unknown.
	Params() GlobalParams

	// ProtocolState returns the dynamic protocol state that the Head block commits to. The
	// compliance layer guarantees that only valid blocks are appended to the protocol state.
	// Returns state.ErrUnknownSnapshotReference if snapshot reference block is unknown.
	// All other errors should be treated as exceptions.
	ProtocolState() (DynamicProtocolState, error)

	// VersionBeacon returns the latest sealed version beacon.
	// If no version beacon has been sealed so far during the current spork, returns nil.
	// The latest VersionBeacon is only updated for finalized blocks. This means that, when
	// querying an un-finalized fork, `VersionBeacon` will have the same value as querying
	// the snapshot for the latest finalized block, even if a newer version beacon is included
	// in a seal along the un-finalized fork.
	VersionBeacon() (*flow.SealedVersionBeacon, error)
}

Snapshot represents an immutable snapshot of the protocol state at a specific block, denoted as the Head block. The Snapshot is fork-specific and only accounts for the information contained in blocks along this fork up to (including) Head. It allows us to read the parameters at the selected block in a deterministic manner.

TODO Epoch / Snapshot API Structure: Currently Epoch and Snapshot APIs are structured to allow chained queries to be used without error checking at each call where errors might occur. Instead, errors are cached in the resulting struct (eg. invalid.Epoch) until the query chain ends with a function which can return an error. This has some negative effects:

  1. Cached intermediary errors result in more complex error handling a) each final call of the chained query needs to handle all intermediary errors, every time b) intermediary errors must be handled by dependencies on the final call of the query chain (eg. conversion functions)
  2. The error caching pattern encourages potentially dangerous snapshot query patterns

See https://github.com/dapperlabs/flow-go/issues/6368 for details and proposal

A snapshot with an unknown reference block will return state.ErrUnknownSnapshotReference for all methods.

TODO document error returns

type State

type State interface {

	// Params gives access to a number of stable parameters of the protocol state.
	Params() Params

	// Final returns the snapshot of the persistent protocol state at the latest
	// finalized block, and the returned snapshot is therefore immutable over
	// time.
	Final() Snapshot

	// Sealed returns the snapshot of the persistent protocol state at the
	// latest sealed block, and the returned snapshot is therefore immutable
	// over time.
	Sealed() Snapshot

	// AtHeight returns the snapshot of the persistent protocol state at the
	// given block number. It is only available for finalized blocks and the
	// returned snapshot is therefore immutable over time.
	AtHeight(height uint64) Snapshot

	// AtBlockID returns the snapshot of the persistent protocol state at the
	// given block ID. It is available for any block that was introduced into
	// the protocol state, and can thus represent an ambiguous state that was or
	// will never be finalized.
	AtBlockID(blockID flow.Identifier) Snapshot
}

State represents the full protocol state of the local node. It allows us to obtain snapshots of the state at any point of the protocol state history.

type StateMutator

type StateMutator interface {
	// Build returns:
	//   - hasChanges: flag whether there were any changes; otherwise, `updatedState` and `stateID` equal the parent state
	//   - updatedState: the ProtocolState after applying all updates.
	//   - stateID: the hash commitment to the `updatedState`
	//   - dbUpdates: database updates necessary for persisting the updated protocol state's *dependencies*.
	//     If hasChanges is false, updatedState is empty. Caution: persisting the `updatedState` itself and adding
	//     it to the relevant indices is _not_ in `dbUpdates`. Persisting and indexing `updatedState` is the responsibility
	//     of the calling code (specifically `FollowerState`).
	//
	// updated protocol state entry, state ID and a flag indicating if there were any changes.
	Build() (hasChanges bool, updatedState *flow.ProtocolStateEntry, stateID flow.Identifier, dbUpdates []transaction.DeferredDBUpdate)

	// ApplyServiceEventsFromValidatedSeals applies the state changes that are delivered via
	// sealed service events:
	//   - iterating over the sealed service events in order of increasing height
	//   - identifying state-changing service event and calling into the embedded
	//     ProtocolStateMachine to apply the respective state update
	//   - tracking deferred database updates necessary to persist the updated
	//     protocol state's *dependencies*. Persisting and indexing `updatedState`
	//     is the responsibility of the calling code (specifically `FollowerState`)
	//
	// All updates only mutate the `StateMutator`'s internal in-memory copy of the
	// protocol state, without changing the parent state (i.e. the state we started from).
	//
	// SAFETY REQUIREMENT:
	// The StateMutator assumes that the proposal has passed the following correctness checks!
	//   - The seals in the payload continuously follow the ancestry of this fork. Specifically,
	//     there are no gaps in the seals.
	//   - The seals guarantee correctness of the sealed execution result, including the contained
	//     service events. This is actively checked by the verification node, whose aggregated
	//     approvals in the form of a seal attest to the correctness of the sealed execution result,
	//     including the contained.
	//
	// Consensus nodes actively verify protocol compliance for any block proposal they receive,
	// including integrity of each seal individually as well as the seals continuously following the
	// fork. Light clients only process certified blocks, which guarantees that consensus nodes already
	// ran those checks and found the proposal to be valid.
	//
	// Details on SERVICE EVENTS:
	// Consider a chain where a service event is emitted during execution of block A.
	// Block B contains an execution receipt for A. Block C contains a seal for block
	// A's execution result.
	//
	//	A <- .. <- B(RA) <- .. <- C(SA)
	//
	// Service Events are included within execution results, which are stored
	// opaquely as part of the block payload in block B. We only validate, process and persist
	// the typed service event to storage once we process C, the block containing the
	// seal for block A. This is because we rely on the sealing subsystem to validate
	// correctness of the service event before processing it.
	// Consequently, any change to the protocol state introduced by a service event
	// emitted during execution of block A would only become visible when querying
	// C or its descendants.
	//
	// Error returns:
	//   - Per convention, the input seals from the block payload have already confirmed to be protocol compliant.
	//     Hence, the service events in the sealed execution results represent the honest execution path.
	//     Therefore, the sealed service events should encode a valid evolution of the protocol state -- provided
	//     the system smart contracts are correct.
	//   - As we can rule out byzantine attacks as the source of failures, the only remaining sources of problems
	//     can be (a) bugs in the system smart contracts or (b) bugs in the node implementation.
	//     A service event not representing a valid state transition despite all consistency checks passing
	//     is interpreted as case (a) and handled internally within the StateMutator. In short, we go into Epoch
	//     Fallback Mode by copying the parent state (a valid state snapshot) and setting the
	//     `InvalidEpochTransitionAttempted` flag. All subsequent Epoch-lifecycle events are ignored.
	//   - A consistency or sanity check failing within the StateMutator is likely the symptom of an internal bug
	//     in the node software or state corruption, i.e. case (b). This is the only scenario where the error return
	//     of this function is not nil. If such an exception is returned, continuing is not an option.
	ApplyServiceEventsFromValidatedSeals(seals []*flow.Seal) error
}

StateMutator is a stateful object to evolve the protocol state. It is instantiated from the parent block's protocol state. State-changing operations can be iteratively applied and the StateMutator will internally evolve its in-memory state. While the StateMutator does not modify the database, it internally tracks the necessary database updates to persist its dependencies (specifically EpochSetup and EpochCommit events). Upon calling `Build` the StateMutator returns the updated protocol state, its ID and all database updates necessary for persisting the updated protocol state.

The StateMutator is used by a replica's compliance layer to update protocol state when observing state-changing service in blocks. It is used by the primary in the block building process to obtain the correct protocol state for a proposal. Specifically, the leader may include state-changing service events in the block payload. The flow protocol prescribes that the proposal needs to include the ID of the protocol state, _after_ processing the payload incl. all state-changing events. Therefore, the leader instantiates a StateMutator, applies the service events to it and builds the updated protocol state ID.

Not safe for concurrent use.

type UnfinalizedSealingSegmentError added in v0.30.0

type UnfinalizedSealingSegmentError struct {
	// contains filtered or unexported fields
}

UnfinalizedSealingSegmentError indicates that including unfinalized blocks in the sealing segment is illegal.

func (UnfinalizedSealingSegmentError) Error added in v0.30.0

func (UnfinalizedSealingSegmentError) Unwrap added in v0.30.0

Directories

Path Synopsis

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL