Skip to content

Add Test for EVM #91

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 13 commits into
base: dev
Choose a base branch
from
164 changes: 164 additions & 0 deletions execution/evm/account.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,164 @@
package evm

import (
"encoding/json"

"reflect"
"sync"
)

type Account struct {
Info AccountInfo
Storage EvmStorage
Status AccountStatus
}
type AccountInfo struct {
Balance U256

Check failure on line 16 in execution/evm/account.go

View workflow job for this annotation

GitHub Actions / build (1.22.3)

undefined: U256

Check failure on line 16 in execution/evm/account.go

View workflow job for this annotation

GitHub Actions / test

undefined: U256

Check failure on line 16 in execution/evm/account.go

View workflow job for this annotation

GitHub Actions / golangci-lint (/home/runner/work/selene/selene)

undefined: U256
Nonce uint64
CodeHash B256

Check failure on line 18 in execution/evm/account.go

View workflow job for this annotation

GitHub Actions / build (1.22.3)

undefined: B256

Check failure on line 18 in execution/evm/account.go

View workflow job for this annotation

GitHub Actions / test

undefined: B256

Check failure on line 18 in execution/evm/account.go

View workflow job for this annotation

GitHub Actions / golangci-lint (/home/runner/work/selene/selene)

undefined: B256
Code *Bytecode
}

func NewAccountInfo(balance U256, nonce uint64, codeHash B256, code Bytecode) AccountInfo {
return AccountInfo{
Balance: balance,
Nonce: nonce,
CodeHash: codeHash,
Code: &code,
}
}

type EvmStorage map[U256]EvmStorageSlot

Check failure on line 31 in execution/evm/account.go

View workflow job for this annotation

GitHub Actions / build (1.22.3)

undefined: U256

Check failure on line 31 in execution/evm/account.go

View workflow job for this annotation

GitHub Actions / test

undefined: U256

Check failure on line 31 in execution/evm/account.go

View workflow job for this annotation

GitHub Actions / golangci-lint (/home/runner/work/selene/selene)

undefined: U256
type EvmStorageSlot struct {
OriginalValue U256

Check failure on line 33 in execution/evm/account.go

View workflow job for this annotation

GitHub Actions / build (1.22.3)

undefined: U256

Check failure on line 33 in execution/evm/account.go

View workflow job for this annotation

GitHub Actions / test

undefined: U256

Check failure on line 33 in execution/evm/account.go

View workflow job for this annotation

GitHub Actions / golangci-lint (/home/runner/work/selene/selene)

undefined: U256
PresentValue U256

Check failure on line 34 in execution/evm/account.go

View workflow job for this annotation

GitHub Actions / build (1.22.3)

undefined: U256

Check failure on line 34 in execution/evm/account.go

View workflow job for this annotation

GitHub Actions / test

undefined: U256

Check failure on line 34 in execution/evm/account.go

View workflow job for this annotation

GitHub Actions / golangci-lint (/home/runner/work/selene/selene)

undefined: U256
IsCold bool
}
type AccountStatus uint8

const (
Loaded AccountStatus = 0b00000000 // Account is loaded but not interacted with
Created AccountStatus = 0b00000001 // Account is newly created, no DB fetch required
SelfDestructed AccountStatus = 0b00000010 // Account is marked for self-destruction
Touched AccountStatus = 0b00000100 // Account is touched and will be saved to DB
LoadedAsNotExisting AccountStatus = 0b0001000 // Pre-spurious state; account loaded but marked as non-existing
Cold AccountStatus = 0b0010000 // Account is marked as cold (not frequently accessed)
)

type BytecodeKind int

const (
LegacyRawKind BytecodeKind = iota
LegacyAnalyzedKind
EofKind
)

// BytecodeKind serves as discriminator for Bytecode to identify which variant of enum is being used
// 1 , 2 or 3 in this case
type Bytecode struct {
Kind BytecodeKind
LegacyRaw []byte // For LegacyRaw variant
LegacyAnalyzed *LegacyAnalyzedBytecode // For LegacyAnalyzed variant
Eof *Eof // For Eof variant
}
type LegacyAnalyzedBytecode struct {
Bytecode []byte
OriginalLen uint64
JumpTable JumpTable
}

// JumpTable equivalent in Go, using a sync.Once pointer to simulate Arc and BitVec<u8>.
type JumpTable struct {
BitVector *Bitvector // Simulating BitVec<u8> as []byte
Once sync.Once // Lazy initialization if needed
}
type Bitvector struct {
Bits []uint8
Size int // Total number of bits represented
}
type Opcode struct {
InitCode Eof `json:"initcode"`
Input Bytes `json:"input"`

Check failure on line 81 in execution/evm/account.go

View workflow job for this annotation

GitHub Actions / build (1.22.3)

undefined: Bytes

Check failure on line 81 in execution/evm/account.go

View workflow job for this annotation

GitHub Actions / test

undefined: Bytes

Check failure on line 81 in execution/evm/account.go

View workflow job for this annotation

GitHub Actions / golangci-lint (/home/runner/work/selene/selene)

undefined: Bytes
CreatedAddress Address `json:"created_address"`
}

