github.com/onflow/flow-go@v0.35.7-crescendo-preview.23-atree-inlining/engine/consensus/approvals/caching_assignment_collector.go (about)

     1  package approvals
     2  
     3  import (
     4  	"fmt"
     5  
     6  	"github.com/rs/zerolog"
     7  
     8  	"github.com/onflow/flow-go/engine"
     9  	"github.com/onflow/flow-go/engine/consensus"
    10  	"github.com/onflow/flow-go/model/flow"
    11  )
    12  
    13  // CachingAssignmentCollector is an AssignmentCollectorState with the fixed `ProcessingStatus` of `CachingApprovals`.
    14  type CachingAssignmentCollector struct {
    15  	AssignmentCollectorBase
    16  
    17  	log            zerolog.Logger
    18  	approvalsCache *ApprovalsCache           // in-memory cache of approvals (not-verified)
    19  	incResCache    *IncorporatedResultsCache // in-memory cache for incorporated results that were processed
    20  }
    21  
    22  func NewCachingAssignmentCollector(collectorBase AssignmentCollectorBase) *CachingAssignmentCollector {
    23  	return &CachingAssignmentCollector{
    24  		AssignmentCollectorBase: collectorBase,
    25  		log:                     collectorBase.log.With().Str("component", "caching_assignment_collector").Logger(),
    26  		approvalsCache:          NewApprovalsCache(0),
    27  		incResCache:             NewIncorporatedResultsCache(0),
    28  	}
    29  }
    30  
    31  func (ac *CachingAssignmentCollector) ProcessingStatus() ProcessingStatus { return CachingApprovals }
    32  func (ac *CachingAssignmentCollector) CheckEmergencySealing(consensus.SealingObservation, uint64) error {
    33  	return nil
    34  }
    35  func (ac *CachingAssignmentCollector) RequestMissingApprovals(consensus.SealingObservation, uint64) (uint, error) {
    36  	return 0, nil
    37  }
    38  
    39  // ProcessIncorporatedResult starts tracking the approval for IncorporatedResult.
    40  // Method is idempotent.
    41  // Error Returns:
    42  //   - no errors expected during normal operation;
    43  //     errors might be symptoms of bugs or internal state corruption (fatal)
    44  func (ac *CachingAssignmentCollector) ProcessIncorporatedResult(incorporatedResult *flow.IncorporatedResult) error {
    45  	// check that result is the one that this VerifyingAssignmentCollector manages
    46  	if resID := incorporatedResult.Result.ID(); resID != ac.ResultID() {
    47  		return fmt.Errorf("this VerifyingAssignmentCollector manages result %x but got %x", ac.ResultID(), resID)
    48  	}
    49  
    50  	// In case the result is already cached, we first read the cache.
    51  	// This is much cheaper than attempting to write right away.
    52  	irID := incorporatedResult.ID()
    53  	if cached := ac.incResCache.Get(irID); cached != nil {
    54  		return nil
    55  	}
    56  	ac.incResCache.Put(irID, incorporatedResult)
    57  	return nil
    58  }
    59  
    60  // ProcessApproval ingests Result Approvals and triggers sealing of execution result
    61  // when sufficient approvals have arrived.
    62  // Error Returns:
    63  //   - nil in case of success (outdated approvals might be silently discarded)
    64  //   - engine.InvalidInputError if the result approval is invalid
    65  //   - any other errors might be symptoms of bugs or internal state corruption (fatal)
    66  func (ac *CachingAssignmentCollector) ProcessApproval(approval *flow.ResultApproval) error {
    67  	ac.log.Debug().
    68  		Str("result_id", approval.Body.ExecutionResultID.String()).
    69  		Str("verifier_id", approval.Body.ApproverID.String()).
    70  		Msg("processing result approval")
    71  
    72  	// check that approval is for the expected result to reject incompatible inputs
    73  	if approval.Body.ExecutionResultID != ac.ResultID() {
    74  		return fmt.Errorf("this CachingAssignmentCollector processes only approvals for result (%x) but got an approval for (%x)", ac.resultID, approval.Body.ExecutionResultID)
    75  	}
    76  	// approval has to refer same block as execution result
    77  	if approval.Body.BlockID != ac.BlockID() {
    78  		return engine.NewInvalidInputErrorf("result approval for invalid block, expected (%x) vs (%x)",
    79  			ac.BlockID(), approval.Body.BlockID)
    80  	}
    81  
    82  	// if we have this approval cached already, no need to process it again
    83  	approvalCacheID := approval.Body.PartialID()
    84  	if cached := ac.approvalsCache.Get(approvalCacheID); cached != nil {
    85  		return nil
    86  	}
    87  	ac.approvalsCache.Put(approvalCacheID, approval)
    88  	return nil
    89  }
    90  
    91  func (ac *CachingAssignmentCollector) GetIncorporatedResults() []*flow.IncorporatedResult {
    92  	return ac.incResCache.All()
    93  }
    94  
    95  func (ac *CachingAssignmentCollector) GetApprovals() []*flow.ResultApproval {
    96  	return ac.approvalsCache.All()
    97  }