github.com/koko1123/flow-go-1@v0.29.6/fvm/environment/derived_data_invalidator_test.go (about) 1 package environment_test 2 3 import ( 4 "testing" 5 6 "github.com/onflow/cadence/runtime/common" 7 "github.com/stretchr/testify/require" 8 9 "github.com/koko1123/flow-go-1/fvm" 10 "github.com/koko1123/flow-go-1/fvm/derived" 11 "github.com/koko1123/flow-go-1/fvm/environment" 12 "github.com/koko1123/flow-go-1/fvm/meter" 13 "github.com/koko1123/flow-go-1/fvm/state" 14 "github.com/koko1123/flow-go-1/fvm/tracing" 15 "github.com/koko1123/flow-go-1/fvm/utils" 16 "github.com/koko1123/flow-go-1/model/flow" 17 "github.com/koko1123/flow-go-1/utils/unittest" 18 ) 19 20 func TestDerivedDataProgramInvalidator(t *testing.T) { 21 22 // create the following dependency graph 23 // ```mermaid 24 // graph TD 25 // C-->D 26 // C-->B 27 // B-->A 28 // ``` 29 30 addressA := flow.HexToAddress("0xa") 31 cAddressA := common.MustBytesToAddress(addressA.Bytes()) 32 programALoc := common.AddressLocation{Address: cAddressA, Name: "A"} 33 programA := &derived.Program{ 34 Program: nil, 35 Dependencies: map[common.Address]struct{}{ 36 cAddressA: {}, 37 }, 38 } 39 40 addressB := flow.HexToAddress("0xb") 41 cAddressB := common.MustBytesToAddress(addressB.Bytes()) 42 programBLoc := common.AddressLocation{Address: cAddressB, Name: "B"} 43 programB := &derived.Program{ 44 Program: nil, 45 Dependencies: map[common.Address]struct{}{ 46 cAddressA: {}, 47 cAddressB: {}, 48 }, 49 } 50 51 addressD := flow.HexToAddress("0xd") 52 cAddressD := common.MustBytesToAddress(addressD.Bytes()) 53 programDLoc := common.AddressLocation{Address: cAddressD, Name: "D"} 54 programD := &derived.Program{ 55 Program: nil, 56 Dependencies: map[common.Address]struct{}{ 57 cAddressD: {}, 58 }, 59 } 60 61 addressC := flow.HexToAddress("0xc") 62 cAddressC := common.MustBytesToAddress(addressC.Bytes()) 63 programCLoc := common.AddressLocation{Address: cAddressC, Name: "C"} 64 programC := &derived.Program{ 65 Program: nil, 66 Dependencies: map[common.Address]struct{}{ 67 // C indirectly depends on A trough B 68 cAddressA: {}, 69 cAddressB: {}, 70 cAddressC: {}, 71 cAddressD: {}, 72 }, 73 } 74 75 t.Run("empty invalidator does not invalidate entries", func(t *testing.T) { 76 invalidator := environment.DerivedDataInvalidator{}.ProgramInvalidator() 77 78 require.False(t, invalidator.ShouldInvalidateEntries()) 79 require.False(t, invalidator.ShouldInvalidateEntry(programALoc, programA, nil)) 80 require.False(t, invalidator.ShouldInvalidateEntry(programBLoc, programB, nil)) 81 require.False(t, invalidator.ShouldInvalidateEntry(programCLoc, programC, nil)) 82 require.False(t, invalidator.ShouldInvalidateEntry(programDLoc, programD, nil)) 83 }) 84 t.Run("meter parameters invalidator invalidates all entries", func(t *testing.T) { 85 invalidator := environment.DerivedDataInvalidator{ 86 MeterParamOverridesUpdated: true, 87 }.ProgramInvalidator() 88 89 require.True(t, invalidator.ShouldInvalidateEntries()) 90 require.True(t, invalidator.ShouldInvalidateEntry(programALoc, programA, nil)) 91 require.True(t, invalidator.ShouldInvalidateEntry(programBLoc, programB, nil)) 92 require.True(t, invalidator.ShouldInvalidateEntry(programCLoc, programC, nil)) 93 require.True(t, invalidator.ShouldInvalidateEntry(programDLoc, programD, nil)) 94 }) 95 96 t.Run("address invalidator A invalidates all but D", func(t *testing.T) { 97 invalidator := environment.DerivedDataInvalidator{ 98 FrozenAccounts: []common.Address{ 99 cAddressA, 100 }, 101 }.ProgramInvalidator() 102 103 require.True(t, invalidator.ShouldInvalidateEntries()) 104 require.True(t, invalidator.ShouldInvalidateEntry(programALoc, programA, nil)) 105 require.True(t, invalidator.ShouldInvalidateEntry(programBLoc, programB, nil)) 106 require.True(t, invalidator.ShouldInvalidateEntry(programCLoc, programC, nil)) 107 require.False(t, invalidator.ShouldInvalidateEntry(programDLoc, programD, nil)) 108 }) 109 110 t.Run("address invalidator D invalidates D, C", func(t *testing.T) { 111 invalidator := environment.DerivedDataInvalidator{ 112 FrozenAccounts: []common.Address{ 113 cAddressD, 114 }, 115 }.ProgramInvalidator() 116 117 require.True(t, invalidator.ShouldInvalidateEntries()) 118 require.False(t, invalidator.ShouldInvalidateEntry(programALoc, programA, nil)) 119 require.False(t, invalidator.ShouldInvalidateEntry(programBLoc, programB, nil)) 120 require.True(t, invalidator.ShouldInvalidateEntry(programCLoc, programC, nil)) 121 require.True(t, invalidator.ShouldInvalidateEntry(programDLoc, programD, nil)) 122 }) 123 124 t.Run("address invalidator B invalidates B, C", func(t *testing.T) { 125 invalidator := environment.DerivedDataInvalidator{ 126 FrozenAccounts: []common.Address{ 127 cAddressB, 128 }, 129 }.ProgramInvalidator() 130 131 require.True(t, invalidator.ShouldInvalidateEntries()) 132 require.False(t, invalidator.ShouldInvalidateEntry(programALoc, programA, nil)) 133 require.True(t, invalidator.ShouldInvalidateEntry(programBLoc, programB, nil)) 134 require.True(t, invalidator.ShouldInvalidateEntry(programCLoc, programC, nil)) 135 require.False(t, invalidator.ShouldInvalidateEntry(programDLoc, programD, nil)) 136 }) 137 138 t.Run("contract invalidator A invalidates all but D", func(t *testing.T) { 139 invalidator := environment.DerivedDataInvalidator{ 140 ContractUpdateKeys: []environment.ContractUpdateKey{ 141 { 142 Address: cAddressA, 143 Name: "A", 144 }, 145 }, 146 }.ProgramInvalidator() 147 148 require.True(t, invalidator.ShouldInvalidateEntries()) 149 require.True(t, invalidator.ShouldInvalidateEntry(programALoc, programA, nil)) 150 require.True(t, invalidator.ShouldInvalidateEntry(programBLoc, programB, nil)) 151 require.True(t, invalidator.ShouldInvalidateEntry(programCLoc, programC, nil)) 152 require.False(t, invalidator.ShouldInvalidateEntry(programDLoc, programD, nil)) 153 }) 154 155 t.Run("contract invalidator C invalidates C", func(t *testing.T) { 156 invalidator := environment.DerivedDataInvalidator{ 157 ContractUpdateKeys: []environment.ContractUpdateKey{ 158 { 159 Address: cAddressC, 160 Name: "C", 161 }, 162 }, 163 }.ProgramInvalidator() 164 165 require.True(t, invalidator.ShouldInvalidateEntries()) 166 require.False(t, invalidator.ShouldInvalidateEntry(programALoc, programA, nil)) 167 require.False(t, invalidator.ShouldInvalidateEntry(programBLoc, programB, nil)) 168 require.True(t, invalidator.ShouldInvalidateEntry(programCLoc, programC, nil)) 169 require.False(t, invalidator.ShouldInvalidateEntry(programDLoc, programD, nil)) 170 }) 171 172 t.Run("contract invalidator D invalidates C, D", func(t *testing.T) { 173 invalidator := environment.DerivedDataInvalidator{ 174 ContractUpdateKeys: []environment.ContractUpdateKey{ 175 { 176 Address: cAddressD, 177 Name: "D", 178 }, 179 }, 180 }.ProgramInvalidator() 181 182 require.True(t, invalidator.ShouldInvalidateEntries()) 183 require.False(t, invalidator.ShouldInvalidateEntry(programALoc, programA, nil)) 184 require.False(t, invalidator.ShouldInvalidateEntry(programBLoc, programB, nil)) 185 require.True(t, invalidator.ShouldInvalidateEntry(programCLoc, programC, nil)) 186 require.True(t, invalidator.ShouldInvalidateEntry(programDLoc, programD, nil)) 187 }) 188 } 189 190 func TestMeterParamOverridesInvalidator(t *testing.T) { 191 invalidator := environment.DerivedDataInvalidator{}. 192 MeterParamOverridesInvalidator() 193 194 require.False(t, invalidator.ShouldInvalidateEntries()) 195 require.False(t, invalidator.ShouldInvalidateEntry( 196 struct{}{}, 197 derived.MeterParamOverrides{}, 198 nil)) 199 200 invalidator = environment.DerivedDataInvalidator{ 201 ContractUpdateKeys: nil, 202 FrozenAccounts: nil, 203 MeterParamOverridesUpdated: true, 204 }.MeterParamOverridesInvalidator() 205 206 require.True(t, invalidator.ShouldInvalidateEntries()) 207 require.True(t, invalidator.ShouldInvalidateEntry( 208 struct{}{}, 209 derived.MeterParamOverrides{}, 210 nil)) 211 } 212 213 func TestMeterParamOverridesUpdated(t *testing.T) { 214 memoryLimit := uint64(666) 215 216 compKind := common.ComputationKind(12345) 217 compWeight := uint64(10) 218 computationWeights := meter.ExecutionEffortWeights{ 219 compKind: compWeight, 220 } 221 222 memKind := common.MemoryKind(23456) 223 memWeight := uint64(20000) 224 memoryWeights := meter.ExecutionMemoryWeights{ 225 memKind: memWeight, 226 } 227 228 baseView := utils.NewSimpleView() 229 ctx := fvm.NewContext(fvm.WithChain(flow.Testnet.Chain())) 230 231 vm := fvm.NewVirtualMachine() 232 err := vm.Run( 233 ctx, 234 fvm.Bootstrap( 235 unittest.ServiceAccountPublicKey, 236 fvm.WithExecutionMemoryLimit(memoryLimit), 237 fvm.WithExecutionEffortWeights(computationWeights), 238 fvm.WithExecutionMemoryWeights(memoryWeights)), 239 baseView) 240 require.NoError(t, err) 241 242 view := baseView.NewChild().(*utils.SimpleView) 243 txnState := state.NewTransactionState(view, state.DefaultParameters()) 244 245 derivedBlockData := derived.NewEmptyDerivedBlockData() 246 derivedTxnData, err := derivedBlockData.NewDerivedTransactionData(0, 0) 247 require.NoError(t, err) 248 249 computer := fvm.NewMeterParamOverridesComputer(ctx, derivedTxnData) 250 251 overrides, err := computer.Compute(txnState, struct{}{}) 252 require.NoError(t, err) 253 254 // Sanity check. Note that bootstrap creates additional computation / 255 // memory weight entries. We'll only check the entries we added. 256 require.NotNil(t, overrides.MemoryLimit) 257 require.Equal(t, memoryLimit, *overrides.MemoryLimit) 258 require.Equal(t, compWeight, overrides.ComputationWeights[compKind]) 259 require.Equal(t, memWeight, overrides.MemoryWeights[memKind]) 260 261 // 262 // Actual test 263 // 264 265 ctx.TxBody = &flow.TransactionBody{} 266 267 checkForUpdates := func(owner string, key string, expected bool) { 268 view := utils.NewSimpleView() 269 txnState := state.NewTransactionState(view, state.DefaultParameters()) 270 271 err := txnState.Set(owner, key, flow.RegisterValue("blah"), false) 272 require.NoError(t, err) 273 274 env := environment.NewTransactionEnvironment( 275 tracing.NewTracerSpan(), 276 ctx.EnvironmentParams, 277 txnState, 278 nil) 279 280 invalidator := environment.NewDerivedDataInvalidator(nil, env) 281 require.Equal(t, expected, invalidator.MeterParamOverridesUpdated) 282 } 283 284 for registerId := range view.Ledger.RegisterTouches { 285 checkForUpdates(registerId.Owner, registerId.Key, true) 286 checkForUpdates("other owner", registerId.Key, false) 287 } 288 289 stabIndex := "$12345678" 290 require.True(t, state.IsSlabIndex(stabIndex)) 291 292 checkForUpdates( 293 string(ctx.Chain.ServiceAddress().Bytes()), 294 stabIndex, 295 true) 296 297 checkForUpdates( 298 string(ctx.Chain.ServiceAddress().Bytes()), 299 "other keys", 300 false) 301 302 checkForUpdates("other owner", stabIndex, false) 303 304 checkForUpdates("other owner", "other key", false) 305 }