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

     1  package entity
     2  
     3  import (
     4  	"github.com/onflow/flow-go/model/flow"
     5  )
     6  
     7  // A complete collection contains the guarantee and the transactions.
     8  // the guarantee is the hash of all the transactions. The execution node
     9  // receives the guarantee from the block, and queries the transactions by
    10  // the guarantee from the collection node.
    11  // when receiving a collection from collection node, the execution node will
    12  // update the Transactions field of a CompleteCollection and make it complete.
    13  type CompleteCollection struct {
    14  	Guarantee    *flow.CollectionGuarantee
    15  	Transactions []*flow.TransactionBody
    16  }
    17  
    18  // ExecutableBlock represents a block that can be executed by the VM
    19  //
    20  // It assumes that the Block attached is immutable, so take care in not modifying or changing the inner
    21  // *flow.Block, otherwise the struct will be in an inconsistent state. It requires the Block is immutable
    22  // because the it lazy lodas the Block.ID() into the private id field, on the first call to ExecutableBlock.ID()
    23  // All future calls to ID will not call Block.ID(), therefore it Block changes, the id will not match the Block.
    24  type ExecutableBlock struct {
    25  	id                  flow.Identifier
    26  	Block               *flow.Block
    27  	CompleteCollections map[flow.Identifier]*CompleteCollection // key is the collection ID.
    28  	StartState          *flow.StateCommitment
    29  	Executing           bool // flag used to indicate if block is being executed, to avoid re-execution
    30  }
    31  
    32  // BlocksByCollection represents a collection that the execution node.
    33  // has not received its transactions yet.
    34  // it also holds references to the blocks that contains this collection
    35  // and are waiting to be executed.
    36  type BlocksByCollection struct {
    37  	CollectionID flow.Identifier
    38  	// a reversed map to look up which block contains this collection. key is the collection id
    39  	ExecutableBlocks map[flow.Identifier]*ExecutableBlock
    40  }
    41  
    42  func (c CompleteCollection) Collection() flow.Collection {
    43  	return flow.Collection{Transactions: c.Transactions}
    44  }
    45  
    46  func (c CompleteCollection) IsCompleted() bool {
    47  	return len(c.Transactions) > 0
    48  }
    49  
    50  func (b *BlocksByCollection) ID() flow.Identifier {
    51  	return b.CollectionID
    52  }
    53  
    54  func (b *BlocksByCollection) Checksum() flow.Identifier {
    55  	return b.CollectionID
    56  }
    57  
    58  // ID lazy loads the Block.ID() into the private id field on the first call, and returns
    59  // the id field in all future calls
    60  func (b *ExecutableBlock) ID() flow.Identifier {
    61  	if b.id == flow.ZeroID {
    62  		b.id = b.Block.ID()
    63  	}
    64  	return b.id
    65  }
    66  
    67  func (b *ExecutableBlock) Checksum() flow.Identifier {
    68  	return b.Block.Checksum()
    69  }
    70  
    71  func (b *ExecutableBlock) Height() uint64 {
    72  	return b.Block.Header.Height
    73  }
    74  
    75  func (b *ExecutableBlock) ParentID() flow.Identifier {
    76  	return b.Block.Header.ParentID
    77  }
    78  
    79  func (b *ExecutableBlock) Collections() []*CompleteCollection {
    80  	collections := make([]*CompleteCollection, len(b.Block.Payload.Guarantees))
    81  
    82  	for i, cg := range b.Block.Payload.Guarantees {
    83  		collections[i] = b.CompleteCollections[cg.ID()]
    84  	}
    85  
    86  	return collections
    87  }
    88  
    89  // CompleteCollectionAt returns a complete collection at the given index,
    90  // if index out of range, nil will be returned
    91  func (b *ExecutableBlock) CompleteCollectionAt(index int) *CompleteCollection {
    92  	if index < 0 || index >= len(b.Block.Payload.Guarantees) {
    93  		return nil
    94  	}
    95  	return b.CompleteCollections[b.Block.Payload.Guarantees[index].ID()]
    96  }
    97  
    98  // CollectionAt returns a collection at the given index,
    99  // if index out of range, nil will be returned
   100  func (b *ExecutableBlock) CollectionAt(index int) *flow.Collection {
   101  	cc := b.CompleteCollectionAt(index)
   102  	if cc == nil {
   103  		return nil
   104  	}
   105  	return &flow.Collection{Transactions: cc.Transactions}
   106  }
   107  
   108  // HasAllTransactions returns whether all the transactions for all collections
   109  // in the block have been received.
   110  func (b *ExecutableBlock) HasAllTransactions() bool {
   111  	for _, collection := range b.Block.Payload.Guarantees {
   112  
   113  		completeCollection, ok := b.CompleteCollections[collection.ID()]
   114  		if ok && completeCollection.IsCompleted() {
   115  			continue
   116  		}
   117  		return false
   118  	}
   119  	return true
   120  }
   121  
   122  // HasStartState returns whether the block has StartState, which
   123  // indicates whether its parent has been executed.
   124  func (b *ExecutableBlock) HasStartState() bool {
   125  	return b.StartState != nil
   126  }
   127  
   128  // IsComplete returns whether all the data needed to executed the block are
   129  // ready.
   130  func (b *ExecutableBlock) IsComplete() bool {
   131  	return b.HasAllTransactions() && b.HasStartState()
   132  }