Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
77 commits
Select commit Hold shift + click to select a range
bd55b27
init simulateV1 method
Akohjesse Jul 24, 2025
8881f7d
simulatev1 wip
Akohjesse Aug 5, 2025
075cd37
complete simulateV1 processblock function, import receipt type
Akohjesse Aug 7, 2025
b7929fa
finalize changes in Apply()
Akohjesse Aug 8, 2025
8400532
add debug logs
Akohjesse Aug 8, 2025
f12fb8a
debug if balance is set
Akohjesse Aug 8, 2025
0aed2e7
remove double pointer
Akohjesse Aug 8, 2025
1c0a77e
remove extra finalise call
Akohjesse Aug 8, 2025
22824ed
prune codebase, add AddLogs
Akohjesse Aug 12, 2025
505131c
Added blockOverrides to simBlock object
philip-morlier Aug 26, 2025
d731135
interative error experiment
philip-morlier Aug 26, 2025
7b67e89
Added normalize utility function to transaction args
philip-morlier Aug 27, 2025
7de6a5d
txArgs logging
philip-morlier Aug 27, 2025
b0cd859
Added normalize to toMessage()
philip-morlier Aug 27, 2025
b67ea8d
added basefee added to context
philip-morlier Aug 27, 2025
60ac312
First experiment with successful build with marshalling logic
philip-morlier Aug 28, 2025
3470b57
Calling Bytes() on logsBloom when marshalling header
philip-morlier Sep 9, 2025
f774ef1
hexutil.Ecode() logBloom byte string to hex string
philip-morlier Sep 9, 2025
d44e804
Uncommented logs types in processBlock
philip-morlier Sep 9, 2025
4b24b7b
Initialize state db logs map
philip-morlier Sep 9, 2025
ee0f0ce
First attempt getting withdrawals through
philip-morlier Sep 10, 2025
9bfb706
Added fd5 config
philip-morlier Sep 17, 2025
2e47bcf
Set waiting = true for null broker
Sep 23, 2025
c494d1b
Updated select in start function, null broker
philip-morlier Sep 24, 2025
01ea092
Added nil check on args.Gas EstimateGas
philip-morlier Oct 1, 2025
0274f6e
added IsOsaka case to chain config rules
philip-morlier Oct 1, 2025
e9b9303
set empty withdrawals
Akohjesse Oct 2, 2025
55bb814
sanitize calls and chain
Akohjesse Oct 2, 2025
0f8ba97
first pass at tracer logs
Akohjesse Oct 2, 2025
8ff51be
add debug logs
Akohjesse Oct 2, 2025
c9a60f2
add tracer debug logs, use txHash
Akohjesse Oct 3, 2025
54d7216
reorder execution flow
Akohjesse Oct 3, 2025
308cbac
set Debug true
Akohjesse Oct 3, 2025
b02bfdd
Attempt to collect logs in capture start
Akohjesse Oct 3, 2025
9e613c2
add log formatting code
Akohjesse Oct 3, 2025
30fe8e5
rearrange tx order
Akohjesse Oct 9, 2025
62b2ad5
use manual defaults for simulate
Akohjesse Oct 9, 2025
ad68ceb
log out transaction params
Akohjesse Oct 9, 2025
43bb8c5
add missing fields
Akohjesse Oct 9, 2025
cdacacc
make gasprice assignment conditional
Akohjesse Oct 9, 2025
1d6ead2
format, fix return fields
Akohjesse Oct 9, 2025
3c4d57c
Update block.go
Akohjesse Oct 9, 2025
1b95c17
fix txHash
Akohjesse Oct 9, 2025
b17965a
attempt to fix parentBeaconRoot
Akohjesse Oct 9, 2025
1ae84c7
implement proper trie hashing
Akohjesse Oct 9, 2025
bc1e2b8
set block size and correct timestamp
Akohjesse Oct 9, 2025
b8aab8b
attempt to fix size and timestamp fields
Akohjesse Oct 9, 2025
8b471af
Update simulate.go
Akohjesse Oct 9, 2025
faf6cab
debug logs inside excessblobgas calculation logic
Akohjesse Oct 9, 2025
7a2bf34
change BlobTxTargetBlobGasPerBlock to represent blob target ** BlobTx…
Akohjesse Oct 9, 2025
a31b567
Merge branch 'hardfork/fusaka' into feature/blockoverrides
Akohjesse Oct 9, 2025
ff86a66
Merge branch 'hardfork/fusaka' into feature/blockoverrides
Akohjesse Oct 13, 2025
0aae305
attempt to resolve baseFee issue
Akohjesse Oct 13, 2025
23750ab
attempt to debug requestHash
Akohjesse Oct 13, 2025
5c26825
Added fd5 config
philip-morlier Sep 17, 2025
fa5bbc7
Removed duplicate fd5 chain config
philip-morlier Oct 13, 2025
30a59ae
Update transaction_args.go
Akohjesse Oct 14, 2025
d0aae2d
add debug logs before setdefaults
Akohjesse Oct 14, 2025
b81e1e6
add logs to statedb and set fakebalance when copying state
Akohjesse Oct 14, 2025
a92640f
add more debug logs
Akohjesse Oct 14, 2025
cb6da86
return balance if fake balance is set
Akohjesse Oct 14, 2025
95c6672
fix maxFeePerGas error
Akohjesse Oct 14, 2025
f7414cd
skip gas estimation
Akohjesse Oct 14, 2025
be3428b
comment out setDefaults
Akohjesse Oct 15, 2025
c1301f9
update simulate.go
Akohjesse Oct 15, 2025
3281105
cap gas at gasPool
Akohjesse Oct 15, 2025
e8b9882
move tracer out of loop
Akohjesse Oct 16, 2025
5c2d6b5
Merge branch 'feature/blockoverrides' into feature/integration-test
Akohjesse Oct 16, 2025
0653c66
simulatev1 integration test
Akohjesse Oct 16, 2025
ec5ff7b
Merge remote-tracking branch 'origin/master' into feature/integration…
philip-morlier Oct 17, 2025
fcd9f6a
Added integration test chain config
philip-morlier Oct 17, 2025
d00dab0
add aggregation logic
Akohjesse Oct 20, 2025
240656b
Added genesis and config for custom genesis data extraction
philip-morlier Oct 20, 2025
537cd0e
Merge branch 'feature/integration-test' into feature/custom-genesis-init
Akohjesse Oct 21, 2025
7c1f493
store genesis block header during init-genesis
Akohjesse Oct 21, 2025
cd049a3
add control data, ignore parentHash
Akohjesse Oct 24, 2025
8896b28
add contract creation and multi state calls to payload
Akohjesse Oct 27, 2025
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
4 changes: 2 additions & 2 deletions api/api_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -67,9 +67,9 @@ func (f TransactionEmitterFunc) Emit(tx *types.Transaction) error {
return f(tx)
}

