diff --git a/mocks/mock_vm.go b/mocks/mock_vm.go index 3e27bc03d7..ee93d1ccaf 100644 --- a/mocks/mock_vm.go +++ b/mocks/mock_vm.go @@ -71,3 +71,48 @@ func (mr *MockVMMockRecorder) Execute(txns, declaredClasses, paidFeesOnL1, block mr.mock.ctrl.T.Helper() return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Execute", reflect.TypeOf((*MockVM)(nil).Execute), txns, declaredClasses, paidFeesOnL1, blockInfo, state, skipChargeFee, skipValidate, errOnRevert, errStack, allowBinarySearch, isEstimateFee, returnInitialReads) } + +// Simulate mocks base method. +func (m *MockVM) Simulate(txns []core.Transaction, declaredClasses []core.ClassDefinition, paidFeesOnL1 []*felt.Felt, blockInfo *vm.BlockInfo, state core.StateReader, opts vm.SimulateOptions) (vm.ExecutionResults, error) { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "Simulate", txns, declaredClasses, paidFeesOnL1, blockInfo, state, opts) + ret0, _ := ret[0].(vm.ExecutionResults) + ret1, _ := ret[1].(error) + return ret0, ret1 +} + +// Simulate indicates an expected call of Simulate. +func (mr *MockVMMockRecorder) Simulate(txns, declaredClasses, paidFeesOnL1, blockInfo, state, opts any) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Simulate", reflect.TypeOf((*MockVM)(nil).Simulate), txns, declaredClasses, paidFeesOnL1, blockInfo, state, opts) +} + +// Trace mocks base method. +func (m *MockVM) Trace(txns []core.Transaction, declaredClasses []core.ClassDefinition, paidFeesOnL1 []*felt.Felt, blockInfo *vm.BlockInfo, state core.StateReader, opts vm.TraceOptions) (vm.ExecutionResults, error) { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "Trace", txns, declaredClasses, paidFeesOnL1, blockInfo, state, opts) + ret0, _ := ret[0].(vm.ExecutionResults) + ret1, _ := ret[1].(error) + return ret0, ret1 +} + +// Trace indicates an expected call of Trace. +func (mr *MockVMMockRecorder) Trace(txns, declaredClasses, paidFeesOnL1, blockInfo, state, opts any) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Trace", reflect.TypeOf((*MockVM)(nil).Trace), txns, declaredClasses, paidFeesOnL1, blockInfo, state, opts) +} + +// BuildBlock mocks base method. +func (m *MockVM) BuildBlock(txns []core.Transaction, declaredClasses []core.ClassDefinition, paidFeesOnL1 []*felt.Felt, blockInfo *vm.BlockInfo, state core.StateReader, opts vm.BuildBlockOptions) (vm.ExecutionResults, error) { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "BuildBlock", txns, declaredClasses, paidFeesOnL1, blockInfo, state, opts) + ret0, _ := ret[0].(vm.ExecutionResults) + ret1, _ := ret[1].(error) + return ret0, ret1 +} + +// BuildBlock indicates an expected call of BuildBlock. +func (mr *MockVMMockRecorder) BuildBlock(txns, declaredClasses, paidFeesOnL1, blockInfo, state, opts any) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "BuildBlock", reflect.TypeOf((*MockVM)(nil).BuildBlock), txns, declaredClasses, paidFeesOnL1, blockInfo, state, opts) +} diff --git a/node/throttled_vm.go b/node/throttled_vm.go index 47d1332efd..31bb089450 100644 --- a/node/throttled_vm.go +++ b/node/throttled_vm.go @@ -77,3 +77,53 @@ func (tvm *ThrottledVM) Execute( return err }) } + +func (tvm *ThrottledVM) runExec( + fn func(inner vm.VM) (vm.ExecutionResults, error), +) (vm.ExecutionResults, error) { + var result vm.ExecutionResults + return result, tvm.Do(func(inner *vm.VM) error { + var err error + result, err = fn(*inner) + return err + }) +} + +func (tvm *ThrottledVM) Simulate( + txns []core.Transaction, + declaredClasses []core.ClassDefinition, + paidFeesOnL1 []*felt.Felt, + blockInfo *vm.BlockInfo, + state core.StateReader, + opts vm.SimulateOptions, +) (vm.ExecutionResults, error) { + return tvm.runExec(func(inner vm.VM) (vm.ExecutionResults, error) { + return inner.Simulate(txns, declaredClasses, paidFeesOnL1, blockInfo, state, opts) + }) +} + +func (tvm *ThrottledVM) Trace( + txns []core.Transaction, + declaredClasses []core.ClassDefinition, + paidFeesOnL1 []*felt.Felt, + blockInfo *vm.BlockInfo, + state core.StateReader, + opts vm.TraceOptions, +) (vm.ExecutionResults, error) { + return tvm.runExec(func(inner vm.VM) (vm.ExecutionResults, error) { + return inner.Trace(txns, declaredClasses, paidFeesOnL1, blockInfo, state, opts) + }) +} + +func (tvm *ThrottledVM) BuildBlock( + txns []core.Transaction, + declaredClasses []core.ClassDefinition, + paidFeesOnL1 []*felt.Felt, + blockInfo *vm.BlockInfo, + state core.StateReader, + opts vm.BuildBlockOptions, +) (vm.ExecutionResults, error) { + return tvm.runExec(func(inner vm.VM) (vm.ExecutionResults, error) { + return inner.BuildBlock(txns, declaredClasses, paidFeesOnL1, blockInfo, state, opts) + }) +} diff --git a/vm/vm.go b/vm/vm.go index 88c5307628..78ab0d79a0 100644 --- a/vm/vm.go +++ b/vm/vm.go @@ -45,6 +45,32 @@ type CallResult struct { ExecutionFailed bool } +// SimulateOptions carries the per-request flags relevant to RPC simulate / +// estimateFee. errStack and allowBinarySearch are constants for this path +// and are set internally. +type SimulateOptions struct { + SkipChargeFee bool + SkipValidate bool + ErrOnRevert bool + IsEstimateFee bool + ReturnInitialReads bool +} + +// TraceOptions carries the per-request flags relevant to replaying an +// existing block. All execution flags are off; only errStack is on. +type TraceOptions struct { + ReturnInitialReads bool +} + +// BuildBlockOptions carries flags used when producing a block (builder or +// genesis bootstrap). errStack is hardcoded true; the trace/estimate flags +// don't apply here. +type BuildBlockOptions struct { + SkipChargeFee bool + SkipValidate bool + ErrOnRevert bool +} + //go:generate mockgen -destination=../mocks/mock_vm.go -package=mocks github.com/NethermindEth/juno/vm VM type VM interface { Call( @@ -70,6 +96,30 @@ type VM interface { isEstimateFee bool, returnInitialReads bool, ) (ExecutionResults, error) + Simulate( + txns []core.Transaction, + declaredClasses []core.ClassDefinition, + paidFeesOnL1 []*felt.Felt, + blockInfo *BlockInfo, + state core.StateReader, + opts SimulateOptions, + ) (ExecutionResults, error) + Trace( + txns []core.Transaction, + declaredClasses []core.ClassDefinition, + paidFeesOnL1 []*felt.Felt, + blockInfo *BlockInfo, + state core.StateReader, + opts TraceOptions, + ) (ExecutionResults, error) + BuildBlock( + txns []core.Transaction, + declaredClasses []core.ClassDefinition, + paidFeesOnL1 []*felt.Felt, + blockInfo *BlockInfo, + state core.StateReader, + opts BuildBlockOptions, + ) (ExecutionResults, error) } type vm struct { @@ -444,6 +494,72 @@ func (v *vm) Execute( }, nil } +// Simulate runs the txn set under RPC simulate / estimateFee semantics: +// errStack and allowBinarySearch are always on. +func (v *vm) Simulate( + txns []core.Transaction, + declaredClasses []core.ClassDefinition, + paidFeesOnL1 []*felt.Felt, + blockInfo *BlockInfo, + state core.StateReader, + opts SimulateOptions, +) (ExecutionResults, error) { + return v.Execute( + txns, declaredClasses, paidFeesOnL1, blockInfo, state, + opts.SkipChargeFee, + opts.SkipValidate, + opts.ErrOnRevert, + true, // errStack + true, // allowBinarySearch + opts.IsEstimateFee, + opts.ReturnInitialReads, + ) +} + +// Trace replays an existing block. All exec flags are off; only errStack +// is on so we get structured error frames if anything goes wrong. +func (v *vm) Trace( + txns []core.Transaction, + declaredClasses []core.ClassDefinition, + paidFeesOnL1 []*felt.Felt, + blockInfo *BlockInfo, + state core.StateReader, + opts TraceOptions, +) (ExecutionResults, error) { + return v.Execute( + txns, declaredClasses, paidFeesOnL1, blockInfo, state, + false, // skipChargeFee + false, // skipValidate + false, // errOnRevert + true, // errStack + false, // allowBinarySearch + false, // isEstimateFee + opts.ReturnInitialReads, + ) +} + +// BuildBlock executes txns in block-production mode (builder or genesis). +// errStack is on; trace/estimate flags don't apply. +func (v *vm) BuildBlock( + txns []core.Transaction, + declaredClasses []core.ClassDefinition, + paidFeesOnL1 []*felt.Felt, + blockInfo *BlockInfo, + state core.StateReader, + opts BuildBlockOptions, +) (ExecutionResults, error) { + return v.Execute( + txns, declaredClasses, paidFeesOnL1, blockInfo, state, + opts.SkipChargeFee, + opts.SkipValidate, + opts.ErrOnRevert, + true, // errStack + false, // allowBinarySearch + false, // isEstimateFee + false, // returnInitialReads + ) +} + func marshalTxnsAndDeclaredClasses( txns []core.Transaction, declaredClasses []core.ClassDefinition,