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  }