github.com/koko1123/flow-go-1@v0.29.6/engine/consensus/approvals/tracker/record.go (about)

     1  package tracker
     2  
     3  import (
     4  	"encoding/hex"
     5  	"encoding/json"
     6  	"fmt"
     7  
     8  	"github.com/koko1123/flow-go-1/model/flow"
     9  	"github.com/koko1123/flow-go-1/storage"
    10  )
    11  
    12  type Rec map[string]interface{}
    13  
    14  // SealingRecord is a record of the sealing status for a specific
    15  // incorporated result. It holds information whether the result is sealable,
    16  // or what is missing to be sealable.
    17  // Not concurrency safe.
    18  type SealingRecord struct {
    19  	*SealingObservation
    20  
    21  	// the incorporated result whose sealing status is tracked
    22  	IncorporatedResult *flow.IncorporatedResult
    23  
    24  	// entries holds the individual entries of the sealing record
    25  	entries Rec
    26  }
    27  
    28  func (r *SealingRecord) QualifiesForEmergencySealing(emergencySealable bool) {
    29  	r.entries["qualifies_for_emergency_sealing"] = emergencySealable
    30  }
    31  
    32  func (r *SealingRecord) ApprovalsMissing(chunksWithMissingApprovals map[uint64]flow.IdentifierList) {
    33  	sufficientApprovals := len(chunksWithMissingApprovals) == 0
    34  	r.entries["sufficient_approvals_for_sealing"] = sufficientApprovals
    35  	if !sufficientApprovals {
    36  		chunksInfo := make([]map[string]interface{}, 0, len(chunksWithMissingApprovals))
    37  		for i, list := range chunksWithMissingApprovals {
    38  			chunk := make(map[string]interface{})
    39  			chunk["chunk_index"] = i
    40  			chunk["missing_approvals_from_verifiers"] = list
    41  			chunksInfo = append(chunksInfo, chunk)
    42  		}
    43  		bytes, err := json.Marshal(chunksInfo)
    44  		if err != nil {
    45  			bytes = []byte("failed to marshal data about chunks with missing approvals")
    46  		}
    47  		r.entries["chunks_with_insufficient_approvals"] = string(bytes)
    48  	}
    49  }
    50  
    51  func (r *SealingRecord) ApprovalsRequested(requestCount uint) {
    52  	r.entries["number_requested_approvals"] = requestCount
    53  }
    54  
    55  // Generate generates a key-value map capturing the application-submitted data
    56  // plus auxiliary data.
    57  func (r *SealingRecord) Generate() (Rec, error) {
    58  	rec := make(Rec)
    59  	for k, v := range r.entries {
    60  		rec[k] = v
    61  	}
    62  
    63  	irID := r.IncorporatedResult.ID()
    64  	result := r.IncorporatedResult.Result
    65  	resultID := result.ID()
    66  	executedBlock, err := r.headersDB.ByBlockID(result.BlockID)
    67  	if err != nil {
    68  		return nil, fmt.Errorf("failed to retrieve executed block %v: %w", result.BlockID, err)
    69  	}
    70  	incorporatingBlock, err := r.headersDB.ByBlockID(r.IncorporatedResult.IncorporatedBlockID)
    71  	if err != nil {
    72  		return nil, fmt.Errorf("failed to retrieve incorporating block %v: %w", r.IncorporatedResult.IncorporatedBlockID, err)
    73  	}
    74  	initialState, err := result.InitialStateCommit()
    75  	if err != nil {
    76  		return nil, fmt.Errorf("failed to retrieve initial state from result %v: %w", resultID, err)
    77  	}
    78  	finalizationStatus, err := r.assignmentFinalizationStatus(incorporatingBlock)
    79  	if err != nil {
    80  		return nil, fmt.Errorf("failed to determine finalization status of incorporating block %v: %w", r.IncorporatedResult.IncorporatedBlockID, err)
    81  	}
    82  	numberReceipts, err := numberExecutionReceipts(r.receiptsDB, resultID, r.IncorporatedResult.Result.BlockID)
    83  	if err != nil {
    84  		return nil, fmt.Errorf("failed to determine whether result %v has multiple receipt: %w", resultID, err)
    85  	}
    86  
    87  	rec["executed_block_id"] = result.BlockID.String()
    88  	rec["executed_block_height"] = executedBlock.Height
    89  	rec["result_id"] = resultID.String()
    90  	rec["result_incorporated_at_height"] = incorporatingBlock.Height
    91  	rec["incorporated_result_id"] = irID.String()
    92  	rec["result_initial_state"] = hex.EncodeToString(initialState[:])
    93  	rec["number_chunks"] = len(result.Chunks)
    94  	rec["number_receipts"] = numberReceipts
    95  	_, rec["candidate_seal_in_mempool"] = r.sealsPl.ByID(irID)
    96  
    97  	if finalizationStatus != nil {
    98  		rec["incorporating_block"] = *finalizationStatus
    99  	}
   100  
   101  	return rec, nil
   102  }
   103  
   104  // assignmentFinalizationStatus check whether the verifier assignment is finalized.
   105  // This information can only be obtained without traversing the forks, if the result
   106  // is incorporated at a height that was already finalized.
   107  // Convention for return values:
   108  //   - nil if result is incorporated at an unfinalized height
   109  //   - "finalized" if result is incorporated at a finalized block
   110  //   - "orphaned" if result is incorporated in an orphaned block
   111  func (r *SealingRecord) assignmentFinalizationStatus(incorporatingBlock *flow.Header) (*string, error) {
   112  	if incorporatingBlock.Height > r.finalizedBlock.Height {
   113  		return nil, nil // result is incorporated at an unfinalized height.
   114  	}
   115  	finalizedBlockAtSameHeight, err := r.headersDB.ByHeight(incorporatingBlock.Height)
   116  	if err != nil {
   117  		return nil, fmt.Errorf("failed to retrieve incorporating block %v: %w", r.IncorporatedResult.IncorporatedBlockID, err)
   118  	}
   119  	var stat string
   120  	if finalizedBlockAtSameHeight.ID() == r.IncorporatedResult.IncorporatedBlockID {
   121  		stat = "finalized"
   122  	} else {
   123  		stat = "orphaned"
   124  	}
   125  	return &stat, nil
   126  }
   127  
   128  // numberExecutionReceipts determines how many receipts from _different_ ENs are committing to this result.
   129  func numberExecutionReceipts(receiptsDB storage.ExecutionReceipts, resultID, executedBlockID flow.Identifier) (int, error) {
   130  	// get all receipts that are known for the block
   131  	receipts, err := receiptsDB.ByBlockID(executedBlockID)
   132  	if err != nil {
   133  		return -1, fmt.Errorf("internal error querying receipts for block %v: %w", executedBlockID, err)
   134  	}
   135  
   136  	// Index receipts for given incorporatedResult by their executor. In case
   137  	// there are multiple receipts from the same executor, we keep the last one.
   138  	receiptsForIncorporatedResults := receipts.GroupByResultID().GetGroup(resultID)
   139  	return receiptsForIncorporatedResults.GroupByExecutorID().NumberGroups(), nil
   140  }