From 346c59f6e4f60f610d90ebf69aaf332673f3a778 Mon Sep 17 00:00:00 2001 From: mmsqe Date: Wed, 26 Nov 2025 11:44:23 +0800 Subject: [PATCH] feat: allow dynamic retrieval of coin denom from multi store at runtime (#25600) --- CHANGELOG.md | 1 + blockstm/txnrunner.go | 7 ++++--- blockstm/txnrunner_test.go | 29 +++++++++++++++++------------ 3 files changed, 22 insertions(+), 15 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 5c31c6a05e..77043d899b 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -57,6 +57,7 @@ Ref: https://keepachangelog.com/en/1.0.0/ * (abci_utils) [#25008](https://github.com/cosmos/cosmos-sdk/pull/25008) add the ability to assign a custom signer extraction adapter in `DefaultProposalHandler`. * (crypto/ledger) [#25435](https://github.com/cosmos/cosmos-sdk/pull/25435) Add SetDERConversion to reset skipDERConversion and App name for ledger. * (gRPC) [#25565](https://github.com/cosmos/cosmos-sdk/pull/25565) Support for multi gRPC query clients serve with historical binaries to serve proper historical state. +* (blockstm) [#25600](https://github.com/cosmos/cosmos-sdk/pull/25600) Allow dynamic retrieval of the coin denomination from multi store at runtime. ### Improvements diff --git a/blockstm/txnrunner.go b/blockstm/txnrunner.go index 9e50c60522..cbdb5d43a7 100644 --- a/blockstm/txnrunner.go +++ b/blockstm/txnrunner.go @@ -18,7 +18,8 @@ var _ sdk.TxRunner = STMRunner{} func NewSTMRunner( txDecoder sdk.TxDecoder, stores []storetypes.StoreKey, - workers int, estimate bool, coinDenom string, + workers int, estimate bool, + coinDenom func(storetypes.MultiStore) string, ) *STMRunner { return &STMRunner{ txDecoder: txDecoder, @@ -35,7 +36,7 @@ type STMRunner struct { stores []storetypes.StoreKey workers int estimate bool - coinDenom string + coinDenom func(storetypes.MultiStore) string } func (e STMRunner) Run(ctx context.Context, ms storetypes.MultiStore, txs [][]byte, deliverTx sdk.DeliverTxFunc) ([]*abci.ExecTxResult, error) { @@ -68,7 +69,7 @@ func (e STMRunner) Run(ctx context.Context, ms storetypes.MultiStore, txs [][]by ) if e.estimate { - memTxs, estimates = preEstimates(txs, e.workers, authStore, bankStore, e.coinDenom, e.txDecoder) + memTxs, estimates = preEstimates(txs, e.workers, authStore, bankStore, e.coinDenom(ms), e.txDecoder) } if err := ExecuteBlockWithEstimates( diff --git a/blockstm/txnrunner_test.go b/blockstm/txnrunner_test.go index 0dc0779f80..53c8791135 100644 --- a/blockstm/txnrunner_test.go +++ b/blockstm/txnrunner_test.go @@ -30,6 +30,12 @@ func mockTxDecoder(txBytes []byte) (sdk.Tx, error) { return &mockTx{txBytes: txBytes}, nil } +const TestCoinDenom = "stake" + +func testCoinDenomFunc(ms storetypes.MultiStore) string { + return TestCoinDenom +} + type mockTx struct { txBytes []byte } @@ -84,23 +90,22 @@ func TestNewSTMRunner(t *testing.T) { stores := []storetypes.StoreKey{StoreKeyAuth, StoreKeyBank} workers := 4 estimate := true - coinDenom := "stake" - runner := NewSTMRunner(decoder, stores, workers, estimate, coinDenom) + runner := NewSTMRunner(decoder, stores, workers, estimate, testCoinDenomFunc) require.NotNil(t, runner) require.NotNil(t, runner.txDecoder) require.Equal(t, stores, runner.stores) require.Equal(t, workers, runner.workers) require.Equal(t, estimate, runner.estimate) - require.Equal(t, coinDenom, runner.coinDenom) + require.Equal(t, TestCoinDenom, runner.coinDenom(nil)) } // TestSTMRunner_Run_EmptyBlock tests STMRunner with empty block func TestSTMRunner_Run_EmptyBlock(t *testing.T) { decoder := mockTxDecoder stores := []storetypes.StoreKey{StoreKeyAuth, StoreKeyBank} - runner := NewSTMRunner(decoder, stores, 4, false, "stake") + runner := NewSTMRunner(decoder, stores, 4, false, testCoinDenomFunc) ctx := context.Background() ms := msWrapper{NewMultiMemDB(map[storetypes.StoreKey]int{ @@ -123,7 +128,7 @@ func TestSTMRunner_Run_EmptyBlock(t *testing.T) { func TestSTMRunner_Run_WithoutEstimation(t *testing.T) { decoder := mockTxDecoder stores := []storetypes.StoreKey{StoreKeyAuth, StoreKeyBank} - runner := NewSTMRunner(decoder, stores, 2, false, "stake") + runner := NewSTMRunner(decoder, stores, 2, false, testCoinDenomFunc) ctx := context.Background() storeIndex := map[storetypes.StoreKey]int{ @@ -157,7 +162,7 @@ func TestSTMRunner_Run_WithoutEstimation(t *testing.T) { func TestSTMRunner_Run_WithEstimation(t *testing.T) { decoder := mockTxDecoderWithFeeTx stores := []storetypes.StoreKey{StoreKeyAuth, StoreKeyBank} - runner := NewSTMRunner(decoder, stores, 2, true, "stake") + runner := NewSTMRunner(decoder, stores, 2, true, testCoinDenomFunc) ctx := context.Background() storeIndex := map[storetypes.StoreKey]int{ @@ -191,7 +196,7 @@ func TestSTMRunner_Run_WithEstimation(t *testing.T) { func TestSTMRunner_Run_IncarnationCache(t *testing.T) { decoder := mockTxDecoder stores := []storetypes.StoreKey{StoreKeyAuth, StoreKeyBank} - runner := NewSTMRunner(decoder, stores, 2, false, "stake") + runner := NewSTMRunner(decoder, stores, 2, false, testCoinDenomFunc) ctx := context.Background() storeIndex := map[storetypes.StoreKey]int{ @@ -227,7 +232,7 @@ func TestSTMRunner_Run_IncarnationCache(t *testing.T) { func TestSTMRunner_Run_StoreIndexMapping(t *testing.T) { decoder := mockTxDecoder stores := []storetypes.StoreKey{StoreKeyAuth, StoreKeyBank} - runner := NewSTMRunner(decoder, stores, 2, false, "stake") + runner := NewSTMRunner(decoder, stores, 2, false, testCoinDenomFunc) ctx := context.Background() storeIndex := map[storetypes.StoreKey]int{ @@ -257,7 +262,7 @@ func TestSTMRunner_Run_StoreIndexMapping(t *testing.T) { func TestSTMRunner_Run_ContextCancellation(t *testing.T) { decoder := mockTxDecoder stores := []storetypes.StoreKey{StoreKeyAuth, StoreKeyBank} - runner := NewSTMRunner(decoder, stores, 2, false, "stake") + runner := NewSTMRunner(decoder, stores, 2, false, testCoinDenomFunc) ctx, cancel := context.WithTimeout(context.Background(), 1*time.Millisecond) defer cancel() @@ -426,14 +431,14 @@ func TestPreEstimates_KeyEncoding(t *testing.T) { func TestTxRunnerInterface(t *testing.T) { decoder := mockTxDecoder - var _ sdk.TxRunner = NewSTMRunner(decoder, []storetypes.StoreKey{}, 1, false, "") + var _ sdk.TxRunner = NewSTMRunner(decoder, []storetypes.StoreKey{}, 1, false, testCoinDenomFunc) } // TestSTMRunner_Integration tests integration between STMRunner and actual block execution func TestSTMRunner_Integration(t *testing.T) { decoder := mockTxDecoder stores := []storetypes.StoreKey{StoreKeyAuth, StoreKeyBank} - runner := NewSTMRunner(decoder, stores, 4, false, "stake") + runner := NewSTMRunner(decoder, stores, 4, false, testCoinDenomFunc) ctx := context.Background() storeIndex := map[storetypes.StoreKey]int{ @@ -503,7 +508,7 @@ func TestRunnerComparison(t *testing.T) { // Test STMRunner t.Run("STMRunner", func(t *testing.T) { stores := []storetypes.StoreKey{StoreKeyAuth, StoreKeyBank} - runner := NewSTMRunner(decoder, stores, 2, false, "stake") + runner := NewSTMRunner(decoder, stores, 2, false, testCoinDenomFunc) storeIndex := map[storetypes.StoreKey]int{ StoreKeyAuth: 0, StoreKeyBank: 1,