From a8c5d4ec0d8e6967b22842aaa28c01da6ed763f8 Mon Sep 17 00:00:00 2001 From: Danno Ferrin Date: Wed, 9 Sep 2026 08:12:53 -0600 Subject: [PATCH 1/5] fix(evmrpc): stop double-logging recovered panics when a hook is set recoverAndLog printed the panic and stack trace unconditionally, then also invoked the panic hook if one was set. Tests that install a hook to capture panics were getting the default stderr logging on top of it, adding noise. Fall back to the default logging only when no hook handles the panic. --- evmrpc/utils.go | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/evmrpc/utils.go b/evmrpc/utils.go index 4622c7ea05..0f838434f7 100644 --- a/evmrpc/utils.go +++ b/evmrpc/utils.go @@ -370,6 +370,7 @@ type ParallelRunner struct { var panicHook atomic.Value +// SetPanicHook sets a handler that replaces default recovered-panic logging. func SetPanicHook(h func(interface{})) { panicHook.Store(h) } @@ -399,13 +400,14 @@ func runWithRecovery(f func()) { func recoverAndLog() { if e := recover(); e != nil { - fmt.Printf("Panic recovered: %s\n", e) - debug.PrintStack() if v := panicHook.Load(); v != nil { if hook, ok := v.(func(interface{})); ok && hook != nil { hook(e) + return } } + fmt.Printf("Panic recovered: %s\n", e) + debug.PrintStack() } } From 31c822f55d27a4b0fbdd55a1354f266096c8740f Mon Sep 17 00:00:00 2001 From: Danno Ferrin Date: Wed, 9 Sep 2026 08:13:02 -0600 Subject: [PATCH 2/5] test(sei-tendermint): fix flaky freeze test RPC listener on macOS TestFreezeModeDisablesMempoolTraffic reserved an RPC listen address via tcp.TestReserveAddr and handed it to node Start, but net.Listen cannot adopt a reservation made by closing a :0 bind, and that address is stealable by another process on macOS in the window between reservation and Start. The test only calls rpcEnv in-process, so skip the TCP listener entirely by leaving RPC.ListenAddress empty. --- sei-tendermint/node/freeze_test.go | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/sei-tendermint/node/freeze_test.go b/sei-tendermint/node/freeze_test.go index 587549a9fd..d6f93184dc 100644 --- a/sei-tendermint/node/freeze_test.go +++ b/sei-tendermint/node/freeze_test.go @@ -2,7 +2,6 @@ package node import ( "errors" - "fmt" "math" "slices" "testing" @@ -10,7 +9,6 @@ import ( "github.com/sei-protocol/sei-chain/sei-tendermint/config" mempoolreactor "github.com/sei-protocol/sei-chain/sei-tendermint/internal/mempool/reactor" rpccore "github.com/sei-protocol/sei-chain/sei-tendermint/internal/rpc/core" - "github.com/sei-protocol/sei-chain/sei-tendermint/libs/utils/tcp" "github.com/sei-protocol/sei-chain/sei-tendermint/rpc/coretypes" "github.com/sei-protocol/sei-chain/sei-tendermint/types" ) @@ -78,7 +76,10 @@ func TestFreezeModeDisablesMempoolTraffic(t *testing.T) { t.Fatal(err) } cfg.Mode = config.ModeFull - cfg.RPC.ListenAddress = fmt.Sprintf("tcp://%s", tcp.TestReserveAddr()) + // Broadcast checks below call rpcEnv in-process; skip the TCP listener + // so Start does not race a freeLoopbackAddr (net.Listen cannot adopt a + // TestReserveAddr, and a closed :0 bind is stealable on macOS). + cfg.RPC.ListenAddress = "" nodeService, err := newLocalNodeService(t.Context(), cfg, WithFreezeHeight(2)) if err != nil { t.Fatal(err) From 6cefa3e2b86463c801caebc81f31b347f8abceee Mon Sep 17 00:00:00 2001 From: Danno Ferrin Date: Wed, 9 Sep 2026 08:13:10 -0600 Subject: [PATCH 3/5] test(processblock): fix timezone-dependent mint release test NewMinter derived the minter's start/end dates from local wall-clock time, so the recorded calendar dates could shift by a day relative to the block time depending on the local timezone, making the test flaky outside UTC. Anchor start/end to UTC calendar dates instead. MintRelease independently recomputed the expected release amount from parsed start/end dates rather than through the minter's own release calculation, which no longer agreed with the UTC-anchored dates. Use Minter.GetReleaseAmountToday instead of re-deriving it. --- testutil/processblock/genesismint.go | 10 ++++++---- testutil/processblock/verify/mint.go | 15 +++------------ 2 files changed, 9 insertions(+), 16 deletions(-) diff --git a/testutil/processblock/genesismint.go b/testutil/processblock/genesismint.go index e4beda3827..bdccdc768b 100644 --- a/testutil/processblock/genesismint.go +++ b/testutil/processblock/genesismint.go @@ -7,11 +7,13 @@ import ( ) func (a *App) NewMinter(amount uint64) { - today := time.Now() - dayAfterTomorrow := today.Add(48 * time.Hour) + // UTC calendar dates so DaysBetween(blockTime, end) matches the + // formatted start/end regardless of local timezone. + today := time.Now().UTC() + start := time.Date(today.Year(), today.Month(), today.Day(), 0, 0, 0, 0, time.UTC) a.MintKeeper.SetMinter(a.Ctx(), minttypes.Minter{ - StartDate: today.Format(minttypes.TokenReleaseDateFormat), - EndDate: dayAfterTomorrow.Format(minttypes.TokenReleaseDateFormat), + StartDate: start.Format(minttypes.TokenReleaseDateFormat), + EndDate: start.AddDate(0, 0, 2).Format(minttypes.TokenReleaseDateFormat), Denom: "usei", TotalMintAmount: amount, RemainingMintAmount: amount, diff --git a/testutil/processblock/verify/mint.go b/testutil/processblock/verify/mint.go index 7a300c51a0..778d1a2b2c 100644 --- a/testutil/processblock/verify/mint.go +++ b/testutil/processblock/verify/mint.go @@ -2,12 +2,11 @@ package verify import ( "testing" - "time" + + "github.com/stretchr/testify/require" "github.com/sei-protocol/sei-chain/sei-cosmos/x/auth/signing" "github.com/sei-protocol/sei-chain/testutil/processblock" - minttypes "github.com/sei-protocol/sei-chain/x/mint/types" - "github.com/stretchr/testify/require" ) func MintRelease(t *testing.T, app *processblock.App, f BlockRunnable, _ []signing.Tx) BlockRunnable { @@ -23,15 +22,7 @@ func MintRelease(t *testing.T, app *processblock.App, f BlockRunnable, _ []signi } newPoch := app.EpochKeeper.GetEpoch(app.Ctx()) require.Equal(t, oldEpoch.CurrentEpoch+1, newPoch.CurrentEpoch) - startDate, err := time.Parse(minttypes.TokenReleaseDateFormat, oldMinter.StartDate) - if err != nil { - panic(err) - } - endDate, err := time.Parse(minttypes.TokenReleaseDateFormat, oldMinter.EndDate) - if err != nil { - panic(err) - } - expectedMintedAmount := oldMinter.TotalMintAmount / uint64(endDate.Sub(startDate)/(24*time.Hour)) //nolint:gosec + expectedMintedAmount := oldMinter.GetReleaseAmountToday(app.Ctx().BlockTime()).AmountOf("usei").Uint64() require.Equal(t, expectedMintedAmount, oldMinter.RemainingMintAmount-newMinter.RemainingMintAmount) newSupply := app.BankKeeper.GetSupply(app.Ctx(), "usei") require.Equal(t, expectedMintedAmount, uint64(newSupply.Amount.Int64()-oldSupply.Amount.Int64())) //nolint:gosec From 352d46a8811cb3a21647d264645bd60a7cab1750 Mon Sep 17 00:00:00 2001 From: Danno Ferrin Date: Wed, 9 Sep 2026 15:10:45 -0600 Subject: [PATCH 4/5] fix(processblock): use epoch start time for expected mint amount Review feedback (seidroid, Cursor Bugbot) on the previous commit: MintRelease computed the expected release amount from the post-block BlockTime, but AfterEpochEnd computes the actual mint from the ended epoch's own CurrentEpochStartTime. Those two timestamps are roughly one epoch duration apart, so they can land on different UTC calendar dates around midnight and reintroduce the same flake this test was fixed to remove. oldEpoch already holds the timestamp the hook used. --- testutil/processblock/verify/mint.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/testutil/processblock/verify/mint.go b/testutil/processblock/verify/mint.go index 778d1a2b2c..05ce1733b5 100644 --- a/testutil/processblock/verify/mint.go +++ b/testutil/processblock/verify/mint.go @@ -22,7 +22,7 @@ func MintRelease(t *testing.T, app *processblock.App, f BlockRunnable, _ []signi } newPoch := app.EpochKeeper.GetEpoch(app.Ctx()) require.Equal(t, oldEpoch.CurrentEpoch+1, newPoch.CurrentEpoch) - expectedMintedAmount := oldMinter.GetReleaseAmountToday(app.Ctx().BlockTime()).AmountOf("usei").Uint64() + expectedMintedAmount := oldMinter.GetReleaseAmountToday(oldEpoch.CurrentEpochStartTime.UTC()).AmountOf("usei").Uint64() require.Equal(t, expectedMintedAmount, oldMinter.RemainingMintAmount-newMinter.RemainingMintAmount) newSupply := app.BankKeeper.GetSupply(app.Ctx(), "usei") require.Equal(t, expectedMintedAmount, uint64(newSupply.Amount.Int64()-oldSupply.Amount.Int64())) //nolint:gosec From afac58de7a63afa5b09a7f6654fde1f332b27f7b Mon Sep 17 00:00:00 2001 From: Danno Ferrin Date: Wed, 9 Sep 2026 15:13:02 -0600 Subject: [PATCH 5/5] fix(processblock): apply mint test fixes to giga/deps duplicate giga/deps/testutil/processblock carries a copy of NewMinter and MintRelease with the same timezone- and BlockTime-dependent bugs just fixed in testutil/processblock. Apply the identical fixes here: UTC-anchored start/end calendar dates, and computing the expected release amount via Minter.GetReleaseAmountToday(oldEpoch.CurrentEpochStartTime) instead of re-deriving it by hand. --- giga/deps/testutil/processblock/genesismint.go | 10 ++++++---- giga/deps/testutil/processblock/verify/mint.go | 15 +++------------ 2 files changed, 9 insertions(+), 16 deletions(-) diff --git a/giga/deps/testutil/processblock/genesismint.go b/giga/deps/testutil/processblock/genesismint.go index e4beda3827..bdccdc768b 100644 --- a/giga/deps/testutil/processblock/genesismint.go +++ b/giga/deps/testutil/processblock/genesismint.go @@ -7,11 +7,13 @@ import ( ) func (a *App) NewMinter(amount uint64) { - today := time.Now() - dayAfterTomorrow := today.Add(48 * time.Hour) + // UTC calendar dates so DaysBetween(blockTime, end) matches the + // formatted start/end regardless of local timezone. + today := time.Now().UTC() + start := time.Date(today.Year(), today.Month(), today.Day(), 0, 0, 0, 0, time.UTC) a.MintKeeper.SetMinter(a.Ctx(), minttypes.Minter{ - StartDate: today.Format(minttypes.TokenReleaseDateFormat), - EndDate: dayAfterTomorrow.Format(minttypes.TokenReleaseDateFormat), + StartDate: start.Format(minttypes.TokenReleaseDateFormat), + EndDate: start.AddDate(0, 0, 2).Format(minttypes.TokenReleaseDateFormat), Denom: "usei", TotalMintAmount: amount, RemainingMintAmount: amount, diff --git a/giga/deps/testutil/processblock/verify/mint.go b/giga/deps/testutil/processblock/verify/mint.go index 7a300c51a0..05ce1733b5 100644 --- a/giga/deps/testutil/processblock/verify/mint.go +++ b/giga/deps/testutil/processblock/verify/mint.go @@ -2,12 +2,11 @@ package verify import ( "testing" - "time" + + "github.com/stretchr/testify/require" "github.com/sei-protocol/sei-chain/sei-cosmos/x/auth/signing" "github.com/sei-protocol/sei-chain/testutil/processblock" - minttypes "github.com/sei-protocol/sei-chain/x/mint/types" - "github.com/stretchr/testify/require" ) func MintRelease(t *testing.T, app *processblock.App, f BlockRunnable, _ []signing.Tx) BlockRunnable { @@ -23,15 +22,7 @@ func MintRelease(t *testing.T, app *processblock.App, f BlockRunnable, _ []signi } newPoch := app.EpochKeeper.GetEpoch(app.Ctx()) require.Equal(t, oldEpoch.CurrentEpoch+1, newPoch.CurrentEpoch) - startDate, err := time.Parse(minttypes.TokenReleaseDateFormat, oldMinter.StartDate) - if err != nil { - panic(err) - } - endDate, err := time.Parse(minttypes.TokenReleaseDateFormat, oldMinter.EndDate) - if err != nil { - panic(err) - } - expectedMintedAmount := oldMinter.TotalMintAmount / uint64(endDate.Sub(startDate)/(24*time.Hour)) //nolint:gosec + expectedMintedAmount := oldMinter.GetReleaseAmountToday(oldEpoch.CurrentEpochStartTime.UTC()).AmountOf("usei").Uint64() require.Equal(t, expectedMintedAmount, oldMinter.RemainingMintAmount-newMinter.RemainingMintAmount) newSupply := app.BankKeeper.GetSupply(app.Ctx(), "usei") require.Equal(t, expectedMintedAmount, uint64(newSupply.Amount.Int64()-oldSupply.Amount.Int64())) //nolint:gosec