Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
40 commits
Select commit Hold shift + click to select a range
cd6ecad
integrate eth tests
ceyonur Dec 16, 2025
6ecc876
readd submodule
ceyonur Dec 16, 2025
b3d828c
recursive checkout for ci
ceyonur Dec 16, 2025
33f61ea
add gencodec tool
ceyonur Dec 16, 2025
3a2fdf3
increase timeout
ceyonur Dec 16, 2025
b318591
run only short tests
ceyonur Dec 16, 2025
9144414
retry running all tests
ceyonur Dec 16, 2025
cff1884
Revert "retry running all tests"
ceyonur Dec 17, 2025
f3e2dc3
insert with faked base fee
ceyonur Dec 23, 2025
822b7b1
fix jank init
ceyonur Dec 23, 2025
fc5083f
resolve todos
ceyonur Dec 23, 2025
647863b
Merge branch 'main' into ceyonur/eth-tests
ceyonur Dec 23, 2025
2514095
linters
ceyonur Dec 23, 2025
047cc4e
add eest tests
ceyonur Dec 24, 2025
1255d15
Merge branch 'main' into ceyonur/eth-tests
ceyonur Dec 24, 2025
21586c6
add NewGenesisFromSpec
ceyonur Dec 24, 2025
2007d73
comments
ceyonur Dec 29, 2025
55a58f2
comments
ceyonur Dec 29, 2025
ae5adc5
fix target param
ceyonur Dec 29, 2025
308dd5d
uncommitted file
ceyonur Dec 29, 2025
e29cb8c
add checksum verificaiton
ceyonur Dec 31, 2025
ad3d299
Merge branch 'main' into ceyonur/eth-tests
ceyonur Jan 2, 2026
0c4cf09
linters
ceyonur Jan 2, 2026
d912c37
merge new genesis helpers
ceyonur Jan 2, 2026
a2fafb1
Merge branch 'main' into ceyonur/eth-tests
ceyonur Jan 2, 2026
1787110
fix license header
ceyonur Jan 2, 2026
ac16882
add checksums file
ceyonur Jan 2, 2026
b8a5a9c
fix paths
ceyonur Jan 2, 2026
f94a0bb
move checksums file
ceyonur Jan 2, 2026
0662874
add WithFakeBaseFee
ceyonur Jan 13, 2026
3be8b19
change default overriding
ceyonur Jan 13, 2026
b12f7ae
move spec testing to new step
ceyonur Jan 13, 2026
29dfc1a
use insert
ceyonur Jan 13, 2026
b2a5466
change block fetching functions
ceyonur Jan 13, 2026
283d305
conditionally add the hook
ceyonur Jan 13, 2026
95208fa
Merge branch 'main' into ceyonur/eth-tests
ceyonur Jan 13, 2026
2484133
use worst case boundaries in Insert
ceyonur Jan 13, 2026
dbb0487
comments
ceyonur Jan 13, 2026
1636b3d
debug tests
ceyonur Jan 13, 2026
33ee46d
Revert "debug tests"
ceyonur Jan 13, 2026
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
26 changes: 25 additions & 1 deletion .github/workflows/go.yml
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ concurrency:
group: ${{ github.workflow }}-${{ github.ref }}
cancel-in-progress: ${{ github.ref != 'refs/heads/main' }}


permissions:
contents: read

Expand All @@ -18,12 +19,13 @@ jobs:
# what gates PRs.
go:
runs-on: ubuntu-latest
needs: [go_test, go_generate, go_tidy, require_fuzz_corpus]
needs: [go_test, go_spec_tests, go_generate, go_tidy, require_fuzz_corpus]
# TODO(arr4n) investigate why setup-go wasn't properly caching fuzz corpora
# and then reinstate a go_fuzz job that extends them.
steps:
- run: echo "Dependencies successful"

# TODO(cey): we should only run -short tests in PRs and then run the full tests in main.
go_test:
runs-on: ubuntu-latest
steps:
Expand All @@ -34,6 +36,28 @@ jobs:
go-version-file: "go.mod"
- run: go test ./...

go_spec_tests:
runs-on: ubuntu-latest
env:
EXECUTION_SPEC_TESTS_VERSION: v2.1.0
EXECUTION_SPEC_TESTS_FILE: fixtures_develop.tar.gz
steps:
- uses: actions/checkout@v4
with:
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please put all of these in a new job, perhaps go_spec_tests, and add it to the needs of go (to make CI require it). The rationale is that the other tests are more likely to be the ones failing and we want to give that feedback as quickly as possible—placing these in a new job makes it run in parallel.

