github.com/onflow/flow-go@v0.35.7-crescendo-preview.23-atree-inlining/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 return &DerivedTransactionData{ 86 programs: block.programs.NewSnapshotReadTableTransaction(), 87 meterParamOverrides: block.meterParamOverrides.NewSnapshotReadTableTransaction(), 88 } 89 } 90 91 func (block *DerivedBlockData) NewCachingSnapshotReadDerivedTransactionData() *DerivedTransactionData { 92 return &DerivedTransactionData{ 93 programs: block.programs.NewCachingSnapshotReadTableTransaction(), 94 meterParamOverrides: block.meterParamOverrides.NewCachingSnapshotReadTableTransaction(), 95 } 96 } 97 98 func (block *DerivedBlockData) NewDerivedTransactionData( 99 snapshotTime logical.Time, 100 executionTime logical.Time, 101 ) ( 102 *DerivedTransactionData, 103 error, 104 ) { 105 txnPrograms, err := block.programs.NewTableTransaction( 106 snapshotTime, 107 executionTime) 108 if err != nil { 109 return nil, err 110 } 111 112 txnMeterParamOverrides, err := block.meterParamOverrides.NewTableTransaction( 113 snapshotTime, 114 executionTime) 115 if err != nil { 116 return nil, err 117 } 118 119 return &DerivedTransactionData{ 120 programs: txnPrograms, 121 meterParamOverrides: txnMeterParamOverrides, 122 }, nil 123 } 124 125 func (block *DerivedBlockData) NextTxIndexForTestingOnly() uint32 { 126 // NOTE: We can use next tx index from any table since they are identical. 127 return block.programs.NextTxIndexForTestingOnly() 128 } 129 130 func (block *DerivedBlockData) GetProgramForTestingOnly( 131 addressLocation common.AddressLocation, 132 ) *invalidatableEntry[*Program] { 133 return block.programs.GetForTestingOnly(addressLocation) 134 } 135 136 // CachedPrograms returns the number of programs cached. 137 // Note: this should only be called after calling commit, otherwise 138 // the count will contain invalidated entries. 139 func (block *DerivedBlockData) CachedPrograms() int { 140 return len(block.programs.items) 141 } 142 143 func (transaction *DerivedTransactionData) GetOrComputeProgram( 144 txState state.NestedTransactionPreparer, 145 addressLocation common.AddressLocation, 146 programComputer ValueComputer[common.AddressLocation, *Program], 147 ) ( 148 *Program, 149 error, 150 ) { 151 return transaction.programs.GetOrCompute( 152 txState, 153 addressLocation, 154 programComputer) 155 } 156 157 // GetProgram returns the program for the given address location. 158 // This does NOT apply reads/metering to any nested transaction. 159 // Use with caution! 160 func (transaction *DerivedTransactionData) GetProgram( 161 location common.AddressLocation, 162 ) ( 163 *Program, 164 bool, 165 ) { 166 program, _, ok := transaction.programs.get(location) 167 return program, ok 168 } 169 170 func (transaction *DerivedTransactionData) AddInvalidator( 171 invalidator TransactionInvalidator, 172 ) { 173 if invalidator == nil { 174 return 175 } 176 177 transaction.programs.AddInvalidator(invalidator.ProgramInvalidator()) 178 transaction.meterParamOverrides.AddInvalidator( 179 invalidator.MeterParamOverridesInvalidator()) 180 } 181 182 func (transaction *DerivedTransactionData) GetMeterParamOverrides( 183 txnState state.NestedTransactionPreparer, 184 getMeterParamOverrides ValueComputer[struct{}, MeterParamOverrides], 185 ) ( 186 MeterParamOverrides, 187 error, 188 ) { 189 return transaction.meterParamOverrides.GetOrCompute( 190 txnState, 191 struct{}{}, 192 getMeterParamOverrides) 193 } 194 195 func (transaction *DerivedTransactionData) Validate() error { 196 err := transaction.programs.Validate() 197 if err != nil { 198 return fmt.Errorf("programs validate failed: %w", err) 199 } 200 201 err = transaction.meterParamOverrides.Validate() 202 if err != nil { 203 return fmt.Errorf("meter param overrides validate failed: %w", err) 204 } 205 206 return nil 207 } 208 209 func (transaction *DerivedTransactionData) Commit() error { 210 err := transaction.programs.Commit() 211 if err != nil { 212 return fmt.Errorf("programs commit failed: %w", err) 213 } 214 215 err = transaction.meterParamOverrides.Commit() 216 if err != nil { 217 return fmt.Errorf("meter param overrides commit failed: %w", err) 218 } 219 220 return nil 221 }