func (o *Opcode) UnmarshalJSON(data []byte) error {
return unmarshalJSON(data, o)
}

type Eof struct {
Header EofHeader `json:"header"`
Body EofBody `json:"body"`
Raw Bytes `json:"raw"`

Check failure on line 92 in execution/evm/account.go

View workflow job for this annotation

GitHub Actions / build (1.22.3)

undefined: Bytes

Check failure on line 92 in execution/evm/account.go

View workflow job for this annotation

GitHub Actions / test

undefined: Bytes

Check failure on line 92 in execution/evm/account.go

View workflow job for this annotation

GitHub Actions / golangci-lint (/home/runner/work/selene/selene)

undefined: Bytes
}

func (e *Eof) UnmarshalJSON(data []byte) error {
return unmarshalJSON(data, e)
}

// EofHeader represents the header of the EOF.
type EofHeader struct {
TypesSize uint16 `json:"types_size"`
CodeSizes []uint16 `json:"code_sizes"`
ContainerSizes []uint16 `json:"container_sizes"`
DataSize uint16 `json:"data_size"`
SumCodeSizes int `json:"sum_code_sizes"`
SumContainerSizes int `json:"sum_container_sizes"`
}

func (e *EofHeader) UnmarshalJSON(data []byte) error {
return unmarshalJSON(data, e)
}

// Marshaler interface for custom marshaling
type Marshaler interface {
MarshalType(val reflect.Value, b []byte, lastWrittenIdx uint64) (nextIdx uint64, err error)
}

// Unmarshaler interface for custom unmarshaling
type Unmarshaler interface {
UnmarshalType(target reflect.Value, b []byte, lastReadIdx uint64) (nextIdx uint64, err error)
}

// Implement Marshaler for EOFCreateInputs
func (eci EOFCreateInputs) MarshalType(val reflect.Value, b []byte, lastWrittenIdx uint64) (nextIdx uint64, err error) {
jsonData, err := json.Marshal(eci)
if err != nil {
return lastWrittenIdx, err
}

return uint64(len(jsonData)), nil
}

// Implement Unmarshaler for EOFCreateInputs
func (eci *EOFCreateInputs) UnmarshalType(target reflect.Value, b []byte, lastReadIdx uint64) (nextIdx uint64, err error) {
err = json.Unmarshal(b, eci)
if err != nil {
return lastReadIdx, err
}

return lastReadIdx + uint64(len(b)), nil
}

type EofBody struct {
TypesSection []TypesSection `json:"types_section"`
CodeSection []Bytes `json:"code_section"` // Using [][]byte for Vec<Bytes>

Check failure on line 145 in execution/evm/account.go

View workflow job for this annotation

GitHub Actions / build (1.22.3)

undefined: Bytes

Check failure on line 145 in execution/evm/account.go

View workflow job for this annotation

GitHub Actions / test

undefined: Bytes

Check failure on line 145 in execution/evm/account.go

View workflow job for this annotation

GitHub Actions / golangci-lint (/home/runner/work/selene/selene)

undefined: Bytes
ContainerSection []Bytes `json:"container_section"` // Using [][]byte for Vec<Bytes>

Check failure on line 146 in execution/evm/account.go

View workflow job for this annotation

GitHub Actions / build (1.22.3)

undefined: Bytes

Check failure on line 146 in execution/evm/account.go

View workflow job for this annotation

GitHub Actions / test

undefined: Bytes

Check failure on line 146 in execution/evm/account.go

View workflow job for this annotation

GitHub Actions / golangci-lint (/home/runner/work/selene/selene)

undefined: Bytes
DataSection Bytes `json:"data_section"` // Using []byte for Bytes

Check failure on line 147 in execution/evm/account.go

View workflow job for this annotation

GitHub Actions / build (1.22.3)

undefined: Bytes

Check failure on line 147 in execution/evm/account.go

View workflow job for this annotation

GitHub Actions / test

undefined: Bytes

Check failure on line 147 in execution/evm/account.go

View workflow job for this annotation

GitHub Actions / golangci-lint (/home/runner/work/selene/selene)

undefined: Bytes
IsDataFilled bool `json:"is_data_filled"`
}

func (e *EofBody) UnmarshalJSON(data []byte) error {
return unmarshalJSON(data, e)
}

// TypesSection represents a section describing the types used in the EOF body.
type TypesSection struct {
Inputs uint8 `json:"inputs"` // 1 byte
Outputs uint8 `json:"outputs"` // 1 byte
MaxStackSize uint16 `json:"max_stack_size"` // 2 bytes
}

func (t *TypesSection) UnmarshalJSON(data []byte) error {
return unmarshalJSON(data, t)
}
162 changes: 162 additions & 0 deletions execution/evm/account_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,162 @@
package evm