submodules: recursive
- name: Download spec tests
run: curl -o "${EXECUTION_SPEC_TESTS_FILE}" -L "https://github.com/ethereum/execution-spec-tests/releases/download/${EXECUTION_SPEC_TESTS_VERSION}/${EXECUTION_SPEC_TESTS_FILE}"
- name: Verify spec tests
run: |
sha256sum --ignore-missing --check checksums.txt | grep "${EXECUTION_SPEC_TESTS_FILE}: OK"
- name: Extract spec tests
run: mkdir -p saexec/ethtests/spec-tests && tar -xz -f "${EXECUTION_SPEC_TESTS_FILE}" -C saexec/ethtests/spec-tests
- name: Set up Go
uses: actions/setup-go@v5
with:
go-version-file: "go.mod"
- run: go test -short ./saexec/ethtests/...

go_generate:
env:
EXCLUDE_REGEX: "ava-labs/libevm/(accounts/usbwallet/trezor)$"
Expand Down
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -1 +1,2 @@
.vscode
saexec/ethtests/spec-tests
4 changes: 4 additions & 0 deletions .gitmodules
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
[submodule "saexec/ethtests/testdata"]
path = saexec/ethtests/testdata
url = https://github.com/ethereum/tests
shallow = true
6 changes: 6 additions & 0 deletions .golangci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -103,3 +103,9 @@ issues:
- EXC0013
- EXC0014
- EXC0015
exclude-rules:
# These files include an upstream (go-ethereum) notice block that we want to
# keep verbatim; allow them to deviate from the standard short header.
- path: ^saexec/ethtests/(block_test|block_test_util|init|init_test)\.go$
linters:
- goheader
81 changes: 68 additions & 13 deletions blocks/blockstest/blocks.go
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ import (
"math"
"math/big"
"slices"
"sort"
"sync/atomic"
"testing"
"time"
Expand Down Expand Up @@ -109,19 +110,17 @@ func NewGenesis(tb testing.TB, db ethdb.Database, config *params.ChainConfig, al
tb.Helper()
conf := &genesisConfig{
gasTarget: math.MaxUint64,
genesisSpec: &core.Genesis{
Config: config,
Alloc: alloc,
},
}
options.ApplyTo(conf, opts...)

gen := &core.Genesis{
Config: config,
Timestamp: conf.timestamp,
Alloc: alloc,
}
gen := conf.genesisSpec

tdb := state.NewDatabaseWithConfig(db, conf.tdbConfig).TrieDB()
_, hash, err := core.SetupGenesisBlock(db, tdb, gen)
_, _, err := core.SetupGenesisBlock(db, tdb, gen)
require.NoError(tb, err, "core.SetupGenesisBlock()")
require.NoErrorf(tb, tdb.Commit(hash, true), "%T.Commit(core.SetupGenesisBlock(...))", tdb)

b := NewBlock(tb, gen.ToBlock(), nil, nil)
require.NoErrorf(tb, b.MarkExecuted(
Expand All @@ -138,10 +137,10 @@ func NewGenesis(tb testing.TB, db ethdb.Database, config *params.ChainConfig, al
}

type genesisConfig struct {
tdbConfig *triedb.Config
timestamp uint64
gasTarget gas.Gas
gasExcess gas.Gas
tdbConfig *triedb.Config
gasTarget gas.Gas
gasExcess gas.Gas
genesisSpec *core.Genesis
}

// A GenesisOption configures [NewGenesis].
Expand All @@ -154,10 +153,17 @@ func WithTrieDBConfig(tc *triedb.Config) GenesisOption {
})
}

// WithGenesisSpec overrides the genesis spec used by [NewGenesis].
func WithGenesisSpec(gen *core.Genesis) GenesisOption {
return options.Func[genesisConfig](func(gc *genesisConfig) {
gc.genesisSpec = gen
})
}

// WithTimestamp overrides the timestamp used by [NewGenesis].
func WithTimestamp(timestamp uint64) GenesisOption {
return options.Func[genesisConfig](func(gc *genesisConfig) {
gc.timestamp = timestamp
gc.genesisSpec.Timestamp = timestamp
})
}

Expand All @@ -175,6 +181,55 @@ func WithGasExcess(excess gas.Gas) GenesisOption {
})
}

