Skip to content
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

Evm/fourth #85

Open
wants to merge 4 commits into
base: dev
Choose a base branch
from
Open
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
185 changes: 185 additions & 0 deletions execution/evm/account.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,185 @@
package evm
import(
"sync"
"fmt"
"encoding/json"
"reflect")
type Account struct {
Info AccountInfo
Storage EvmStorage
Status AccountStatus
}
type AccountInfo struct {
Balance U256
Nonce uint64
CodeHash 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
type EvmStorageSlot struct {
OriginalValue U256
PresentValue 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

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

View workflow job for this annotation

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

field `once` is unused (unused)
}
type Bitvector struct {
bits []uint8

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

View workflow job for this annotation

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

field `bits` is unused (unused)
size int // Total number of bits represented

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

View workflow job for this annotation

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

field `size` is unused (unused)
}
type Opcode struct {
InitCode Eof `json:"initcode"`
Input Bytes `json:"input"`
CreatedAddress Address `json:"created_address"`
}
type Eof struct {
Header EofHeader `json:"header"`
Body EofBody `json:"body"`
Raw Bytes `json:"raw"`
}

// 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"`
}

// 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>
ContainerSection []Bytes `json:"container_section"` // Using [][]byte for Vec<Bytes>
DataSection Bytes `json:"data_section"` // Using []byte for Bytes
IsDataFilled bool `json:"is_data_filled"`
}

// 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
}

// MarshalJSON customizes the JSON marshalling for EOFCreateKind.
func (e *EOFCreateKind) MarshalJSON() ([]byte, error) {
switch e.Kind {
case TxK:
return json.Marshal(map[string]interface{}{
"type": "Tx",
"data": e.Data,
})
case OpcodeK:
return json.Marshal(map[string]interface{}{
"type": "Opcode",
"data": e.Data,
})
default:
return nil, fmt.Errorf("unknown EOFCreateKind type")
}
}

// UnmarshalJSON customizes the JSON unmarshalling for EOFCreateKind.
func (e *EOFCreateKind) UnmarshalJSON(data []byte) error {
var aux struct {
Type string `json:"type"`
Data json.RawMessage `json:"data"`
}

if err := json.Unmarshal(data, &aux); err != nil {
return err
}

switch aux.Type {
case "Tx":
var tx Tx
if err := json.Unmarshal(aux.Data, &tx); err != nil {
return err
}
e.Kind = TxK
e.Data = tx
case "Opcode":
var opcode Opcode
if err := json.Unmarshal(aux.Data, &opcode); err != nil {
return err
}
e.Kind = OpcodeK
e.Data = opcode
default:
return fmt.Errorf("unknown EOFCreateKind type: %s", aux.Type)
}

return nil
}
170 changes: 170 additions & 0 deletions execution/evm/call_inputs.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,170 @@
package evm
import(
"encoding/json"
)
func (c *CallInputs) New(txEnv *TxEnv, gasLimit uint64) *CallInputs {
// Check if the transaction kind is Call and extract the target address.
if txEnv.TransactTo.Type != Call2 {
return nil
}
targetAddress := txEnv.TransactTo.Address
// Create and return the CallInputs instance.
return &CallInputs{
Input: txEnv.Data,
GasLimit: gasLimit,
TargetAddress: *targetAddress,
BytecodeAddress: *targetAddress, // Set to target_address as in Rust code.
Caller: txEnv.Caller,
Value: CallValue{ValueType: "transfer", Amount: txEnv.Value},
Scheme: ICall, // Assuming CallScheme.Call is represented by Call.
IsStatic: false,
IsEof: false,
ReturnMemoryOffset: Range{Start: 0, End: 0},
}
}
func (c *CallInputs) NewBoxed(txEnv *TxEnv, gasLimit uint64) *CallInputs {
return c.New(txEnv, gasLimit) // Returns a pointer or nil, similar to Option<Box<Self>> in Rust.
}

func (e EOFCreateInputs) NewTx(tx *TxEnv, gasLimit uint64) EOFCreateInputs {
return EOFCreateInputs{
Caller: tx.Caller,
Value: tx.Value,
GasLimit: gasLimit,
Kind: EOFCreateKind{
Kind: TxK,
Data: tx.Data,
},
}
}

