protocol

package
v0.37.10 Latest Latest
Warning

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

Go to latest
Published: Aug 31, 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")

	// ErrUnknownEpochBoundary is a sentinel returned when a query is made for an
	// epoch boundary which is unknown to this node.
	//
	// There are 2 cases where an epoch boundary can be unknown.
	// Consider an epoch boundary between epoch N and epoch M=N+1.
	// Let:
	//   - n be the final block in epoch N
	//   - m be the first block in epoch M
	//   - r be this node's lowest known block
	//   - f be this node's latest finalized block
	//
	// CASE 1: `r.Height > n.Height`
	// The boundary occurred before this node's lowest known block
	// Note that this includes the case where `r == m` (we know the first block
	// of epoch M but not the final block of epoch N).
	//
	// CASE 2: `f.Height < m.Height`
	// The boundary has not been finalized yet. Note that we may have finalized
	// n but not m.
	ErrUnknownEpochBoundary = fmt.Errorf("unknown epoch boundary for current chain state")

	// 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 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. This is a side-effect-free function. This function only returns protocol.InvalidServiceEventError as errors.

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, epochState *flow.MinEpochStateEntry, 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 This is a side-effect-free function. This function only returns protocol.InvalidServiceEventError as errors.

func IsValidExtendingEpochSetup added in v0.33.30

func IsValidExtendingEpochSetup(extendingSetup *flow.EpochSetup, epochState *flow.EpochStateEntry) 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 This is a side-effect-free function. This function only returns protocol.InvalidServiceEventError as errors.

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 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)

	// EpochFallbackModeTriggered is called when Epoch Fallback Mode [EFM] is triggered.
	// EFM is triggered when an invalid or unexpected epoch-related service event is observed,
	// or an expected service event is not observed before the epoch commitment deadline.
	// After EFM is triggered, we drop any potentially pending but uncommitted future epoch setup.
	// When an EpochRecover event is observed, regular epoch transitions begin again.
	// Usually, this means we remain in the current epoch until EFM is exited.
	// If EFM was triggered within the EpochCommitted phase, then we complete the transition
	// to the next, already-committed epoch, then remain in that epoch until EFM is exited.
	// Consumers can get context for handling events from:
	//   - epochCounter is the current epoch counter at the block when EFM was triggered
	//   - header is the block when EFM was triggered
	//
	// NOTE: This notification is emitted when the block triggering EFM is finalized.
	EpochFallbackModeTriggered(epochCounter uint64, header *flow.Header)

	// EpochFallbackModeExited is called when epoch fallback mode [EFM] is exited.
	// EFM is exited when an EpochRecover service event is processed, which defines
	// a final view for the current epoch and fully specifies the subsequent epoch.
	// Consumers can get context for handling events from:
	//   - epochCounter is the current epoch counter at the block when EFM was triggered
	//   - header is the block when EFM was triggered
	//
	// NOTE: Only called once the block incorporating the EpochRecover is finalized.
	EpochFallbackModeExited(epochCounter uint64, header *flow.Header)

	// EpochExtended is called when a flow.EpochExtension is added to the current epoch
	// Consumers can get context for handling events from:
	//   - epochCounter is the current epoch counter at the block when EFM was triggered
	//   - header is the block when EFM was triggered
	//
	// NOTE: This notification is emitted when the block triggering the EFM extension is finalized.
	EpochExtended(epochCounter uint64, header *flow.Header, extension flow.EpochExtension)
}

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 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.
	// The largest view number is the greatest of:
	//   - the FinalView field of the flow.EpochSetup event for this epoch
	//   - the FinalView field of the most recent flow.EpochExtension for this epoch
	// If EFM is not triggered during this epoch, this value will be static.
	// If EFM is triggered during this epoch, this value may increase with increasing
	// reference block heights, as new epoch extensions are included.
	// 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.
	// 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.ErrUnknownEpochBoundary - if the first block of the epoch is unknown.
	// * 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.
	// 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.ErrUnknownEpochBoundary - if the first block of the next epoch is unknown.
	// * 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 EpochProtocolState added in v0.33.30