func newRPCBalance(balance *big.Int) **hexutil.Big {
func newRPCBalance(balance *big.Int) *hexutil.Big {
rpcBalance := (*hexutil.Big)(balance)
return &rpcBalance
return rpcBalance
}

func hex2Bytes(str string) *hexutil.Bytes {
Expand Down
47 changes: 46 additions & 1 deletion api/error.go
Original file line number Diff line number Diff line change
Expand Up @@ -106,6 +106,23 @@ var (

)

const (
errCodeNonceTooHigh = -38011
errCodeNonceTooLow = -38010
errCodeIntrinsicGas = -38013
errCodeInsufficientFunds = -38014
errCodeBlockGasLimitReached = -38015
errCodeBlockNumberInvalid = -38020
errCodeBlockTimestampInvalid = -38021
errCodeSenderIsNotEOA = -38024
errCodeMaxInitCodeSizeExceeded = -38025
errCodeClientLimitExceeded = -38026
errCodeInternalError = -32603
errCodeInvalidParams = -32602
errCodeReverted = -32000
errCodeVMError = -32015
)


// EIP-7702 state transition errors.
// Note these are just informational, and do not cause tx execution abort.
Expand All @@ -115,4 +132,32 @@ var (
ErrAuthorizationInvalidSignature = errors.New("EIP-7702 authorization has invalid signature")
ErrAuthorizationDestinationHasCode = errors.New("EIP-7702 authorization destination is a contract")
ErrAuthorizationNonceMismatch = errors.New("EIP-7702 authorization nonce does not match current account nonce")
)
)

type callError struct {
Message string `json:"message"`
Code int `json:"code"`
Data string `json:"data,omitempty"`
}

type invalidParamsError struct{ message string }

func (e *invalidParamsError) Error() string { return e.message }
func (e *invalidParamsError) ErrorCode() int { return errCodeInvalidParams }

type clientLimitExceededError struct{ message string }

type invalidBlockNumberError struct{ message string }
func (e *invalidBlockNumberError) Error() string { return e.message }
func (e *invalidBlockNumberError) ErrorCode() int { return errCodeBlockNumberInvalid }

type invalidBlockTimestampError struct{ message string }
func (e *invalidBlockTimestampError) Error() string { return e.message }

func (e *clientLimitExceededError) Error() string { return e.message }
func (e *clientLimitExceededError) ErrorCode() int { return errCodeClientLimitExceeded }

type blockGasLimitReachedError struct{ message string }

func (e *blockGasLimitReachedError) Error() string { return e.message }
func (e *blockGasLimitReachedError) ErrorCode() int { return errCodeBlockGasLimitReached }
85 changes: 83 additions & 2 deletions api/eth.go
Original file line number Diff line number Diff line change
Expand Up @@ -133,7 +133,7 @@ func (s *PublicBlockChainAPI) GetStorageAt(ctx *rpc.CallContext, address common.
type OverrideAccount struct {
Nonce *hexutil.Uint64 `json:"nonce"`
Code *hexutil.Bytes `json:"code"`
Balance **hexutil.Big `json:"balance"`
Balance *hexutil.Big `json:"balance"`
State *map[ctypes.Hash]ctypes.Hash `json:"state"`
StateDiff *map[ctypes.Hash]ctypes.Hash `json:"stateDiff"`
}
Expand Down Expand Up @@ -176,7 +176,7 @@ func (diff *StateOverride) Apply(state state.StateDB) error {
}
// Override account balance.
if account.Balance != nil {
state.SetBalance(addr, (*big.Int)(*account.Balance))
state.SetBalance(addr, (*big.Int)(account.Balance))
}
if account.State != nil && account.StateDiff != nil {
return fmt.Errorf("account %s has both 'state' and 'stateDiff'", addr.Hex())
Expand All @@ -192,9 +192,35 @@ func (diff *StateOverride) Apply(state state.StateDB) error {
}
}
}

// Now finalize the changes. Finalize is normally performed between transactions.
// By using finalize, the overrides are semantically behaving as
// if they were created in a transaction just before the tracing occur.
state.Finalise()
return nil
}

