github.com/onflow/flow-go@v0.35.7-crescendo-preview.23-atree-inlining/fvm/meter/meter_test.go (about) 1 package meter_test 2 3 import ( 4 "fmt" 5 "math" 6 "testing" 7 8 "github.com/stretchr/testify/assert" 9 "github.com/stretchr/testify/require" 10 11 "github.com/onflow/cadence/runtime/common" 12 13 "github.com/onflow/flow-go/fvm/errors" 14 "github.com/onflow/flow-go/fvm/meter" 15 "github.com/onflow/flow-go/model/flow" 16 ) 17 18 func TestWeightedComputationMetering(t *testing.T) { 19 20 t.Run("get limits", func(t *testing.T) { 21 m := meter.NewMeter( 22 meter.DefaultParameters(). 23 WithComputationLimit(1). 24 WithMemoryLimit(2), 25 ) 26 require.Equal(t, uint(1), m.TotalComputationLimit()) 27 require.Equal(t, uint64(2), m.TotalMemoryLimit()) 28 }) 29 30 t.Run("get limits max", func(t *testing.T) { 31 m := meter.NewMeter( 32 meter.DefaultParameters(). 33 WithComputationLimit(math.MaxUint32). 34 WithMemoryLimit(math.MaxUint32), 35 ) 36 require.Equal(t, uint(math.MaxUint32), m.TotalComputationLimit()) 37 require.Equal(t, uint64(math.MaxUint32), m.TotalMemoryLimit()) 38 }) 39 40 t.Run("meter computation and memory", func(t *testing.T) { 41 m := meter.NewMeter( 42 meter.DefaultParameters(). 43 WithComputationLimit(10). 44 WithComputationWeights( 45 map[common.ComputationKind]uint64{0: 1 << meter.MeterExecutionInternalPrecisionBytes}). 46 WithMemoryLimit(10). 47 WithMemoryWeights(map[common.MemoryKind]uint64{0: 1}), 48 ) 49 50 err := m.MeterComputation(0, 1) 51 require.NoError(t, err) 52 require.Equal(t, uint64(1), m.TotalComputationUsed()) 53 54 err = m.MeterComputation(0, 2) 55 require.NoError(t, err) 56 require.Equal(t, uint64(1+2), m.TotalComputationUsed()) 57 58 err = m.MeterComputation(0, 8) 59 require.Error(t, err) 60 require.True(t, errors.IsComputationLimitExceededError(err)) 61 require.Equal(t, err.Error(), errors.NewComputationLimitExceededError(10).Error()) 62 63 err = m.MeterMemory(0, 2) 64 require.NoError(t, err) 65 require.Equal(t, uint64(2), m.TotalMemoryEstimate()) 66 67 err = m.MeterMemory(0, 3) 68 require.NoError(t, err) 69 require.Equal(t, uint64(2+3), m.TotalMemoryEstimate()) 70 71 err = m.MeterMemory(0, 8) 72 require.Error(t, err) 73 require.True(t, errors.IsMemoryLimitExceededError(err)) 74 require.Equal(t, err.Error(), errors.NewMemoryLimitExceededError(10).Error()) 75 }) 76 77 t.Run("meter computation and memory with weights", func(t *testing.T) { 78 m := meter.NewMeter( 79 meter.DefaultParameters(). 80 WithComputationLimit(100). 81 WithComputationWeights( 82 map[common.ComputationKind]uint64{0: 13 << meter.MeterExecutionInternalPrecisionBytes}). 83 WithMemoryLimit(100). 84 WithMemoryWeights(map[common.MemoryKind]uint64{0: 17}), 85 ) 86 87 err := m.MeterComputation(0, 1) 88 require.NoError(t, err) 89 require.Equal(t, uint64(13), m.TotalComputationUsed()) 90 require.Equal(t, uint(1), m.ComputationIntensities()[0]) 91 92 err = m.MeterMemory(0, 2) 93 require.NoError(t, err) 94 require.Equal(t, uint64(34), m.TotalMemoryEstimate()) 95 require.Equal(t, uint(2), m.MemoryIntensities()[0]) 96 }) 97 98 t.Run("meter computation with weights lower than MeterInternalPrecisionBytes", func(t *testing.T) { 99 m := meter.NewMeter( 100 meter.DefaultParameters(). 101 WithComputationLimit(100). 102 WithComputationWeights(map[common.ComputationKind]uint64{0: 1}). 103 WithMemoryLimit(100). 104 WithMemoryWeights(map[common.MemoryKind]uint64{0: 1}), 105 ) 106 107 internalPrecisionMinusOne := uint((1 << meter.MeterExecutionInternalPrecisionBytes) - 1) 108 109 err := m.MeterComputation(0, internalPrecisionMinusOne) 110 require.NoError(t, err) 111 require.Equal(t, uint64(0), m.TotalComputationUsed()) 112 require.Equal(t, internalPrecisionMinusOne, m.ComputationIntensities()[0]) 113 114 err = m.MeterComputation(0, 1) 115 require.NoError(t, err) 116 require.Equal(t, uint64(1), m.TotalComputationUsed()) 117 require.Equal(t, uint(1<<meter.MeterExecutionInternalPrecisionBytes), m.ComputationIntensities()[0]) 118 }) 119 120 t.Run("check computation capacity", func(t *testing.T) { 121 m := meter.NewMeter( 122 meter.DefaultParameters(). 123 WithComputationLimit(10). 124 WithComputationWeights( 125 map[common.ComputationKind]uint64{0: 1 << meter.MeterExecutionInternalPrecisionBytes}), 126 ) 127 128 hasCapacity := m.ComputationAvailable(0, 1) 129 require.True(t, hasCapacity) 130 131 err := m.MeterComputation(0, 1) 132 require.NoError(t, err) 133 require.Equal(t, uint64(1), m.TotalComputationUsed()) 134 135 require.True(t, m.ComputationAvailable(0, 9)) 136 require.False(t, m.ComputationAvailable(0, 10)) 137 138 // test a type without a weight (default zero) 139 require.True(t, m.ComputationAvailable(1, 10)) 140 }) 141 142 t.Run("merge meters", func(t *testing.T) { 143 compKind := common.ComputationKind(0) 144 m := meter.NewMeter( 145 meter.DefaultParameters(). 146 WithComputationLimit(9). 147 WithComputationWeights( 148 map[common.ComputationKind]uint64{0: 1 << meter.MeterExecutionInternalPrecisionBytes}). 149 WithMemoryLimit(0). 150 WithMemoryWeights(map[common.MemoryKind]uint64{0: 1}), 151 ) 152 153 err := m.MeterComputation(compKind, 1) 154 require.NoError(t, err) 155 156 child1 := meter.NewMeter(m.MeterParameters) 157 err = child1.MeterComputation(compKind, 2) 158 require.NoError(t, err) 159 160 child2 := meter.NewMeter(m.MeterParameters) 161 err = child2.MeterComputation(compKind, 3) 162 require.NoError(t, err) 163 164 child3 := meter.NewMeter(m.MeterParameters) 165 err = child3.MeterComputation(compKind, 4) 166 require.NoError(t, err) 167 168 m.MergeMeter(child1) 169 require.Equal(t, uint64(1+2), m.TotalComputationUsed()) 170 require.Equal(t, uint(1+2), m.ComputationIntensities()[compKind]) 171 172 m.MergeMeter(child2) 173 require.Equal(t, uint64(1+2+3), m.TotalComputationUsed()) 174 require.Equal(t, uint(1+2+3), m.ComputationIntensities()[compKind]) 175 176 // merge hits limit, but is accepted. 177 m.MergeMeter(child3) 178 require.Equal(t, uint64(1+2+3+4), m.TotalComputationUsed()) 179 require.Equal(t, uint(1+2+3+4), m.ComputationIntensities()[compKind]) 180 181 // error after merge (hitting limit) 182 err = m.MeterComputation(compKind, 0) 183 require.Error(t, err) 184 require.True(t, errors.IsComputationLimitExceededError(err)) 185 require.Equal(t, err.Error(), errors.NewComputationLimitExceededError(9).Error()) 186 }) 187 188 t.Run("merge meters - ignore limits", func(t *testing.T) { 189 compKind := common.ComputationKind(0) 190 m := meter.NewMeter( 191 meter.DefaultParameters(). 192 WithComputationLimit(9). 193 WithMemoryLimit(0). 194 WithComputationWeights(map[common.ComputationKind]uint64{0: 1 << meter.MeterExecutionInternalPrecisionBytes}), 195 ) 196 197 err := m.MeterComputation(compKind, 1) 198 require.NoError(t, err) 199 200 child := meter.NewMeter(m.MeterParameters) 201 err = child.MeterComputation(compKind, 1) 202 require.NoError(t, err) 203 204 // hitting limit and ignoring it 205 m.MergeMeter(child) 206 require.Equal(t, uint64(1+1), m.TotalComputationUsed()) 207 require.Equal(t, uint(1+1), m.ComputationIntensities()[compKind]) 208 }) 209 210 t.Run("merge meters - large values - computation", func(t *testing.T) { 211 m := meter.NewMeter( 212 meter.DefaultParameters(). 213 WithComputationLimit(math.MaxUint32). 214 WithComputationWeights(map[common.ComputationKind]uint64{ 215 0: math.MaxUint32 << meter.MeterExecutionInternalPrecisionBytes, 216 }), 217 ) 218 219 err := m.MeterComputation(0, 1) 220 require.NoError(t, err) 221 222 child1 := meter.NewMeter(m.MeterParameters) 223 err = child1.MeterComputation(0, 1) 224 require.NoError(t, err) 225 226 m.MergeMeter(child1) 227 228 err = m.MeterComputation(0, 0) 229 require.True(t, errors.IsComputationLimitExceededError(err)) 230 }) 231 232 t.Run("merge meters - large values - memory", func(t *testing.T) { 233 m := meter.NewMeter( 234 meter.DefaultParameters(). 235 WithMemoryLimit(math.MaxUint32). 236 WithMemoryWeights(map[common.MemoryKind]uint64{ 237 0: math.MaxUint32, 238 }), 239 ) 240 241 err := m.MeterMemory(0, 1) 242 require.NoError(t, err) 243 244 child1 := meter.NewMeter(m.MeterParameters) 245 err = child1.MeterMemory(0, 1) 246 require.NoError(t, err) 247 248 m.MergeMeter(child1) 249 250 err = m.MeterMemory(0, 0) 251 require.Error(t, err) 252 require.True(t, errors.IsMemoryLimitExceededError(err)) 253 require.Equal(t, err.Error(), errors.NewMemoryLimitExceededError(math.MaxUint32).Error()) 254 }) 255 256 t.Run("add intensity - test limits - computation", func(t *testing.T) { 257 var m *meter.Meter 258 reset := func() { 259 m = meter.NewMeter( 260 meter.DefaultParameters(). 261 WithComputationLimit(math.MaxUint32). 262 WithComputationWeights(map[common.ComputationKind]uint64{ 263 0: 0, 264 1: 1, 265 2: 1 << meter.MeterExecutionInternalPrecisionBytes, 266 3: math.MaxUint64, 267 }), 268 ) 269 } 270 271 reset() 272 err := m.MeterComputation(0, 1) 273 require.NoError(t, err) 274 require.Equal(t, uint64(0), m.TotalComputationUsed()) 275 reset() 276 err = m.MeterComputation(0, 1<<meter.MeterExecutionInternalPrecisionBytes) 277 require.NoError(t, err) 278 require.Equal(t, uint64(0), m.TotalComputationUsed()) 279 reset() 280 err = m.MeterComputation(0, math.MaxUint32) 281 require.NoError(t, err) 282 require.Equal(t, uint64(0), m.TotalComputationUsed()) 283 284 reset() 285 err = m.MeterComputation(1, 1) 286 require.NoError(t, err) 287 require.Equal(t, uint64(0), m.TotalComputationUsed()) 288 reset() 289 err = m.MeterComputation(1, 1<<meter.MeterExecutionInternalPrecisionBytes) 290 require.NoError(t, err) 291 require.Equal(t, uint64(1), m.TotalComputationUsed()) 292 reset() 293 err = m.MeterComputation(1, math.MaxUint32) 294 require.NoError(t, err) 295 require.Equal(t, uint64(1<<16-1), m.TotalComputationUsed()) 296 297 reset() 298 err = m.MeterComputation(2, 1) 299 require.NoError(t, err) 300 require.Equal(t, uint64(1), m.TotalComputationUsed()) 301 reset() 302 err = m.MeterComputation(2, 1<<meter.MeterExecutionInternalPrecisionBytes) 303 require.NoError(t, err) 304 require.Equal(t, uint64(1<<16), m.TotalComputationUsed()) 305 reset() 306 err = m.MeterComputation(2, math.MaxUint32) 307 require.NoError(t, err) 308 require.Equal(t, uint64(math.MaxUint32), m.TotalComputationUsed()) 309 310 reset() 311 err = m.MeterComputation(3, 1) 312 require.True(t, errors.IsComputationLimitExceededError(err)) 313 reset() 314 err = m.MeterComputation(3, 1<<meter.MeterExecutionInternalPrecisionBytes) 315 require.True(t, errors.IsComputationLimitExceededError(err)) 316 reset() 317 err = m.MeterComputation(3, math.MaxUint32) 318 require.True(t, errors.IsComputationLimitExceededError(err)) 319 }) 320 321 t.Run("add intensity - test limits - memory", func(t *testing.T) { 322 var m *meter.Meter 323 reset := func() { 324 m = meter.NewMeter( 325 meter.DefaultParameters(). 326 WithMemoryLimit(math.MaxUint32). 327 WithMemoryWeights(map[common.MemoryKind]uint64{ 328 0: 0, 329 1: 1, 330 2: 2, 331 3: math.MaxUint64, 332 }), 333 ) 334 } 335 336 reset() 337 err := m.MeterMemory(0, 1) 338 require.NoError(t, err) 339 require.Equal(t, uint64(0), m.TotalMemoryEstimate()) 340 reset() 341 err = m.MeterMemory(0, 1) 342 require.NoError(t, err) 343 require.Equal(t, uint64(0), m.TotalMemoryEstimate()) 344 reset() 345 err = m.MeterMemory(0, math.MaxUint32) 346 require.NoError(t, err) 347 require.Equal(t, uint64(0), m.TotalMemoryEstimate()) 348 349 reset() 350 err = m.MeterMemory(1, 1) 351 require.NoError(t, err) 352 require.Equal(t, uint64(1), m.TotalMemoryEstimate()) 353 reset() 354 err = m.MeterMemory(1, 1) 355 require.NoError(t, err) 356 require.Equal(t, uint64(1), m.TotalMemoryEstimate()) 357 reset() 358 err = m.MeterMemory(1, math.MaxUint32) 359 require.NoError(t, err) 360 require.Equal(t, uint64(math.MaxUint32), m.TotalMemoryEstimate()) 361 362 reset() 363 err = m.MeterMemory(2, 1) 364 require.NoError(t, err) 365 require.Equal(t, uint64(2), m.TotalMemoryEstimate()) 366 reset() 367 err = m.MeterMemory(2, 1) 368 require.NoError(t, err) 369 require.Equal(t, uint64(2), m.TotalMemoryEstimate()) 370 reset() 371 err = m.MeterMemory(2, math.MaxUint32) 372 require.True(t, errors.IsMemoryLimitExceededError(err)) 373 374 reset() 375 err = m.MeterMemory(3, 1) 376 require.True(t, errors.IsMemoryLimitExceededError(err)) 377 reset() 378 err = m.MeterMemory(3, 1) 379 require.True(t, errors.IsMemoryLimitExceededError(err)) 380 reset() 381 err = m.MeterMemory(3, math.MaxUint32) 382 require.True(t, errors.IsMemoryLimitExceededError(err)) 383 }) 384 } 385 386 func TestMemoryWeights(t *testing.T) { 387 for kind := common.MemoryKindUnknown + 1; kind < common.MemoryKindLast; kind++ { 388 weight, ok := meter.DefaultMemoryWeights[kind] 389 if !assert.True(t, ok, fmt.Sprintf("missing weight for memory kind '%s'", kind.String())) { 390 continue 391 } 392 assert.Greater( 393 t, 394 weight, 395 uint64(0), 396 fmt.Sprintf( 397 "weight for memory kind '%s' is not a positive integer: %d", 398 kind.String(), 399 weight, 400 ), 401 ) 402 } 403 } 404 405 func TestStorageLimits(t *testing.T) { 406 t.Run("metering storage read - within limit", func(t *testing.T) { 407 meter1 := meter.NewMeter( 408 meter.DefaultParameters(), 409 ) 410 411 key1 := flow.NewRegisterID(flow.EmptyAddress, "1") 412 val1 := []byte{0x1, 0x2, 0x3} 413 size1 := meter.GetStorageKeyValueSizeForTesting(key1, val1) 414 415 // first read of key1 416 err := meter1.MeterStorageRead(key1, val1, false) 417 require.NoError(t, err) 418 require.Equal(t, meter1.TotalBytesReadFromStorage(), size1) 419 420 // second read of key1 421 err = meter1.MeterStorageRead(key1, val1, false) 422 require.NoError(t, err) 423 require.Equal(t, meter1.TotalBytesReadFromStorage(), size1) 424 425 // first read of key2 426 key2 := flow.NewRegisterID(flow.EmptyAddress, "2") 427 val2 := []byte{0x3, 0x2, 0x1} 428 size2 := meter.GetStorageKeyValueSizeForTesting(key2, val2) 429 430 err = meter1.MeterStorageRead(key2, val2, false) 431 require.NoError(t, err) 432 require.Equal(t, meter1.TotalBytesReadFromStorage(), size1+size2) 433 }) 434 435 t.Run("metering storage written - within limit", func(t *testing.T) { 436 meter1 := meter.NewMeter( 437 meter.DefaultParameters(), 438 ) 439 440 key1 := flow.NewRegisterID(flow.EmptyAddress, "1") 441 val1 := []byte{0x1, 0x2, 0x3} 442 val2 := []byte{0x1, 0x2, 0x3, 0x4} 443 444 // first write of key1 445 err := meter1.MeterStorageWrite(key1, val1, false) 446 require.NoError(t, err) 447 require.Equal(t, meter1.TotalBytesWrittenToStorage(), meter.GetStorageKeyValueSizeForTesting(key1, val1)) 448 449 // second write of key1 with val2 450 err = meter1.MeterStorageWrite(key1, val2, false) 451 require.NoError(t, err) 452 require.Equal(t, meter1.TotalBytesWrittenToStorage(), meter.GetStorageKeyValueSizeForTesting(key1, val2)) 453 454 // first write of key2 455 key2 := flow.NewRegisterID(flow.EmptyAddress, "2") 456 err = meter1.MeterStorageWrite(key2, val2, false) 457 require.NoError(t, err) 458 require.Equal(t, meter1.TotalBytesWrittenToStorage(), 459 meter.GetStorageKeyValueSizeForTesting(key1, val2)+meter.GetStorageKeyValueSizeForTesting(key2, val2)) 460 }) 461 462 t.Run("metering storage read - exceeding limit - not enforced", func(t *testing.T) { 463 meter1 := meter.NewMeter( 464 meter.DefaultParameters().WithStorageInteractionLimit(1), 465 ) 466 467 key1 := flow.NewRegisterID(flow.EmptyAddress, "1") 468 val1 := []byte{0x1, 0x2, 0x3} 469 470 err := meter1.MeterStorageRead(key1, val1, false /* not enforced */) 471 require.NoError(t, err) 472 require.Equal(t, meter1.TotalBytesReadFromStorage(), meter.GetStorageKeyValueSizeForTesting(key1, val1)) 473 }) 474 475 t.Run("metering storage read - exceeding limit - enforced", func(t *testing.T) { 476 testLimit := uint64(1) 477 meter1 := meter.NewMeter( 478 meter.DefaultParameters().WithStorageInteractionLimit(testLimit), 479 ) 480 481 key1 := flow.NewRegisterID(flow.EmptyAddress, "1") 482 val1 := []byte{0x1, 0x2, 0x3} 483 484 err := meter1.MeterStorageRead(key1, val1, true /* enforced */) 485 486 ledgerInteractionLimitExceedError := errors.NewLedgerInteractionLimitExceededError( 487 meter.GetStorageKeyValueSizeForTesting(key1, val1), 488 testLimit, 489 ) 490 require.ErrorAs(t, err, &ledgerInteractionLimitExceedError) 491 }) 492 493 t.Run("metering storage written - exceeding limit - not enforced", func(t *testing.T) { 494 testLimit := uint64(1) 495 meter1 := meter.NewMeter( 496 meter.DefaultParameters().WithStorageInteractionLimit(testLimit), 497 ) 498 499 key1 := flow.NewRegisterID(flow.EmptyAddress, "1") 500 val1 := []byte{0x1, 0x2, 0x3} 501 502 err := meter1.MeterStorageWrite(key1, val1, false /* not enforced */) 503 require.NoError(t, err) 504 }) 505 506 t.Run("metering storage written - exceeding limit - enforced", func(t *testing.T) { 507 testLimit := uint64(1) 508 meter1 := meter.NewMeter( 509 meter.DefaultParameters().WithStorageInteractionLimit(testLimit), 510 ) 511 512 key1 := flow.NewRegisterID(flow.EmptyAddress, "1") 513 val1 := []byte{0x1, 0x2, 0x3} 514 515 err := meter1.MeterStorageWrite(key1, val1, true /* enforced */) 516 517 ledgerInteractionLimitExceedError := errors.NewLedgerInteractionLimitExceededError( 518 meter.GetStorageKeyValueSizeForTesting(key1, val1), 519 testLimit, 520 ) 521 require.ErrorAs(t, err, &ledgerInteractionLimitExceedError) 522 }) 523 524 t.Run("metering storage read and written - within limit", func(t *testing.T) { 525 meter1 := meter.NewMeter( 526 meter.DefaultParameters(), 527 ) 528 529 key1 := flow.NewRegisterID(flow.EmptyAddress, "1") 530 key2 := flow.NewRegisterID(flow.EmptyAddress, "2") 531 val1 := []byte{0x1, 0x2, 0x3} 532 val2 := []byte{0x1, 0x2, 0x3, 0x4} 533 size1 := meter.GetStorageKeyValueSizeForTesting(key1, val1) 534 size2 := meter.GetStorageKeyValueSizeForTesting(key2, val2) 535 536 // read of key1 537 err := meter1.MeterStorageRead(key1, val1, false) 538 require.NoError(t, err) 539 require.Equal(t, meter1.TotalBytesReadFromStorage(), size1) 540 require.Equal(t, meter1.TotalBytesOfStorageInteractions(), size1) 541 542 // write of key2 543 err = meter1.MeterStorageWrite(key2, val2, false) 544 require.NoError(t, err) 545 require.Equal(t, meter1.TotalBytesWrittenToStorage(), size2) 546 require.Equal(t, meter1.TotalBytesOfStorageInteractions(), size1+size2) 547 }) 548 549 t.Run("metering storage read and written - exceeding limit - not enforced", func(t *testing.T) { 550 key1 := flow.NewRegisterID(flow.EmptyAddress, "1") 551 key2 := flow.NewRegisterID(flow.EmptyAddress, "2") 552 val1 := []byte{0x1, 0x2, 0x3} 553 val2 := []byte{0x1, 0x2, 0x3, 0x4} 554 size1 := meter.GetStorageKeyValueSizeForTesting(key1, val1) 555 size2 := meter.GetStorageKeyValueSizeForTesting(key2, val2) 556 557 meter1 := meter.NewMeter( 558 meter.DefaultParameters().WithStorageInteractionLimit(size1 + size2 - 1), 559 ) 560 561 // read of key1 562 err := meter1.MeterStorageRead(key1, val1, false) 563 require.NoError(t, err) 564 require.Equal(t, meter1.TotalBytesReadFromStorage(), size1) 565 require.Equal(t, meter1.TotalBytesOfStorageInteractions(), size1) 566 567 // write of key2 568 err = meter1.MeterStorageWrite(key2, val2, false) 569 require.NoError(t, err) 570 require.Equal(t, meter1.TotalBytesWrittenToStorage(), size2) 571 require.Equal(t, meter1.TotalBytesOfStorageInteractions(), size1+size2) 572 }) 573 574 t.Run("metering storage read and written - exceeding limit - enforced", func(t *testing.T) { 575 key1 := flow.NewRegisterID(flow.EmptyAddress, "1") 576 key2 := flow.NewRegisterID(flow.EmptyAddress, "2") 577 val1 := []byte{0x1, 0x2, 0x3} 578 val2 := []byte{0x1, 0x2, 0x3, 0x4} 579 size1 := meter.GetStorageKeyValueSizeForTesting(key1, val1) 580 size2 := meter.GetStorageKeyValueSizeForTesting(key2, val2) 581 testLimit := size1 + size2 - 1 582 meter1 := meter.NewMeter( 583 meter.DefaultParameters().WithStorageInteractionLimit(testLimit), 584 ) 585 586 // read of key1 587 err := meter1.MeterStorageRead(key1, val1, true) 588 require.NoError(t, err) 589 require.Equal(t, meter1.TotalBytesReadFromStorage(), size1) 590 require.Equal(t, meter1.TotalBytesOfStorageInteractions(), size1) 591 592 // write of key2 593 err = meter1.MeterStorageWrite(key2, val2, true) 594 ledgerInteractionLimitExceedError := errors.NewLedgerInteractionLimitExceededError( 595 size1+size2, 596 testLimit, 597 ) 598 require.ErrorAs(t, err, &ledgerInteractionLimitExceedError) 599 }) 600 601 t.Run("merge storage metering", func(t *testing.T) { 602 // meter 1 603 meter1 := meter.NewMeter( 604 meter.DefaultParameters(), 605 ) 606 readKey1 := flow.NewRegisterID(flow.EmptyAddress, "r1") 607 readVal1 := []byte{0x1, 0x2, 0x3} 608 readSize1 := meter.GetStorageKeyValueSizeForTesting(readKey1, readVal1) 609 err := meter1.MeterStorageRead(readKey1, readVal1, false) 610 require.NoError(t, err) 611 612 writeKey1 := flow.NewRegisterID(flow.EmptyAddress, "w1") 613 writeVal1 := []byte{0x1, 0x2, 0x3, 0x4} 614 writeSize1 := meter.GetStorageKeyValueSizeForTesting(writeKey1, writeVal1) 615 err = meter1.MeterStorageWrite(writeKey1, writeVal1, false) 616 require.NoError(t, err) 617 618 // meter 2 619 meter2 := meter.NewMeter( 620 meter.DefaultParameters(), 621 ) 622 623 writeKey2 := flow.NewRegisterID(flow.EmptyAddress, "w2") 624 writeVal2 := []byte{0x1, 0x2, 0x3, 0x4, 0x5} 625 writeSize2 := meter.GetStorageKeyValueSizeForTesting(writeKey2, writeVal2) 626 627 err = meter1.MeterStorageRead(readKey1, readVal1, false) 628 require.NoError(t, err) 629 630 err = meter1.MeterStorageWrite(writeKey1, writeVal1, false) 631 require.NoError(t, err) 632 633 // read the same key value as meter1 634 err = meter2.MeterStorageRead(readKey1, readVal1, false) 635 require.NoError(t, err) 636 637 err = meter2.MeterStorageWrite(writeKey2, writeVal2, false) 638 require.NoError(t, err) 639 640 // merge 641 meter1.MergeMeter(meter2) 642 643 require.Equal(t, meter1.TotalBytesOfStorageInteractions(), readSize1+writeSize1+writeSize2) 644 require.Equal(t, meter1.TotalBytesReadFromStorage(), readSize1) 645 require.Equal(t, meter1.TotalBytesWrittenToStorage(), writeSize1+writeSize2) 646 647 reads, writes := meter1.GetStorageRWSizeMapForTesting() 648 readKey1Val, ok := reads[readKey1] 649 require.True(t, ok) 650 require.Equal(t, readKey1Val, readSize1) // meter merge only takes child values for rw bookkeeping 651 652 writeKey1Val, ok := writes[writeKey1] 653 require.True(t, ok) 654 require.Equal(t, writeKey1Val, writeSize1) 655 656 writeKey2Val, ok := writes[writeKey2] 657 require.True(t, ok) 658 require.Equal(t, writeKey2Val, writeSize2) 659 }) 660 } 661 662 func TestEventLimits(t *testing.T) { 663 t.Run("metering event emit - within limit", func(t *testing.T) { 664 meter1 := meter.NewMeter( 665 meter.DefaultParameters(), 666 ) 667 668 testSize1, testSize2 := uint64(123), uint64(234) 669 670 err := meter1.MeterEmittedEvent(testSize1) 671 require.NoError(t, err) 672 require.Equal(t, testSize1, meter1.TotalEmittedEventBytes()) 673 674 err = meter1.MeterEmittedEvent(testSize2) 675 require.NoError(t, err) 676 require.Equal(t, testSize1+testSize2, meter1.TotalEmittedEventBytes()) 677 }) 678 679 t.Run("metering event emit - exceeding limit", func(t *testing.T) { 680 testSize1, testSize2 := uint64(123), uint64(234) 681 testEventLimit := testSize1 + testSize2 - 1 // make it fail at 2nd meter 682 meter1 := meter.NewMeter( 683 meter.DefaultParameters().WithEventEmitByteLimit(testEventLimit), 684 ) 685 686 err := meter1.MeterEmittedEvent(testSize1) 687 require.NoError(t, err) 688 require.Equal(t, testSize1, meter1.TotalEmittedEventBytes()) 689 690 err = meter1.MeterEmittedEvent(testSize2) 691 eventLimitExceededError := errors.NewEventLimitExceededError( 692 testSize1+testSize2, 693 testEventLimit) 694 require.ErrorAs(t, err, &eventLimitExceededError) 695 }) 696 697 t.Run("merge event metering", func(t *testing.T) { 698 // meter 1 699 meter1 := meter.NewMeter( 700 meter.DefaultParameters(), 701 ) 702 testSize1 := uint64(123) 703 err := meter1.MeterEmittedEvent(testSize1) 704 require.NoError(t, err) 705 706 // meter 2 707 meter2 := meter.NewMeter( 708 meter.DefaultParameters(), 709 ) 710 testSize2 := uint64(234) 711 err = meter2.MeterEmittedEvent(testSize2) 712 require.NoError(t, err) 713 714 // merge 715 meter1.MergeMeter(meter2) 716 require.Equal(t, testSize1+testSize2, meter1.TotalEmittedEventBytes()) 717 }) 718 }