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

     1  package committer
     2  
     3  import (
     4  	"fmt"
     5  	"sync"
     6  
     7  	"github.com/hashicorp/go-multierror"
     8  
     9  	"github.com/onflow/flow-go/engine/execution"
    10  	execState "github.com/onflow/flow-go/engine/execution/state"
    11  	"github.com/onflow/flow-go/fvm/storage/snapshot"
    12  	"github.com/onflow/flow-go/ledger"
    13  	"github.com/onflow/flow-go/ledger/common/convert"
    14  	"github.com/onflow/flow-go/model/flow"
    15  	"github.com/onflow/flow-go/module"
    16  )
    17  
    18  type LedgerViewCommitter struct {
    19  	ledger ledger.Ledger
    20  	tracer module.Tracer
    21  }
    22  
    23  func NewLedgerViewCommitter(
    24  	ledger ledger.Ledger,
    25  	tracer module.Tracer,
    26  ) *LedgerViewCommitter {
    27  	return &LedgerViewCommitter{
    28  		ledger: ledger,
    29  		tracer: tracer,
    30  	}
    31  }
    32  
    33  func (committer *LedgerViewCommitter) CommitView(
    34  	snapshot *snapshot.ExecutionSnapshot,
    35  	baseStorageSnapshot execution.ExtendableStorageSnapshot,
    36  ) (
    37  	newCommit flow.StateCommitment,
    38  	proof []byte,
    39  	trieUpdate *ledger.TrieUpdate,
    40  	newStorageSnapshot execution.ExtendableStorageSnapshot,
    41  	err error,
    42  ) {
    43  	var err1, err2 error
    44  	var wg sync.WaitGroup
    45  	wg.Add(1)
    46  	go func() {
    47  		proof, err2 = committer.collectProofs(snapshot, baseStorageSnapshot)
    48  		wg.Done()
    49  	}()
    50  
    51  	newCommit, trieUpdate, newStorageSnapshot, err1 = execState.CommitDelta(
    52  		committer.ledger,
    53  		snapshot,
    54  		baseStorageSnapshot)
    55  	wg.Wait()
    56  
    57  	if err1 != nil {
    58  		err = multierror.Append(err, err1)
    59  	}
    60  	if err2 != nil {
    61  		err = multierror.Append(err, err2)
    62  	}
    63  	return
    64  }
    65  
    66  func (committer *LedgerViewCommitter) collectProofs(
    67  	snapshot *snapshot.ExecutionSnapshot,
    68  	baseStorageSnapshot execution.ExtendableStorageSnapshot,
    69  ) (
    70  	proof []byte,
    71  	err error,
    72  ) {
    73  	baseState := baseStorageSnapshot.Commitment()
    74  	// Reason for including AllRegisterIDs (read and written registers) instead of ReadRegisterIDs (only read registers):
    75  	// AllRegisterIDs returns deduplicated register IDs that were touched by both
    76  	// reads and writes during the block execution.
    77  	// Verification nodes only need the registers in the storage proof that were touched by reads
    78  	// in order to execute transactions in a chunk. However, without the registers touched
    79  	// by writes, especially the interim trie nodes for them, verification nodes won't be
    80  	// able to reconstruct the trie root hash of the execution state post execution. That's why
    81  	// the storage proof needs both read registers and write registers, which specifically is AllRegisterIDs
    82  	allIds := snapshot.AllRegisterIDs()
    83  	keys := make([]ledger.Key, 0, len(allIds))
    84  	for _, id := range allIds {
    85  		keys = append(keys, convert.RegisterIDToLedgerKey(id))
    86  	}
    87  
    88  	query, err := ledger.NewQuery(ledger.State(baseState), keys)
    89  	if err != nil {
    90  		return nil, fmt.Errorf("cannot create ledger query: %w", err)
    91  	}
    92  
    93  	return committer.ledger.Prove(query)
    94  }