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