diff --git a/validator/server_common/machine_locator.go b/validator/server_common/machine_locator.go index 4c25448dda..c8b4d9a165 100644 --- a/validator/server_common/machine_locator.go +++ b/validator/server_common/machine_locator.go @@ -8,21 +8,20 @@ import ( "strings" "github.com/ethereum/go-ethereum/common" + "github.com/ethereum/go-ethereum/log" ) type MachineLocator struct { - rootPath string - latest common.Hash + rootPath string + latest common.Hash + moduleRoots []common.Hash } var ErrMachineNotFound = errors.New("machine not found") func NewMachineLocator(rootPath string) (*MachineLocator, error) { - var places []string - - if rootPath != "" { - places = append(places, rootPath) - } else { + dirs := []string{rootPath} + if rootPath == "" { // Check the project dir: /arbnode/node.go => ../../target/machines _, thisFile, _, ok := runtime.Caller(0) if !ok { @@ -30,7 +29,7 @@ func NewMachineLocator(rootPath string) (*MachineLocator, error) { } projectDir := filepath.Dir(filepath.Dir(filepath.Dir(thisFile))) projectPath := filepath.Join(filepath.Join(projectDir, "target"), "machines") - places = append(places, projectPath) + dirs = append(dirs, projectPath) // Check the working directory: ./machines and ./target/machines workDir, err := os.Getwd() @@ -39,8 +38,8 @@ func NewMachineLocator(rootPath string) (*MachineLocator, error) { } workPath1 := filepath.Join(workDir, "machines") workPath2 := filepath.Join(filepath.Join(workDir, "target"), "machines") - places = append(places, workPath1) - places = append(places, workPath2) + dirs = append(dirs, workPath1) + dirs = append(dirs, workPath2) // Check above the executable: => ../../machines execfile, err := os.Executable() @@ -48,22 +47,59 @@ func NewMachineLocator(rootPath string) (*MachineLocator, error) { return nil, err } execPath := filepath.Join(filepath.Dir(filepath.Dir(execfile)), "machines") - places = append(places, execPath) + dirs = append(dirs, execPath) } - for _, place := range places { - if _, err := os.Stat(place); err == nil { - var latestModuleRoot common.Hash - latestModuleRootPath := filepath.Join(place, "latest", "module-root.txt") - fileBytes, err := os.ReadFile(latestModuleRootPath) - if err == nil { - s := strings.TrimSpace(string(fileBytes)) - latestModuleRoot = common.HexToHash(s) + var ( + moduleRoots = make(map[common.Hash]bool) + latestModuleRoot common.Hash + ) + + for _, dir := range dirs { + fInfo, err := os.Stat(dir) + if err != nil { + log.Warn("Getting file info", "error", err) + continue + } + if !fInfo.IsDir() { + // Skip files that are not directories. + continue + } + files, err := os.ReadDir(dir) + if err != nil { + log.Warn("Reading directory", "dir", dir, "error", err) + } + for _, file := range files { + mrFile := filepath.Join(dir, file.Name(), "module-root.txt") + if _, err := os.Stat(mrFile); errors.Is(err, os.ErrNotExist) { + // Skip if module-roots file does not exist. + continue + } + mrContent, err := os.ReadFile(mrFile) + if err != nil { + log.Warn("Reading module roots file", "file path", mrFile, "error", err) + continue + } + moduleRoot := common.HexToHash(strings.TrimSpace(string(mrContent))) + if file.Name() != "latest" && file.Name() != moduleRoot.Hex() { + continue + } + moduleRoots[moduleRoot] = true + if file.Name() == "latest" { + latestModuleRoot = moduleRoot + rootPath = dir } - return &MachineLocator{place, latestModuleRoot}, nil } } - return nil, ErrMachineNotFound + var roots []common.Hash + for k := range moduleRoots { + roots = append(roots, k) + } + return &MachineLocator{ + rootPath: rootPath, + latest: latestModuleRoot, + moduleRoots: roots, + }, nil } func (l MachineLocator) GetMachinePath(moduleRoot common.Hash) string { @@ -81,3 +117,7 @@ func (l MachineLocator) LatestWasmModuleRoot() common.Hash { func (l MachineLocator) RootPath() string { return l.rootPath } + +func (l MachineLocator) ModuleRoots() []common.Hash { + return l.moduleRoots +} diff --git a/validator/server_common/machine_locator_test.go b/validator/server_common/machine_locator_test.go new file mode 100644 index 0000000000..7c1575871c --- /dev/null +++ b/validator/server_common/machine_locator_test.go @@ -0,0 +1,36 @@ +package server_common + +import ( + "sort" + "testing" + + "github.com/google/go-cmp/cmp" +) + +var ( + wantLatestModuleRoot = "0xf4389b835497a910d7ba3ebfb77aa93da985634f3c052de1290360635be40c4a" + wantModuleRoots = []string{ + "0x8b104a2e80ac6165dc58b9048de12f301d70b02a0ab51396c22b4b4b802a16a4", + "0x68e4fe5023f792d4ef584796c84d710303a5e12ea02d6e37e2b5e9c4332507c4", + "0xf4389b835497a910d7ba3ebfb77aa93da985634f3c052de1290360635be40c4a", + } +) + +func TestNewMachineLocator(t *testing.T) { + ml, err := NewMachineLocator("testdata") + if err != nil { + t.Fatalf("Error creating new machine locator: %v", err) + } + if ml.latest.Hex() != wantLatestModuleRoot { + t.Errorf("NewMachineLocator() got latestModuleRoot: %v, want: %v", ml.latest, wantLatestModuleRoot) + } + var got []string + for _, s := range ml.ModuleRoots() { + got = append(got, s.Hex()) + } + sort.Strings(got) + sort.Strings(wantModuleRoots) + if diff := cmp.Diff(got, wantModuleRoots); diff != "" { + t.Errorf("NewMachineLocator() unexpected diff (-want +got):\n%s", diff) + } +} diff --git a/validator/server_common/testdata/0x68e4fe5023f792d4ef584796c84d710303a5e12ea02d6e37e2b5e9c4332507c4/module-root.txt b/validator/server_common/testdata/0x68e4fe5023f792d4ef584796c84d710303a5e12ea02d6e37e2b5e9c4332507c4/module-root.txt new file mode 100644 index 0000000000..067f2db9f5 --- /dev/null +++ b/validator/server_common/testdata/0x68e4fe5023f792d4ef584796c84d710303a5e12ea02d6e37e2b5e9c4332507c4/module-root.txt @@ -0,0 +1 @@ +0x68e4fe5023f792d4ef584796c84d710303a5e12ea02d6e37e2b5e9c4332507c4 diff --git a/validator/server_common/testdata/0x8b104a2e80ac6165dc58b9048de12f301d70b02a0ab51396c22b4b4b802a16a4/module-root.txt b/validator/server_common/testdata/0x8b104a2e80ac6165dc58b9048de12f301d70b02a0ab51396c22b4b4b802a16a4/module-root.txt new file mode 100644 index 0000000000..ad3a905ab7 --- /dev/null +++ b/validator/server_common/testdata/0x8b104a2e80ac6165dc58b9048de12f301d70b02a0ab51396c22b4b4b802a16a4/module-root.txt @@ -0,0 +1 @@ +0x8b104a2e80ac6165dc58b9048de12f301d70b02a0ab51396c22b4b4b802a16a4 diff --git a/validator/server_common/testdata/0xf4389b835497a910d7ba3ebfb77aa93da985634f3c052de1290360635be40c4a/module-root.txt b/validator/server_common/testdata/0xf4389b835497a910d7ba3ebfb77aa93da985634f3c052de1290360635be40c4a/module-root.txt new file mode 100644 index 0000000000..1a359ae1cd --- /dev/null +++ b/validator/server_common/testdata/0xf4389b835497a910d7ba3ebfb77aa93da985634f3c052de1290360635be40c4a/module-root.txt @@ -0,0 +1 @@ +0xf4389b835497a910d7ba3ebfb77aa93da985634f3c052de1290360635be40c4a diff --git a/validator/server_common/testdata/latest b/validator/server_common/testdata/latest new file mode 120000 index 0000000000..42d98792a0 --- /dev/null +++ b/validator/server_common/testdata/latest @@ -0,0 +1 @@ +0xf4389b835497a910d7ba3ebfb77aa93da985634f3c052de1290360635be40c4a \ No newline at end of file