github.com/koko1123/flow-go-1@v0.29.6/state/protocol/badger/snapshot.go (about)

     1  // (c) 2019 Dapper Labs - ALL RIGHTS RESERVED
     2  
     3  package badger
     4  
     5  import (
     6  	"errors"
     7  	"fmt"
     8  
     9  	"github.com/koko1123/flow-go-1/model/flow"
    10  	"github.com/koko1123/flow-go-1/model/flow/filter"
    11  	"github.com/koko1123/flow-go-1/model/flow/mapfunc"
    12  	"github.com/koko1123/flow-go-1/model/flow/order"
    13  	"github.com/koko1123/flow-go-1/state"
    14  	"github.com/koko1123/flow-go-1/state/fork"
    15  	"github.com/koko1123/flow-go-1/state/protocol"
    16  	"github.com/koko1123/flow-go-1/state/protocol/inmem"
    17  	"github.com/koko1123/flow-go-1/state/protocol/invalid"
    18  	"github.com/koko1123/flow-go-1/state/protocol/seed"
    19  	"github.com/koko1123/flow-go-1/storage"
    20  	"github.com/koko1123/flow-go-1/storage/badger/operation"
    21  	"github.com/koko1123/flow-go-1/storage/badger/procedure"
    22  )
    23  
    24  // Snapshot implements the protocol.Snapshot interface.
    25  // It represents a read-only immutable snapshot of the protocol state at the
    26  // block it is constructed with. It allows efficient access to data associated directly
    27  // with blocks at a given state (finalized, sealed), such as the related header, commit,
    28  // seed or descending blocks. A block snapshot can lazily convert to an epoch snapshot in
    29  // order to make data associated directly with epochs accessible through its API.
    30  type Snapshot struct {
    31  	state   *State
    32  	blockID flow.Identifier // reference block for this snapshot
    33  }
    34  
    35  func NewSnapshot(state *State, blockID flow.Identifier) *Snapshot {
    36  	return &Snapshot{
    37  		state:   state,
    38  		blockID: blockID,
    39  	}
    40  }
    41  
    42  func (s *Snapshot) Head() (*flow.Header, error) {
    43  	head, err := s.state.headers.ByBlockID(s.blockID)
    44  	return head, err
    45  }
    46  
    47  // QuorumCertificate (QC) returns a valid quorum certificate pointing to the
    48  // header at this snapshot. With the exception of the root block, a valid child
    49  // block must be which contains the desired QC. The sentinel error
    50  // state.NoValidChildBlockError is returned if the the QC is unknown.
    51  //
    52  // For root block snapshots, returns the root quorum certificate. For all other
    53  // blocks, generates a quorum certificate from a valid child, if one exists.
    54  func (s *Snapshot) QuorumCertificate() (*flow.QuorumCertificate, error) {
    55  
    56  	// CASE 1: for the root block, return the root QC
    57  	root, err := s.state.Params().Root()
    58  	if err != nil {
    59  		return nil, fmt.Errorf("could not get root: %w", err)
    60  	}
    61  
    62  	if s.blockID == root.ID() {
    63  		var rootQC flow.QuorumCertificate
    64  		err := s.state.db.View(operation.RetrieveRootQuorumCertificate(&rootQC))
    65  		if err != nil {
    66  			return nil, fmt.Errorf("could not retrieve root qc: %w", err)
    67  		}
    68  		return &rootQC, nil
    69  	}
    70  
    71  	// CASE 2: for any other block, generate the root QC from a valid child
    72  	child, err := s.validChild()
    73  	if err != nil {
    74  		return nil, fmt.Errorf("could not get valid child of block %x: %w", s.blockID, err)
    75  	}
    76  
    77  	// sanity check: ensure the child has the snapshot block as parent
    78  	if child.ParentID != s.blockID {
    79  		return nil, fmt.Errorf("child parent id (%x) does not match snapshot id (%x)", child.ParentID, s.blockID)
    80  	}
    81  
    82  	// retrieve the full header as we need the view for the quorum certificate
    83  	head, err := s.Head()
    84  	if err != nil {
    85  		return nil, fmt.Errorf("could not get head: %w", err)
    86  	}
    87  
    88  	qc := &flow.QuorumCertificate{
    89  		View:          head.View,
    90  		BlockID:       s.blockID,
    91  		SignerIndices: child.ParentVoterIndices,
    92  		SigData:       child.ParentVoterSigData,
    93  	}
    94  
    95  	return qc, nil
    96  }
    97  
    98  // validChild returns a child of the snapshot head that has been validated
    99  // by HotStuff. Returns state.NoValidChildBlockError if no valid child exists.
   100  //
   101  // Any valid child may be returned. Subsequent calls are not guaranteed to
   102  // return the same child.
   103  func (s *Snapshot) validChild() (*flow.Header, error) {
   104  
   105  	var childIDs flow.IdentifierList
   106  	err := s.state.db.View(procedure.LookupBlockChildren(s.blockID, &childIDs))
   107  	if err != nil {
   108  		return nil, fmt.Errorf("could not look up children: %w", err)
   109  	}
   110  
   111  	// find the first child that has been validated
   112  	validChildID := flow.ZeroID
   113  	for _, childID := range childIDs {
   114  		var valid bool
   115  		err = s.state.db.View(operation.RetrieveBlockValidity(childID, &valid))
   116  		// skip blocks whose validity hasn't been checked yet
   117  		if errors.Is(err, storage.ErrNotFound) {
   118  			continue
   119  		}
   120  		if err != nil {
   121  			return nil, fmt.Errorf("failed to determine validity of child block %v: %w", childID, err)
   122  		}
   123  		if valid {
   124  			validChildID = childID
   125  			break
   126  		}
   127  	}
   128  
   129  	if validChildID == flow.ZeroID {
   130  		return nil, state.NewNoValidChildBlockErrorf("block has no valid children (total children: %d)", len(childIDs))
   131  	}
   132  
   133  	// get the header of the first child
   134  	child, err := s.state.headers.ByBlockID(validChildID)
   135  	return child, err
   136  }
   137  
   138  func (s *Snapshot) Phase() (flow.EpochPhase, error) {
   139  	status, err := s.state.epoch.statuses.ByBlockID(s.blockID)
   140  	if err != nil {
   141  		return flow.EpochPhaseUndefined, fmt.Errorf("could not retrieve epoch status: %w", err)
   142  	}
   143  	phase, err := status.Phase()
   144  	return phase, err
   145  }
   146  
   147  func (s *Snapshot) Identities(selector flow.IdentityFilter) (flow.IdentityList, error) {
   148  
   149  	// TODO: CAUTION SHORTCUT
   150  	// we retrieve identities based on the initial identity table from the EpochSetup
   151  	// event here -- this will need revision to support mid-epoch identity changes
   152  	// once slashing is implemented
   153  
   154  	status, err := s.state.epoch.statuses.ByBlockID(s.blockID)
   155  	if err != nil {
   156  		return nil, err
   157  	}
   158  
   159  	setup, err := s.state.epoch.setups.ByID(status.CurrentEpoch.SetupID)
   160  	if err != nil {
   161  		return nil, err
   162  	}
   163  
   164  	// sort the identities so the 'Exists' binary search works
   165  	identities := setup.Participants.Sort(order.Canonical)
   166  
   167  	// get identities that are in either last/next epoch but NOT in the current epoch
   168  	var otherEpochIdentities flow.IdentityList
   169  	phase, err := status.Phase()
   170  	if err != nil {
   171  		return nil, fmt.Errorf("could not get phase: %w", err)
   172  	}
   173  	switch phase {
   174  	// during staking phase (the beginning of the epoch) we include identities
   175  	// from the previous epoch that are now un-staking
   176  	case flow.EpochPhaseStaking:
   177  
   178  		if !status.HasPrevious() {
   179  			break
   180  		}
   181  
   182  		previousSetup, err := s.state.epoch.setups.ByID(status.PreviousEpoch.SetupID)
   183  		if err != nil {
   184  			return nil, fmt.Errorf("could not get previous epoch setup event: %w", err)
   185  		}
   186  
   187  		for _, identity := range previousSetup.Participants {
   188  			exists := identities.Exists(identity)
   189  			// add identity from previous epoch that is not in current epoch
   190  			if !exists {
   191  				otherEpochIdentities = append(otherEpochIdentities, identity)
   192  			}
   193  		}
   194  
   195  	// during setup and committed phases (the end of the epoch) we include
   196  	// identities that will join in the next epoch
   197  	case flow.EpochPhaseSetup, flow.EpochPhaseCommitted:
   198  
   199  		nextSetup, err := s.state.epoch.setups.ByID(status.NextEpoch.SetupID)
   200  		if err != nil {
   201  			return nil, fmt.Errorf("could not get next epoch setup: %w", err)
   202  		}
   203  
   204  		for _, identity := range nextSetup.Participants {
   205  			exists := identities.Exists(identity)
   206  
   207  			// add identity from next epoch that is not in current epoch
   208  			if !exists {
   209  				otherEpochIdentities = append(otherEpochIdentities, identity)
   210  			}
   211  		}
   212  
   213  	default:
   214  		return nil, fmt.Errorf("invalid epoch phase: %s", phase)
   215  	}
   216  
   217  	// add the identities from next/last epoch, with weight set to 0
   218  	identities = append(
   219  		identities,
   220  		otherEpochIdentities.Map(mapfunc.WithWeight(0))...,
   221  	)
   222  
   223  	// apply the filter to the participants
   224  	identities = identities.Filter(selector)
   225  
   226  	// apply a deterministic sort to the participants
   227  	identities = identities.Sort(order.Canonical)
   228  
   229  	return identities, nil
   230  }
   231  
   232  func (s *Snapshot) Identity(nodeID flow.Identifier) (*flow.Identity, error) {
   233  	// filter identities at snapshot for node ID
   234  	identities, err := s.Identities(filter.HasNodeID(nodeID))
   235  	if err != nil {
   236  		return nil, fmt.Errorf("could not get identities: %w", err)
   237  	}
   238  
   239  	// check if node ID is part of identities
   240  	if len(identities) == 0 {
   241  		return nil, protocol.IdentityNotFoundError{NodeID: nodeID}
   242  	}
   243  	return identities[0], nil
   244  }
   245  
   246  // Commit retrieves the latest execution state commitment at the current block snapshot. This
   247  // commitment represents the execution state as currently finalized.
   248  func (s *Snapshot) Commit() (flow.StateCommitment, error) {
   249  	// get the ID of the sealed block
   250  	seal, err := s.state.seals.HighestInFork(s.blockID)
   251  	if err != nil {
   252  		return flow.DummyStateCommitment, fmt.Errorf("could not retrieve sealed state commit: %w", err)
   253  	}
   254  	return seal.FinalState, nil
   255  }
   256  
   257  func (s *Snapshot) SealedResult() (*flow.ExecutionResult, *flow.Seal, error) {
   258  	seal, err := s.state.seals.HighestInFork(s.blockID)
   259  	if err != nil {
   260  		return nil, nil, fmt.Errorf("could not look up latest seal: %w", err)
   261  	}
   262  	result, err := s.state.results.ByID(seal.ResultID)
   263  	if err != nil {
   264  		return nil, nil, fmt.Errorf("could not get latest result: %w", err)
   265  	}
   266  	return result, seal, nil
   267  }
   268  
   269  // SealingSegment will walk through the chain backward until we reach the block referenced
   270  // by the latest seal and build a SealingSegment. As we visit each block we check each execution
   271  // receipt in the block's payload to make sure we have a corresponding execution result, any execution
   272  // results missing from blocks are stored in the SealingSegment.ExecutionResults field.
   273  func (s *Snapshot) SealingSegment() (*flow.SealingSegment, error) {
   274  	var rootHeight uint64
   275  	err := s.state.db.View(operation.RetrieveRootHeight(&rootHeight))
   276  	if err != nil {
   277  		return nil, fmt.Errorf("could not get root height: %w", err)
   278  	}
   279  	head, err := s.Head()
   280  	if err != nil {
   281  		return nil, fmt.Errorf("could not get snapshot reference block: %w", err)
   282  	}
   283  	if head.Height < rootHeight {
   284  		return nil, protocol.ErrSealingSegmentBelowRootBlock
   285  	}
   286  
   287  	seal, err := s.state.seals.HighestInFork(s.blockID)
   288  	if err != nil {
   289  		return nil, fmt.Errorf("could not get seal for sealing segment: %w", err)
   290  	}
   291  
   292  	// walk through the chain backward until we reach the block referenced by
   293  	// the latest seal - the returned segment includes this block
   294  	builder := flow.NewSealingSegmentBuilder(s.state.results.ByID, s.state.seals.HighestInFork)
   295  	scraper := func(header *flow.Header) error {
   296  		blockID := header.ID()
   297  		block, err := s.state.blocks.ByID(blockID)
   298  		if err != nil {
   299  			return fmt.Errorf("could not get block: %w", err)
   300  		}
   301  
   302  		err = builder.AddBlock(block)
   303  		if err != nil {
   304  			return fmt.Errorf("could not add block to sealing segment: %w", err)
   305  		}
   306  
   307  		return nil
   308  	}
   309  
   310  	err = fork.TraverseForward(s.state.headers, s.blockID, scraper, fork.IncludingBlock(seal.BlockID))
   311  	if err != nil {
   312  		return nil, fmt.Errorf("could not traverse sealing segment: %w", err)
   313  	}
   314  
   315  	segment, err := builder.SealingSegment()
   316  	if err != nil {
   317  		return nil, fmt.Errorf("could not build sealing segment: %w", err)
   318  	}
   319  
   320  	return segment, nil
   321  }
   322  
   323  func (s *Snapshot) Descendants() ([]flow.Identifier, error) {
   324  	descendants, err := s.descendants(s.blockID)
   325  	if err != nil {
   326  		return nil, fmt.Errorf("failed to traverse the descendants tree of block %v: %w", s.blockID, err)
   327  	}
   328  	return descendants, nil
   329  }
   330  
   331  func (s *Snapshot) ValidDescendants() ([]flow.Identifier, error) {
   332  	valid, err := s.lookupValidity(s.blockID)
   333  	if err != nil {
   334  		return nil, fmt.Errorf("could not determine validity of block %v: %w", s.blockID, err)
   335  	}
   336  	if !valid {
   337  		return []flow.Identifier{}, nil
   338  	}
   339  
   340  	descendants, err := s.validDescendants(s.blockID)
   341  	if err != nil {
   342  		return nil, fmt.Errorf("failed to traverse the descendants tree of block %v: %w", s.blockID, err)
   343  	}
   344  	return descendants, nil
   345  }
   346  
   347  func (s *Snapshot) lookupChildren(blockID flow.Identifier) ([]flow.Identifier, error) {
   348  	var children flow.IdentifierList
   349  	err := s.state.db.View(procedure.LookupBlockChildren(blockID, &children))
   350  	if err != nil {
   351  		return nil, fmt.Errorf("could not get children of block %v: %w", blockID, err)
   352  	}
   353  	return children, nil
   354  }
   355  
   356  func (s *Snapshot) lookupValidity(blockID flow.Identifier) (bool, error) {
   357  	valid := false
   358  	err := s.state.db.View(operation.RetrieveBlockValidity(blockID, &valid))
   359  	if err != nil {
   360  		// We only store the validity flag for blocks that have been marked valid.
   361  		// For blocks that haven't been marked valid (yet), the flag is simply absent.
   362  		if !errors.Is(err, storage.ErrNotFound) {
   363  			return false, fmt.Errorf("could not retrieve validity of block %v: %w", blockID, err)
   364  		}
   365  	}
   366  	return valid, nil
   367  }
   368  
   369  func (s *Snapshot) validDescendants(blockID flow.Identifier) ([]flow.Identifier, error) {
   370  	var descendantIDs []flow.Identifier
   371  
   372  	children, err := s.lookupChildren(blockID)
   373  	if err != nil {
   374  		return nil, err
   375  	}
   376  
   377  	for _, descendantID := range children {
   378  		valid, err := s.lookupValidity(descendantID)
   379  		if err != nil {
   380  			return nil, err
   381  		}
   382  
   383  		if valid {
   384  			descendantIDs = append(descendantIDs, descendantID)
   385  			additionalIDs, err := s.validDescendants(descendantID)
   386  			if err != nil {
   387  				return nil, err
   388  			}
   389  			descendantIDs = append(descendantIDs, additionalIDs...)
   390  		}
   391  	}
   392  	return descendantIDs, nil
   393  }
   394  
   395  func (s *Snapshot) descendants(blockID flow.Identifier) ([]flow.Identifier, error) {
   396  	descendantIDs, err := s.lookupChildren(blockID)
   397  	if err != nil {
   398  		return nil, err
   399  	}
   400  
   401  	for _, descendantID := range descendantIDs {
   402  		additionalIDs, err := s.descendants(descendantID)
   403  		if err != nil {
   404  			return nil, err
   405  		}
   406  		descendantIDs = append(descendantIDs, additionalIDs...)
   407  	}
   408  	return descendantIDs, nil
   409  }
   410  
   411  // RandomSource returns the seed for the current block snapshot.
   412  // Expected error returns:
   413  // * state.NoValidChildBlockError if no valid child is known
   414  func (s *Snapshot) RandomSource() ([]byte, error) {
   415  
   416  	// CASE 1: for the root block, generate the seed from the root qc
   417  	root, err := s.state.Params().Root()
   418  	if err != nil {
   419  		return nil, fmt.Errorf("could not get root: %w", err)
   420  	}
   421  
   422  	if s.blockID == root.ID() {
   423  		var rootQC flow.QuorumCertificate
   424  		err := s.state.db.View(operation.RetrieveRootQuorumCertificate(&rootQC))
   425  		if err != nil {
   426  			return nil, fmt.Errorf("could not retrieve root qc: %w", err)
   427  		}
   428  
   429  		seed, err := seed.FromParentQCSignature(rootQC.SigData)
   430  		if err != nil {
   431  			return nil, fmt.Errorf("could not create seed from root qc: %w", err)
   432  		}
   433  		return seed, nil
   434  	}
   435  
   436  	// CASE 2: for any other block, use any valid child
   437  	child, err := s.validChild()
   438  	if err != nil {
   439  		return nil, fmt.Errorf("failed to get valid child of block %x: %w", s.blockID, err)
   440  	}
   441  
   442  	seed, err := seed.FromParentQCSignature(child.ParentVoterSigData)
   443  	if err != nil {
   444  		return nil, fmt.Errorf("could not create seed from header's signature: %w", err)
   445  	}
   446  
   447  	return seed, nil
   448  }
   449  
   450  func (s *Snapshot) Epochs() protocol.EpochQuery {
   451  	return &EpochQuery{
   452  		snap: s,
   453  	}
   454  }
   455  
   456  func (s *Snapshot) Params() protocol.GlobalParams {
   457  	return s.state.Params()
   458  }
   459  
   460  // EpochQuery encapsulates querying epochs w.r.t. a snapshot.
   461  type EpochQuery struct {
   462  	snap *Snapshot
   463  }
   464  
   465  // Current returns the current epoch.
   466  func (q *EpochQuery) Current() protocol.Epoch {
   467  
   468  	// all errors returned from storage reads here are unexpected, because all
   469  	// snapshots reside within a current epoch, which must be queriable
   470  	status, err := q.snap.state.epoch.statuses.ByBlockID(q.snap.blockID)
   471  	if err != nil {
   472  		return invalid.NewEpochf("could not get epoch status for block %x: %w", q.snap.blockID, err)
   473  	}
   474  	setup, err := q.snap.state.epoch.setups.ByID(status.CurrentEpoch.SetupID)
   475  	if err != nil {
   476  		return invalid.NewEpochf("could not get current EpochSetup (id=%x) for block %x: %w", status.CurrentEpoch.SetupID, q.snap.blockID, err)
   477  	}
   478  	commit, err := q.snap.state.epoch.commits.ByID(status.CurrentEpoch.CommitID)
   479  	if err != nil {
   480  		return invalid.NewEpochf("could not get current EpochCommit (id=%x) for block %x: %w", status.CurrentEpoch.CommitID, q.snap.blockID, err)
   481  	}
   482  
   483  	epoch, err := inmem.NewCommittedEpoch(setup, commit)
   484  	if err != nil {
   485  		// all conversion errors are critical and indicate we have stored invalid epoch info - strip error type info
   486  		return invalid.NewEpochf("could not convert current epoch at block %x: %s", q.snap.blockID, err.Error())
   487  	}
   488  	return epoch
   489  }
   490  
   491  // Next returns the next epoch, if it is available.
   492  func (q *EpochQuery) Next() protocol.Epoch {
   493  
   494  	status, err := q.snap.state.epoch.statuses.ByBlockID(q.snap.blockID)
   495  	if err != nil {
   496  		return invalid.NewEpochf("could not get epoch status for block %x: %w", q.snap.blockID, err)
   497  	}
   498  	phase, err := status.Phase()
   499  	if err != nil {
   500  		// critical error: malformed EpochStatus in storage
   501  		return invalid.NewEpochf("read malformed EpochStatus from storage: %w", err)
   502  	}
   503  	// if we are in the staking phase, the next epoch is not setup yet
   504  	if phase == flow.EpochPhaseStaking {
   505  		return invalid.NewEpoch(protocol.ErrNextEpochNotSetup)
   506  	}
   507  
   508  	// if we are in setup phase, return a SetupEpoch
   509  	nextSetup, err := q.snap.state.epoch.setups.ByID(status.NextEpoch.SetupID)
   510  	if err != nil {
   511  		// all errors are critical, because we must be able to retrieve EpochSetup when in setup phase
   512  		return invalid.NewEpochf("could not get next EpochSetup (id=%x) for block %x: %w", status.NextEpoch.SetupID, q.snap.blockID, err)
   513  	}
   514  	if phase == flow.EpochPhaseSetup {
   515  		epoch, err := inmem.NewSetupEpoch(nextSetup)
   516  		if err != nil {
   517  			// all conversion errors are critical and indicate we have stored invalid epoch info - strip error type info
   518  			return invalid.NewEpochf("could not convert next (setup) epoch: %s", err.Error())
   519  		}
   520  		return epoch
   521  	}
   522  
   523  	// if we are in committed phase, return a CommittedEpoch
   524  	nextCommit, err := q.snap.state.epoch.commits.ByID(status.NextEpoch.CommitID)
   525  	if err != nil {
   526  		// all errors are critical, because we must be able to retrieve EpochCommit when in committed phase
   527  		return invalid.NewEpochf("could not get next EpochCommit (id=%x) for block %x: %w", status.NextEpoch.CommitID, q.snap.blockID, err)
   528  	}
   529  	epoch, err := inmem.NewCommittedEpoch(nextSetup, nextCommit)
   530  	if err != nil {
   531  		// all conversion errors are critical and indicate we have stored invalid epoch info - strip error type info
   532  		return invalid.NewEpochf("could not convert next (committed) epoch: %s", err.Error())
   533  	}
   534  	return epoch
   535  }
   536  
   537  // Previous returns the previous epoch. During the first epoch after the root
   538  // block, this returns a sentinel error (since there is no previous epoch).
   539  // For all other epochs, returns the previous epoch.
   540  func (q *EpochQuery) Previous() protocol.Epoch {
   541  
   542  	status, err := q.snap.state.epoch.statuses.ByBlockID(q.snap.blockID)
   543  	if err != nil {
   544  		return invalid.NewEpochf("could not get epoch status for block %x: %w", q.snap.blockID, err)
   545  	}
   546  
   547  	// CASE 1: there is no previous epoch - this indicates we are in the first
   548  	// epoch after a spork root or genesis block
   549  	if !status.HasPrevious() {
   550  		return invalid.NewEpoch(protocol.ErrNoPreviousEpoch)
   551  	}
   552  
   553  	// CASE 2: we are in any other epoch - retrieve the setup and commit events
   554  	// for the previous epoch
   555  	setup, err := q.snap.state.epoch.setups.ByID(status.PreviousEpoch.SetupID)
   556  	if err != nil {
   557  		// all errors are critical, because we must be able to retrieve EpochSetup for previous epoch
   558  		return invalid.NewEpochf("could not get previous EpochSetup (id=%x) for block %x: %w", status.PreviousEpoch.SetupID, q.snap.blockID, err)
   559  	}
   560  	commit, err := q.snap.state.epoch.commits.ByID(status.PreviousEpoch.CommitID)
   561  	if err != nil {
   562  		// all errors are critical, because we must be able to retrieve EpochCommit for previous epoch
   563  		return invalid.NewEpochf("could not get current EpochCommit (id=%x) for block %x: %w", status.PreviousEpoch.CommitID, q.snap.blockID, err)
   564  	}
   565  
   566  	epoch, err := inmem.NewCommittedEpoch(setup, commit)
   567  	if err != nil {
   568  		// all conversion errors are critical and indicate we have stored invalid epoch info - strip error type info
   569  		return invalid.NewEpochf("could not convert previous epoch: %s", err.Error())
   570  	}
   571  	return epoch
   572  }