github.com/onflow/flow-go@v0.33.17/fvm/storage/block_database.go (about)

     1  package storage
     2  
     3  import (
     4  	"fmt"
     5  
     6  	"github.com/onflow/flow-go/fvm/storage/derived"
     7  	"github.com/onflow/flow-go/fvm/storage/logical"
     8  	"github.com/onflow/flow-go/fvm/storage/primary"
     9  	"github.com/onflow/flow-go/fvm/storage/snapshot"
    10  	"github.com/onflow/flow-go/fvm/storage/state"
    11  )
    12  
    13  // BlockDatabase packages the primary index (BlockData) and secondary indices
    14  // (DerivedBlockData) into a single database via 2PC.
    15  type BlockDatabase struct {
    16  	*primary.BlockData
    17  	*derived.DerivedBlockData
    18  }
    19  
    20  type transaction struct {
    21  	*primary.TransactionData
    22  	*derived.DerivedTransactionData
    23  }
    24  
    25  // NOTE: storageSnapshot must be thread safe.
    26  func NewBlockDatabase(
    27  	storageSnapshot snapshot.StorageSnapshot,
    28  	snapshotTime logical.Time,
    29  	cachedDerivedBlockData *derived.DerivedBlockData, // optional
    30  ) *BlockDatabase {
    31  	derivedBlockData := cachedDerivedBlockData
    32  	if derivedBlockData == nil {
    33  		derivedBlockData = derived.NewEmptyDerivedBlockData(snapshotTime)
    34  	}
    35  
    36  	return &BlockDatabase{
    37  		BlockData:        primary.NewBlockData(storageSnapshot, snapshotTime),
    38  		DerivedBlockData: derivedBlockData,
    39  	}
    40  }
    41  
    42  func (database *BlockDatabase) NewTransaction(
    43  	executionTime logical.Time,
    44  	parameters state.StateParameters,
    45  ) (
    46  	Transaction,
    47  	error,
    48  ) {
    49  	primaryTxn, err := database.BlockData.NewTransactionData(
    50  		executionTime,
    51  		parameters)
    52  	if err != nil {
    53  		return nil, fmt.Errorf("failed to create primary transaction: %w", err)
    54  	}
    55  
    56  	derivedTxn, err := database.DerivedBlockData.NewDerivedTransactionData(
    57  		primaryTxn.SnapshotTime(),
    58  		executionTime)
    59  	if err != nil {
    60  		return nil, fmt.Errorf("failed to create dervied transaction: %w", err)
    61  	}
    62  
    63  	return &transaction{
    64  		TransactionData:        primaryTxn,
    65  		DerivedTransactionData: derivedTxn,
    66  	}, nil
    67  }
    68  
    69  func (database *BlockDatabase) NewSnapshotReadTransaction(
    70  	parameters state.StateParameters,
    71  ) Transaction {
    72  
    73  	return &transaction{
    74  		TransactionData: database.BlockData.
    75  			NewSnapshotReadTransactionData(parameters),
    76  		DerivedTransactionData: database.DerivedBlockData.
    77  			NewSnapshotReadDerivedTransactionData(),
    78  	}
    79  }
    80  
    81  func (txn *transaction) Validate() error {
    82  	err := txn.DerivedTransactionData.Validate()
    83  	if err != nil {
    84  		return fmt.Errorf("derived indices validate failed: %w", err)
    85  	}
    86  
    87  	// NOTE: Since the primary txn's SnapshotTime() is exposed to the user,
    88  	// the primary txn should be validated last to prevent primary txn'
    89  	// snapshot time advancement in case of derived txn validation failure.
    90  	err = txn.TransactionData.Validate()
    91  	if err != nil {
    92  		return fmt.Errorf("primary index validate failed: %w", err)
    93  	}
    94  
    95  	return nil
    96  }
    97  
    98  func (txn *transaction) Finalize() error {
    99  	// NOTE: DerivedTransactionData does not need to be finalized.
   100  	return txn.TransactionData.Finalize()
   101  }
   102  
   103  func (txn *transaction) Commit() (*snapshot.ExecutionSnapshot, error) {
   104  	err := txn.DerivedTransactionData.Commit()
   105  	if err != nil {
   106  		return nil, fmt.Errorf("derived indices commit failed: %w", err)
   107  	}
   108  
   109  	// NOTE: Since the primary txn's SnapshotTime() is exposed to the user,
   110  	// the primary txn should be committed last to prevent primary txn'
   111  	// snapshot time advancement in case of derived txn commit failure.
   112  	executionSnapshot, err := txn.TransactionData.Commit()
   113  	if err != nil {
   114  		return nil, fmt.Errorf("primary index commit failed: %w", err)
   115  	}
   116  
   117  	return executionSnapshot, nil
   118  }