diff --git a/tools/cosmovisor/CHANGELOG.md b/tools/cosmovisor/CHANGELOG.md index bc30766aff70..cbb2377ca461 100644 --- a/tools/cosmovisor/CHANGELOG.md +++ b/tools/cosmovisor/CHANGELOG.md @@ -36,6 +36,10 @@ Ref: https://keepachangelog.com/en/1.0.0/ ## [Unreleased] +### Bug Fixes + +* [#26819](https://github.com/cosmos/cosmos-sdk/pull/26819) Fix the inverted retry condition when `upgrade-info.json` is still empty: the watcher now keeps waiting (up to 10 × 2 ms) until the write lands instead of giving up after the first empty stat. + ### Improvements * [#23720](https://github.com/cosmos/cosmos-sdk/pull/23720) Get block height from db after node execution fails diff --git a/tools/cosmovisor/scanner.go b/tools/cosmovisor/scanner.go index 930421bb6795..81648404d067 100644 --- a/tools/cosmovisor/scanner.go +++ b/tools/cosmovisor/scanner.go @@ -143,7 +143,8 @@ func (fw *fileWatcher) CheckUpdate(currentUpgrade upgradetypes.Plan) bool { panic(fmt.Errorf("failed to stat upgrade info file: %w", err)) } } - if stat.Size() == 0 { + // stop waiting as soon as the write has landed + if stat.Size() != 0 { break } } diff --git a/tools/cosmovisor/scanner_test.go b/tools/cosmovisor/scanner_test.go index 36de3b68074e..133de80364a0 100644 --- a/tools/cosmovisor/scanner_test.go +++ b/tools/cosmovisor/scanner_test.go @@ -1,8 +1,10 @@ package cosmovisor import ( + "os" "path/filepath" "testing" + "time" "github.com/stretchr/testify/require" @@ -90,3 +92,26 @@ func TestParseUpgradeInfoFile(t *testing.T) { }) } } + +func TestCheckUpdateWaitsForEmptyFileWrite(t *testing.T) { + filename := filepath.Join(t.TempDir(), "upgrade-info.json") + require.NoError(t, os.WriteFile(filename, nil, 0o600)) + + fw := &fileWatcher{ + filename: filename, + currentInfo: upgradetypes.Plan{Name: "upgrade1", Height: 1}, + initialized: true, + } + + // Simulate the daemon finishing its write a few milliseconds after the + // watcher observed the empty file; CheckUpdate should keep waiting instead + // of giving up after the first still-empty stat. + go func() { + time.Sleep(5 * time.Millisecond) + _ = os.WriteFile(filename, []byte(`{"name":"upgrade2","height":10}`), 0o600) + }() + + require.True(t, fw.CheckUpdate(upgradetypes.Plan{Name: "upgrade1"})) + require.Equal(t, "upgrade2", fw.currentInfo.Name) + require.Equal(t, int64(10), fw.currentInfo.Height) +}