Skip to content

Commit 4c135f3

Browse files
authored
Merge pull request #16 from initia-labs/fix/wasm-stargate
fix: wasm stargate query
2 parents 94f9b37 + 8c47da2 commit 4c135f3

File tree

19 files changed

+2110
-3
lines changed

19 files changed

+2110
-3
lines changed

app/app.go

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -680,9 +680,9 @@ func NewMinitiaApp(
680680

681681
// allow slinky queries
682682
queryAllowlist := make(map[string]proto.Message)
683-
queryAllowlist["/slinky.oracle.v1.Query/GetAllCurrencyPairs"] = &oracletypes.GetAllCurrencyPairsRequest{}
684-
queryAllowlist["/slinky.oracle.v1.Query/GetPrice"] = &oracletypes.GetPriceRequest{}
685-
queryAllowlist["/slinky.oracle.v1.Query/GetPrices"] = &oracletypes.GetPricesRequest{}
683+
queryAllowlist["/slinky.oracle.v1.Query/GetAllCurrencyPairs"] = &oracletypes.GetAllCurrencyPairsResponse{}
684+
queryAllowlist["/slinky.oracle.v1.Query/GetPrice"] = &oracletypes.GetPriceResponse{}
685+
queryAllowlist["/slinky.oracle.v1.Query/GetPrices"] = &oracletypes.GetPricesResponse{}
686686

687687
// use accept list stargate querier
688688
wasmOpts = append(wasmOpts, wasmkeeper.WithQueryPlugins(&wasmkeeper.QueryPlugins{

app/wasmtesting/common_test.go

Lines changed: 328 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,328 @@
1+
package wasm_hooks_test
2+
3+
import (
4+
"encoding/binary"
5+
"testing"
6+
"time"
7+
8+
"github.com/stretchr/testify/require"
9+
10+
"github.com/cometbft/cometbft/crypto"
11+
"github.com/cometbft/cometbft/crypto/ed25519"
12+
tmproto "github.com/cometbft/cometbft/proto/tendermint/types"
13+
14+
"cosmossdk.io/log"
15+
"cosmossdk.io/math"
16+
"cosmossdk.io/store"
17+
"cosmossdk.io/store/metrics"
18+
storetypes "cosmossdk.io/store/types"
19+
"cosmossdk.io/x/tx/signing"
20+
dbm "github.com/cosmos/cosmos-db"
21+
"github.com/cosmos/cosmos-sdk/baseapp"
22+
"github.com/cosmos/cosmos-sdk/client"
23+
"github.com/cosmos/cosmos-sdk/codec"
24+
codecaddress "github.com/cosmos/cosmos-sdk/codec/address"
25+
codectypes "github.com/cosmos/cosmos-sdk/codec/types"
26+
"github.com/cosmos/cosmos-sdk/runtime"
27+
"github.com/cosmos/cosmos-sdk/std"
28+
sdk "github.com/cosmos/cosmos-sdk/types"
29+
"github.com/cosmos/cosmos-sdk/types/module"
30+
"github.com/cosmos/cosmos-sdk/x/auth"
31+
authcodec "github.com/cosmos/cosmos-sdk/x/auth/codec"
32+
authkeeper "github.com/cosmos/cosmos-sdk/x/auth/keeper"
33+
"github.com/cosmos/cosmos-sdk/x/auth/tx"
34+
authtypes "github.com/cosmos/cosmos-sdk/x/auth/types"
35+
"github.com/cosmos/cosmos-sdk/x/bank"
36+
bankkeeper "github.com/cosmos/cosmos-sdk/x/bank/keeper"
37+
banktypes "github.com/cosmos/cosmos-sdk/x/bank/types"
38+
distributiontypes "github.com/cosmos/cosmos-sdk/x/distribution/types"
39+
govtypes "github.com/cosmos/cosmos-sdk/x/gov/types"
40+
stakingtypes "github.com/cosmos/cosmos-sdk/x/staking/types"
41+
"github.com/cosmos/gogoproto/proto"
42+
43+
"github.com/CosmWasm/wasmd/x/wasm"
44+
wasmkeeper "github.com/CosmWasm/wasmd/x/wasm/keeper"
45+
wasmtypes "github.com/CosmWasm/wasmd/x/wasm/types"
46+
47+
"github.com/skip-mev/slinky/x/oracle"
48+
oraclekeeper "github.com/skip-mev/slinky/x/oracle/keeper"
49+
oracletypes "github.com/skip-mev/slinky/x/oracle/types"
50+
)
51+
52+
var ModuleBasics = module.NewBasicManager(
53+
auth.AppModuleBasic{},
54+
bank.AppModuleBasic{},
55+
wasm.AppModuleBasic{},
56+
oracle.AppModuleBasic{},
57+
)
58+
59+
var (
60+
initiaSupply = math.NewInt(100_000_000_000)
61+
testDenoms = []string{
62+
"test1",
63+
"test2",
64+
"test3",
65+
"test4",
66+
"test5",
67+
}
68+
)
69+
70+
type EncodingConfig struct {
71+
InterfaceRegistry codectypes.InterfaceRegistry
72+
Codec codec.Codec
73+
TxConfig client.TxConfig
74+
Amino *codec.LegacyAmino
75+
}
76+
77+
func MakeTestCodec(t testing.TB) codec.Codec {
78+
return MakeEncodingConfig(t).Codec
79+
}
80+
81+
func MakeEncodingConfig(_ testing.TB) EncodingConfig {
82+
interfaceRegistry, _ := codectypes.NewInterfaceRegistryWithOptions(codectypes.InterfaceRegistryOptions{
83+
ProtoFiles: proto.HybridResolver,
84+
SigningOptions: signing.Options{
85+
AddressCodec: codecaddress.NewBech32Codec(sdk.GetConfig().GetBech32AccountAddrPrefix()),
86+
ValidatorAddressCodec: codecaddress.NewBech32Codec(sdk.GetConfig().GetBech32ValidatorAddrPrefix()),
87+
},
88+
})
89+
appCodec := codec.NewProtoCodec(interfaceRegistry)
90+
legacyAmino := codec.NewLegacyAmino()
91+
txConfig := tx.NewTxConfig(appCodec, tx.DefaultSignModes)
92+
93+
std.RegisterInterfaces(interfaceRegistry)
94+
std.RegisterLegacyAminoCodec(legacyAmino)
95+
96+
ModuleBasics.RegisterLegacyAminoCodec(legacyAmino)
97+
ModuleBasics.RegisterInterfaces(interfaceRegistry)
98+
99+
return EncodingConfig{
100+
InterfaceRegistry: interfaceRegistry,
101+
Codec: appCodec,
102+
TxConfig: txConfig,
103+
Amino: legacyAmino,
104+
}
105+
}
106+
107+
var bondDenom = sdk.DefaultBondDenom
108+
109+
func initialTotalSupply() sdk.Coins {
110+
faucetBalance := sdk.NewCoins(sdk.NewCoin(bondDenom, initiaSupply))
111+
for _, testDenom := range testDenoms {
112+
faucetBalance = faucetBalance.Add(sdk.NewCoin(testDenom, initiaSupply))
113+
}
114+
115+
return faucetBalance
116+
}
117+
118+
type TestFaucet struct {
119+
t testing.TB
120+
bankKeeper bankkeeper.Keeper
121+
sender sdk.AccAddress
122+
balance sdk.Coins
123+
minterModuleName string
124+
}
125+
126+
func NewTestFaucet(t testing.TB, ctx sdk.Context, bankKeeper bankkeeper.Keeper, minterModuleName string, initiaSupply ...sdk.Coin) *TestFaucet {
127+
require.NotEmpty(t, initiaSupply)
128+
r := &TestFaucet{t: t, bankKeeper: bankKeeper, minterModuleName: minterModuleName}
129+
_, _, addr := keyPubAddr()
130+
r.sender = addr
131+
r.Mint(ctx, addr, initiaSupply...)
132+
r.balance = initiaSupply
133+
return r
134+
}
135+
136+
func (f *TestFaucet) Mint(parentCtx sdk.Context, addr sdk.AccAddress, amounts ...sdk.Coin) {
137+
amounts = sdk.Coins(amounts).Sort()
138+
require.NotEmpty(f.t, amounts)
139+
ctx := parentCtx.WithEventManager(sdk.NewEventManager()) // discard all faucet related events
140+
err := f.bankKeeper.MintCoins(ctx, f.minterModuleName, amounts)
141+
require.NoError(f.t, err)
142+
err = f.bankKeeper.SendCoinsFromModuleToAccount(ctx, f.minterModuleName, addr, amounts)
143+
require.NoError(f.t, err)
144+
f.balance = f.balance.Add(amounts...)
145+
}
146+
147+
func (f *TestFaucet) Fund(parentCtx sdk.Context, receiver sdk.AccAddress, amounts ...sdk.Coin) {
148+
require.NotEmpty(f.t, amounts)
149+
// ensure faucet is always filled
150+
if !f.balance.IsAllGTE(amounts) {
151+
f.Mint(parentCtx, f.sender, amounts...)
152+
}
153+
ctx := parentCtx.WithEventManager(sdk.NewEventManager()) // discard all faucet related events
154+
err := f.bankKeeper.SendCoins(ctx, f.sender, receiver, amounts)
155+
require.NoError(f.t, err)
156+
f.balance = f.balance.Sub(amounts...)
157+
}
158+
159+
func (f *TestFaucet) NewFundedAccount(ctx sdk.Context, amounts ...sdk.Coin) sdk.AccAddress {
160+
_, _, addr := keyPubAddr()
161+
f.Fund(ctx, addr, amounts...)
162+
return addr
163+
}
164+
165+
type TestKeepers struct {
166+
AccountKeeper authkeeper.AccountKeeper
167+
BankKeeper bankkeeper.Keeper
168+
WasmKeeper wasmkeeper.Keeper
169+
OracleKeeper oraclekeeper.Keeper
170+
171+
EncodingConfig EncodingConfig
172+
Faucet *TestFaucet
173+
MultiStore storetypes.CommitMultiStore
174+
}
175+
176+
// createDefaultTestInput common settings for createTestInput
177+
func createDefaultTestInput(t testing.TB) (sdk.Context, TestKeepers) {
178+
return createTestInput(t, false)
179+
}
180+
181+
// createTestInput encoders can be nil to accept the defaults, or set it to override some of the message handlers (like default)
182+
func createTestInput(t testing.TB, isCheckTx bool) (sdk.Context, TestKeepers) {
183+
// Load default move config
184+
return _createTestInput(t, isCheckTx, dbm.NewMemDB())
185+
}
186+
187+
var keyCounter uint64
188+
189+
// we need to make this deterministic (same every test run), as encoded address size and thus gas cost,
190+
// depends on the actual bytes (due to ugly CanonicalAddress encoding)
191+
func keyPubAddr() (crypto.PrivKey, crypto.PubKey, sdk.AccAddress) {
192+
keyCounter++
193+
seed := make([]byte, 8)
194+
binary.BigEndian.PutUint64(seed, keyCounter)
195+
196+
key := ed25519.GenPrivKeyFromSecret(seed)
197+
pub := key.PubKey()
198+
addr := sdk.AccAddress(pub.Address())
199+
return key, pub, addr
200+
}
201+
202+
// encoders can be nil to accept the defaults, or set it to override some of the message handlers (like default)
203+
func _createTestInput(
204+
t testing.TB,
205+
isCheckTx bool,
206+
db dbm.DB,
207+
) (sdk.Context, TestKeepers) {
208+
keys := storetypes.NewKVStoreKeys(
209+
authtypes.StoreKey, banktypes.StoreKey, stakingtypes.StoreKey,
210+
distributiontypes.StoreKey, wasmtypes.StoreKey,
211+
oracletypes.StoreKey,
212+
)
213+
ms := store.NewCommitMultiStore(db, log.NewNopLogger(), metrics.NewNoOpMetrics())
214+
for _, v := range keys {
215+
ms.MountStoreWithDB(v, storetypes.StoreTypeIAVL, db)
216+
}
217+
memKeys := storetypes.NewMemoryStoreKeys()
218+
for _, v := range memKeys {
219+
ms.MountStoreWithDB(v, storetypes.StoreTypeMemory, db)
220+
}
221+
222+
require.NoError(t, ms.LoadLatestVersion())
223+
224+
ctx := sdk.NewContext(ms, tmproto.Header{
225+
Height: 1,
226+
Time: time.Date(2020, time.April, 22, 12, 0, 0, 0, time.UTC),
227+
}, isCheckTx, log.NewNopLogger()).WithHeaderHash(make([]byte, 32))
228+
229+
encodingConfig := MakeEncodingConfig(t)
230+
appCodec := encodingConfig.Codec
231+
232+
maccPerms := map[string][]string{ // module account permissions
233+
authtypes.FeeCollectorName: nil,
234+
235+
// for testing
236+
authtypes.Minter: {authtypes.Minter, authtypes.Burner},
237+
}
238+
239+
ac := authcodec.NewBech32Codec(sdk.GetConfig().GetBech32AccountAddrPrefix())
240+
241+
accountKeeper := authkeeper.NewAccountKeeper(
242+
appCodec,
243+
runtime.NewKVStoreService(keys[authtypes.StoreKey]), // target store
244+
authtypes.ProtoBaseAccount, // prototype
245+
maccPerms,
246+
ac,
247+
sdk.GetConfig().GetBech32AccountAddrPrefix(),
248+
authtypes.NewModuleAddress(govtypes.ModuleName).String(),
249+
)
250+
blockedAddrs := make(map[string]bool)
251+
for acc := range maccPerms {
252+
blockedAddrs[authtypes.NewModuleAddress(acc).String()] = true
253+
}
254+
255+
bankKeeper := bankkeeper.NewBaseKeeper(
256+
appCodec,
257+
runtime.NewKVStoreService(keys[banktypes.StoreKey]),
258+
accountKeeper,
259+
blockedAddrs,
260+
authtypes.NewModuleAddress(govtypes.ModuleName).String(),
261+
ctx.Logger().With("module", "x/"+banktypes.ModuleName),
262+
)
263+
require.NoError(t, bankKeeper.SetParams(ctx, banktypes.DefaultParams()))
264+
265+
oracleKeeper := oraclekeeper.NewKeeper(
266+
runtime.NewKVStoreService(keys[oracletypes.StoreKey]),
267+
appCodec,
268+
authtypes.NewModuleAddress(govtypes.ModuleName),
269+
)
270+
271+
msgRouter := baseapp.NewMsgServiceRouter()
272+
msgRouter.SetInterfaceRegistry(encodingConfig.InterfaceRegistry)
273+
queryRouter := baseapp.NewGRPCQueryRouter()
274+
queryRouter.SetInterfaceRegistry(encodingConfig.InterfaceRegistry)
275+
276+
queryAllowlist := make(map[string]proto.Message)
277+
queryAllowlist["/slinky.oracle.v1.Query/GetAllCurrencyPairs"] = &oracletypes.GetAllCurrencyPairsResponse{}
278+
queryAllowlist["/slinky.oracle.v1.Query/GetPrice"] = &oracletypes.GetPriceResponse{}
279+
queryAllowlist["/slinky.oracle.v1.Query/GetPrices"] = &oracletypes.GetPricesResponse{}
280+
281+
// use accept list stargate querier
282+
wasmOpts := []wasmkeeper.Option{}
283+
wasmOpts = append(wasmOpts, wasmkeeper.WithQueryPlugins(&wasmkeeper.QueryPlugins{
284+
Stargate: wasmkeeper.AcceptListStargateQuerier(queryAllowlist, queryRouter, appCodec),
285+
}))
286+
287+
wasmKeeper := wasmkeeper.NewKeeper(
288+
appCodec,
289+
runtime.NewKVStoreService(keys[wasmtypes.StoreKey]),
290+
accountKeeper,
291+
bankKeeper,
292+
nil,
293+
nil,
294+
nil,
295+
nil,
296+
nil,
297+
nil,
298+
nil,
299+
msgRouter,
300+
queryRouter,
301+
t.TempDir(),
302+
wasmtypes.DefaultWasmConfig(),
303+
"iterator,stargate,cosmwasm_1_1,cosmwasm_1_2,cosmwasm_1_3,cosmwasm_1_4",
304+
authtypes.NewModuleAddress(govtypes.ModuleName).String(),
305+
wasmOpts...,
306+
)
307+
wasmParams := wasmtypes.DefaultParams()
308+
require.NoError(t, wasmKeeper.SetParams(ctx, wasmParams))
309+
310+
faucet := NewTestFaucet(t, ctx, bankKeeper, authtypes.Minter, initialTotalSupply()...)
311+
312+
// register query service
313+
am := module.NewManager( // minimal module set that we use for message/ query tests
314+
oracle.NewAppModule(appCodec, oracleKeeper),
315+
)
316+
am.RegisterServices(module.NewConfigurator(appCodec, msgRouter, queryRouter)) //nolint:errcheck
317+
318+
keepers := TestKeepers{
319+
AccountKeeper: accountKeeper,
320+
WasmKeeper: wasmKeeper,
321+
BankKeeper: bankKeeper,
322+
OracleKeeper: oracleKeeper,
323+
EncodingConfig: encodingConfig,
324+
Faucet: faucet,
325+
MultiStore: ms,
326+
}
327+
return ctx, keepers
328+
}
Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
[alias]
2+
wasm = "build --release --target wasm32-unknown-unknown"
3+
wasm-debug = "build --target wasm32-unknown-unknown"
4+
unit-test = "test --lib"
5+
schema = "run --example schema"
6+
7+
[build]
8+
rustflags = ["-C", "link-args=-s"]

app/wasmtesting/contracts/.gitignore

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
# macOS
2+
.DS_Store
3+
4+
# Text file backups
5+
**/*.rs.bk
6+
7+
# Build results
8+
target/
9+
10+
# IDEs
11+
.vscode/
12+
.idea/
13+
*.iml

0 commit comments

Comments
 (0)