func (c *CreateInputs) New(txEnv *TxEnv, gasLimit uint64) *CreateInputs {
if txEnv.TransactTo.Type != Create2 {
return nil
}
return &CreateInputs{
Caller: txEnv.Caller,
Scheme: CreateScheme{
SchemeType: SchemeTypeCreate,
},
Value: txEnv.Value,
InitCode: txEnv.Data,
GasLimit: gasLimit,
}
}

func (c *CreateInputs) NewBoxed(txEnv *TxEnv, gasLimit uint64) *CreateInputs {
return c.New(txEnv, gasLimit)
}

type CallValue struct {
ValueType string `json:"value_type"`
Amount U256 `json:"amount,omitempty"`
}

// Transfer creates a CallValue representing a transfer.
func Transfer(amount U256) CallValue {
return CallValue{ValueType: "transfer", Amount: amount}
}

// Apparent creates a CallValue representing an apparent value.
func Apparent(amount U256) CallValue {
return CallValue{ValueType: "apparent", Amount: amount}
}

type CallScheme int
const (
ICall CallScheme = iota
ICallCode
IDelegateCall
IStaticCall
IExtCall
IExtStaticCall
IExtDelegateCall
)
type CallInputs struct {
Input Bytes `json:"input"`
ReturnMemoryOffset Range `json:"return_memory_offset"`
GasLimit uint64 `json:"gas_limit"`
BytecodeAddress Address `json:"bytecode_address"`
TargetAddress Address `json:"target_address"`
Caller Address `json:"caller"`
Value CallValue `json:"value"`
Scheme CallScheme `json:"scheme"`
IsStatic bool `json:"is_static"`
IsEof bool `json:"is_eof"`
}

// JSON serialization for CallValue
func (cv CallValue) MarshalJSON() ([]byte, error) {
return json.Marshal(struct {
ValueType string `json:"value_type"`
Amount *U256 `json:"amount,omitempty"`
}{
ValueType: cv.ValueType,
Amount: &cv.Amount,
})
}

// JSON deserialization for CallValue
func (cv *CallValue) UnmarshalJSON(data []byte) error {
var aux struct {
ValueType string `json:"value_type"`
Amount *U256 `json:"amount,omitempty"`
}
if err := json.Unmarshal(data, &aux); err != nil {
return err
}
cv.ValueType = aux.ValueType
if aux.ValueType == "transfer" {
cv.Amount = *aux.Amount
} else if aux.ValueType == "apparent" {
cv.Amount = *aux.Amount
}
return nil
}

type CreateInputs struct {
Caller Address `json:"caller"`
Scheme CreateScheme `json:"scheme"`
Value U256 `json:"value"`
InitCode Bytes `json:"init_code"`
GasLimit uint64 `json:"gas_limit"`
}
type CreateScheme struct {
SchemeType SchemeType `json:"scheme_type"` // can be "create" or "create2"
Salt *U256 `json:"salt,omitempty"` // salt is optional for Create
}

// SchemeType represents the type of creation scheme
type SchemeType int

const (
SchemeTypeCreate SchemeType = iota
SchemeTypeCreate2
)

type EOFCreateKindType int

const (
TxK EOFCreateKindType = iota
OpcodeK
)

// / Inputs for EOF create call.
type EOFCreateInputs struct {
Caller Address `json:"caller"`
Value U256 `json:"value"`
GasLimit uint64 `json:"gas_limit"`
Kind EOFCreateKind `json:"kind"`
}

type EOFCreateKind struct {
Kind EOFCreateKindType
Data interface{} // Use an interface to hold the associated data (Tx or Opcode)
}

// TxKind represents a transaction-based EOF create kind.
type Tx struct {
InitData Bytes `json:"initdata"`
}
11 changes: 11 additions & 0 deletions execution/evm/common.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
package evm
import(
"github.com/BlocSoc-iitr/selene/common"
Common "github.com/ethereum/go-ethereum/common"
"math/big"
)
type BlockTag = common.BlockTag
type U256 = *big.Int
type B256 = Common.Hash
type Address = common.Address
type Bytes=[]byte
Loading
Loading