Skip to content

Commit

Permalink
Refactor lfvm.go
Browse files Browse the repository at this point in the history
- Define public and private interface.
- Test coverage complete
- Add configuration arguments prototype
  • Loading branch information
LuisPH3 committed Oct 14, 2024
1 parent 6f0cbcf commit 7743183
Show file tree
Hide file tree
Showing 11 changed files with 332 additions and 121 deletions.
16 changes: 8 additions & 8 deletions go/interpreter/lfvm/converter.go
Original file line number Diff line number Diff line change
Expand Up @@ -29,18 +29,18 @@ type ConversionConfig struct {
// Positive values larger than 0 but less than maxCachedCodeLength are
// reported as invalid cache sizes during initialization.
CacheSize int
// WithSuperInstructions enables the use of super instructions.
WithSuperInstructions bool
// SuperInstructionsEnabled mark the use of super instructions.
SuperInstructionsEnabled bool
}

// Converter converts EVM code to LFVM code.
type Converter struct {
// converter converts EVM code to LFVM code.
type converter struct {
config ConversionConfig
cache *lru.Cache[tosca.Hash, Code]
}

// NewConverter creates a new code converter with the provided configuration.
func NewConverter(config ConversionConfig) (*Converter, error) {
func NewConverter(config ConversionConfig) (*converter, error) {
if config.CacheSize == 0 {
config.CacheSize = (1 << 30) // = 1GiB
}
Expand All @@ -55,7 +55,7 @@ func NewConverter(config ConversionConfig) (*Converter, error) {
return nil, err
}
}
return &Converter{
return &converter{
config: config,
cache: cache,
}, nil
Expand All @@ -64,7 +64,7 @@ func NewConverter(config ConversionConfig) (*Converter, error) {
// Convert converts EVM code to LFVM code. If the provided code hash is not nil,
// it is assumed to be a valid hash of the code and is used to cache the
// conversion result. If the hash is nil, the conversion result is not cached.
func (c *Converter) Convert(code []byte, codeHash *tosca.Hash) Code {
func (c *converter) Convert(code []byte, codeHash *tosca.Hash) Code {
if c.cache == nil || codeHash == nil {
return convert(code, c.config)
}
Expand Down Expand Up @@ -165,7 +165,7 @@ func convertWithObserver(

// Convert instructions
observer(i, res.nextPos)
inc := appendInstructions(&res, i, code, options.WithSuperInstructions)
inc := appendInstructions(&res, i, code, options.SuperInstructionsEnabled)
i += inc + 1
}
return res.toCode()
Expand Down
6 changes: 3 additions & 3 deletions go/interpreter/lfvm/converter_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -267,7 +267,7 @@ func TestConvert_ProgramCounterBeyond16bitAreConvertedIntoInvalidInstructions(t

func TestConvert_BaseInstructionsAreConvertedToEquivalents(t *testing.T) {
config := ConversionConfig{
WithSuperInstructions: false,
SuperInstructionsEnabled: false,
}
for _, op := range allOpCodesWhere(OpCode.isBaseInstruction) {
t.Run(op.String(), func(t *testing.T) {
Expand Down Expand Up @@ -372,7 +372,7 @@ func TestConvert_AllJumpToOperationsPointToSubsequentJumpdest(t *testing.T) {

func TestConvert_SI_WhenEnabledSuperInstructionsAreUsed(t *testing.T) {
config := ConversionConfig{
WithSuperInstructions: true,
SuperInstructionsEnabled: true,
}
for _, op := range allOpCodesWhere(OpCode.isSuperInstruction) {
t.Run(op.String(), func(t *testing.T) {
Expand All @@ -393,7 +393,7 @@ func TestConvert_SI_WhenEnabledSuperInstructionsAreUsed(t *testing.T) {

func TestConvert_SI_WhenDisabledNoSuperInstructionsAreUsed(t *testing.T) {
config := ConversionConfig{
WithSuperInstructions: false,
SuperInstructionsEnabled: false,
}
for _, op := range allOpCodesWhere(OpCode.isSuperInstruction) {
t.Run(op.String(), func(t *testing.T) {
Expand Down
8 changes: 3 additions & 5 deletions go/interpreter/lfvm/ct.go
Original file line number Diff line number Diff line change
Expand Up @@ -24,9 +24,7 @@ import (
)

func NewConformanceTestingTarget() ct.Evm {
converter, err := NewConverter(ConversionConfig{
WithSuperInstructions: false,
})
converter, err := NewConverter(DefaultConfiguration().ConversionConfig)
if err != nil {
panic("failed to create converter: " + err.Error())
}
Expand All @@ -38,7 +36,7 @@ func NewConformanceTestingTarget() ct.Evm {
}

type ctAdapter struct {
converter *Converter
converter *converter
pcMapCache *lru.Cache[[32]byte, *pcMap]
}

Expand Down Expand Up @@ -135,7 +133,7 @@ func genPcMap(code []byte) *pcMap {
lfvmToEvm := make([]uint16, len(code)+1)

config := ConversionConfig{
WithSuperInstructions: false,
SuperInstructionsEnabled: false,
}
res := convertWithObserver(code, config, func(evm, lfvm int) {
evmToLfvm[evm] = uint16(lfvm)
Expand Down
2 changes: 1 addition & 1 deletion go/interpreter/lfvm/ct_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -317,7 +317,7 @@ func TestConvertToLfvm_CodeWithSuperInstructions(t *testing.T) {

for name, test := range tests {
t.Run(name, func(t *testing.T) {
options := ConversionConfig{WithSuperInstructions: true}
options := ConversionConfig{SuperInstructionsEnabled: true}
got := convert(test.evmCode, options)
if !reflect.DeepEqual(test.want, got) {
t.Fatalf("unexpected code, wanted %v, got %v", test.want, got)
Expand Down
12 changes: 3 additions & 9 deletions go/interpreter/lfvm/instruction_logger_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -55,9 +55,7 @@ func TestInterpreter_Logger_ExecutesCodeAndLogs(t *testing.T) {
code := test.code
buffer := bytes.NewBuffer([]byte{})
logger := newLogger(buffer)
config := interpreterConfig{
runner: logger,
}
config := DefaultConfiguration().WithRunner(logger)
_, err := run(config, params, code)
if err != nil {
t.Errorf("unexpected error: %v", err)
Expand Down Expand Up @@ -88,9 +86,7 @@ func TestInterpreter_Logger_RunsWithoutOutput(t *testing.T) {
defer func() { os.Stderr = oldErr }()

logger := newLogger(nil)
config := interpreterConfig{
runner: logger,
}
config := DefaultConfiguration().WithRunner(logger)

_, err := run(config, params, code)
if err != nil {
Expand Down Expand Up @@ -132,9 +128,7 @@ func (l loggerErrorMock) Write(p []byte) (n int, err error) {
func TestInterpreter_logger_PropagatesWriterError(t *testing.T) {

logger := newLogger(loggerErrorMock{})
config := interpreterConfig{
runner: logger,
}
config := DefaultConfiguration().WithRunner(logger)
// Get tosca.Parameters
params := tosca.Parameters{}
code := []Instruction{{STOP, 0}}
Expand Down
6 changes: 2 additions & 4 deletions go/interpreter/lfvm/instruction_statistcs_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@ func TestStatisticsRunner_RunWithStatistics(t *testing.T) {
statsRunner := &statisticRunner{
stats: newStatistics(),
}
config := interpreterConfig{
config := Configuration{
runner: statsRunner,
}
_, err := run(config, params, code)
Expand Down Expand Up @@ -84,9 +84,7 @@ func TestStatisticsRunner_DumpProfilePrintsExpectedOutput(t *testing.T) {
stats: newStatistics(),
}

instance, err := newVm(config{
runner: statsRunner,
})
instance, err := NewInterpreter(DefaultConfiguration().WithRunner(statsRunner))
if err != nil {
t.Fatalf("Failed to create VM: %v", err)
}
Expand Down
9 changes: 2 additions & 7 deletions go/interpreter/lfvm/interpreter.go
Original file line number Diff line number Diff line change
Expand Up @@ -83,13 +83,8 @@ type runner interface {
run(*context) (status, error)
}

type interpreterConfig struct {
withShaCache bool
runner runner
}

func run(
config interpreterConfig,
config Configuration,
params tosca.Parameters,
code Code,
) (tosca.Result, error) {
Expand All @@ -110,7 +105,7 @@ func run(
stack: NewStack(),
memory: NewMemory(),
code: code,
withShaCache: config.withShaCache,
withShaCache: config.ShaCache,
}
defer ReturnStack(ctxt.stack)

Expand Down
8 changes: 4 additions & 4 deletions go/interpreter/lfvm/interpreter_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -284,7 +284,7 @@ func TestInterpreter_Vanilla_RunsWithoutOutput(t *testing.T) {
os.Stdout = w

// Run testing code
_, err := run(interpreterConfig{}, params, code)
_, err := run(Configuration{}, params, code)
// read the output
_ = w.Close() // ignore error in test
out, _ := io.ReadAll(r)
Expand All @@ -302,7 +302,7 @@ func TestInterpreter_Vanilla_RunsWithoutOutput(t *testing.T) {
func TestInterpreter_EmptyCodeBypassesRunnerAndSucceeds(t *testing.T) {
code := []Instruction{}
params := tosca.Parameters{}
config := interpreterConfig{
config := Configuration{
runner: NewMockrunner(gomock.NewController(t)),
}

Expand All @@ -321,7 +321,7 @@ func TestInterpreter_run_ReturnsErrorOnRuntimeError(t *testing.T) {
runner := NewMockrunner(gomock.NewController(t))
code := []Instruction{{JUMPDEST, 0}}
params := tosca.Parameters{Gas: 20}
config := interpreterConfig{runner: runner}
config := Configuration{runner: runner}

expectedError := fmt.Errorf("runtime error")

Expand Down Expand Up @@ -716,7 +716,7 @@ func benchmarkFib(b *testing.B, arg int, with_super_instructions bool) {
example := getFibExample()

// Convert example to LFVM format.
converted := convert(example.code, ConversionConfig{WithSuperInstructions: with_super_instructions})
converted := convert(example.code, ConversionConfig{SuperInstructionsEnabled: with_super_instructions})

// Create input data.

Expand Down
Loading

0 comments on commit 7743183

Please sign in to comment.