From be95a5777da97fed3adbadfe107e8f2a9045fcdf Mon Sep 17 00:00:00 2001 From: Luis Ayuso Date: Mon, 14 Oct 2024 16:06:14 +0200 Subject: [PATCH 1/2] Use lowercase for errors As recommended in best practices --- go/tosca/interpreter.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/go/tosca/interpreter.go b/go/tosca/interpreter.go index 9a6741c52..3d6668fa8 100644 --- a/go/tosca/interpreter.go +++ b/go/tosca/interpreter.go @@ -199,7 +199,7 @@ type ErrUnsupportedRevision struct { } func (e *ErrUnsupportedRevision) Error() string { - return fmt.Sprintf("Unsupported revision %d", e.Revision) + return fmt.Sprintf("unsupported revision %d", e.Revision) } // ProfilingInterpreter is an optional extension to the Interpreter interface From 1065d2f191f4a3e60b610cafd4a872b887d57989 Mon Sep 17 00:00:00 2001 From: Luis Ayuso Date: Tue, 15 Oct 2024 11:01:16 +0200 Subject: [PATCH 2/2] Test registration of experimental lfvm instances. --- go/interpreter/lfvm/lfvm.go | 45 +++++++------- go/interpreter/lfvm/lfvm_interface_test.go | 72 ++++++++++++++++++++++ go/interpreter/lfvm/lfvm_test.go | 26 ++++++++ 3 files changed, 120 insertions(+), 23 deletions(-) create mode 100644 go/interpreter/lfvm/lfvm_interface_test.go diff --git a/go/interpreter/lfvm/lfvm.go b/go/interpreter/lfvm/lfvm.go index ad331549c..58a018076 100644 --- a/go/interpreter/lfvm/lfvm.go +++ b/go/interpreter/lfvm/lfvm.go @@ -45,6 +45,9 @@ func init() { // function should not be called in production code, as the resulting VMs are // not officially supported. func RegisterExperimentalInterpreterConfigurations() error { + + configs := map[string]config{} + for _, si := range []string{"", "-si"} { for _, shaCache := range []string{"", "-no-sha-cache"} { for _, mode := range []string{"", "-stats", "-logging"} { @@ -67,35 +70,31 @@ func RegisterExperimentalInterpreterConfigurations() error { } name := "lfvm" + si + shaCache + mode - if name != "lfvm" { - err := tosca.RegisterInterpreterFactory( - name, - func(any) (tosca.Interpreter, error) { - return newVm(config) - }, - ) - if err != nil { - return fmt.Errorf("failed to register interpreter %q: %v", name, err) - } + if name == "lfvm" { + continue } + + configs[name] = config } } } - lfvmNoCodeCache := "lfvm-no-code-cache" - err := tosca.RegisterInterpreterFactory( - lfvmNoCodeCache, - func(any) (tosca.Interpreter, error) { - return newVm(config{ - ConversionConfig: ConversionConfig{ - CacheSize: -1, - }, - }) - }, - ) - if err != nil { - return fmt.Errorf("failed to register interpreter %q: %v", lfvmNoCodeCache, err) + configs["lfvm-no-code-cache"] = config{ + ConversionConfig: ConversionConfig{CacheSize: -1}, } + + for name, config := range configs { + err := tosca.RegisterInterpreterFactory( + name, + func(any) (tosca.Interpreter, error) { + return newVm(config) + }, + ) + if err != nil { + return fmt.Errorf("failed to register interpreter %q: %v", name, err) + } + } + return nil } diff --git a/go/interpreter/lfvm/lfvm_interface_test.go b/go/interpreter/lfvm/lfvm_interface_test.go new file mode 100644 index 000000000..b1c9133f6 --- /dev/null +++ b/go/interpreter/lfvm/lfvm_interface_test.go @@ -0,0 +1,72 @@ +// Copyright (c) 2024 Fantom Foundation +// +// Use of this software is governed by the Business Source License included +// in the LICENSE file and at fantom.foundation/bsl11. +// +// Change Date: 2028-4-16 +// +// On the date above, in accordance with the Business Source License, use of +// this software will be governed by the GNU Lesser General Public License v3. + +package lfvm_test + +import ( + "testing" + + "github.com/Fantom-foundation/Tosca/go/interpreter/lfvm" + "github.com/Fantom-foundation/Tosca/go/tosca" +) + +// TestLfvm_RegisterExperimentalConfigurations tests the registration of +// experimental configurations. +// This test is slightly different from other tests because of dealing with the +// global registry: +// - It is declared in it's own package to avoid leaking the registration to other tests. +// - It tests different properties, in one single function. The reason is that the +// order of different functions may change, invalidating the test. +func TestLfvm_RegisterExperimentalConfigurations(t *testing.T) { + + // Fist registration must succeed. + err := lfvm.RegisterExperimentalInterpreterConfigurations() + if err != nil { + t.Fatalf("failed to register experimental configurations: %v", err) + } + + // Registering a second time must fail. + err = lfvm.RegisterExperimentalInterpreterConfigurations() + if err == nil { + t.Fatalf("expected error when registering experimental configurations twice") + } + + // Check that lfvm is registered by default, in addition to experimental configurations + if _, ok := tosca.GetAllRegisteredInterpreters()["lfvm"]; !ok { + t.Fatalf("lfvm is not registered") + } + + // Construct all registered interpreter configurations + for name, factory := range tosca.GetAllRegisteredInterpreters() { + t.Run(name, func(t *testing.T) { + vm, err := factory(lfvm.Config{}) + if err != nil { + t.Fatalf("failed to create interpreter: %v", err) + } + + // Vms are opaque, we can't check their configuration directly. + // We can only check that they do execute some basic code. + params := tosca.Parameters{} + params.Code = []byte{byte(lfvm.PUSH1), 0xff, byte(lfvm.POP), byte(lfvm.STOP)} + params.Gas = 5 + res, err := vm.Run(params) + if err != nil { + t.Fatalf("failed to run interpreter: %v", err) + } + + if want, got := true, res.Success; want != got { + t.Fatalf("unexpected success result: want %v, got %v", want, got) + } + if want, got := tosca.Gas(0), res.GasLeft; want != got { + t.Fatalf("unexpected gas used: want %v, got %v", want, got) + } + }) + } +} diff --git a/go/interpreter/lfvm/lfvm_test.go b/go/interpreter/lfvm/lfvm_test.go index 22a5e56c7..774ed4470 100644 --- a/go/interpreter/lfvm/lfvm_test.go +++ b/go/interpreter/lfvm/lfvm_test.go @@ -11,6 +11,7 @@ package lfvm import ( + "fmt" "testing" "github.com/Fantom-foundation/Tosca/go/tosca" @@ -45,3 +46,28 @@ func TestLfvm_OfficialConfigurationHasSanctionedProperties(t *testing.T) { t.Fatalf("lfvm is configured with super instructions") } } + +func TestLfvm_InterpreterReturnsErrorWhenExecutingUnsupportedRevision(t *testing.T) { + vm, err := tosca.NewInterpreter("lfvm") + if err != nil { + t.Fatalf("lfvm is not registered: %v", err) + } + + params := tosca.Parameters{} + params.Revision = newestSupportedRevision + 1 + + _, err = vm.Run(params) + if want, got := fmt.Sprintf("unsupported revision %d", params.Revision), err.Error(); want != got { + t.Fatalf("unexpected error: want %q, got %q", want, got) + } +} + +func TestLfvm_newVm_returnsErrorWithWrongConfiguration(t *testing.T) { + config := config{ + ConversionConfig: ConversionConfig{CacheSize: maxCachedCodeLength / 2}, + } + _, err := newVm(config) + if err == nil { + t.Fatalf("expected error, got nil") + } +}