import (
"encoding/hex"
"encoding/json"
"reflect"
"testing"
)

// Test case structure for unmarshaling JSON data
type TestCase struct {
name string
input string
expected Opcode
hasError bool
}

func TestOpcodeUnmarshalJSON(t *testing.T) {
testCases := []TestCase{
{
name: "Valid JSON",
input: `{
"initcode": {
"header": {
"types_size": "0xa",
"code_sizes": ["0x14", "0x1e"],
"container_sizes": ["0x28", "0x32"],
"data_size": "0x3c",
"sum_code_sizes": "0x46",
"sum_container_sizes": "0x50"
},
"body": {
"types_section": [
{
"inputs": "0x1",
"outputs": "0x2",
"max_stack_size": "0x200"
}
],
"code_section": ["0x010203"],
"container_section": ["0x040506"],
"data_section": "0x070809",
"is_data_filled": true
},
"raw": "0x010203"
},
"created_address": "0x1234567890abcdef1234567890abcdef12345678",
"input": "0x1234567890abcdef1234567890abcdef12345678"
}`,
expected: Opcode{
InitCode: Eof{
Header: EofHeader{
TypesSize: 10,
CodeSizes: []uint16{20, 30},
ContainerSizes: []uint16{40, 50},
DataSize: 60,
SumCodeSizes: 70,
SumContainerSizes: 80,
},
Body: EofBody{
TypesSection: []TypesSection{
{Inputs: 1, Outputs: 2, MaxStackSize: 512},
},
CodeSection: [][]byte{hexToBytes("0x010203")},
ContainerSection: [][]byte{hexToBytes("0x040506")},
DataSection: hexToBytes("0x070809"),
IsDataFilled: true,
},
Raw: hexToBytes("0x010203"),
},
CreatedAddress: Address{
Addr: parseHexAddress("0x1234567890abcdef1234567890abcdef12345678"),
},
Input: hexToBytes("0x1234567890abcdef1234567890abcdef12345678"),
},
hasError: false,
},
{
name: "Invalid JSON",
input: `{
"initcode": {
"header": {
"types_size": "not_a_number",
"code_sizes": ["20", "30"],
"container_sizes": ["40", "50"],
"data_size": "60",
"sum_code_sizes": "70",
"sum_container_sizes": "80"
},
"body": {
"types_section": [
{"inputs": 1, "outputs": 2, "max_stack_size": "512"}
],
"code_section": ["0x010203"],
"container_section": ["0x040506"],
"data_section": "0x070809",
"is_data_filled": true
},
"raw": "0x010203"
},
"created_address": "0x1234567890abcdef1234567890abcdef12345678",
"input": "0x1234567890abcdef1234567890abcdef12345678"
}`,
expected: Opcode{},
hasError: true,
},
}

for _, tc := range testCases {
t.Run(tc.name, func(t *testing.T) {
var opcode Opcode
err := json.Unmarshal([]byte(tc.input), &opcode)

if (err != nil) != tc.hasError {
t.Errorf("expected error: %v, got: %v", tc.hasError, err)
}
if !tc.hasError && !compareOpcodes(opcode, tc.expected) {
t.Errorf("expected: %+v, got: %+v", tc.expected, opcode)
}
})
}
}

func hexToBytes(hexStr string) []byte {
bytes, err := hex.DecodeString(hexStr[2:])
if err != nil {
return nil
}
return bytes
}
func parseHexAddress(hexStr string) [20]byte {
var addr [20]byte
bytes, _ := hex.DecodeString(hexStr[2:])
copy(addr[:], bytes)
return addr
}
func compareOpcodes(a, b Opcode) bool {
return compareEof(a.InitCode, b.InitCode) && a.CreatedAddress == b.CreatedAddress && reflect.DeepEqual(a.Input, b.Input)
}
func compareEof(a, b Eof) bool {
return compareEofHeader(a.Header, b.Header) &&
compareEofBody(a.Body, b.Body) &&
reflect.DeepEqual(a.Raw, b.Raw)
}

func compareEofHeader(a, b EofHeader) bool {
return a.TypesSize == b.TypesSize &&
reflect.DeepEqual(a.CodeSizes, b.CodeSizes) &&
reflect.DeepEqual(a.ContainerSizes, b.ContainerSizes) &&
a.DataSize == b.DataSize &&
a.SumCodeSizes == b.SumCodeSizes &&
a.SumContainerSizes == b.SumContainerSizes
}

// Comparison function for EofBody struct
func compareEofBody(a, b EofBody) bool {
return reflect.DeepEqual(a.TypesSection, b.TypesSection) &&
reflect.DeepEqual(a.CodeSection, b.CodeSection) &&
reflect.DeepEqual(a.ContainerSection, b.ContainerSection) &&
reflect.DeepEqual(a.DataSection, b.DataSection) &&
a.IsDataFilled == b.IsDataFilled
}
Loading
Loading