diff --git a/staker/bold/bold_state_provider.go b/staker/bold/bold_state_provider.go index 98b4875a31b..3e6a8eb0b55 100644 --- a/staker/bold/bold_state_provider.go +++ b/staker/bold/bold_state_provider.go @@ -432,7 +432,11 @@ func (s *BOLDStateProvider) CollectMachineHashes( if err != nil { return nil, err } - result, err := s.statelessValidator.BOLDExecutionSpawners()[0].GetMachineHashesWithStepSize( + spawner, err := s.statelessValidator.BOLDExecutionSpawnerForModuleRoot(cfg.AssertionMetadata.WasmModuleRoot) + if err != nil { + return nil, err + } + result, err := spawner.GetMachineHashesWithStepSize( ctx, cfg.AssertionMetadata.WasmModuleRoot, input, @@ -558,7 +562,11 @@ func (s *BOLDStateProvider) CollectProof( "machineIndex", machineIndex, "startState", fmt.Sprintf("%+v", input.StartState), ) - baseProof, err := s.statelessValidator.BOLDExecutionSpawners()[0].GetProofAt( + spawner, err := s.statelessValidator.BOLDExecutionSpawnerForModuleRoot(assertionMetadata.WasmModuleRoot) + if err != nil { + return nil, err + } + baseProof, err := spawner.GetProofAt( ctx, assertionMetadata.WasmModuleRoot, input, diff --git a/staker/stateless_block_validator.go b/staker/stateless_block_validator.go index 0435cc33ba8..abc85fda3ce 100644 --- a/staker/stateless_block_validator.go +++ b/staker/stateless_block_validator.go @@ -308,6 +308,22 @@ func (v *StatelessBlockValidator) BOLDExecutionSpawners() []validator.BOLDExecut return v.boldExecSpawners } +func (v *StatelessBlockValidator) BOLDExecutionSpawnerForModuleRoot(moduleRoot common.Hash) (validator.BOLDExecutionSpawner, error) { + for _, spawner := range v.boldExecSpawners { + supportedRoots, err := spawner.WasmModuleRoots() + if err != nil { + log.Warn("WasmModuleRoots returned error", "err", err) + continue + } + for _, root := range supportedRoots { + if root == moduleRoot { + return spawner, nil + } + } + } + return nil, fmt.Errorf("validation with WasmModuleRoot %v not supported by node", moduleRoot) +} + func (v *StatelessBlockValidator) readFullBatch(ctx context.Context, batchNum uint64) (bool, *FullBatchInfo, error) { batchCount, err := v.inboxTracker.GetBatchCount() if err != nil { diff --git a/staker/stateless_block_validator_test.go b/staker/stateless_block_validator_test.go new file mode 100644 index 00000000000..5030575829a --- /dev/null +++ b/staker/stateless_block_validator_test.go @@ -0,0 +1,74 @@ +// Copyright 2026, Offchain Labs, Inc. +// For license information, see https://github.com/OffchainLabs/nitro/blob/master/LICENSE.md +package staker + +import ( + "context" + "errors" + "testing" + + "github.com/ethereum/go-ethereum/common" + + "github.com/offchainlabs/nitro/validator" +) + +type testBOLDExecutionSpawner struct { + moduleRoots []common.Hash + err error +} + +func (s *testBOLDExecutionSpawner) Start(context.Context) error { return nil } + +func (s *testBOLDExecutionSpawner) Stop() {} + +func (s *testBOLDExecutionSpawner) WasmModuleRoots() ([]common.Hash, error) { + return s.moduleRoots, s.err +} + +func (s *testBOLDExecutionSpawner) GetMachineHashesWithStepSize(context.Context, common.Hash, *validator.ValidationInput, uint64, uint64, uint64) ([]common.Hash, error) { + return nil, nil +} + +func (s *testBOLDExecutionSpawner) GetProofAt(context.Context, common.Hash, *validator.ValidationInput, uint64) ([]byte, error) { + return nil, nil +} + +func TestBOLDExecutionSpawnerForModuleRootSelectsMatchingSpawner(t *testing.T) { + targetRoot := common.HexToHash("0x2") + first := &testBOLDExecutionSpawner{ + moduleRoots: []common.Hash{common.HexToHash("0x1")}, + } + second := &testBOLDExecutionSpawner{ + moduleRoots: []common.Hash{targetRoot}, + } + validator := &StatelessBlockValidator{ + boldExecSpawners: []validator.BOLDExecutionSpawner{first, second}, + } + + spawner, err := validator.BOLDExecutionSpawnerForModuleRoot(targetRoot) + if err != nil { + t.Fatalf("BOLDExecutionSpawnerForModuleRoot() error = %v", err) + } + if spawner != second { + t.Fatalf("BOLDExecutionSpawnerForModuleRoot() returned %p, want %p", spawner, second) + } +} + +func TestBOLDExecutionSpawnerForModuleRootReturnsErrorWhenUnsupported(t *testing.T) { + targetRoot := common.HexToHash("0x3") + validator := &StatelessBlockValidator{ + boldExecSpawners: []validator.BOLDExecutionSpawner{ + &testBOLDExecutionSpawner{ + moduleRoots: []common.Hash{common.HexToHash("0x1")}, + }, + &testBOLDExecutionSpawner{ + err: errors.New("unavailable"), + }, + }, + } + + _, err := validator.BOLDExecutionSpawnerForModuleRoot(targetRoot) + if err == nil { + t.Fatal("BOLDExecutionSpawnerForModuleRoot() error = nil, want non-nil") + } +}