protocol

package
v0.32.11-verification-... Latest Latest
Warning

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

Go to latest
Published: Dec 22, 2023 License: AGPL-3.0 Imports: 12 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) (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.IdentityList) ([]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 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(payload *flow.Payload, 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.IdentityList) (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 initial set of collector nodes in this cluster.
	Members() flow.IdentityList

	// 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 c is incorporated.
	// The block parameter is the first block of the epoch setup phase (block c).
	//
	// |<-- Epoch N ------------------------------------------------->|
	// |<-- StakingPhase -->|<-- SetupPhase -->|<-- CommittedPhase -->|
	//                    ^--- block A - this block's execution result contains an EpochSetup event
	//                      ^--- block b - contains seal for block A
	//                         ^--- block c - contains qc for block b, first block of Setup phase
	//                           ^--- block d - finalizes block c, 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 f is received.
	// The block parameter is the first block of the epoch committed phase (block f).
	//
	// |<-- Epoch N ------------------------------------------------->|
	// |<-- StakingPhase -->|<-- SetupPhase -->|<-- CommittedPhase -->|
	//                                       ^--- block D - this block's execution result contains an EpochCommit event
	//                                         ^--- block e - contains seal for block D
	//                                            ^--- block f - contains qc for block e, first block of Committed phase
	//                                              ^--- block g - finalizes block f, 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 (EECC) is triggered.
	// Since EECC 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 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)

	// 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.IdentityList, 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.
	// No errors are expected during normal operation.
	ChainID() (flow.ChainID, error)

	// 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.
	// No errors are expected during normal operation.
	SporkID() (flow.Identifier, error)

	// 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.
	// No errors are expected during normal operation.
	SporkRootBlockHeight() (uint64, error)

	// ProtocolVersion returns the protocol version, the major software version
	// of the protocol software.
	// No errors are expected during normal operation.
	ProtocolVersion() (uint, error)

	// EpochCommitSafetyThreshold 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
	//
	// 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 (EECC) 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. Although the use of this deadline DOES NOT
	// guarantee these properties, it is a simpler way to assure them with high
	// likelihood, given reasonable configuration.
	// In particular, all nodes will agree about EECC being triggered (or not)
	// if at least one block with view in [d, f] is finalized - in other words
	// at least one block is finalized after the epoch commitment deadline, and
	// before the next epoch begins.
	//
	// 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
	//
	//                /- Epoch Commitment Deadline
	// EPOCH N        v        EPOCH N+1
	// ...------------|------||-----...
	//
	// No errors are expected during normal operation.
	EpochCommitSafetyThreshold() (uint64, error)
}

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.
	// No errors are expected during normal operation.
	FinalizedRoot() (*flow.Header, error)

	// SealedRoot returns the sealed root block. If it's different from FinalizedRoot() block,
	// it means the node is bootstrapped from mid-spork.
	// No errors are expected during normal operation.
	SealedRoot() (*flow.Header, error)

	// Seal returns the root block seal of the current protocol state. This will be
	// the seal for the root block used to bootstrap this state and may differ from
	// node to node for the same protocol state.
	// No errors are expected during normal operation.
	Seal() (*flow.Seal, error)

	// EpochFallbackTriggered returns whether epoch fallback mode (EECC) has been triggered.
	// EECC is a permanent, spork-scoped state which is triggered when the next
	// epoch fails to be committed in the allocated time. Once EECC is triggered,
	// it will remain in effect until the next spork.
	// 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 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 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 (order.Canonical).
	//
	// 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.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

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

Directories

Path Synopsis

Jump to

Keyboard shortcuts

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