diff --git a/accounts/keystore/key.go b/accounts/keystore/key.go index 6a554d831c..6ef756aa03 100644 --- a/accounts/keystore/key.go +++ b/accounts/keystore/key.go @@ -205,9 +205,8 @@ func writeTemporaryKeyFile(file string, content []byte) (string, error) { os.Remove(f.Name()) return "", err } - // Persist the contents to disk before the caller renames it into place, - // so that a crash or power loss between the write and the rename cannot - // leave a zero-length keyfile at the final path. + // Sync before rename so a crash between the write and the rename + // cannot leave a zero-length keyfile at the final path. if err := f.Sync(); err != nil { f.Close() os.Remove(f.Name()) diff --git a/accounts/keystore/key_test.go b/accounts/keystore/key_test.go new file mode 100644 index 0000000000..da8e264724 --- /dev/null +++ b/accounts/keystore/key_test.go @@ -0,0 +1,54 @@ +// Copyright 2026 The go-ethereum Authors +// This file is part of the go-ethereum library. +// +// The go-ethereum library is free software: you can redistribute it and/or modify +// it under the terms of the GNU Lesser General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// The go-ethereum library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public License +// along with the go-ethereum library. If not, see . + +package keystore + +import ( + "bytes" + "os" + "path/filepath" + "testing" +) + +func TestWriteKeyFile(t *testing.T) { + t.Parallel() + dir := t.TempDir() + path := filepath.Join(dir, "keyfile") + content := []byte(`{"address":"deadbeef"}`) + + if err := writeKeyFile(path, content); err != nil { + t.Fatalf("writeKeyFile: %v", err) + } + got, err := os.ReadFile(path) + if err != nil { + t.Fatalf("read back: %v", err) + } + if !bytes.Equal(got, content) { + t.Fatalf("content mismatch: got %q want %q", got, content) + } + // Verify no temp file leaked into the directory. + entries, err := os.ReadDir(dir) + if err != nil { + t.Fatalf("readdir: %v", err) + } + if len(entries) != 1 || entries[0].Name() != "keyfile" { + var names []string + for _, e := range entries { + names = append(names, e.Name()) + } + t.Fatalf("unexpected directory contents: %v", names) + } +}