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 }