type EpochProtocolState interface {
	// Epoch returns the current epoch counter.
	Epoch() uint64

	// Clustering returns initial clustering from epoch setup.
	// CAUTION: This describes the initial epoch configuration from the view point of the Epoch
	// Smart Contract. It does _not_ account for subsequent node ejections. For Byzantine Fault
	// Tolerance, the calling code must account for ejections!
	// 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.
	// CAUTION: This describes the initial epoch configuration from the view point of the Epoch
	// Smart Contract. It does _not_ account for subsequent node ejections. For Byzantine Fault
	// Tolerance, the calling code must account for ejections!
	EpochSetup() *flow.EpochSetup

	// EpochCommit returns original epoch commit event that was used to update the protocol state.
	// CAUTION: This describes the initial epoch configuration from the view point of the Epoch
	// Smart Contract. It does _not_ account for subsequent node ejections. For Byzantine Fault
	// Tolerance, the calling code must account for ejections!
	EpochCommit() *flow.EpochCommit

	// DKG returns information about DKG that was obtained from EpochCommit event.
	// CAUTION: This describes the initial epoch configuration from the view point of the Epoch
	// Smart Contract. It does _not_ account for subsequent node ejections. For Byzantine Fault
	// Tolerance, the calling code must account for ejections!
	// No errors are expected during normal operations.
	DKG() (DKG, error)

	// EpochFallbackTriggered denotes whether an invalid epoch state transition was attempted
	// on the fork ending in this block. Once the first block where this flag is true is finalized, epoch
	// fallback mode is triggered. This flag is reset to false when finalizing a block that seals
	// a valid EpochRecover service event.
	EpochFallbackTriggered() 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.
	// See flow.EpochPhase for detailed documentation.
	EpochPhase() flow.EpochPhase

	// EpochExtensions returns the epoch extensions associated with the current epoch, if any.
	EpochExtensions() []flow.EpochExtension

	// 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 S be the set of identities in the subsequent epoch.
	// Let `\` denote the relative set complement (also called 'set difference').
	// 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 S\C with status `flow.EpochParticipationStatusJoining`
	Identities() flow.IdentityList

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

	// 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.RichEpochStateEntry
}

EpochProtocolState represents the subset of the Protocol State KVStore related to epochs: the Identity Table, DKG, cluster assignment, etc. EpochProtocolState is fork-aware and can change on a block-by-block basis. Each EpochProtocolState instance refers to the state with respect to some reference block.

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.
	//
	// Returns invalid.Epoch with ErrNextEpochNotSetup in the case that this method
	// is queried w.r.t. a snapshot within the flow.EpochPhaseStaking 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 invalid.Epoch with 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
	//
	// CAUTION:
	//   - This function expects that `qc` has been validated. (otherwise, the state will be corrupted)
	//   - The parent block must already be stored.
	// 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
}

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 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
}

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 KVStoreReader added in v0.33.30

type KVStoreReader interface {
	// ID returns an identifier for this key-value store snapshot by hashing internal fields.
	// Two different model versions containing the same data must have different IDs.
	// New models should use `makeVersionedModelID` to implement ID.
	ID() flow.Identifier

	VersionedEncodable

	// GetProtocolStateVersion returns the Protocol State Version that created the specific
	// Snapshot backing this interface instance. Slightly simplified, the Protocol State
	// Version defines the key-value store's data model (specifically, the set of all keys
	// and the respective type for each corresponding value).
	// Generally, changes in the protocol state version correspond to changes in the set
	// of key-value pairs which are supported, and which model is used for serialization.
	// The protocol state version is updated by UpdateKVStoreVersion service events.
	GetProtocolStateVersion() uint64

	// GetVersionUpgrade returns the upgrade version of protocol.
	// VersionUpgrade is a view-based activator that specifies the version which has to be applied
	// and the view from which on it has to be applied. It may return the current protocol version
	// with a past view if the upgrade has already been activated.
	GetVersionUpgrade() *ViewBasedActivator[uint64]

	// GetEpochStateID returns the state ID of the epoch state.
	// This is part of the most basic model and is used to commit the epoch state to the KV store.
	GetEpochStateID() flow.Identifier

	// GetEpochExtensionViewCount returns the number of views for a hypothetical epoch extension. Note
	// that this value can change at runtime (through a service event). When a new extension is added,
	// the view count is used right at this point in the protocol state's evolution. In other words,
	// different extensions can have different view counts.
	GetEpochExtensionViewCount() uint64

	// GetEpochCommitSafetyThreshold [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
	//
	GetEpochCommitSafetyThreshold() uint64
}

KVStoreReader is the latest read-only interface to the Protocol State key-value store at a particular block.

Caution: Engineers evolving this interface must ensure that it is backwards-compatible with all versions of Protocol State Snapshots that can be retrieved from the local database, which should exactly correspond to the versioned model types defined in ./kvstore/models.go

type MutableProtocolState added in v0.33.30

