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 }