// WithFakeBaseFee creates a new block wrapping the given eth block with a fake
// parent that has its gastime adjusted to produce the desired base fee.
// Upon execution of the resulting block, the fake parent will have its base fee
// set to the desired base fee, thus overriding the base fee mechanism.
// This is useful for tests that need to override the base fee mechanism.
//
// The fake parent is marked as executed with the gastime configured to yield
// the specified base fee. The build time is set to match the block time to
// prevent fast-forwarding the excess during execution.
func WithFakeBaseFee(tb testing.TB, db ethdb.Database, parent *blocks.Block, eth *types.Block, baseFee *big.Int) *blocks.Block {
tb.Helper()

target := parent.ExecutedByGasTime().Target()
desiredExcessGas := desiredExcess(gas.Price(baseFee.Uint64()), target)

var grandParent *blocks.Block
if parent.NumberU64() != 0 {
grandParent = parent.ParentBlock()
}

fakeParent := NewBlock(tb, parent.EthBlock(), grandParent, nil)
// Set the build time to the block time so that we do not fast forward
// the excess to the block time during execution.
require.NoError(tb, fakeParent.MarkExecuted(
db,
gastime.New(eth.Time(), target, desiredExcessGas),
time.Time{},
baseFee,
nil,
parent.PostExecutionStateRoot(),
new(atomic.Pointer[blocks.Block]),
))
require.Equal(tb, baseFee.Uint64(), fakeParent.ExecutedByGasTime().BaseFee().Uint64())

return NewBlock(tb, eth, fakeParent, nil)
}

// desiredExcess calculates the excess gas needed to produce the desired price.
func desiredExcess(desiredPrice gas.Price, target gas.Gas) gas.Gas {
// This could be solved directly by calculating D * ln(desiredPrice / P)
// using floating point math. However, it introduces inaccuracies. So, we
// use a binary search to find the closest integer solution.
return gas.Gas(sort.Search(math.MaxInt32, func(excessGuess int) bool { //nolint:gosec // Known to not overflow
tm := gastime.New(0, target, gas.Gas(excessGuess)) //nolint:gosec // Known to not overflow
price := tm.Price()
return price >= desiredPrice
}))
}

