Skip to content
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
5 changes: 4 additions & 1 deletion Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ LDFLAGS := -X github.com/Overclock-Validator/mithril/pkg/version.Version=$(VERSI
-X github.com/Overclock-Validator/mithril/pkg/version.GitBranch=$(GIT_BRANCH) \
-X github.com/Overclock-Validator/mithril/pkg/version.BuildDate=$(BUILD_DATE)

.PHONY: build release clean server-setup disk-setup tune
.PHONY: build release clean server-setup disk-setup tune test-conformance-elf

build:
go build -ldflags "$(LDFLAGS)" -o mithril ./cmd/mithril
Expand All @@ -28,3 +28,6 @@ disk-setup:

tune:
./scripts/performance-tune.sh $(ARGS)

test-conformance-elf:
go test ./conformance/ -run TestConformance_ElfLoader_Firedancer -v
210 changes: 210 additions & 0 deletions conformance/elf_loader_fb_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,210 @@
package conformance

import (
"encoding/binary"
"fmt"
"os"
"path/filepath"
"sort"
"strings"
"testing"

"github.com/Overclock-Validator/mithril/conformance/sealevel"
"github.com/Overclock-Validator/mithril/pkg/features"
"github.com/Overclock-Validator/mithril/pkg/sbpf"
"github.com/Overclock-Validator/mithril/pkg/sbpf/loader"
sealevelPkg "github.com/Overclock-Validator/mithril/pkg/sealevel"
)

func parseFBFeatures(fbFeatures *sealevel.FeatureSet) *features.Features {
f := features.NewFeaturesDefault()
if fbFeatures == nil {
return f
}
n := fbFeatures.FeaturesLength()
for i := 0; i < n; i++ {
ftr := fbFeatures.Features(i)
for _, featureGate := range features.AllFeatureGates {
featureIdInt := binary.LittleEndian.Uint64(featureGate.Address[:8])
if featureIdInt == ftr {
f.EnableFeature(featureGate, 0)
}
}
}
return f
}

func TestConformance_ElfLoader_Firedancer(t *testing.T) {
basePath := "test-vectors/elf_loader/fixtures"

entries, err := os.ReadDir(basePath)
if err != nil {
t.Skipf("test-vectors not available: %v", err)
}

var fixtures []string
for _, entry := range entries {
if strings.HasSuffix(entry.Name(), ".fix") {
fixtures = append(fixtures, filepath.Join(basePath, entry.Name()))
}
}

if len(fixtures) == 0 {
t.Skip("no .fix fixtures found")
}

t.Logf("Found %d ELF loader fixtures", len(fixtures))

var (
total int
passPass int
failFail int
falsePass int
falseFail int
panics int
parseErrors int
entryMatch int
entryTotal int
textMatch int
textTotal int
)

var failures []string
var panicFixtures []string

for _, fixturePath := range fixtures {
total++
name := filepath.Base(fixturePath)

data, err := os.ReadFile(fixturePath)
if err != nil {
t.Errorf("%s: read error: %v", name, err)
continue
}

fixture := sealevel.GetRootAsELFLoaderFixture(data, 0)
if fixture == nil {
parseErrors++
continue
}

input := fixture.Input(nil)
if input == nil {
parseErrors++
continue
}

elfData := input.ElfDataBytes()
if elfData == nil {
parseErrors++
continue
}

output := fixture.Output(nil)
fixtureExpectsSuccess := output != nil && output.ErrCode() == 0

fbFeatures := input.Features(nil)
f := parseFBFeatures(fbFeatures)

syscalls := sbpf.SyscallRegistry(func(hash uint32) (sbpf.Syscall, bool) {
return sealevelPkg.Syscalls(f, input.DeployChecks(), hash)
})

var program *sbpf.Program
var loadErr error
var didPanic bool

func() {
defer func() {
if r := recover(); r != nil {
didPanic = true
panics++
panicFixtures = append(panicFixtures, fmt.Sprintf("PANIC %s: %v", name, r))
}
}()

l, err := loader.NewLoaderWithSyscalls(elfData, syscalls, input.DeployChecks(), f)
if err != nil {
loadErr = err
return
}
program, loadErr = l.Load()
}()

if didPanic {
continue
}

if loadErr == nil && fixtureExpectsSuccess {
passPass++

if output != nil {
entryTotal++
if program.Entrypoint == output.EntryPc() {
entryMatch++
} else {
failures = append(failures, fmt.Sprintf("ENTRY_MISMATCH %s: got=%d want=%d", name, program.Entrypoint, output.EntryPc()))
}

textTotal++
if uint64(len(program.Text)) == output.TextCnt() {
textMatch++
} else {
failures = append(failures, fmt.Sprintf("TEXT_CNT_MISMATCH %s: got=%d want=%d", name, len(program.Text), output.TextCnt()))
}
}
} else if loadErr != nil && !fixtureExpectsSuccess {
failFail++
} else if loadErr == nil && !fixtureExpectsSuccess {
falsePass++
failures = append(failures, fmt.Sprintf("FALSE_PASS %s: loaded OK but fixture expects failure", name))
} else {
falseFail++
failures = append(failures, fmt.Sprintf("FALSE_FAIL %s: %v (entry_pc=%d text_cnt=%d)", name, loadErr, output.EntryPc(), output.TextCnt()))
}
}

sort.Strings(failures)

t.Logf("\n=== ELF Loader Conformance Results ===")
t.Logf("Total fixtures: %d", total)
t.Logf("Parse errors: %d", parseErrors)
t.Logf("Both pass: %d", passPass)
t.Logf("Both fail: %d", failFail)
t.Logf("False pass (bad): %d (mithril loads, fixture rejects)", falsePass)
t.Logf("False fail (bad): %d (mithril rejects, fixture loads)", falseFail)
t.Logf("Panics (crash bug): %d", panics)
t.Logf("Entry PC match: %d / %d", entryMatch, entryTotal)
t.Logf("Text count match: %d / %d", textMatch, textTotal)

if len(panicFixtures) > 0 {
t.Logf("\n=== PANICS (crash bugs - highest priority) ===")
for _, p := range panicFixtures {
t.Logf(" %s", p)
}
}

if len(failures) > 0 {
t.Logf("\n=== First 50 failures ===")
limit := 50
if len(failures) < limit {
limit = len(failures)
}
for _, f := range failures[:limit] {
t.Logf(" %s", f)
}
}

// Report pass rate
agree := passPass + failFail
disagree := falsePass + falseFail
passRate := float64(agree) / float64(agree+disagree) * 100
t.Logf("\nConformance rate: %.1f%% (%d/%d)", passRate, agree, agree+disagree)

if panics > 0 {
t.Errorf("CRITICAL: %d fixtures caused panics in the loader", panics)
}
if disagree > 0 {
t.Logf("WARNING: %d disagreements found", disagree)
}
}
120 changes: 120 additions & 0 deletions conformance/sealevel/ELFLoaderCtx.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Loading
Loading