github.com/onflow/flow-go@v0.33.17/fvm/storage/derived/derived_block_data.go (about) 1 package derived 2 3 import ( 4 "fmt" 5 6 "github.com/onflow/cadence/runtime/common" 7 "github.com/onflow/cadence/runtime/interpreter" 8 9 "github.com/onflow/flow-go/fvm/storage/logical" 10 "github.com/onflow/flow-go/fvm/storage/state" 11 ) 12 13 type DerivedTransactionPreparer interface { 14 GetOrComputeProgram( 15 txState state.NestedTransactionPreparer, 16 addressLocation common.AddressLocation, 17 programComputer ValueComputer[common.AddressLocation, *Program], 18 ) ( 19 *Program, 20 error, 21 ) 22 GetProgram(location common.AddressLocation) (*Program, bool) 23 24 GetMeterParamOverrides( 25 txnState state.NestedTransactionPreparer, 26 getMeterParamOverrides ValueComputer[struct{}, MeterParamOverrides], 27 ) ( 28 MeterParamOverrides, 29 error, 30 ) 31 32 AddInvalidator(invalidator TransactionInvalidator) 33 } 34 35 type Program struct { 36 *interpreter.Program 37 38 Dependencies ProgramDependencies 39 } 40 41 // DerivedBlockData is a simple fork-aware OCC database for "caching" derived 42 // data for a particular block. 43 type DerivedBlockData struct { 44 programs *DerivedDataTable[common.AddressLocation, *Program] 45 46 meterParamOverrides *DerivedDataTable[struct{}, MeterParamOverrides] 47 } 48 49 // DerivedTransactionData is the derived data scratch space for a single 50 // transaction. 51 type DerivedTransactionData struct { 52 programs *TableTransaction[ 53 common.AddressLocation, 54 *Program, 55 ] 56 57 // There's only a single entry in this table. For simplicity, we'll use 58 // struct{} as the entry's key. 59 meterParamOverrides *TableTransaction[struct{}, MeterParamOverrides] 60 } 61 62 func NewEmptyDerivedBlockData( 63 initialSnapshotTime logical.Time, 64 ) *DerivedBlockData { 65 return &DerivedBlockData{ 66 programs: NewEmptyTable[ 67 common.AddressLocation, 68 *Program, 69 ](initialSnapshotTime), 70 meterParamOverrides: NewEmptyTable[ 71 struct{}, 72 MeterParamOverrides, 73 ](initialSnapshotTime), 74 } 75 } 76 77 func (block *DerivedBlockData) NewChildDerivedBlockData() *DerivedBlockData { 78 return &DerivedBlockData{ 79 programs: block.programs.NewChildTable(), 80 meterParamOverrides: block.meterParamOverrides.NewChildTable(), 81 } 82 } 83 84 func (block *DerivedBlockData) NewSnapshotReadDerivedTransactionData() *DerivedTransactionData { 85 txnPrograms := block.programs.NewSnapshotReadTableTransaction() 86 87 txnMeterParamOverrides := block.meterParamOverrides.NewSnapshotReadTableTransaction() 88 89 return &DerivedTransactionData{ 90 programs: txnPrograms, 91 meterParamOverrides: txnMeterParamOverrides, 92 } 93 } 94 95 func (block *DerivedBlockData) NewDerivedTransactionData( 96 snapshotTime logical.Time, 97 executionTime logical.Time, 98 ) ( 99 *DerivedTransactionData, 100 error, 101 ) { 102 txnPrograms, err := block.programs.NewTableTransaction( 103 snapshotTime, 104 executionTime) 105 if err != nil { 106 return nil, err 107 } 108 109 txnMeterParamOverrides, err := block.meterParamOverrides.NewTableTransaction( 110 snapshotTime, 111 executionTime) 112 if err != nil { 113 return nil, err 114 } 115 116 return &DerivedTransactionData{ 117 programs: txnPrograms, 118 meterParamOverrides: txnMeterParamOverrides, 119 }, nil 120 } 121 122 func (block *DerivedBlockData) NextTxIndexForTestingOnly() uint32 { 123 // NOTE: We can use next tx index from any table since they are identical. 124 return block.programs.NextTxIndexForTestingOnly() 125 } 126 127 func (block *DerivedBlockData) GetProgramForTestingOnly( 128 addressLocation common.AddressLocation, 129 ) *invalidatableEntry[*Program] { 130 return block.programs.GetForTestingOnly(addressLocation) 131 } 132 133 // CachedPrograms returns the number of programs cached. 134 // Note: this should only be called after calling commit, otherwise 135 // the count will contain invalidated entries. 136 func (block *DerivedBlockData) CachedPrograms() int { 137 return len(block.programs.items) 138 } 139 140 func (transaction *DerivedTransactionData) GetOrComputeProgram( 141 txState state.NestedTransactionPreparer, 142 addressLocation common.AddressLocation, 143 programComputer ValueComputer[common.AddressLocation, *Program], 144 ) ( 145 *Program, 146 error, 147 ) { 148 return transaction.programs.GetOrCompute( 149 txState, 150 addressLocation, 151 programComputer) 152 } 153 154 // GetProgram returns the program for the given address location. 155 // This does NOT apply reads/metering to any nested transaction. 156 // Use with caution! 157 func (transaction *DerivedTransactionData) GetProgram( 158 location common.AddressLocation, 159 ) ( 160 *Program, 161 bool, 162 ) { 163 program, _, ok := transaction.programs.get(location) 164 return program, ok 165 } 166 167 func (transaction *DerivedTransactionData) AddInvalidator( 168 invalidator TransactionInvalidator, 169 ) { 170 if invalidator == nil { 171 return 172 } 173 174 transaction.programs.AddInvalidator(invalidator.ProgramInvalidator()) 175 transaction.meterParamOverrides.AddInvalidator( 176 invalidator.MeterParamOverridesInvalidator()) 177 } 178 179 func (transaction *DerivedTransactionData) GetMeterParamOverrides( 180 txnState state.NestedTransactionPreparer, 181 getMeterParamOverrides ValueComputer[struct{}, MeterParamOverrides], 182 ) ( 183 MeterParamOverrides, 184 error, 185 ) { 186 return transaction.meterParamOverrides.GetOrCompute( 187 txnState, 188 struct{}{}, 189 getMeterParamOverrides) 190 } 191 192 func (transaction *DerivedTransactionData) Validate() error { 193 err := transaction.programs.Validate() 194 if err != nil { 195 return fmt.Errorf("programs validate failed: %w", err) 196 } 197 198 err = transaction.meterParamOverrides.Validate() 199 if err != nil { 200 return fmt.Errorf("meter param overrides validate failed: %w", err) 201 } 202 203 return nil 204 } 205 206 func (transaction *DerivedTransactionData) Commit() error { 207 err := transaction.programs.Commit() 208 if err != nil { 209 return fmt.Errorf("programs commit failed: %w", err) 210 } 211 212 err = transaction.meterParamOverrides.Commit() 213 if err != nil { 214 return fmt.Errorf("meter param overrides commit failed: %w", err) 215 } 216 217 return nil 218 }