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

     1  // Package pusher implements an engine for providing access to resources held
     2  // by the collection node, including collections, collection guarantees, and
     3  // transactions.
     4  package pusher
     5  
     6  import (
     7  	"fmt"
     8  
     9  	"github.com/rs/zerolog"
    10  
    11  	"github.com/onflow/flow-go/engine"
    12  	"github.com/onflow/flow-go/model/flow"
    13  	"github.com/onflow/flow-go/model/flow/filter"
    14  	"github.com/onflow/flow-go/model/messages"
    15  	"github.com/onflow/flow-go/module"
    16  	"github.com/onflow/flow-go/module/metrics"
    17  	"github.com/onflow/flow-go/network"
    18  	"github.com/onflow/flow-go/network/channels"
    19  	"github.com/onflow/flow-go/state/protocol"
    20  	"github.com/onflow/flow-go/storage"
    21  	"github.com/onflow/flow-go/utils/logging"
    22  )
    23  
    24  // Engine is the collection pusher engine, which provides access to resources
    25  // held by the collection node.
    26  type Engine struct {
    27  	unit         *engine.Unit
    28  	log          zerolog.Logger
    29  	engMetrics   module.EngineMetrics
    30  	colMetrics   module.CollectionMetrics
    31  	conduit      network.Conduit
    32  	me           module.Local
    33  	state        protocol.State
    34  	collections  storage.Collections
    35  	transactions storage.Transactions
    36  }
    37  
    38  func New(log zerolog.Logger, net network.EngineRegistry, state protocol.State, engMetrics module.EngineMetrics, colMetrics module.CollectionMetrics, me module.Local, collections storage.Collections, transactions storage.Transactions) (*Engine, error) {
    39  	e := &Engine{
    40  		unit:         engine.NewUnit(),
    41  		log:          log.With().Str("engine", "pusher").Logger(),
    42  		engMetrics:   engMetrics,
    43  		colMetrics:   colMetrics,
    44  		me:           me,
    45  		state:        state,
    46  		collections:  collections,
    47  		transactions: transactions,
    48  	}
    49  
    50  	conduit, err := net.Register(channels.PushGuarantees, e)
    51  	if err != nil {
    52  		return nil, fmt.Errorf("could not register for push protocol: %w", err)
    53  	}
    54  	e.conduit = conduit
    55  
    56  	return e, nil
    57  }
    58  
    59  // Ready returns a ready channel that is closed once the engine has fully
    60  // started.
    61  func (e *Engine) Ready() <-chan struct{} {
    62  	return e.unit.Ready()
    63  }
    64  
    65  // Done returns a done channel that is closed once the engine has fully stopped.
    66  func (e *Engine) Done() <-chan struct{} {
    67  	return e.unit.Done()
    68  }
    69  
    70  // SubmitLocal submits an event originating on the local node.
    71  func (e *Engine) SubmitLocal(event interface{}) {
    72  	e.unit.Launch(func() {
    73  		err := e.process(e.me.NodeID(), event)
    74  		if err != nil {
    75  			engine.LogError(e.log, err)
    76  		}
    77  	})
    78  }
    79  
    80  // Submit submits the given event from the node with the given origin ID
    81  // for processing in a non-blocking manner. It returns instantly and logs
    82  // a potential processing error internally when done.
    83  func (e *Engine) Submit(channel channels.Channel, originID flow.Identifier, event interface{}) {
    84  	e.unit.Launch(func() {
    85  		err := e.process(originID, event)
    86  		if err != nil {
    87  			engine.LogError(e.log, err)
    88  		}
    89  	})
    90  }
    91  
    92  // ProcessLocal processes an event originating on the local node.
    93  func (e *Engine) ProcessLocal(event interface{}) error {
    94  	return e.unit.Do(func() error {
    95  		return e.process(e.me.NodeID(), event)
    96  	})
    97  }
    98  
    99  // Process processes the given event from the node with the given origin ID in
   100  // a blocking manner. It returns the potential processing error when done.
   101  func (e *Engine) Process(channel channels.Channel, originID flow.Identifier, event interface{}) error {
   102  	return e.unit.Do(func() error {
   103  		return e.process(originID, event)
   104  	})
   105  }
   106  
   107  // process processes events for the pusher engine on the collection node.
   108  func (e *Engine) process(originID flow.Identifier, event interface{}) error {
   109  	switch ev := event.(type) {
   110  	case *messages.SubmitCollectionGuarantee:
   111  		e.engMetrics.MessageReceived(metrics.EngineCollectionProvider, metrics.MessageSubmitGuarantee)
   112  		defer e.engMetrics.MessageHandled(metrics.EngineCollectionProvider, metrics.MessageSubmitGuarantee)
   113  		return e.onSubmitCollectionGuarantee(originID, ev)
   114  	default:
   115  		return fmt.Errorf("invalid event type (%T)", event)
   116  	}
   117  }
   118  
   119  // onSubmitCollectionGuarantee handles submitting the given collection guarantee
   120  // to consensus nodes.
   121  func (e *Engine) onSubmitCollectionGuarantee(originID flow.Identifier, req *messages.SubmitCollectionGuarantee) error {
   122  	if originID != e.me.NodeID() {
   123  		return fmt.Errorf("invalid remote request to submit collection guarantee (from=%x)", originID)
   124  	}
   125  
   126  	return e.SubmitCollectionGuarantee(&req.Guarantee)
   127  }
   128  
   129  // SubmitCollectionGuarantee submits the collection guarantee to all consensus nodes.
   130  func (e *Engine) SubmitCollectionGuarantee(guarantee *flow.CollectionGuarantee) error {
   131  	consensusNodes, err := e.state.Final().Identities(filter.HasRole[flow.Identity](flow.RoleConsensus))
   132  	if err != nil {
   133  		return fmt.Errorf("could not get consensus nodes: %w", err)
   134  	}
   135  
   136  	// NOTE: Consensus nodes do not broadcast guarantees among themselves, so it needs that
   137  	// at least one collection node make a publish to all of them.
   138  	err = e.conduit.Publish(guarantee, consensusNodes.NodeIDs()...)
   139  	if err != nil {
   140  		return fmt.Errorf("could not submit collection guarantee: %w", err)
   141  	}
   142  
   143  	e.engMetrics.MessageSent(metrics.EngineCollectionProvider, metrics.MessageCollectionGuarantee)
   144  
   145  	e.log.Debug().
   146  		Hex("guarantee_id", logging.ID(guarantee.ID())).
   147  		Hex("ref_block_id", logging.ID(guarantee.ReferenceBlockID)).
   148  		Msg("submitting collection guarantee")
   149  
   150  	return nil
   151  }