type MutableProtocolState interface {
	ProtocolState

	// EvolveState updates the overall Protocol State based on information in the candidate block
	// (potentially still under construction). Information that may change the state is:
	//   - the candidate block's view
	//   - Service Events from execution results sealed in the candidate block
	//
	// EvolveState is compatible with speculative processing: it evolves an *in-memory copy* of the parent state
	// and collects *deferred database updates* for persisting the resulting Protocol State, including all of its
	// dependencies and respective indices. Though, the resulting batch of deferred database updates still depends
	// on the candidate block's ID, which is still unknown at the time of block construction. Executing the deferred
	// database updates is the caller's responsibility.
	//
	// SAFETY REQUIREMENTS:
	//  1. The seals must be a protocol-compliant extension of the parent block. Intuitively, we require that the
	//     seals follow the ancestry of this fork without gaps. The Consensus Participant's Compliance Layer enforces
	//     the necessary constrains. Analogously, the block building logic should always produce protocol-compliant
	//     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 (specifically the Service Events contained in the result
	//     and their order).
	//  2. For Consensus Participants that are replicas, the calling code must check that the returned `stateID` matches
	//     the commitment in the block proposal! If they don't match, the proposer is byzantine and should be slashed.
	//
	// 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.
	//
	// SERVICE EVENTS form an order-preserving, asynchronous, one-way message bus from the System Smart Contracts
	// (verified honest execution) to the Protocol State. For example, consider a fork where a service event is
	// emitted during execution of block A. Block B contains an execution receipt `RA` for A. Block C holds a
	// seal `SA` for 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
	// (block B in our example). Though, to ensure correctness of the service events, we only process them upon sealing.
	// There is some non-deterministic delay when the Protocol State observes the Service Events from block A.
	// In our example, any change to the protocol state requested by the system smart contracts in block A, would only
	// become visible in block C's Protocol State (and descendants).
	//
	// Error returns:
	// [TLDR] All error returns indicate potential state corruption and should therefore be treated as fatal.
	//   - Per convention, the input seals from the block payload have already been 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 _should be_ handled internally by the respective state machine. Otherwise, any bug or
	//     unforeseen edge cases in the system smart contracts would result in consensus halt, due to errors while
	//     evolving the protocol state.
	//   - 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.
	EvolveState(parentBlockID flow.Identifier, candidateView uint64, candidateSeals []*flow.Seal) (stateID flow.Identifier, dbUpdates *transaction.DeferredBlockPersist, err error)
}

MutableProtocolState is the read-write interface for protocol state. It allows evolving the protocol state by calling `EvolveState` for each block with arguments that might trigger state changes.

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.
	//
	// CAUTION: per convention, the protocol state requires that the candidate's
	// parent has already been ingested. Otherwise, an exception is returned.
	//
	// 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 {
	// EpochStateAtBlockID returns epoch protocol state at block ID.
	// The resulting epoch 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:
	// - (EpochProtocolState, nil) - if there is an epoch protocol state associated with given block ID.
	// - (nil, storage.ErrNotFound) - if there is no epoch protocol state associated with given block ID.
	// - (nil, exception) - any other error should be treated as exception.
	EpochStateAtBlockID(blockID flow.Identifier) (EpochProtocolState, error)

	// KVStoreAtBlockID 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:
	// - (KVStoreReader, 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.
	KVStoreAtBlockID(blockID flow.Identifier) (KVStoreReader, 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 querying the Protocol KVStore or Epoch sub-state by block, and retrieving global network params.

type SafetyParams added in v0.37.1

type SafetyParams struct {
	FinalizationSafetyThreshold uint64
	EpochExtensionViewCount     uint64
}

SafetyParams contains the safety parameters for the protocol related to the epochs. For extra details, refer to documentation of protocol.KVStoreReader.

func DefaultEpochSafetyParams added in v0.37.1

func DefaultEpochSafetyParams(chain flow.ChainID) (SafetyParams, error)

DefaultEpochSafetyParams returns the default epoch safety parameters for each chain ID.

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.
	// Expected error returns:
	//   - state.ErrUnknownSnapshotReference if the reference point for the snapshot
	//     (height or block ID) does not resolve to a queriable block in the state.
	// All other errors should be treated as exceptions.
	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.
	// Expected error returns:
	//   - state.ErrUnknownSnapshotReference if the reference point for the snapshot
	//     (height or block ID) does not resolve to a queriable block in the state.
	// All other errors should be treated as exceptions.
	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.
	// Expected error returns:
	//   - state.ErrUnknownSnapshotReference if the reference point for the snapshot
	//     (height or block ID) does not resolve to a queriable block in the state.
	//   - protocol.IdentityNotFoundError if nodeID does not correspond to a valid node.
	// All other errors should be treated as exceptions.
	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
	EpochPhase() (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

	// EpochProtocolState returns the epoch part of 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.
	EpochProtocolState() (EpochProtocolState, error)

	// 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() (KVStoreReader, 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 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

type VersionedEncodable added in v0.33.30

type VersionedEncodable interface {
	// VersionedEncode encodes the key-value store, returning the version separately
	// from the encoded bytes.
	// No errors are expected during normal operation.
	VersionedEncode() (uint64, []byte, error)
}

VersionedEncodable defines the interface for a versioned key-value store independent of the set of keys which are supported. This allows the storage layer to support storing different key-value model versions within the same software version.

type ViewBasedActivator added in v0.33.30

type ViewBasedActivator[T any] struct {
	Data           T
	ActivationView uint64 // first view at which Data will take effect
}

ViewBasedActivator allows setting value that will be active from specific view.

Jump to

Keyboard shortcuts

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