func applyMessageWithEVM(ctx *rpc.CallContext, evm *vm.EVM, msg *Msg, timeout time.Duration, gp *GasPool) (*ExecutionResult, error) {
// Wait for the context to be done and cancel the evm. Even if the
// EVM has finished, cancelling may be done (repeatedly)
go func() {
<-ctx.Context().Done()
evm.Cancel()
}()

// Execute the message.
result, err := ApplyMessage(evm, msg, gp)

// If the timer caused an abort, return an appropriate error message
if evm.Cancelled() {
return nil, fmt.Errorf("execution aborted (timeout = %v)", timeout)
}
if err != nil {
return result, fmt.Errorf("err: %w (supplied gas %d)", err, msg.gasLimit)
}
return result, nil
}

func DoCall(cctx *rpc.CallContext, getEVM func(state.StateDB, *vm.Config, common.Address, *big.Int) *vm.EVM, args TransactionArgs, prevState *PreviousState, blockNrOrHash vm.BlockNumberOrHash, overrides *StateOverride, timeout time.Duration, globalGasCap uint64) (*ExecutionResult, *PreviousState, error) {
defer func(start time.Time) { log.Debug("Executing EVM call finished", "runtime", time.Since(start)) }(time.Now())
if prevState == nil || prevState.header == nil || prevState.state == nil {
Expand Down Expand Up @@ -340,6 +366,61 @@ func (s *PublicBlockChainAPI) Call(ctx *rpc.CallContext, args TransactionArgs, b
return res, err
}

// SimulateV1 executes series of transactions on top of a base state.
// The transactions are packed into blocks. For each block, block header
// fields can be overridden. The state can also be overridden prior to
// execution of each block.
//
// Note, this function doesn't make any changes in the state/blockchain and is
// useful to execute and retrieve values.
func (s *PublicBlockChainAPI) SimulateV1(ctx *rpc.CallContext, opts simOpts, blockNrOrHash *vm.BlockNumberOrHash) ([]*simBlockResult, error) {
if len(opts.BlockStateCalls) == 0 {
return nil, &invalidParamsError{message: "empty input"}
} else if len(opts.BlockStateCalls) > maxSimulateBlocks {
return nil, &clientLimitExceededError{message: "too many blocks"}
}

bNrOrHash := vm.BlockNumberOrHashWithNumber(rpc.PendingBlockNumber)
if blockNrOrHash != nil {
bNrOrHash = *blockNrOrHash
}

var results []*simBlockResult

err := s.evmmgr.View(bNrOrHash, &vm.Config{NoBaseFee: !opts.Validation}, ctx, func(statedb state.StateDB, baseHeader *types.Header, evmFn func(state.StateDB, *vm.Config, common.Address, *big.Int) *vm.EVM, chaincfg *params.ChainConfig) error {
gasCap := s.gasLimit(baseHeader)
if gasCap == 0 {
gasCap = math.MaxUint64
}

sim := &simulator{
timeout: 30 * time.Second,
state: statedb.Copy(),
base: types.CopyHeader(baseHeader),
chainConfig: chaincfg,
// Each tx and all the series of txes shouldn't consume more gas than cap
gp: new(GasPool).AddGas(gasCap),
traceTransfers: opts.TraceTransfers,
validate: opts.Validation,
fullTx: opts.ReturnFullTransactions,
evmFn: evmFn,
}
var err error
results, err = sim.execute(ctx, opts.BlockStateCalls)
return err
})

if err != nil {
switch err.(type) {
case codedError:
default:
err = evmError{err}
}
return nil, err
}
return results, nil
}

//
type estimateGasError struct {
error string // Concrete error type if it's failed to estimate gas usage
Expand Down
87 changes: 87 additions & 0 deletions api/logtracer.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,87 @@
package api

import (
"math/big"
"time"

"github.com/openrelayxyz/cardinal-evm/common"
"github.com/openrelayxyz/cardinal-evm/types"
"github.com/openrelayxyz/cardinal-evm/vm"
ctypes "github.com/openrelayxyz/cardinal-types"
)

var (
// keccak256("Transfer(address,address,uint256)")
transferTopic = ctypes.HexToHash("ddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef")
// ERC-7528
transferAddress = common.HexToAddress("0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE")
)


type tracer struct {
// logs keeps logs for all open call frames.
// This lets us clear logs for failed calls.
logs []*types.Log
count int
traceTransfers bool
blockNumber uint64
blockTimestamp uint64
blockHash ctypes.Hash
txHash ctypes.Hash
txIdx uint
}

func newTracer(traceTransfers bool, blockNumber uint64, blockTimestamp uint64, blockHash, txHash ctypes.Hash, txIndex uint) *tracer {
return &tracer{
logs: make([]*types.Log, 0),
traceTransfers: traceTransfers,
blockNumber: blockNumber,
blockHash: blockHash,
txHash: txHash,
txIdx: txIndex,
blockTimestamp: blockTimestamp,
}
}

func (t *tracer) CaptureEnter(typ vm.OpCode, from common.Address, to common.Address, input []byte, gas uint64, value *big.Int) {}

func (t *tracer) CaptureStart(from common.Address, to common.Address, create bool, input []byte, gas uint64, value *big.Int){
if !t.traceTransfers {
return
}
// Capture the initial transaction value transfer
if !create && value != nil && value.Sign() > 0 {
topics := []ctypes.Hash{
transferTopic,
ctypes.BytesToHash(from.Bytes()),
ctypes.BytesToHash(to.Bytes()),
}
t.logs = append(t.logs, &types.Log{
Address: transferAddress,
Topics: topics,
Data: ctypes.BigToHash(value).Bytes(),
BlockNumber: t.blockNumber,
BlockHash: t.blockHash,
TxHash: t.txHash,
TxIndex: t.txIdx,
Index: uint(t.count),
BlockTimestamp: t.blockTimestamp,
})
t.count++
}
}
func (t *tracer) CaptureState(pc uint64, op vm.OpCode, gas, cost uint64, scope *vm.ScopeContext, rData []byte, depth int, err error){}
func (t *tracer) CaptureExit(output []byte, gasUsed uint64, err error){}
func (t *tracer) CaptureFault(pc uint64, op vm.OpCode, gas, cost uint64, scope *vm.ScopeContext, depth int, err error){}
func (t *tracer) CaptureEnd(output []byte, gasUsed uint64, time time.Duration, err error){}

// reset prepares the tracer for the next transaction.
func (t *tracer) reset(txHash ctypes.Hash, txIdx uint) {
t.logs = make([]*types.Log, 0)
t.txHash = txHash
t.txIdx = txIdx
}

func (t *tracer) Logs() []*types.Log {
return t.logs
}
Loading