Skip to content

Commit 18cc4d8

Browse files
committed
fix(app): reconciliation saveUnbalancedBlockHeight store-key mismatch (MOCA-670)
saveUnbalancedBlockHeight resolved the reconciliation commit store with a freshly built storetypes.NewKVStoreKey, but rootmulti keys its store map by StoreKey identity (rs.stores[key]). The fresh key is absent, so GetCommitStore returns nil and the (*iavl.Store) assertion panics: "interface conversion: types.CommitStore is nil, not *iavl.Store". getUnbalancedBlockHeight already uses the mounted app.GetKey; align save with it (and drop the now-unused storetypes import). The panic is masked when inter-block-cache is enabled (the default): the cache's Unwrap resolves by name and returns the underlying store. It only bites nodes with inter-block-cache=false, where a reconciliation imbalance then halts consensus with the opaque panic instead of the intended graceful "unbalanced state at block height N, please use hardfork to bypass it". Reproduced on the test-box: unit test (no cache) + single-node and 4-node localnets with inter-block-cache=false. Adds a regression test that panics before the fix and round-trips after. Signed-off-by: puneetmahajan <59960662+puneet2019@users.noreply.github.com>
1 parent df98706 commit 18cc4d8

2 files changed

Lines changed: 20 additions & 2 deletions

File tree

app/reconciliation.go

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,6 @@ import (
88

99
"cosmossdk.io/math"
1010
"cosmossdk.io/store/iavl"
11-
storetypes "cosmossdk.io/store/types"
1211
sdk "github.com/cosmos/cosmos-sdk/types"
1312
banktypes "github.com/cosmos/cosmos-sdk/x/bank/types"
1413

@@ -160,7 +159,7 @@ func (app *Moca) reconPaymentChanges(ctx sdk.Context, paymentIavl *iavl.Store) b
160159
}
161160

162161
func (app *Moca) saveUnbalancedBlockHeight(ctx sdk.Context) {
163-
reconStore := app.CommitMultiStore().GetCommitStore(storetypes.NewKVStoreKey(reconStoreKey)).(*iavl.Store)
162+
reconStore := app.CommitMultiStore().GetCommitStore(app.GetKey(reconStoreKey)).(*iavl.Store)
164163
bz := make([]byte, 8)
165164
binary.BigEndian.PutUint64(bz, uint64(ctx.BlockHeight()))
166165
reconStore.Set(unbalancedBlockHeightKey, bz)

app/reconciliation_test.go

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,3 +25,22 @@ func TestParseDenomFromSupplyKey(t *testing.T) {
2525
key, _ := hex.DecodeString("00616d6f6361")
2626
require.Equal(t, "amoca", parseDenomFromSupplyKey(key))
2727
}
28+
29+
// TestSaveUnbalancedBlockHeight_UsesMountedStoreKey is the regression test for MOCA-670.
30+
// saveUnbalancedBlockHeight resolved the reconciliation commit store with a freshly built
31+
// storetypes.NewKVStoreKey(reconStoreKey). rootmulti keys its store map by StoreKey identity
32+
// (rs.stores[key]), so a fresh key is absent -> GetCommitStore returns nil -> the (*iavl.Store)
33+
// assertion panics ("interface conversion: types.CommitStore is nil, not *iavl.Store").
34+
// getUnbalancedBlockHeight already uses the mounted app.GetKey and works; this asserts save
35+
// resolves + round-trips the same way. It panics (fails) on the unfixed code.
36+
func TestSaveUnbalancedBlockHeight_UsesMountedStoreKey(t *testing.T) {
37+
mocaApp := EthSetup(false, nil)
38+
ctx := mocaApp.NewContext(false).WithBlockHeight(4242)
39+
40+
require.NotPanics(t, func() { mocaApp.saveUnbalancedBlockHeight(ctx) },
41+
"saveUnbalancedBlockHeight must resolve the recon store via the mounted key (app.GetKey)")
42+
43+
h, ok := mocaApp.getUnbalancedBlockHeight(ctx)
44+
require.True(t, ok, "unbalanced height must be persisted")
45+
require.Equal(t, uint64(4242), h)
46+
}

0 commit comments

Comments
 (0)