Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
14 changes: 3 additions & 11 deletions cannon/cmd/load_elf.go
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ import (
var (
LoadELFVMTypeFlag = &cli.StringFlag{
Name: "type",
Usage: "VM type to create state for. Valid options: " + openum.EnumString(stateVersions()),
Usage: "VM type to create state for. Valid options: " + openum.EnumString(versions.GetStateVersionStrings()),
Required: true,
}
LoadELFPathFlag = &cli.PathFlag{
Expand All @@ -43,14 +43,6 @@ var (
}
)

func stateVersions() []string {
vers := make([]string, len(versions.StateVersionTypes))
for i, v := range versions.StateVersionTypes {
vers[i] = v.String()
}
return vers
}

func LoadELF(ctx *cli.Context) error {
elfPath := ctx.Path(LoadELFPathFlag.Name)
elfProgram, err := elf.Open(elfPath)
Expand All @@ -69,7 +61,7 @@ func LoadELF(ctx *cli.Context) error {
return err
}
switch ver {
case versions.VersionSingleThreaded2:
case versions.GetCurrentSingleThreaded():
createInitialState = func(f *elf.File) (mipsevm.FPVMState, error) {
return program.LoadELF(f, singlethreaded.CreateInitialState)
}
Expand All @@ -80,7 +72,7 @@ func LoadELF(ctx *cli.Context) error {
}
return program.PatchStack(state)
}
case versions.VersionMultiThreaded_v2, versions.VersionMultiThreaded64_v3:
case versions.GetCurrentMultiThreaded(), versions.GetCurrentMultiThreaded64():
createInitialState = func(f *elf.File) (mipsevm.FPVMState, error) {
return program.LoadELF(f, multithreaded.CreateInitialState)
}
Expand Down
6 changes: 2 additions & 4 deletions cannon/mipsevm/versions/detect.go
Original file line number Diff line number Diff line change
Expand Up @@ -26,10 +26,8 @@ func DetectVersion(path string) (StateVersion, error) {
return 0, err
}

switch ver {
case VersionSingleThreaded, VersionMultiThreaded, VersionSingleThreaded2, VersionMultiThreaded64, VersionMultiThreaded64_v2, VersionMultiThreaded_v2, VersionMultiThreaded64_v3:
return ver, nil
default:
if !IsValidStateVersion(ver) {
return 0, fmt.Errorf("%w: %d", ErrUnknownVersion, ver)
}
return ver, nil
}
6 changes: 3 additions & 3 deletions cannon/mipsevm/versions/detect_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -50,7 +50,7 @@ func TestDetectVersion_fromFile(t *testing.T) {

// Check that the latest supported versions write new states in a way that is detected correctly
func TestDetectVersion_singleThreadedBinary(t *testing.T) {
targetVersion := VersionSingleThreaded2
targetVersion := GetCurrentSingleThreaded()
if !arch.IsMips32 {
t.Skip("Single-threaded states are not supported for 64-bit VMs")
}
Expand All @@ -64,9 +64,9 @@ func TestDetectVersion_singleThreadedBinary(t *testing.T) {
}

func TestDetectVersion_multiThreadedBinary(t *testing.T) {
targetVersion := VersionMultiThreaded_v2
targetVersion := GetCurrentMultiThreaded()
if !arch.IsMips32 {
targetVersion = VersionMultiThreaded64_v3
targetVersion = GetCurrentMultiThreaded64()
}

state, err := NewFromState(multithreaded.CreateEmptyState())
Expand Down
76 changes: 6 additions & 70 deletions cannon/mipsevm/versions/state.go
Original file line number Diff line number Diff line change
Expand Up @@ -14,34 +14,12 @@ import (
"github.com/ethereum-optimism/optimism/op-service/serialize"
)

type StateVersion uint8

const (
// VersionSingleThreaded is the version of the Cannon STF found in op-contracts/v1.6.0 - https://github.com/ethereum-optimism/optimism/blob/op-contracts/v1.6.0/packages/contracts-bedrock/src/cannon/MIPS.sol
VersionSingleThreaded StateVersion = iota
// VersionMultiThreaded is the original implementation of 32-bit multithreaded cannon, tagged at cannon/v1.3.0
VersionMultiThreaded
// VersionSingleThreaded2 is based on VersionSingleThreaded with the addition of support for fcntl(F_GETFD) syscall
// This is the latest 32-bit single-threaded vm
VersionSingleThreaded2
// VersionMultiThreaded64 is the original 64-bit MTCannon implementation (pre-audit), tagged at cannon/v1.2.0
VersionMultiThreaded64
// VersionMultiThreaded64_v2 includes an audit fix to ensure futex values are always 32-bit, tagged at cannon/v1.3.0
VersionMultiThreaded64_v2
// VersionMultiThreaded_v2 is the latest 32-bit multithreaded vm
VersionMultiThreaded_v2
// VersionMultiThreaded64_v3 is the latest 64-bit multithreaded vm
VersionMultiThreaded64_v3
)

var (
ErrUnknownVersion = errors.New("unknown version")
ErrJsonNotSupported = errors.New("json not supported")
ErrUnsupportedMipsArch = errors.New("mips architecture is not supported")
)

var StateVersionTypes = []StateVersion{VersionSingleThreaded, VersionMultiThreaded, VersionSingleThreaded2, VersionMultiThreaded64, VersionMultiThreaded64_v2, VersionMultiThreaded_v2, VersionMultiThreaded64_v3}

func LoadStateFromFile(path string) (*VersionedState, error) {
if !serialize.IsBinaryFile(path) {
// Always use singlethreaded for JSON states
Expand All @@ -61,18 +39,18 @@ func NewFromState(state mipsevm.FPVMState) (*VersionedState, error) {
return nil, ErrUnsupportedMipsArch
}
return &VersionedState{
Version: VersionSingleThreaded2,
Version: GetCurrentSingleThreaded(),
FPVMState: state,
}, nil
case *multithreaded.State:
if arch.IsMips32 {
return &VersionedState{
Version: VersionMultiThreaded_v2,
Version: GetCurrentMultiThreaded(),
FPVMState: state,
}, nil
} else {
return &VersionedState{
Version: VersionMultiThreaded64_v3,
Version: GetCurrentMultiThreaded64(),
FPVMState: state,
}, nil
}
Expand Down Expand Up @@ -103,7 +81,7 @@ func (s *VersionedState) Deserialize(in io.Reader) error {
}

switch s.Version {
case VersionSingleThreaded2:
case GetCurrentSingleThreaded():
if !arch.IsMips32 {
return ErrUnsupportedMipsArch
}
Expand All @@ -113,7 +91,7 @@ func (s *VersionedState) Deserialize(in io.Reader) error {
}
s.FPVMState = state
return nil
case VersionMultiThreaded_v2:
case GetCurrentMultiThreaded():
if !arch.IsMips32 {
return ErrUnsupportedMipsArch
}
Expand All @@ -123,7 +101,7 @@ func (s *VersionedState) Deserialize(in io.Reader) error {
}
s.FPVMState = state
return nil
case VersionMultiThreaded64_v3:
case GetCurrentMultiThreaded64():
if arch.IsMips32 {
return ErrUnsupportedMipsArch
}
Expand All @@ -149,45 +127,3 @@ func (s *VersionedState) MarshalJSON() ([]byte, error) {
}
return json.Marshal(s.FPVMState)
}

func (s StateVersion) String() string {
switch s {
case VersionSingleThreaded:
return "singlethreaded"
case VersionMultiThreaded:
return "multithreaded"
case VersionSingleThreaded2:
return "singlethreaded-2"
case VersionMultiThreaded64:
return "multithreaded64"
case VersionMultiThreaded64_v2:
return "multithreaded64-2"
case VersionMultiThreaded_v2:
return "multithreaded-2"
case VersionMultiThreaded64_v3:
return "multithreaded64-3"
default:
return "unknown"
}
}

func ParseStateVersion(ver string) (StateVersion, error) {
switch ver {
case "singlethreaded":
return VersionSingleThreaded, nil
case "multithreaded":
return VersionMultiThreaded, nil
case "singlethreaded-2":
return VersionSingleThreaded2, nil
case "multithreaded64":
return VersionMultiThreaded64, nil
case "multithreaded64-2":
return VersionMultiThreaded64_v2, nil
case "multithreaded-2":
return VersionMultiThreaded_v2, nil
case "multithreaded64-3":
return VersionMultiThreaded64_v3, nil
default:
return StateVersion(0), errors.New("unknown state version")
}
}
4 changes: 2 additions & 2 deletions cannon/mipsevm/versions/state64_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ func TestNewFromState(t *testing.T) {
actual, err := NewFromState(multithreaded.CreateEmptyState())
require.NoError(t, err)
require.IsType(t, &multithreaded.State{}, actual.FPVMState)
require.Equal(t, VersionMultiThreaded64_v3, actual.Version)
require.Equal(t, GetCurrentMultiThreaded64(), actual.Version)
})
}

Expand All @@ -40,7 +40,7 @@ func TestVersionsOtherThanZeroDoNotSupportJSON(t *testing.T) {
version StateVersion
createState func() mipsevm.FPVMState
}{
{VersionMultiThreaded64_v3, func() mipsevm.FPVMState { return multithreaded.CreateEmptyState() }},
{GetCurrentMultiThreaded64(), func() mipsevm.FPVMState { return multithreaded.CreateEmptyState() }},
}
for _, test := range tests {
test := test
Expand Down
18 changes: 4 additions & 14 deletions cannon/mipsevm/versions/state_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -20,14 +20,14 @@ func TestNewFromState(t *testing.T) {
actual, err := NewFromState(singlethreaded.CreateEmptyState())
require.NoError(t, err)
require.IsType(t, &singlethreaded.State{}, actual.FPVMState)
require.Equal(t, VersionSingleThreaded2, actual.Version)
require.Equal(t, GetCurrentSingleThreaded(), actual.Version)
})

t.Run("multithreaded-latestVersion", func(t *testing.T) {
actual, err := NewFromState(multithreaded.CreateEmptyState())
require.NoError(t, err)
require.IsType(t, &multithreaded.State{}, actual.FPVMState)
require.Equal(t, VersionMultiThreaded_v2, actual.Version)
require.Equal(t, GetCurrentMultiThreaded(), actual.Version)
})
}

Expand Down Expand Up @@ -58,8 +58,8 @@ func TestVersionsOtherThanZeroDoNotSupportJSON(t *testing.T) {
version StateVersion
createState func() mipsevm.FPVMState
}{
{VersionSingleThreaded2, func() mipsevm.FPVMState { return singlethreaded.CreateEmptyState() }},
{VersionMultiThreaded_v2, func() mipsevm.FPVMState { return multithreaded.CreateEmptyState() }},
{GetCurrentSingleThreaded(), func() mipsevm.FPVMState { return singlethreaded.CreateEmptyState() }},
{GetCurrentMultiThreaded(), func() mipsevm.FPVMState { return multithreaded.CreateEmptyState() }},
}
for _, test := range tests {
test := test
Expand All @@ -75,16 +75,6 @@ func TestVersionsOtherThanZeroDoNotSupportJSON(t *testing.T) {
}
}

func TestParseStateVersion(t *testing.T) {
for _, version := range StateVersionTypes {
t.Run(version.String(), func(t *testing.T) {
result, err := ParseStateVersion(version.String())
require.NoError(t, err)
require.Equal(t, version, result)
})
}
}

func writeToFile(t *testing.T, filename string, data serialize.Serializable) string {
dir := t.TempDir()
path := filepath.Join(dir, filename)
Expand Down
105 changes: 105 additions & 0 deletions cannon/mipsevm/versions/version.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,105 @@
package versions

import (
"errors"
"slices"
)

type StateVersion uint8

const (
// VersionSingleThreaded is the version of the Cannon STF found in op-contracts/v1.6.0 - https://github.com/ethereum-optimism/optimism/blob/op-contracts/v1.6.0/packages/contracts-bedrock/src/cannon/MIPS.sol
VersionSingleThreaded StateVersion = iota
// VersionMultiThreaded is the original implementation of 32-bit multithreaded cannon, tagged at cannon/v1.3.0
VersionMultiThreaded
// VersionSingleThreaded2 is based on VersionSingleThreaded with the addition of support for fcntl(F_GETFD) syscall
// This is the latest 32-bit single-threaded vm
VersionSingleThreaded2
// VersionMultiThreaded64 is the original 64-bit MTCannon implementation (pre-audit), tagged at cannon/v1.2.0
VersionMultiThreaded64
// VersionMultiThreaded64_v2 includes an audit fix to ensure futex values are always 32-bit, tagged at cannon/v1.3.0
VersionMultiThreaded64_v2
// VersionMultiThreaded_v2 is the latest 32-bit multithreaded vm
VersionMultiThreaded_v2
// VersionMultiThreaded64_v3 is the latest 64-bit multithreaded vm
VersionMultiThreaded64_v3
)

var StateVersionTypes = []StateVersion{
VersionSingleThreaded,
VersionMultiThreaded,
VersionSingleThreaded2,
VersionMultiThreaded64,
VersionMultiThreaded64_v2,
VersionMultiThreaded_v2,
VersionMultiThreaded64_v3,
}

func (s StateVersion) String() string {
switch s {
case VersionSingleThreaded:
return "singlethreaded"
case VersionMultiThreaded:
return "multithreaded"
case VersionSingleThreaded2:
return "singlethreaded-2"
case VersionMultiThreaded64:
return "multithreaded64"
case VersionMultiThreaded64_v2:
return "multithreaded64-2"
case VersionMultiThreaded_v2:
return "multithreaded-2"
case VersionMultiThreaded64_v3:
return "multithreaded64-3"
default:
return "unknown"
}
}

func ParseStateVersion(ver string) (StateVersion, error) {
switch ver {
case "singlethreaded":
return VersionSingleThreaded, nil
case "multithreaded":
return VersionMultiThreaded, nil
case "singlethreaded-2":
return VersionSingleThreaded2, nil
case "multithreaded64":
return VersionMultiThreaded64, nil
case "multithreaded64-2":
return VersionMultiThreaded64_v2, nil
case "multithreaded-2":
return VersionMultiThreaded_v2, nil
case "multithreaded64-3":
return VersionMultiThreaded64_v3, nil
default:
return StateVersion(0), errors.New("unknown state version")
}
}

func IsValidStateVersion(ver StateVersion) bool {
return slices.Contains(StateVersionTypes, ver)
}

func GetStateVersionStrings() []string {
vers := make([]string, len(StateVersionTypes))
for i, v := range StateVersionTypes {
vers[i] = v.String()
}
return vers
}

// GetCurrentMultiThreaded64 returns the 64-bit multithreaded VM version that is currently supported
func GetCurrentMultiThreaded64() StateVersion {
return VersionMultiThreaded64_v3
}

// GetCurrentMultiThreaded returns the 32-bit multithreaded VM version that is currently supported
func GetCurrentMultiThreaded() StateVersion {
return VersionMultiThreaded_v2
}

// GetCurrentSingleThreaded returns the 32-bit single-threaded VM version that is currently supported
func GetCurrentSingleThreaded() StateVersion {
return VersionSingleThreaded2
}
17 changes: 17 additions & 0 deletions cannon/mipsevm/versions/version_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
package versions

import (
"testing"

"github.com/stretchr/testify/require"
)

func TestParseStateVersion(t *testing.T) {
for _, version := range StateVersionTypes {
t.Run(version.String(), func(t *testing.T) {
result, err := ParseStateVersion(version.String())
require.NoError(t, err)
require.Equal(t, version, result)
})
}
}
Loading