github.com/onflow/flow-go@v0.35.7-crescendo-preview.23-atree-inlining/model/flow/execution_receipt.go (about)

     1  package flow
     2  
     3  import (
     4  	"encoding/json"
     5  
     6  	"github.com/onflow/crypto"
     7  )
     8  
     9  type Spock []byte
    10  
    11  // ExecutionReceipt is the full execution receipt, as sent by the Execution Node.
    12  // Specifically, it contains the detailed execution result.
    13  type ExecutionReceipt struct {
    14  	ExecutorID Identifier
    15  	ExecutionResult
    16  	Spocks            []crypto.Signature
    17  	ExecutorSignature crypto.Signature
    18  }
    19  
    20  // ID returns the canonical ID of the execution receipt.
    21  func (er *ExecutionReceipt) ID() Identifier {
    22  	return er.Meta().ID()
    23  }
    24  
    25  // Checksum returns a checksum for the execution receipt including the signatures.
    26  func (er *ExecutionReceipt) Checksum() Identifier {
    27  	return MakeID(er)
    28  }
    29  
    30  // Meta returns the receipt metadata for the receipt.
    31  func (er *ExecutionReceipt) Meta() *ExecutionReceiptMeta {
    32  	return &ExecutionReceiptMeta{
    33  		ExecutorID:        er.ExecutorID,
    34  		ResultID:          er.ExecutionResult.ID(),
    35  		Spocks:            er.Spocks,
    36  		ExecutorSignature: er.ExecutorSignature,
    37  	}
    38  }
    39  
    40  // ExecutionReceiptMeta contains the fields from the Execution Receipts
    41  // that vary from one executor to another (assuming they commit to the same
    42  // result). It only contains the ID (cryptographic hash) of the execution
    43  // result the receipt commits to. The ExecutionReceiptMeta is useful for
    44  // storing results and receipts separately in a composable way.
    45  type ExecutionReceiptMeta struct {
    46  	ExecutorID        Identifier
    47  	ResultID          Identifier
    48  	Spocks            []crypto.Signature
    49  	ExecutorSignature crypto.Signature
    50  }
    51  
    52  func ExecutionReceiptFromMeta(meta ExecutionReceiptMeta, result ExecutionResult) *ExecutionReceipt {
    53  	return &ExecutionReceipt{
    54  		ExecutorID:        meta.ExecutorID,
    55  		ExecutionResult:   result,
    56  		Spocks:            meta.Spocks,
    57  		ExecutorSignature: meta.ExecutorSignature,
    58  	}
    59  }
    60  
    61  // ID returns the canonical ID of the execution receipt.
    62  // It is identical to the ID of the full receipt.
    63  func (er *ExecutionReceiptMeta) ID() Identifier {
    64  	body := struct {
    65  		ExecutorID Identifier
    66  		ResultID   Identifier
    67  		Spocks     []crypto.Signature
    68  	}{
    69  		ExecutorID: er.ExecutorID,
    70  		ResultID:   er.ResultID,
    71  		Spocks:     er.Spocks,
    72  	}
    73  	return MakeID(body)
    74  }
    75  
    76  func (er ExecutionReceiptMeta) MarshalJSON() ([]byte, error) {
    77  	type Alias ExecutionReceiptMeta
    78  	return json.Marshal(struct {
    79  		Alias
    80  		ID string
    81  	}{
    82  		Alias: Alias(er),
    83  		ID:    er.ID().String(),
    84  	})
    85  }
    86  
    87  // Checksum returns a checksum for the execution receipt including the signatures.
    88  func (er *ExecutionReceiptMeta) Checksum() Identifier {
    89  	return MakeID(er)
    90  }
    91  
    92  /*******************************************************************************
    93  GROUPING for full ExecutionReceipts:
    94  allows to split a list of receipts by some property
    95  *******************************************************************************/
    96  
    97  // ExecutionReceiptList is a slice of ExecutionReceipts with the additional
    98  // functionality to group receipts by various properties
    99  type ExecutionReceiptList []*ExecutionReceipt
   100  
   101  // ExecutionReceiptGroupedList is a partition of an ExecutionReceiptList
   102  type ExecutionReceiptGroupedList map[Identifier]ExecutionReceiptList
   103  
   104  // ExecutionReceiptGroupingFunction is a function that assigns an identifier to each receipt
   105  type ExecutionReceiptGroupingFunction func(*ExecutionReceipt) Identifier
   106  
   107  // GroupBy partitions the ExecutionReceiptList. All receipts that are mapped
   108  // by the grouping function to the same identifier are placed in the same group.
   109  // Within each group, the order and multiplicity of the receipts is preserved.
   110  func (l ExecutionReceiptList) GroupBy(grouper ExecutionReceiptGroupingFunction) ExecutionReceiptGroupedList {
   111  	groups := make(map[Identifier]ExecutionReceiptList)
   112  	for _, rcpt := range l {
   113  		groupID := grouper(rcpt)
   114  		groups[groupID] = append(groups[groupID], rcpt)
   115  	}
   116  	return groups
   117  }
   118  
   119  // GroupByExecutorID partitions the ExecutionReceiptList by the receipts' ExecutorIDs.
   120  // Within each group, the order and multiplicity of the receipts is preserved.
   121  func (l ExecutionReceiptList) GroupByExecutorID() ExecutionReceiptGroupedList {
   122  	grouper := func(receipt *ExecutionReceipt) Identifier { return receipt.ExecutorID }
   123  	return l.GroupBy(grouper)
   124  }
   125  
   126  // GroupByResultID partitions the ExecutionReceiptList by the receipts' Result IDs.
   127  // Within each group, the order and multiplicity of the receipts is preserved.
   128  func (l ExecutionReceiptList) GroupByResultID() ExecutionReceiptGroupedList {
   129  	grouper := func(receipt *ExecutionReceipt) Identifier { return receipt.ExecutionResult.ID() }
   130  	return l.GroupBy(grouper)
   131  }
   132  
   133  // Size returns the number of receipts in the list
   134  func (l ExecutionReceiptList) Size() int {
   135  	return len(l)
   136  }
   137  
   138  // GetGroup returns the receipts that were mapped to the same identifier by the
   139  // grouping function. Returns an empty (nil) ExecutionReceiptList if groupID does not exist.
   140  func (g ExecutionReceiptGroupedList) GetGroup(groupID Identifier) ExecutionReceiptList {
   141  	return g[groupID]
   142  }
   143  
   144  // NumberGroups returns the number of groups
   145  func (g ExecutionReceiptGroupedList) NumberGroups() int {
   146  	return len(g)
   147  }
   148  
   149  /*******************************************************************************
   150  GROUPING for ExecutionReceiptMeta information:
   151  allows to split a list of receipt meta information by some property
   152  *******************************************************************************/
   153  
   154  // ExecutionReceiptMetaList is a slice of ExecutionResultMetas with the additional
   155  // functionality to group them by various properties
   156  type ExecutionReceiptMetaList []*ExecutionReceiptMeta
   157  
   158  // ExecutionReceiptMetaGroupedList is a partition of an ExecutionReceiptMetaList
   159  type ExecutionReceiptMetaGroupedList map[Identifier]ExecutionReceiptMetaList
   160  
   161  // ExecutionReceiptMetaGroupingFunction is a function that assigns an identifier to each receipt meta
   162  type ExecutionReceiptMetaGroupingFunction func(*ExecutionReceiptMeta) Identifier
   163  
   164  // GroupBy partitions the ExecutionReceiptMetaList. All receipts that are mapped
   165  // by the grouping function to the same identifier are placed in the same group.
   166  // Within each group, the order and multiplicity of the receipts is preserved.
   167  func (l ExecutionReceiptMetaList) GroupBy(grouper ExecutionReceiptMetaGroupingFunction) ExecutionReceiptMetaGroupedList {
   168  	groups := make(map[Identifier]ExecutionReceiptMetaList)
   169  	for _, rcpt := range l {
   170  		groupID := grouper(rcpt)
   171  		groups[groupID] = append(groups[groupID], rcpt)
   172  	}
   173  	return groups
   174  }
   175  
   176  // GroupByExecutorID partitions the ExecutionReceiptMetaList by the receipts' ExecutorIDs.
   177  // Within each group, the order and multiplicity of the receipts is preserved.
   178  func (l ExecutionReceiptMetaList) GroupByExecutorID() ExecutionReceiptMetaGroupedList {
   179  	grouper := func(receipt *ExecutionReceiptMeta) Identifier { return receipt.ExecutorID }
   180  	return l.GroupBy(grouper)
   181  }
   182  
   183  // GroupByResultID partitions the ExecutionReceiptMetaList by the receipts' Result IDs.
   184  // Within each group, the order and multiplicity of the receipts is preserved.
   185  func (l ExecutionReceiptMetaList) GroupByResultID() ExecutionReceiptMetaGroupedList {
   186  	grouper := func(receipt *ExecutionReceiptMeta) Identifier { return receipt.ResultID }
   187  	return l.GroupBy(grouper)
   188  }
   189  
   190  // Size returns the number of receipts in the list
   191  func (l ExecutionReceiptMetaList) Size() int {
   192  	return len(l)
   193  }
   194  
   195  // GetGroup returns the receipts that were mapped to the same identifier by the
   196  // grouping function. Returns an empty (nil) ExecutionReceiptMetaList if groupID does not exist.
   197  func (g ExecutionReceiptMetaGroupedList) GetGroup(groupID Identifier) ExecutionReceiptMetaList {
   198  	return g[groupID]
   199  }
   200  
   201  // NumberGroups returns the number of groups
   202  func (g ExecutionReceiptMetaGroupedList) NumberGroups() int {
   203  	return len(g)
   204  }
   205  
   206  // Lookup generates a map from ExecutionReceipt ID to ExecutionReceiptMeta
   207  func (l ExecutionReceiptMetaList) Lookup() map[Identifier]*ExecutionReceiptMeta {
   208  	receiptsByID := make(map[Identifier]*ExecutionReceiptMeta, len(l))
   209  	for _, receipt := range l {
   210  		receiptsByID[receipt.ID()] = receipt
   211  	}
   212  	return receiptsByID
   213  }