github.com/onflow/flow-go@v0.35.7-crescendo-preview.23-atree-inlining/module/mempool/consensus/receipt_equivalence_class.go (about)

     1  package consensus
     2  
     3  import (
     4  	"errors"
     5  	"fmt"
     6  
     7  	"github.com/onflow/flow-go/model/flow"
     8  )
     9  
    10  // ReceiptsOfSameResult represents a set of ExecutionReceipt all committing to the same
    11  // ExecutionResult. As an ExecutionResult contains the Block ID, all results with the same
    12  // ID must be for the same block. For optimized storage, we only store the result once.
    13  // Mathematically, a ReceiptsOfSameResult struct represents an Equivalence Class of
    14  // Execution Receipts.
    15  // Implements LevelledForest's Vertex interface.
    16  type ReceiptsOfSameResult struct {
    17  	receipts    map[flow.Identifier]*flow.ExecutionReceiptMeta // map from ExecutionReceipt.ID -> ExecutionReceiptMeta
    18  	result      *flow.ExecutionResult
    19  	resultID    flow.Identifier // precomputed ID of result to avoid expensive hashing on each call
    20  	blockHeader *flow.Header    // header of the block which the result is for
    21  }
    22  
    23  // NewReceiptsOfSameResult instantiates an empty Equivalence Class (without any receipts)
    24  func NewReceiptsOfSameResult(result *flow.ExecutionResult, block *flow.Header) (*ReceiptsOfSameResult, error) {
    25  	//sanity check: initial result should be for block
    26  	if block.ID() != result.BlockID {
    27  		return nil, fmt.Errorf("initial result is for different block")
    28  	}
    29  
    30  	// construct ReceiptsOfSameResult only containing initialReceipt
    31  	rcpts := make(map[flow.Identifier]*flow.ExecutionReceiptMeta)
    32  	rs := &ReceiptsOfSameResult{
    33  		receipts:    rcpts,
    34  		result:      result,
    35  		resultID:    result.ID(),
    36  		blockHeader: block,
    37  	}
    38  	return rs, nil
    39  }
    40  
    41  // AddReceipt adds the receipt to the ReceiptsOfSameResult (if not already stored).
    42  // Returns:
    43  //   - uint: number of receipts added (consistent API with AddReceipts()),
    44  //     Possible values: 0 or 1
    45  //   - error in case of unforeseen problems
    46  func (rsr *ReceiptsOfSameResult) AddReceipt(receipt *flow.ExecutionReceipt) (uint, error) {
    47  	if receipt.ExecutionResult.ID() != rsr.resultID {
    48  		return 0, errors.New("cannot add receipt for different result")
    49  	}
    50  
    51  	receiptID := receipt.ID()
    52  	if rsr.Has(receiptID) {
    53  		return 0, nil
    54  	}
    55  	rsr.receipts[receipt.ID()] = receipt.Meta()
    56  	return 1, nil
    57  }
    58  
    59  // AddReceipts adds the receipts to the ReceiptsOfSameResult (the ones not already stored).
    60  // Returns:
    61  //   - uint: number of receipts added
    62  //   - error in case of unforeseen problems
    63  func (rsr *ReceiptsOfSameResult) AddReceipts(receipts ...*flow.ExecutionReceipt) (uint, error) {
    64  	receiptsAdded := uint(0)
    65  	for i := 0; i < len(receipts); i++ {
    66  		added, err := rsr.AddReceipt(receipts[i])
    67  		if err != nil {
    68  			return receiptsAdded, fmt.Errorf("failed to add receipt (%x) to equivalence class: %w", receipts[i].ID(), err)
    69  		}
    70  		receiptsAdded += added
    71  	}
    72  	return receiptsAdded, nil
    73  }
    74  
    75  func (rsr *ReceiptsOfSameResult) Has(receiptID flow.Identifier) bool {
    76  	_, found := rsr.receipts[receiptID]
    77  	return found
    78  }
    79  
    80  // Size returns the number of receipts in the equivalence class (i.e. the number of
    81  // receipts known for that particular result)
    82  func (rsr *ReceiptsOfSameResult) Size() uint {
    83  	return uint(len(rsr.receipts))
    84  }
    85  
    86  /* Methods implementing LevelledForest's Vertex interface */
    87  
    88  func (rsr *ReceiptsOfSameResult) VertexID() flow.Identifier { return rsr.resultID }
    89  func (rsr *ReceiptsOfSameResult) Level() uint64             { return rsr.blockHeader.Height }
    90  func (rsr *ReceiptsOfSameResult) Parent() (flow.Identifier, uint64) {
    91  	return rsr.result.PreviousResultID, rsr.blockHeader.Height - 1
    92  }