github.com/koko1123/flow-go-1@v0.29.6/engine/execution/computation/computer/result_collector.go (about) 1 package computer 2 3 import ( 4 "fmt" 5 "sync" 6 7 "github.com/hashicorp/go-multierror" 8 otelTrace "go.opentelemetry.io/otel/trace" 9 10 "github.com/koko1123/flow-go-1/engine/execution" 11 "github.com/koko1123/flow-go-1/engine/execution/state/delta" 12 "github.com/koko1123/flow-go-1/fvm" 13 "github.com/koko1123/flow-go-1/fvm/state" 14 "github.com/koko1123/flow-go-1/ledger" 15 "github.com/koko1123/flow-go-1/model/flow" 16 "github.com/koko1123/flow-go-1/module" 17 "github.com/koko1123/flow-go-1/module/mempool/entity" 18 "github.com/koko1123/flow-go-1/module/trace" 19 "github.com/onflow/flow-go/crypto/hash" 20 ) 21 22 // ViewCommitter commits views's deltas to the ledger and collects the proofs 23 type ViewCommitter interface { 24 // CommitView commits a views' register delta and collects proofs 25 CommitView( 26 state.View, 27 flow.StateCommitment, 28 ) ( 29 flow.StateCommitment, 30 []byte, 31 *ledger.TrieUpdate, 32 error, 33 ) 34 } 35 36 type resultCollector struct { 37 tracer module.Tracer 38 blockSpan otelTrace.Span 39 40 metrics module.ExecutionMetrics 41 42 closeOnce sync.Once 43 44 committer ViewCommitter 45 state flow.StateCommitment 46 committerInputChan chan state.View 47 committerDoneChan chan struct{} 48 committerError error 49 50 eventHasherInputChan chan flow.EventsList 51 eventHasherDoneChan chan struct{} 52 eventHasherError error 53 54 signer module.Local 55 spockHasher hash.Hasher 56 spockHasherInputChan chan *delta.SpockSnapshot 57 spockHasherDoneChan chan struct{} 58 spockHasherError error 59 60 result *execution.ComputationResult 61 } 62 63 func newResultCollector( 64 tracer module.Tracer, 65 blockSpan otelTrace.Span, 66 metrics module.ExecutionMetrics, 67 committer ViewCommitter, 68 signer module.Local, 69 spockHasher hash.Hasher, 70 block *entity.ExecutableBlock, 71 numCollections int, 72 ) *resultCollector { 73 collector := &resultCollector{ 74 tracer: tracer, 75 blockSpan: blockSpan, 76 metrics: metrics, 77 committer: committer, 78 state: *block.StartState, 79 committerInputChan: make(chan state.View, numCollections), 80 committerDoneChan: make(chan struct{}), 81 eventHasherInputChan: make(chan flow.EventsList, numCollections), 82 eventHasherDoneChan: make(chan struct{}), 83 signer: signer, 84 spockHasher: spockHasher, 85 spockHasherInputChan: make(chan *delta.SpockSnapshot, numCollections), 86 spockHasherDoneChan: make(chan struct{}), 87 result: execution.NewEmptyComputationResult(block), 88 } 89 90 go collector.runCollectionCommitter() 91 go collector.runEventsHasher() 92 go collector.runSpockHasher() 93 94 return collector 95 } 96 97 func (collector *resultCollector) runCollectionCommitter() { 98 defer close(collector.committerDoneChan) 99 100 for view := range collector.committerInputChan { 101 span := collector.tracer.StartSpanFromParent( 102 collector.blockSpan, 103 trace.EXECommitDelta) 104 105 stateCommit, proof, trieUpdate, err := collector.committer.CommitView( 106 view, 107 collector.state) 108 if err != nil { 109 collector.committerError = fmt.Errorf("committer failed: %w", err) 110 return 111 } 112 113 collector.result.StateCommitments = append( 114 collector.result.StateCommitments, 115 stateCommit) 116 collector.result.Proofs = append(collector.result.Proofs, proof) 117 collector.result.TrieUpdates = append( 118 collector.result.TrieUpdates, 119 trieUpdate) 120 121 collector.state = stateCommit 122 span.End() 123 } 124 } 125 126 func (collector *resultCollector) runEventsHasher() { 127 defer close(collector.eventHasherDoneChan) 128 129 for data := range collector.eventHasherInputChan { 130 span := collector.tracer.StartSpanFromParent( 131 collector.blockSpan, 132 trace.EXEHashEvents) 133 134 rootHash, err := flow.EventsMerkleRootHash(data) 135 if err != nil { 136 collector.eventHasherError = fmt.Errorf( 137 "event hasher failed: %w", 138 err) 139 return 140 } 141 142 collector.result.EventsHashes = append( 143 collector.result.EventsHashes, 144 rootHash) 145 146 span.End() 147 } 148 } 149 150 func (collector *resultCollector) runSpockHasher() { 151 defer close(collector.spockHasherDoneChan) 152 153 for snapshot := range collector.spockHasherInputChan { 154 spock, err := collector.signer.SignFunc( 155 snapshot.SpockSecret, 156 collector.spockHasher, 157 SPOCKProve) 158 if err != nil { 159 collector.spockHasherError = fmt.Errorf( 160 "spock hasher failed: %w", 161 err) 162 return 163 } 164 165 collector.result.SpockSignatures = append( 166 collector.result.SpockSignatures, 167 spock) 168 } 169 } 170 171 func (collector *resultCollector) AddTransactionResult( 172 collectionIndex int, 173 txn *fvm.TransactionProcedure, 174 ) { 175 collector.result.AddTransactionResult(collectionIndex, txn) 176 } 177 178 func (collector *resultCollector) CommitCollection( 179 collection collectionItem, 180 collectionView state.View, 181 ) module.ExecutionResultStats { 182 183 select { 184 case collector.committerInputChan <- collectionView: 185 // Do nothing 186 case <-collector.committerDoneChan: 187 // Committer exited (probably due to an error) 188 } 189 190 select { 191 case collector.eventHasherInputChan <- collector.result.Events[collection.collectionIndex]: 192 // Do nothing 193 case <-collector.eventHasherDoneChan: 194 // Events hasher exited (probably due to an error) 195 } 196 197 snapshot := collectionView.(*delta.View).Interactions() 198 select { 199 case collector.spockHasherInputChan <- snapshot: 200 // do nothing 201 case <-collector.spockHasherDoneChan: 202 // Spock hasher exited (probably due to an error) 203 } 204 205 collector.result.AddCollection(snapshot) 206 return collector.result.CollectionStats(collection.collectionIndex) 207 } 208 209 func (collector *resultCollector) Stop() { 210 collector.closeOnce.Do(func() { 211 close(collector.committerInputChan) 212 close(collector.eventHasherInputChan) 213 close(collector.spockHasherInputChan) 214 }) 215 } 216 217 func (collector *resultCollector) Finalize() ( 218 *execution.ComputationResult, 219 error, 220 ) { 221 collector.Stop() 222 223 <-collector.committerDoneChan 224 <-collector.eventHasherDoneChan 225 <-collector.spockHasherDoneChan 226 227 var err error 228 if collector.committerError != nil { 229 err = multierror.Append(err, collector.committerError) 230 } 231 232 if collector.eventHasherError != nil { 233 err = multierror.Append(err, collector.eventHasherError) 234 } 235 236 if collector.spockHasherError != nil { 237 err = multierror.Append(err, collector.spockHasherError) 238 } 239 240 if err != nil { 241 return nil, err 242 } 243 244 return collector.result, nil 245 }