// SetUninformativeWorstCaseBounds calls [blocks.Block.SetWorstCaseBounds] with
// a base fee of 2^256-1 and tx-sender balances of zero. These are guaranteed to
// pass the checks and never result in error logs, and MUST NOT be used in full
Expand Down
43 changes: 37 additions & 6 deletions blocks/blockstest/chain.go
Original file line number Diff line number Diff line change
Expand Up @@ -34,9 +34,10 @@ type ChainBuilder struct {
func NewChainBuilder(config *params.ChainConfig, genesis *blocks.Block, defaultOpts ...ChainOption) *ChainBuilder {
c := &ChainBuilder{
config: config,
chain: []*blocks.Block{genesis},
chain: []*blocks.Block{},
}
c.SetDefaultOptions(defaultOpts...)
c.insert(genesis)
return c
}

Expand Down Expand Up @@ -81,15 +82,25 @@ func (cb *ChainBuilder) NewBlock(tb testing.TB, txs []*types.Transaction, opts .
last := cb.Last()
eth := NewEthBlock(last.EthBlock(), txs, allOpts.eth...)
b := NewBlock(tb, eth, last, nil, allOpts.sae...) // TODO(arr4n) support last-settled blocks
signer := types.MakeSigner(cb.config, b.Number(), b.BuildTime())
SetUninformativeWorstCaseBounds(tb, signer, b)

cb.chain = append(cb.chain, b)
cb.blocksByHash.Store(b.Hash(), b)

cb.Insert(tb, b)
return b
}

// Insert sets the block's invariants and adds it to the chain.
func (cb *ChainBuilder) Insert(tb testing.TB, block *blocks.Block) {
tb.Helper()
signer := types.MakeSigner(cb.config, block.Number(), block.BuildTime())
SetUninformativeWorstCaseBounds(tb, signer, block)
cb.insert(block)
}

// insert adds a block to the chain.
func (cb *ChainBuilder) insert(block *blocks.Block) {
cb.chain = append(cb.chain, block)
cb.blocksByHash.Store(block.Hash(), block)
}

// Last returns the last block to be built by the builder, which MAY be the
// genesis block passed to the constructor.
func (cb *ChainBuilder) Last() *blocks.Block {
Expand Down Expand Up @@ -120,3 +131,23 @@ func (cb *ChainBuilder) GetBlock(h common.Hash, num uint64) (*blocks.Block, bool
}
return b, true
}

// BlockByNumber returns the block at the given height, and a flag indicating if it was found.
// If the height is greater than the number of blocks in the chain, it returns an empty hash and false.
func (cb *ChainBuilder) BlockByNumber(num uint64) (*blocks.Block, bool) {
if num >= uint64(len(cb.chain)) {
return nil, false
}
block := cb.chain[num]
return block, true
}

// BlockByHash returns the block with the given hash, and a flag indicating if it was found.
func (cb *ChainBuilder) BlockByHash(h common.Hash) (*blocks.Block, bool) {
ifc, _ := cb.blocksByHash.Load(h)
b, ok := ifc.(*blocks.Block)
if !ok {
return nil, false
}
return b, true
}
6 changes: 6 additions & 0 deletions checksums.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
# This file contains sha256 checksums of optional build dependencies.

# version:spec-tests 2.1.0
# https://github.com/ethereum/execution-spec-tests/releases
# https://github.com/ethereum/execution-spec-tests/releases/download/v2.1.0/
ca89c76851b0900bfcc3cbb9a26cbece1f3d7c64a3bed38723e914713290df6c fixtures_develop.tar.gz
9 changes: 8 additions & 1 deletion go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,10 @@ module github.com/ava-labs/strevm

go 1.24.11

tool github.com/go-task/task/v3/cmd/task
tool (
github.com/fjl/gencodec
github.com/go-task/task/v3/cmd/task
)

require (
github.com/ava-labs/avalanchego v1.14.2-0.20260112194842-874bc6c9d305
Expand Down Expand Up @@ -46,7 +49,9 @@ require (
github.com/emirpasic/gods v1.18.1 // indirect
github.com/ethereum/c-kzg-4844 v1.0.0 // indirect
github.com/fatih/color v1.18.0 // indirect
github.com/fjl/gencodec v0.1.1 // indirect
github.com/fsnotify/fsnotify v1.9.0 // indirect
github.com/garslo/gogen v0.0.0-20170306192744-1d203ffc1f61 // indirect
github.com/gballet/go-libpcsclite v0.0.0-20191108122812-4678299bea08 // indirect
github.com/gballet/go-verkle v0.1.1-0.20231031103413-a67434b50f46 // indirect
github.com/getsentry/sentry-go v0.35.0 // indirect
Expand Down Expand Up @@ -112,8 +117,10 @@ require (
github.com/zeebo/xxh3 v1.0.2 // indirect
go.opentelemetry.io/auto/sdk v1.1.0 // indirect
go.yaml.in/yaml/v4 v4.0.0-rc.3 // indirect
golang.org/x/mod v0.29.0 // indirect
golang.org/x/sync v0.18.0 // indirect
golang.org/x/time v0.12.0 // indirect
golang.org/x/tools v0.38.0 // indirect
gopkg.in/warnings.v0 v0.1.2 // indirect
mvdan.cc/sh/moreinterp v0.0.0-20251109230715-65adef8e2c5b // indirect
mvdan.cc/sh/v3 v3.12.0 // indirect
Expand Down
6 changes: 6 additions & 0 deletions go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -141,11 +141,15 @@ github.com/fatih/color v1.18.0/go.mod h1:4FelSpRwEGDpQ12mAdzqdOukCy4u8WUtOY6lkT/
github.com/fatih/structs v1.1.0/go.mod h1:9NiDSp5zOcgEDl+j00MP/WkGVPOlPRLejGD8Ga6PJ7M=
github.com/fatih/structtag v1.2.0 h1:/OdNE99OxoI/PqaW/SuSK9uxxT3f/tcSZgon/ssNSx4=
github.com/fatih/structtag v1.2.0/go.mod h1:mBJUNpUnHmRKrKlQQlmCrh5PuhftFbNv8Ys4/aAZl94=
github.com/fjl/gencodec v0.1.1 h1:DhQY29Q6JLXB/GgMqE86NbOEuvckiYcJCbXFu02toms=
github.com/fjl/gencodec v0.1.1/go.mod h1:chDHL3wKXuBgauP8x3XNZkl5EIAR5SoCTmmmDTZRzmw=
github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo=
github.com/fsnotify/fsnotify v1.4.9/go.mod h1:znqG4EE+3YCdAaPaxE2ZRY/06pZUdp0tY4IgpuI1SZQ=
github.com/fsnotify/fsnotify v1.5.4/go.mod h1:OVB6XrOHzAwXMpEM7uPOzcehqUV2UqJxmVXmkdnm1bU=
github.com/fsnotify/fsnotify v1.9.0 h1:2Ml+OJNzbYCTzsxtv8vKSFD9PbJjmhYF14k/jKC7S9k=
github.com/fsnotify/fsnotify v1.9.0/go.mod h1:8jBTzvmWwFyi3Pb8djgCCO5IBqzKJ/Jwo8TRcHyHii0=
github.com/garslo/gogen v0.0.0-20170306192744-1d203ffc1f61 h1:IZqZOB2fydHte3kUgxrzK5E1fW7RQGeDwE8F/ZZnUYc=
github.com/garslo/gogen v0.0.0-20170306192744-1d203ffc1f61/go.mod h1:Q0X6pkwTILDlzrGEckF6HKjXe48EgsY/l7K7vhY4MW8=
github.com/gavv/httpexpect v2.0.0+incompatible/go.mod h1:x+9tiU1YnrOvnB725RkpoLv1M62hOWzwo5OXotisrKc=
github.com/gballet/go-libpcsclite v0.0.0-20191108122812-4678299bea08 h1:f6D9Hr8xV8uYKlyuj8XIruxlh9WjVjdh1gIicAS7ays=
github.com/gballet/go-libpcsclite v0.0.0-20191108122812-4678299bea08/go.mod h1:x7DCsMOv1taUwEWCzT4cmDeAkigA5/QCwUodaVOe8Ww=
Expand Down Expand Up @@ -665,6 +669,8 @@ golang.org/x/tools v0.0.0-20200619180055-7c47624df98f/go.mod h1:EkVYQZoAsY45+roY
golang.org/x/tools v0.0.0-20201224043029-2b0845dc783e/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA=
golang.org/x/tools v0.0.0-20210106214847-113979e3529a/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA=
golang.org/x/tools v0.1.3/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk=
golang.org/x/tools v0.38.0 h1:Hx2Xv8hISq8Lm16jvBZ2VQf+RLmbd7wVUsALibYI/IQ=
golang.org/x/tools v0.38.0/go.mod h1:yEsQ/d/YK8cjh0L6rZlY8tgtlKiBNTL14pGDJPJpYQs=
golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
Expand Down
3 changes: 3 additions & 0 deletions sae/vm.go
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ import (
"github.com/ava-labs/libevm/common"
"github.com/ava-labs/libevm/core"
"github.com/ava-labs/libevm/core/rawdb"
"github.com/ava-labs/libevm/core/state/snapshot"
"github.com/ava-labs/libevm/core/txpool"
"github.com/ava-labs/libevm/core/txpool/legacypool"
"github.com/ava-labs/libevm/core/types"
Expand Down Expand Up @@ -119,6 +120,7 @@ func (vm *VM) Init(
if err := snowCtx.Metrics.Register("sae", vm.metrics); err != nil {
return err
}
snapshotConfig := snapshot.Config{CacheSize: 128, AsyncBuild: true}

{ // ========== Executor ==========
exec, err := saexec.New(
Expand All @@ -127,6 +129,7 @@ func (vm *VM) Init(
chainConfig,
db,
triedbConfig,
snapshotConfig,
hooks,
snowCtx.Log,
)
Expand Down
4 changes: 2 additions & 2 deletions saetest/logging.go
Original file line number Diff line number Diff line change
Expand Up @@ -108,14 +108,14 @@ func (l *LogRecorder) AtLeast(lvl logging.Level) []*LogRecord {
// NewTBLogger constructs a logger that propagates logs to [testing.TB]. WARNING
// and ERROR logs are sent to [testing.TB.Errorf] while FATAL is sent to
// [testing.TB.Fatalf]. All other logs are sent to [testing.TB.Logf]. Although
// the level can be configured, it is silently capped at [logging.Warn].
// the level can be configured, it is silently capped at [logging.Error].
//
//nolint:thelper // The outputs include the logging site while the TB site is most useful if here
func NewTBLogger(tb testing.TB, level logging.Level) *TBLogger {
l := &TBLogger{tb: tb}
l.logger = &logger{
handler: l, // TODO(arr4n) remove the recursion here and in [LogRecorder]
level: min(level, logging.Warn),
level: min(level, logging.Error),
}
return l
}
Expand Down
Loading