github.com/onflow/flow-go@v0.35.7-crescendo-preview.23-atree-inlining/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 // NewSnapshotReadTransaction creates a new readonly transaction. 70 func (database *BlockDatabase) NewSnapshotReadTransaction( 71 parameters state.StateParameters, 72 ) Transaction { 73 74 return &transaction{ 75 TransactionData: database.BlockData. 76 NewSnapshotReadTransactionData(parameters), 77 DerivedTransactionData: database.DerivedBlockData. 78 NewSnapshotReadDerivedTransactionData(), 79 } 80 } 81 82 // NewCachingSnapshotReadTransaction creates a new readonly transaction that allows writing to the 83 // derived transaction data table. 84 func (database *BlockDatabase) NewCachingSnapshotReadTransaction( 85 parameters state.StateParameters, 86 ) (Transaction, error) { 87 return &transaction{ 88 TransactionData: database.BlockData.NewCachingSnapshotReadTransactionData(parameters), 89 DerivedTransactionData: database.DerivedBlockData.NewCachingSnapshotReadDerivedTransactionData(), 90 }, nil 91 } 92 93 func (txn *transaction) Validate() error { 94 err := txn.DerivedTransactionData.Validate() 95 if err != nil { 96 return fmt.Errorf("derived indices validate failed: %w", err) 97 } 98 99 // NOTE: Since the primary txn's SnapshotTime() is exposed to the user, 100 // the primary txn should be validated last to prevent primary txn' 101 // snapshot time advancement in case of derived txn validation failure. 102 err = txn.TransactionData.Validate() 103 if err != nil { 104 return fmt.Errorf("primary index validate failed: %w", err) 105 } 106 107 return nil 108 } 109 110 func (txn *transaction) Finalize() error { 111 // NOTE: DerivedTransactionData does not need to be finalized. 112 return txn.TransactionData.Finalize() 113 } 114 115 func (txn *transaction) Commit() (*snapshot.ExecutionSnapshot, error) { 116 err := txn.DerivedTransactionData.Commit() 117 if err != nil { 118 return nil, fmt.Errorf("derived indices commit failed: %w", err) 119 } 120 121 // NOTE: Since the primary txn's SnapshotTime() is exposed to the user, 122 // the primary txn should be committed last to prevent primary txn' 123 // snapshot time advancement in case of derived txn commit failure. 124 executionSnapshot, err := txn.TransactionData.Commit() 125 if err != nil { 126 return nil, fmt.Errorf("primary index commit failed: %w", err) 127 } 128 129 return executionSnapshot, nil 130 }