diff --git a/cmd/util/ledger/util/nop_meter.go b/cmd/util/ledger/util/nop_meter.go index 4d17d66c35e..a2b37b8f2d5 100644 --- a/cmd/util/ledger/util/nop_meter.go +++ b/cmd/util/ledger/util/nop_meter.go @@ -14,20 +14,12 @@ type NopMeter struct{} func (n NopMeter) RunWithMeteringDisabled(f func()) {} -func (n NopMeter) ComputationAvailable(_ common.ComputationUsage) bool { - return false -} - func (n NopMeter) MeterComputation(_ common.ComputationUsage) error { return nil } -func (n NopMeter) ComputationUsed() (uint64, error) { - return 0, nil -} - -func (n NopMeter) ComputationIntensities() meter.MeteredComputationIntensities { - return meter.MeteredComputationIntensities{} +func (n NopMeter) MeteringResult() (meter.MeteringResult, error) { + return meter.MeteringResult{}, nil } func (n NopMeter) ComputationRemaining(_ common.ComputationKind) uint64 { @@ -38,18 +30,10 @@ func (n NopMeter) MeterMemory(_ common.MemoryUsage) error { return nil } -func (n NopMeter) MemoryUsed() (uint64, error) { - return 0, nil -} - func (n NopMeter) MeterEmittedEvent(_ uint64) error { return nil } -func (n NopMeter) TotalEmittedEventBytes() uint64 { - return 0 -} - func (n NopMeter) InteractionUsed() (uint64, error) { return 0, nil } diff --git a/engine/execution/computation/computer/transaction_coordinator_test.go b/engine/execution/computation/computer/transaction_coordinator_test.go index 1cca10017d3..3111e512c04 100644 --- a/engine/execution/computation/computer/transaction_coordinator_test.go +++ b/engine/execution/computation/computer/transaction_coordinator_test.go @@ -10,6 +10,7 @@ import ( "github.com/onflow/flow-go/fvm" "github.com/onflow/flow-go/fvm/inspection" + "github.com/onflow/flow-go/fvm/meter" "github.com/onflow/flow-go/fvm/storage" "github.com/onflow/flow-go/fvm/storage/logical" "github.com/onflow/flow-go/fvm/storage/snapshot" @@ -77,7 +78,7 @@ func (testCoordinatorExecutor) Execute() error { func (executor testCoordinatorExecutor) Output() fvm.ProcedureOutput { return fvm.ProcedureOutput{ - ComputationUsed: uint64(executor.executionTime), + MeteringResult: meter.MeteringResult{ComputationUsed: uint64(executor.executionTime)}, } } diff --git a/fvm/environment/event_emitter.go b/fvm/environment/event_emitter.go index 7457b6041ad..73468c39aab 100644 --- a/fvm/environment/event_emitter.go +++ b/fvm/environment/event_emitter.go @@ -307,10 +307,6 @@ func (collection *EventCollection) AppendServiceEvent( return collection.meter.MeterEmittedEvent(size) } -func (collection *EventCollection) TotalByteSize() uint64 { - return collection.meter.TotalEmittedEventBytes() -} - func (collection *EventCollection) TotalEventCounter() uint32 { return collection.eventCounter } diff --git a/fvm/environment/meter.go b/fvm/environment/meter.go index 14b8fcbc0b1..a3d3e3d20d6 100644 --- a/fvm/environment/meter.go +++ b/fvm/environment/meter.go @@ -107,71 +107,34 @@ var MainnetExecutionEffortWeights = meter.ExecutionEffortWeights{ type Meter interface { common.Gauge - ComputationUsed() (uint64, error) - MemoryUsed() (uint64, error) + // MeteringResult returns the metering totals accumulated so far. + // + // No error returns are expected during normal operation. + MeteringResult() (meter.MeteringResult, error) - ComputationIntensities() meter.MeteredComputationIntensities - ComputationAvailable(common.ComputationUsage) bool ComputationRemaining(kind common.ComputationKind) uint64 MeterEmittedEvent(byteSize uint64) error - TotalEmittedEventBytes() uint64 RunWithMeteringDisabled(f func()) } type meterImpl struct { - txnState state.NestedTransactionPreparer + state.NestedTransactionPreparer } func NewMeter(txnState state.NestedTransactionPreparer) Meter { return &meterImpl{ - txnState: txnState, + NestedTransactionPreparer: txnState, } } -func (meter *meterImpl) MeterComputation(usage common.ComputationUsage) error { - return meter.txnState.MeterComputation(usage) -} - -func (meter *meterImpl) ComputationIntensities() meter.MeteredComputationIntensities { - return meter.txnState.ComputationIntensities() -} - -func (meter *meterImpl) ComputationAvailable(usage common.ComputationUsage) bool { - return meter.txnState.ComputationAvailable(usage) -} - -func (meter *meterImpl) ComputationRemaining(kind common.ComputationKind) uint64 { - return meter.txnState.ComputationRemaining(kind) -} - -func (meter *meterImpl) ComputationUsed() (uint64, error) { - return meter.txnState.TotalComputationUsed(), nil -} - -func (meter *meterImpl) MeterMemory(usage common.MemoryUsage) error { - return meter.txnState.MeterMemory(usage) -} - -func (meter *meterImpl) MemoryUsed() (uint64, error) { - return meter.txnState.TotalMemoryEstimate(), nil -} - -func (meter *meterImpl) InteractionUsed() (uint64, error) { - return meter.txnState.InteractionUsed(), nil -} - -func (meter *meterImpl) MeterEmittedEvent(byteSize uint64) error { - return meter.txnState.MeterEmittedEvent(byteSize) -} - -func (meter *meterImpl) TotalEmittedEventBytes() uint64 { - return meter.txnState.TotalEmittedEventBytes() -} - -func (meter *meterImpl) RunWithMeteringDisabled(f func()) { - meter.txnState.RunWithMeteringDisabled(f) +func (m *meterImpl) MeteringResult() (meter.MeteringResult, error) { + return meter.MeteringResult{ + ComputationUsed: m.TotalComputationUsed(), + MemoryEstimate: m.TotalMemoryEstimate(), + ComputationIntensities: m.ComputationIntensities(), + }, nil } type cancellableMeter struct { @@ -186,7 +149,7 @@ func NewCancellableMeter( ) Meter { return &cancellableMeter{ meterImpl: meterImpl{ - txnState: txnState, + NestedTransactionPreparer: txnState, }, ctx: ctx, } diff --git a/fvm/environment/mock/environment.go b/fvm/environment/mock/environment.go index 510bcedb796..b441061e15d 100644 --- a/fvm/environment/mock/environment.go +++ b/fvm/environment/mock/environment.go @@ -808,103 +808,6 @@ func (_c *Environment_CommitBlockProposal_Call) RunAndReturn(run func(blockPropo return _c } -// ComputationAvailable provides a mock function for the type Environment -func (_mock *Environment) ComputationAvailable(computationUsage common0.ComputationUsage) bool { - ret := _mock.Called(computationUsage) - - if len(ret) == 0 { - panic("no return value specified for ComputationAvailable") - } - - var r0 bool - if returnFunc, ok := ret.Get(0).(func(common0.ComputationUsage) bool); ok { - r0 = returnFunc(computationUsage) - } else { - r0 = ret.Get(0).(bool) - } - return r0 -} - -// Environment_ComputationAvailable_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'ComputationAvailable' -type Environment_ComputationAvailable_Call struct { - *mock.Call -} - -// ComputationAvailable is a helper method to define mock.On call -// - computationUsage common0.ComputationUsage -func (_e *Environment_Expecter) ComputationAvailable(computationUsage interface{}) *Environment_ComputationAvailable_Call { - return &Environment_ComputationAvailable_Call{Call: _e.mock.On("ComputationAvailable", computationUsage)} -} - -func (_c *Environment_ComputationAvailable_Call) Run(run func(computationUsage common0.ComputationUsage)) *Environment_ComputationAvailable_Call { - _c.Call.Run(func(args mock.Arguments) { - var arg0 common0.ComputationUsage - if args[0] != nil { - arg0 = args[0].(common0.ComputationUsage) - } - run( - arg0, - ) - }) - return _c -} - -func (_c *Environment_ComputationAvailable_Call) Return(b bool) *Environment_ComputationAvailable_Call { - _c.Call.Return(b) - return _c -} - -func (_c *Environment_ComputationAvailable_Call) RunAndReturn(run func(computationUsage common0.ComputationUsage) bool) *Environment_ComputationAvailable_Call { - _c.Call.Return(run) - return _c -} - -// ComputationIntensities provides a mock function for the type Environment -func (_mock *Environment) ComputationIntensities() meter.MeteredComputationIntensities { - ret := _mock.Called() - - if len(ret) == 0 { - panic("no return value specified for ComputationIntensities") - } - - var r0 meter.MeteredComputationIntensities - if returnFunc, ok := ret.Get(0).(func() meter.MeteredComputationIntensities); ok { - r0 = returnFunc() - } else { - if ret.Get(0) != nil { - r0 = ret.Get(0).(meter.MeteredComputationIntensities) - } - } - return r0 -} - -// Environment_ComputationIntensities_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'ComputationIntensities' -type Environment_ComputationIntensities_Call struct { - *mock.Call -} - -// ComputationIntensities is a helper method to define mock.On call -func (_e *Environment_Expecter) ComputationIntensities() *Environment_ComputationIntensities_Call { - return &Environment_ComputationIntensities_Call{Call: _e.mock.On("ComputationIntensities")} -} - -func (_c *Environment_ComputationIntensities_Call) Run(run func()) *Environment_ComputationIntensities_Call { - _c.Call.Run(func(args mock.Arguments) { - run() - }) - return _c -} - -func (_c *Environment_ComputationIntensities_Call) Return(meteredComputationIntensities meter.MeteredComputationIntensities) *Environment_ComputationIntensities_Call { - _c.Call.Return(meteredComputationIntensities) - return _c -} - -func (_c *Environment_ComputationIntensities_Call) RunAndReturn(run func() meter.MeteredComputationIntensities) *Environment_ComputationIntensities_Call { - _c.Call.Return(run) - return _c -} - // ComputationRemaining provides a mock function for the type Environment func (_mock *Environment) ComputationRemaining(kind common0.ComputationKind) uint64 { ret := _mock.Called(kind) @@ -956,59 +859,6 @@ func (_c *Environment_ComputationRemaining_Call) RunAndReturn(run func(kind comm return _c } -// ComputationUsed provides a mock function for the type Environment -func (_mock *Environment) ComputationUsed() (uint64, error) { - ret := _mock.Called() - - if len(ret) == 0 { - panic("no return value specified for ComputationUsed") - } - - var r0 uint64 - var r1 error - if returnFunc, ok := ret.Get(0).(func() (uint64, error)); ok { - return returnFunc() - } - if returnFunc, ok := ret.Get(0).(func() uint64); ok { - r0 = returnFunc() - } else { - r0 = ret.Get(0).(uint64) - } - if returnFunc, ok := ret.Get(1).(func() error); ok { - r1 = returnFunc() - } else { - r1 = ret.Error(1) - } - return r0, r1 -} - -// Environment_ComputationUsed_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'ComputationUsed' -type Environment_ComputationUsed_Call struct { - *mock.Call -} - -// ComputationUsed is a helper method to define mock.On call -func (_e *Environment_Expecter) ComputationUsed() *Environment_ComputationUsed_Call { - return &Environment_ComputationUsed_Call{Call: _e.mock.On("ComputationUsed")} -} - -func (_c *Environment_ComputationUsed_Call) Run(run func()) *Environment_ComputationUsed_Call { - _c.Call.Run(func(args mock.Arguments) { - run() - }) - return _c -} - -func (_c *Environment_ComputationUsed_Call) Return(v uint64, err error) *Environment_ComputationUsed_Call { - _c.Call.Return(v, err) - return _c -} - -func (_c *Environment_ComputationUsed_Call) RunAndReturn(run func() (uint64, error)) *Environment_ComputationUsed_Call { - _c.Call.Return(run) - return _c -} - // ConvertedServiceEvents provides a mock function for the type Environment func (_mock *Environment) ConvertedServiceEvents() flow.ServiceEventList { ret := _mock.Called() @@ -3030,59 +2880,6 @@ func (_c *Environment_Logs_Call) RunAndReturn(run func() []string) *Environment_ return _c } -// MemoryUsed provides a mock function for the type Environment -func (_mock *Environment) MemoryUsed() (uint64, error) { - ret := _mock.Called() - - if len(ret) == 0 { - panic("no return value specified for MemoryUsed") - } - - var r0 uint64 - var r1 error - if returnFunc, ok := ret.Get(0).(func() (uint64, error)); ok { - return returnFunc() - } - if returnFunc, ok := ret.Get(0).(func() uint64); ok { - r0 = returnFunc() - } else { - r0 = ret.Get(0).(uint64) - } - if returnFunc, ok := ret.Get(1).(func() error); ok { - r1 = returnFunc() - } else { - r1 = ret.Error(1) - } - return r0, r1 -} - -// Environment_MemoryUsed_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'MemoryUsed' -type Environment_MemoryUsed_Call struct { - *mock.Call -} - -// MemoryUsed is a helper method to define mock.On call -func (_e *Environment_Expecter) MemoryUsed() *Environment_MemoryUsed_Call { - return &Environment_MemoryUsed_Call{Call: _e.mock.On("MemoryUsed")} -} - -func (_c *Environment_MemoryUsed_Call) Run(run func()) *Environment_MemoryUsed_Call { - _c.Call.Run(func(args mock.Arguments) { - run() - }) - return _c -} - -func (_c *Environment_MemoryUsed_Call) Return(v uint64, err error) *Environment_MemoryUsed_Call { - _c.Call.Return(v, err) - return _c -} - -func (_c *Environment_MemoryUsed_Call) RunAndReturn(run func() (uint64, error)) *Environment_MemoryUsed_Call { - _c.Call.Return(run) - return _c -} - // MeterComputation provides a mock function for the type Environment func (_mock *Environment) MeterComputation(usage common0.ComputationUsage) error { ret := _mock.Called(usage) @@ -3236,6 +3033,59 @@ func (_c *Environment_MeterMemory_Call) RunAndReturn(run func(usage common0.Memo return _c } +// MeteringResult provides a mock function for the type Environment +func (_mock *Environment) MeteringResult() (meter.MeteringResult, error) { + ret := _mock.Called() + + if len(ret) == 0 { + panic("no return value specified for MeteringResult") + } + + var r0 meter.MeteringResult + var r1 error + if returnFunc, ok := ret.Get(0).(func() (meter.MeteringResult, error)); ok { + return returnFunc() + } + if returnFunc, ok := ret.Get(0).(func() meter.MeteringResult); ok { + r0 = returnFunc() + } else { + r0 = ret.Get(0).(meter.MeteringResult) + } + if returnFunc, ok := ret.Get(1).(func() error); ok { + r1 = returnFunc() + } else { + r1 = ret.Error(1) + } + return r0, r1 +} + +// Environment_MeteringResult_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'MeteringResult' +type Environment_MeteringResult_Call struct { + *mock.Call +} + +// MeteringResult is a helper method to define mock.On call +func (_e *Environment_Expecter) MeteringResult() *Environment_MeteringResult_Call { + return &Environment_MeteringResult_Call{Call: _e.mock.On("MeteringResult")} +} + +func (_c *Environment_MeteringResult_Call) Run(run func()) *Environment_MeteringResult_Call { + _c.Call.Run(func(args mock.Arguments) { + run() + }) + return _c +} + +func (_c *Environment_MeteringResult_Call) Return(meteringResult meter.MeteringResult, err error) *Environment_MeteringResult_Call { + _c.Call.Return(meteringResult, err) + return _c +} + +func (_c *Environment_MeteringResult_Call) RunAndReturn(run func() (meter.MeteringResult, error)) *Environment_MeteringResult_Call { + _c.Call.Return(run) + return _c +} + // MinimumRequiredVersion provides a mock function for the type Environment func (_mock *Environment) MinimumRequiredVersion() (string, error) { ret := _mock.Called() @@ -4409,50 +4259,6 @@ func (_c *Environment_StartChildSpan_Call) RunAndReturn(run func(name trace.Span return _c } -// TotalEmittedEventBytes provides a mock function for the type Environment -func (_mock *Environment) TotalEmittedEventBytes() uint64 { - ret := _mock.Called() - - if len(ret) == 0 { - panic("no return value specified for TotalEmittedEventBytes") - } - - var r0 uint64 - if returnFunc, ok := ret.Get(0).(func() uint64); ok { - r0 = returnFunc() - } else { - r0 = ret.Get(0).(uint64) - } - return r0 -} - -// Environment_TotalEmittedEventBytes_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'TotalEmittedEventBytes' -type Environment_TotalEmittedEventBytes_Call struct { - *mock.Call -} - -// TotalEmittedEventBytes is a helper method to define mock.On call -func (_e *Environment_Expecter) TotalEmittedEventBytes() *Environment_TotalEmittedEventBytes_Call { - return &Environment_TotalEmittedEventBytes_Call{Call: _e.mock.On("TotalEmittedEventBytes")} -} - -func (_c *Environment_TotalEmittedEventBytes_Call) Run(run func()) *Environment_TotalEmittedEventBytes_Call { - _c.Call.Run(func(args mock.Arguments) { - run() - }) - return _c -} - -func (_c *Environment_TotalEmittedEventBytes_Call) Return(v uint64) *Environment_TotalEmittedEventBytes_Call { - _c.Call.Return(v) - return _c -} - -func (_c *Environment_TotalEmittedEventBytes_Call) RunAndReturn(run func() uint64) *Environment_TotalEmittedEventBytes_Call { - _c.Call.Return(run) - return _c -} - // TransactionFeesEnabled provides a mock function for the type Environment func (_mock *Environment) TransactionFeesEnabled() bool { ret := _mock.Called() diff --git a/fvm/environment/mock/meter.go b/fvm/environment/mock/meter.go index e450f76270f..c3e3c115fe2 100644 --- a/fvm/environment/mock/meter.go +++ b/fvm/environment/mock/meter.go @@ -37,103 +37,6 @@ func (_m *Meter) EXPECT() *Meter_Expecter { return &Meter_Expecter{mock: &_m.Mock} } -// ComputationAvailable provides a mock function for the type Meter -func (_mock *Meter) ComputationAvailable(computationUsage common.ComputationUsage) bool { - ret := _mock.Called(computationUsage) - - if len(ret) == 0 { - panic("no return value specified for ComputationAvailable") - } - - var r0 bool - if returnFunc, ok := ret.Get(0).(func(common.ComputationUsage) bool); ok { - r0 = returnFunc(computationUsage) - } else { - r0 = ret.Get(0).(bool) - } - return r0 -} - -// Meter_ComputationAvailable_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'ComputationAvailable' -type Meter_ComputationAvailable_Call struct { - *mock.Call -} - -// ComputationAvailable is a helper method to define mock.On call -// - computationUsage common.ComputationUsage -func (_e *Meter_Expecter) ComputationAvailable(computationUsage interface{}) *Meter_ComputationAvailable_Call { - return &Meter_ComputationAvailable_Call{Call: _e.mock.On("ComputationAvailable", computationUsage)} -} - -func (_c *Meter_ComputationAvailable_Call) Run(run func(computationUsage common.ComputationUsage)) *Meter_ComputationAvailable_Call { - _c.Call.Run(func(args mock.Arguments) { - var arg0 common.ComputationUsage - if args[0] != nil { - arg0 = args[0].(common.ComputationUsage) - } - run( - arg0, - ) - }) - return _c -} - -func (_c *Meter_ComputationAvailable_Call) Return(b bool) *Meter_ComputationAvailable_Call { - _c.Call.Return(b) - return _c -} - -func (_c *Meter_ComputationAvailable_Call) RunAndReturn(run func(computationUsage common.ComputationUsage) bool) *Meter_ComputationAvailable_Call { - _c.Call.Return(run) - return _c -} - -// ComputationIntensities provides a mock function for the type Meter -func (_mock *Meter) ComputationIntensities() meter.MeteredComputationIntensities { - ret := _mock.Called() - - if len(ret) == 0 { - panic("no return value specified for ComputationIntensities") - } - - var r0 meter.MeteredComputationIntensities - if returnFunc, ok := ret.Get(0).(func() meter.MeteredComputationIntensities); ok { - r0 = returnFunc() - } else { - if ret.Get(0) != nil { - r0 = ret.Get(0).(meter.MeteredComputationIntensities) - } - } - return r0 -} - -// Meter_ComputationIntensities_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'ComputationIntensities' -type Meter_ComputationIntensities_Call struct { - *mock.Call -} - -// ComputationIntensities is a helper method to define mock.On call -func (_e *Meter_Expecter) ComputationIntensities() *Meter_ComputationIntensities_Call { - return &Meter_ComputationIntensities_Call{Call: _e.mock.On("ComputationIntensities")} -} - -func (_c *Meter_ComputationIntensities_Call) Run(run func()) *Meter_ComputationIntensities_Call { - _c.Call.Run(func(args mock.Arguments) { - run() - }) - return _c -} - -func (_c *Meter_ComputationIntensities_Call) Return(meteredComputationIntensities meter.MeteredComputationIntensities) *Meter_ComputationIntensities_Call { - _c.Call.Return(meteredComputationIntensities) - return _c -} - -func (_c *Meter_ComputationIntensities_Call) RunAndReturn(run func() meter.MeteredComputationIntensities) *Meter_ComputationIntensities_Call { - _c.Call.Return(run) - return _c -} - // ComputationRemaining provides a mock function for the type Meter func (_mock *Meter) ComputationRemaining(kind common.ComputationKind) uint64 { ret := _mock.Called(kind) @@ -185,112 +88,6 @@ func (_c *Meter_ComputationRemaining_Call) RunAndReturn(run func(kind common.Com return _c } -// ComputationUsed provides a mock function for the type Meter -func (_mock *Meter) ComputationUsed() (uint64, error) { - ret := _mock.Called() - - if len(ret) == 0 { - panic("no return value specified for ComputationUsed") - } - - var r0 uint64 - var r1 error - if returnFunc, ok := ret.Get(0).(func() (uint64, error)); ok { - return returnFunc() - } - if returnFunc, ok := ret.Get(0).(func() uint64); ok { - r0 = returnFunc() - } else { - r0 = ret.Get(0).(uint64) - } - if returnFunc, ok := ret.Get(1).(func() error); ok { - r1 = returnFunc() - } else { - r1 = ret.Error(1) - } - return r0, r1 -} - -// Meter_ComputationUsed_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'ComputationUsed' -type Meter_ComputationUsed_Call struct { - *mock.Call -} - -// ComputationUsed is a helper method to define mock.On call -func (_e *Meter_Expecter) ComputationUsed() *Meter_ComputationUsed_Call { - return &Meter_ComputationUsed_Call{Call: _e.mock.On("ComputationUsed")} -} - -func (_c *Meter_ComputationUsed_Call) Run(run func()) *Meter_ComputationUsed_Call { - _c.Call.Run(func(args mock.Arguments) { - run() - }) - return _c -} - -func (_c *Meter_ComputationUsed_Call) Return(v uint64, err error) *Meter_ComputationUsed_Call { - _c.Call.Return(v, err) - return _c -} - -func (_c *Meter_ComputationUsed_Call) RunAndReturn(run func() (uint64, error)) *Meter_ComputationUsed_Call { - _c.Call.Return(run) - return _c -} - -// MemoryUsed provides a mock function for the type Meter -func (_mock *Meter) MemoryUsed() (uint64, error) { - ret := _mock.Called() - - if len(ret) == 0 { - panic("no return value specified for MemoryUsed") - } - - var r0 uint64 - var r1 error - if returnFunc, ok := ret.Get(0).(func() (uint64, error)); ok { - return returnFunc() - } - if returnFunc, ok := ret.Get(0).(func() uint64); ok { - r0 = returnFunc() - } else { - r0 = ret.Get(0).(uint64) - } - if returnFunc, ok := ret.Get(1).(func() error); ok { - r1 = returnFunc() - } else { - r1 = ret.Error(1) - } - return r0, r1 -} - -// Meter_MemoryUsed_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'MemoryUsed' -type Meter_MemoryUsed_Call struct { - *mock.Call -} - -// MemoryUsed is a helper method to define mock.On call -func (_e *Meter_Expecter) MemoryUsed() *Meter_MemoryUsed_Call { - return &Meter_MemoryUsed_Call{Call: _e.mock.On("MemoryUsed")} -} - -func (_c *Meter_MemoryUsed_Call) Run(run func()) *Meter_MemoryUsed_Call { - _c.Call.Run(func(args mock.Arguments) { - run() - }) - return _c -} - -func (_c *Meter_MemoryUsed_Call) Return(v uint64, err error) *Meter_MemoryUsed_Call { - _c.Call.Return(v, err) - return _c -} - -func (_c *Meter_MemoryUsed_Call) RunAndReturn(run func() (uint64, error)) *Meter_MemoryUsed_Call { - _c.Call.Return(run) - return _c -} - // MeterComputation provides a mock function for the type Meter func (_mock *Meter) MeterComputation(usage common.ComputationUsage) error { ret := _mock.Called(usage) @@ -444,6 +241,59 @@ func (_c *Meter_MeterMemory_Call) RunAndReturn(run func(usage common.MemoryUsage return _c } +// MeteringResult provides a mock function for the type Meter +func (_mock *Meter) MeteringResult() (meter.MeteringResult, error) { + ret := _mock.Called() + + if len(ret) == 0 { + panic("no return value specified for MeteringResult") + } + + var r0 meter.MeteringResult + var r1 error + if returnFunc, ok := ret.Get(0).(func() (meter.MeteringResult, error)); ok { + return returnFunc() + } + if returnFunc, ok := ret.Get(0).(func() meter.MeteringResult); ok { + r0 = returnFunc() + } else { + r0 = ret.Get(0).(meter.MeteringResult) + } + if returnFunc, ok := ret.Get(1).(func() error); ok { + r1 = returnFunc() + } else { + r1 = ret.Error(1) + } + return r0, r1 +} + +// Meter_MeteringResult_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'MeteringResult' +type Meter_MeteringResult_Call struct { + *mock.Call +} + +// MeteringResult is a helper method to define mock.On call +func (_e *Meter_Expecter) MeteringResult() *Meter_MeteringResult_Call { + return &Meter_MeteringResult_Call{Call: _e.mock.On("MeteringResult")} +} + +func (_c *Meter_MeteringResult_Call) Run(run func()) *Meter_MeteringResult_Call { + _c.Call.Run(func(args mock.Arguments) { + run() + }) + return _c +} + +func (_c *Meter_MeteringResult_Call) Return(meteringResult meter.MeteringResult, err error) *Meter_MeteringResult_Call { + _c.Call.Return(meteringResult, err) + return _c +} + +func (_c *Meter_MeteringResult_Call) RunAndReturn(run func() (meter.MeteringResult, error)) *Meter_MeteringResult_Call { + _c.Call.Return(run) + return _c +} + // RunWithMeteringDisabled provides a mock function for the type Meter func (_mock *Meter) RunWithMeteringDisabled(f func()) { _mock.Called(f) @@ -483,47 +333,3 @@ func (_c *Meter_RunWithMeteringDisabled_Call) RunAndReturn(run func(f func())) * _c.Run(run) return _c } - -// TotalEmittedEventBytes provides a mock function for the type Meter -func (_mock *Meter) TotalEmittedEventBytes() uint64 { - ret := _mock.Called() - - if len(ret) == 0 { - panic("no return value specified for TotalEmittedEventBytes") - } - - var r0 uint64 - if returnFunc, ok := ret.Get(0).(func() uint64); ok { - r0 = returnFunc() - } else { - r0 = ret.Get(0).(uint64) - } - return r0 -} - -// Meter_TotalEmittedEventBytes_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'TotalEmittedEventBytes' -type Meter_TotalEmittedEventBytes_Call struct { - *mock.Call -} - -// TotalEmittedEventBytes is a helper method to define mock.On call -func (_e *Meter_Expecter) TotalEmittedEventBytes() *Meter_TotalEmittedEventBytes_Call { - return &Meter_TotalEmittedEventBytes_Call{Call: _e.mock.On("TotalEmittedEventBytes")} -} - -func (_c *Meter_TotalEmittedEventBytes_Call) Run(run func()) *Meter_TotalEmittedEventBytes_Call { - _c.Call.Run(func(args mock.Arguments) { - run() - }) - return _c -} - -func (_c *Meter_TotalEmittedEventBytes_Call) Return(v uint64) *Meter_TotalEmittedEventBytes_Call { - _c.Call.Return(v) - return _c -} - -func (_c *Meter_TotalEmittedEventBytes_Call) RunAndReturn(run func() uint64) *Meter_TotalEmittedEventBytes_Call { - _c.Call.Return(run) - return _c -} diff --git a/fvm/evm/backends/wrappedEnv.go b/fvm/evm/backends/wrappedEnv.go index ff4a491a931..dbc7fad3571 100644 --- a/fvm/evm/backends/wrappedEnv.go +++ b/fvm/evm/backends/wrappedEnv.go @@ -66,23 +66,12 @@ func (we *WrappedEnvironment) MeterComputation(usage common.ComputationUsage) er return handleEnvironmentError(err) } -// ComputationUsed returns the computation used so far -func (we *WrappedEnvironment) ComputationUsed() (uint64, error) { - val, err := we.env.ComputationUsed() +// MeteringResult returns the metering totals accumulated so far. +func (we *WrappedEnvironment) MeteringResult() (meter.MeteringResult, error) { + val, err := we.env.MeteringResult() return val, handleEnvironmentError(err) } -// ComputationIntensities returns a the list of computation intensities -func (we *WrappedEnvironment) ComputationIntensities() meter.MeteredComputationIntensities { - return we.env.ComputationIntensities() -} - -// ComputationAvailable returns true if there is computation room -// for the given kind and intensity operation. -func (we *WrappedEnvironment) ComputationAvailable(usage common.ComputationUsage) bool { - return we.env.ComputationAvailable(usage) -} - // ComputationRemaining returns the remaining computation for the given kind. func (we *WrappedEnvironment) ComputationRemaining(kind common.ComputationKind) uint64 { return we.env.ComputationRemaining(kind) @@ -93,23 +82,12 @@ func (we *WrappedEnvironment) MeterMemory(usage common.MemoryUsage) error { return handleEnvironmentError(err) } -// MemoryUsed returns the total memory used so far. -func (we *WrappedEnvironment) MemoryUsed() (uint64, error) { - val, err := we.env.MemoryUsed() - return val, handleEnvironmentError(err) -} - // MeterEmittedEvent meters a newly emitted event. func (we *WrappedEnvironment) MeterEmittedEvent(byteSize uint64) error { err := we.env.MeterEmittedEvent(byteSize) return handleEnvironmentError(err) } -// TotalEmittedEventBytes returns the total byte size of events emitted so far. -func (we *WrappedEnvironment) TotalEmittedEventBytes() uint64 { - return we.env.TotalEmittedEventBytes() -} - // EmitEvent emits an event. func (we *WrappedEnvironment) EmitEvent(event cadence.Event) error { err := we.env.EmitEvent(event) diff --git a/fvm/evm/handler/handler.go b/fvm/evm/handler/handler.go index 3f935bc87a1..c07c94ddf81 100644 --- a/fvm/evm/handler/handler.go +++ b/fvm/evm/handler/handler.go @@ -682,11 +682,7 @@ func (h *ContractHandler) DryRunWithTxData( // before attempting executing a evm operation func (h *ContractHandler) checkGasLimit(limit types.GasLimit) error { // check gas limit against what has been left on the transaction side - usage := common.ComputationUsage{ - Kind: environment.ComputationKindEVMGasUsage, - Intensity: uint64(limit), - } - if !h.backend.ComputationAvailable(usage) { + if h.backend.ComputationRemaining(environment.ComputationKindEVMGasUsage) < uint64(limit) { return types.ErrInsufficientComputation } return nil diff --git a/fvm/evm/handler/handler_test.go b/fvm/evm/handler/handler_test.go index 49435a2d9f7..9cbfe02a8a5 100644 --- a/fvm/evm/handler/handler_test.go +++ b/fvm/evm/handler/handler_test.go @@ -394,9 +394,9 @@ func TestHandler_COA(t *testing.T) { require.Equal(t, totalGasUsed, blockEventPayload.TotalGasUsed) // check gas usage - computationUsed, err := backend.ComputationUsed() + meteringResult, err := backend.MeteringResult() require.NoError(t, err) - require.Greater(t, computationUsed, types.DefaultDirectCallBaseGasUsage*3) + require.Greater(t, meteringResult.ComputationUsed, types.DefaultDirectCallBaseGasUsage*3) // Withdraw with invalid balance assertPanic(t, types.IsAWithdrawBalanceRoundingError, func() { diff --git a/fvm/evm/testutils/backend.go b/fvm/evm/testutils/backend.go index 428c74504e2..f2b1c671347 100644 --- a/fvm/evm/testutils/backend.go +++ b/fvm/evm/testutils/backend.go @@ -203,11 +203,8 @@ func getSimpleMeter() *testMeter { } return nil }, - hasComputationCapacity: func(usage common.ComputationUsage) bool { - return compUsed+usage.Intensity < TestComputationLimit - }, - computationUsed: func() (uint64, error) { - return compUsed, nil + metering: func() (meter.MeteringResult, error) { + return meter.MeteringResult{ComputationUsed: compUsed}, nil }, computationRemaining: func(kind common.ComputationKind) uint64 { return TestComputationLimit - compUsed @@ -407,17 +404,13 @@ func (vs *TestValueStore) Dump() (map[string][]byte, map[string]uint64) { } type testMeter struct { - meterComputation func(usage common.ComputationUsage) error - hasComputationCapacity func(common.ComputationUsage) bool - computationUsed func() (uint64, error) - computationIntensities func() meter.MeteredComputationIntensities - computationRemaining func(kind common.ComputationKind) uint64 + meterComputation func(usage common.ComputationUsage) error + metering func() (meter.MeteringResult, error) + computationRemaining func(kind common.ComputationKind) uint64 meterMemory func(usage common.MemoryUsage) error - memoryUsed func() (uint64, error) - meterEmittedEvent func(byteSize uint64) error - totalEmittedEventBytes func() uint64 + meterEmittedEvent func(byteSize uint64) error interactionUsed func() (uint64, error) @@ -437,22 +430,6 @@ func (m *testMeter) MeterComputation(usage common.ComputationUsage) error { return meterComputation(usage) } -func (m *testMeter) ComputationAvailable(usage common.ComputationUsage) bool { - hasComputationCapacity := m.hasComputationCapacity - if hasComputationCapacity == nil { - panic("method not set") - } - return hasComputationCapacity(usage) -} - -func (m *testMeter) ComputationIntensities() meter.MeteredComputationIntensities { - computationIntensities := m.computationIntensities - if computationIntensities == nil { - panic("method not set") - } - return computationIntensities() -} - func (m *testMeter) ComputationRemaining(kind common.ComputationKind) uint64 { computationRemaining := m.computationRemaining if computationRemaining == nil { @@ -461,12 +438,12 @@ func (m *testMeter) ComputationRemaining(kind common.ComputationKind) uint64 { return computationRemaining(kind) } -func (m *testMeter) ComputationUsed() (uint64, error) { - computationUsed := m.computationUsed - if computationUsed == nil { +func (m *testMeter) MeteringResult() (meter.MeteringResult, error) { + metering := m.metering + if metering == nil { panic("method not set") } - return computationUsed() + return metering() } func (m *testMeter) RunWithMeteringDisabled(f func()) { @@ -487,14 +464,6 @@ func (m *testMeter) MeterMemory(usage common.MemoryUsage) error { return meterMemory(usage) } -func (m *testMeter) MemoryUsed() (uint64, error) { - memoryUsed := m.memoryUsed - if memoryUsed == nil { - panic("method not set") - } - return memoryUsed() -} - func (m *testMeter) InteractionUsed() (uint64, error) { interactionUsed := m.interactionUsed if interactionUsed == nil { @@ -514,14 +483,6 @@ func (m *testMeter) MeterEmittedEvent(byteSize uint64) error { return meterEmittedEvent(byteSize) } -func (m *testMeter) TotalEmittedEventBytes() uint64 { - totalEmittedEventBytes := m.totalEmittedEventBytes - if totalEmittedEventBytes == nil { - panic("method not set") - } - return totalEmittedEventBytes() -} - type testEventEmitter struct { emitEvent func(event cadence.Event) error events func() flow.EventsList diff --git a/fvm/fvm.go b/fvm/fvm.go index f4edff5c50f..82907a1a98c 100644 --- a/fvm/fvm.go +++ b/fvm/fvm.go @@ -29,14 +29,13 @@ const ( ) type ProcedureOutput struct { + meter.MeteringResult + // Output by both transaction and script. Logs []string Events flow.EventsList ServiceEvents flow.EventsList ConvertedServiceEvents flow.ServiceEventList - ComputationUsed uint64 - ComputationIntensities meter.MeteredComputationIntensities - MemoryEstimate uint64 Err errors.CodedError InspectionResults []inspection.Result @@ -49,19 +48,11 @@ func (output *ProcedureOutput) PopulateEnvironmentValues( ) error { output.Logs = env.Logs() - computationUsed, err := env.ComputationUsed() + meteringResult, err := env.MeteringResult() if err != nil { - return fmt.Errorf("error getting computation used: %w", err) + return fmt.Errorf("error getting metering result: %w", err) } - output.ComputationUsed = computationUsed - - memoryUsed, err := env.MemoryUsed() - if err != nil { - return fmt.Errorf("error getting memory used: %w", err) - } - output.MemoryEstimate = memoryUsed - - output.ComputationIntensities = env.ComputationIntensities() + output.MeteringResult = meteringResult // if tx failed this will only contain fee deduction events output.Events = env.Events() diff --git a/fvm/meter/computation_meter.go b/fvm/meter/computation_meter.go index 3b96983656a..68e1f5a5841 100644 --- a/fvm/meter/computation_meter.go +++ b/fvm/meter/computation_meter.go @@ -105,19 +105,6 @@ func (m *ComputationMeter) MeterComputation(usage common.ComputationUsage) error return nil } -// ComputationAvailable returns true if enough computation is left in the transaction for the given intensity and type -func (m *ComputationMeter) ComputationAvailable(usage common.ComputationUsage) bool { - w, ok := m.params.computationWeights[usage.Kind] - // if not found return has capacity - // given the behaviour of MeterComputation is ignoring intensities without a set weight - if !ok { - return true - } - - potentialComputationUsage := m.computationUsed + w*usage.Intensity - return potentialComputationUsage <= m.params.computationLimit -} - // ComputationRemaining returns the remaining computation (intensity) left in the transaction for the given type func (m *ComputationMeter) ComputationRemaining(kind common.ComputationKind) uint64 { w, ok := m.params.computationWeights[kind] @@ -126,12 +113,14 @@ func (m *ComputationMeter) ComputationRemaining(kind common.ComputationKind) uin return math.MaxUint64 } - remainingComputationUsage := m.params.computationLimit - m.computationUsed - if remainingComputationUsage <= 0 { + // `computationUsed` can exceed `computationLimit`, since `MeterComputation` increments + // the usage before checking the limit; guard against underflow + if m.computationUsed >= m.params.computationLimit { return 0 } - return remainingComputationUsage / w + // never underflows, as we handled the m.params.computationLimit ≤ m.computationUsed above + return (m.params.computationLimit - m.computationUsed) / w } // ComputationIntensities returns all the measured computational intensities diff --git a/fvm/meter/meter.go b/fvm/meter/meter.go index 2654a03aaa7..e367a7b4083 100644 --- a/fvm/meter/meter.go +++ b/fvm/meter/meter.go @@ -1,5 +1,12 @@ package meter +// MeteringResult bundles the metering totals reported after execution. +type MeteringResult struct { + ComputationUsed uint64 + MemoryEstimate uint64 + ComputationIntensities MeteredComputationIntensities +} + type MeterParameters struct { ComputationMeterParameters MemoryMeterParameters diff --git a/fvm/meter/meter_test.go b/fvm/meter/meter_test.go index af40dce69e2..9659b831969 100644 --- a/fvm/meter/meter_test.go +++ b/fvm/meter/meter_test.go @@ -167,7 +167,7 @@ func TestWeightedComputationMetering(t *testing.T) { require.Equal(t, uint64(1< computationLimit { computationUsed = computationLimit diff --git a/integration/internal/emulator/tests/vm_test.go b/integration/internal/emulator/tests/vm_test.go index 39725f276b9..ecf2466dc21 100644 --- a/integration/internal/emulator/tests/vm_test.go +++ b/integration/internal/emulator/tests/vm_test.go @@ -27,6 +27,7 @@ import ( "github.com/onflow/flow-go-sdk/test" "github.com/onflow/flow-go/fvm" + "github.com/onflow/flow-go/fvm/meter" "github.com/onflow/flow-go/integration/internal/emulator" flowgo "github.com/onflow/flow-go/model/flow" ) @@ -53,11 +54,13 @@ func TestVm(t *testing.T) { txnId := flowgo.Identifier(idGenerator.New()) output := fvm.ProcedureOutput{ - Logs: []string{"TestLog1", "TestLog2"}, - Events: []flowgo.Event{*event1, *event2}, - ComputationUsed: 5, - MemoryEstimate: 1211, - Err: nil, + Logs: []string{"TestLog1", "TestLog2"}, + Events: []flowgo.Event{*event1, *event2}, + MeteringResult: meter.MeteringResult{ + ComputationUsed: 5, + MemoryEstimate: 1211, + }, + Err: nil, } tr, err := emulator.VMTransactionResultToEmulator(txnId, output) diff --git a/module/chunks/chunkVerifier_test.go b/module/chunks/chunkVerifier_test.go index 4dfea123dae..bc994c6414b 100644 --- a/module/chunks/chunkVerifier_test.go +++ b/module/chunks/chunkVerifier_test.go @@ -18,6 +18,7 @@ import ( "github.com/onflow/flow-go/fvm" "github.com/onflow/flow-go/fvm/blueprints" fvmErrors "github.com/onflow/flow-go/fvm/errors" + "github.com/onflow/flow-go/fvm/meter" fvmmock "github.com/onflow/flow-go/fvm/mock" "github.com/onflow/flow-go/fvm/storage/snapshot" "github.com/onflow/flow-go/fvm/systemcontracts" @@ -153,7 +154,7 @@ func (s *ChunkVerifierTestSuite) SetupTest() { // subject to overwrite by test cases s.snapshots[string(processTxBody.Script)] = &snapshot.ExecutionSnapshot{} s.outputs[string(processTxBody.Script)] = fvm.ProcedureOutput{ - ComputationUsed: computationUsed, + MeteringResult: meter.MeteringResult{ComputationUsed: computationUsed}, } } @@ -236,8 +237,8 @@ func (s *ChunkVerifierTestSuite) TestFailedTx() { }, } s.outputs["failedTx"] = fvm.ProcedureOutput{ - ComputationUsed: computationUsed, - Err: fvmErrors.NewCadenceRuntimeError(runtime.Error{}), // inside the runtime (e.g. div by zero, access account) + MeteringResult: meter.MeteringResult{ComputationUsed: computationUsed}, + Err: fvmErrors.NewCadenceRuntimeError(runtime.Error{}), // inside the runtime (e.g. div by zero, access account) } spockSecret, err := s.verifier.Verify(vch) @@ -281,7 +282,7 @@ func (s *ChunkVerifierTestSuite) TestServiceEventsMismatch_SystemChunk() { s.snapshots[string(serviceTxBody.Script)] = &snapshot.ExecutionSnapshot{} s.outputs[string(serviceTxBody.Script)] = fvm.ProcedureOutput{ - ComputationUsed: computationUsed, + MeteringResult: meter.MeteringResult{ComputationUsed: computationUsed}, ServiceEvents: unittest.EventsFixture(1), ConvertedServiceEvents: flow.ServiceEventList{*epochCommitServiceEvent}, Events: meta.ChunkEvents, @@ -292,7 +293,7 @@ func (s *ChunkVerifierTestSuite) TestServiceEventsMismatch_SystemChunk() { s.snapshots[string(processTxBody.Script)] = &snapshot.ExecutionSnapshot{} s.outputs[string(processTxBody.Script)] = fvm.ProcedureOutput{ - ComputationUsed: computationUsed, + MeteringResult: meter.MeteringResult{ComputationUsed: computationUsed}, } _, err = s.verifier.Verify(vch) @@ -333,7 +334,7 @@ func (s *ChunkVerifierTestSuite) TestServiceEventsMismatch_NonSystemChunk() { // overwrite the expected output for our custom transaction, passing // in the non-matching EpochCommit event (should cause validation failure) s.outputs[script] = fvm.ProcedureOutput{ - ComputationUsed: computationUsed, + MeteringResult: meter.MeteringResult{ComputationUsed: computationUsed}, ConvertedServiceEvents: flow.ServiceEventList{*epochCommitServiceEvent}, Events: meta.ChunkEvents[:3], // 2 default event + EpochSetup } @@ -490,8 +491,8 @@ func (s *ChunkVerifierTestSuite) TestSystemChunkWithScheduledTransactionsReturni // Setup mock outputs for process callback transaction s.outputs[string(processTxBody.Script)] = fvm.ProcedureOutput{ - ComputationUsed: computationUsed, - Events: flow.EventsList{processEvent}, + MeteringResult: meter.MeteringResult{ComputationUsed: computationUsed}, + Events: flow.EventsList{processEvent}, } // Create execute callback transaction body @@ -503,7 +504,7 @@ func (s *ChunkVerifierTestSuite) TestSystemChunkWithScheduledTransactionsReturni // Setup mock output for execute callback transaction s.outputs[string(executeCallbackTx.Script)] = fvm.ProcedureOutput{ - ComputationUsed: computationUsed, + MeteringResult: meter.MeteringResult{ComputationUsed: computationUsed}, } // Setup system transaction output @@ -511,7 +512,7 @@ func (s *ChunkVerifierTestSuite) TestSystemChunkWithScheduledTransactionsReturni require.NoError(s.T(), err) s.outputs[string(serviceTxBody.Script)] = fvm.ProcedureOutput{ - ComputationUsed: computationUsed, + MeteringResult: meter.MeteringResult{ComputationUsed: computationUsed}, ConvertedServiceEvents: flow.ServiceEventList{*epochSetupServiceEvent}, Events: flow.EventsList{epochSetupEvent}, } @@ -550,8 +551,8 @@ func (s *ChunkVerifierTestSuite) TestSystemChunkWithScheduledTransactionsReturni func (s *ChunkVerifierTestSuite) TestSystemChunkWithNoScheduledTransactions() { // Setup mock outputs for process callback transaction with no events s.outputs[string(processTxBody.Script)] = fvm.ProcedureOutput{ - ComputationUsed: computationUsed, - Events: flow.EventsList{}, // No callback events + MeteringResult: meter.MeteringResult{ComputationUsed: computationUsed}, + Events: flow.EventsList{}, // No callback events } // Setup system transaction output @@ -559,7 +560,7 @@ func (s *ChunkVerifierTestSuite) TestSystemChunkWithNoScheduledTransactions() { require.NoError(s.T(), err) s.outputs[string(serviceTxBody.Script)] = fvm.ProcedureOutput{ - ComputationUsed: computationUsed, + MeteringResult: meter.MeteringResult{ComputationUsed: computationUsed}, ConvertedServiceEvents: flow.ServiceEventList{*epochSetupServiceEvent}, Events: flow.EventsList{epochSetupEvent}, } @@ -749,9 +750,9 @@ func generateDefaultSnapshot() *snapshot.ExecutionSnapshot { func generateDefaultOutput() fvm.ProcedureOutput { return fvm.ProcedureOutput{ - ComputationUsed: computationUsed, - Logs: []string{"log1", "log2"}, - Events: eventsList, + MeteringResult: meter.MeteringResult{ComputationUsed: computationUsed}, + Logs: []string{"log1", "log2"}, + Events: eventsList, } }