Skip to content

Commit 4e7c441

Browse files
authored
Merge pull request #2115 from CosmWasm/co/benchmark-unpack-any
Add gas cost for `UnpackAny`
2 parents 6c087f9 + f85d3f6 commit 4e7c441

File tree

3 files changed

+95
-5
lines changed

3 files changed

+95
-5
lines changed

benchmarks/bench_test.go

Lines changed: 82 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,11 +7,19 @@ import (
77

88
abci "github.com/cometbft/cometbft/abci/types"
99
dbm "github.com/cosmos/cosmos-db"
10+
"github.com/cosmos/gogoproto/proto"
1011
"github.com/stretchr/testify/require"
1112
"github.com/syndtr/goleveldb/leveldb/opt"
1213

14+
"cosmossdk.io/x/tx/signing"
15+
16+
"github.com/cosmos/cosmos-sdk/codec"
17+
"github.com/cosmos/cosmos-sdk/codec/address"
18+
codectypes "github.com/cosmos/cosmos-sdk/codec/types"
1319
"github.com/cosmos/cosmos-sdk/crypto/keys/secp256k1"
20+
"github.com/cosmos/cosmos-sdk/std"
1421
sdk "github.com/cosmos/cosmos-sdk/types"
22+
"github.com/cosmos/cosmos-sdk/x/authz"
1523
banktypes "github.com/cosmos/cosmos-sdk/x/bank/types"
1624

1725
wasmtypes "github.com/CosmWasm/wasmd/x/wasm/types"
@@ -119,6 +127,80 @@ func BenchmarkTxSending(b *testing.B) {
119127
}
120128
}
121129

130+
func BenchmarkUnpackAny(b *testing.B) {
131+
interfaceRegistry, err := codectypes.NewInterfaceRegistryWithOptions(codectypes.InterfaceRegistryOptions{
132+
ProtoFiles: proto.HybridResolver,
133+
SigningOptions: signing.Options{
134+
AddressCodec: address.Bech32Codec{
135+
Bech32Prefix: sdk.GetConfig().GetBech32AccountAddrPrefix(),
136+
},
137+
ValidatorAddressCodec: address.Bech32Codec{
138+
Bech32Prefix: sdk.GetConfig().GetBech32ValidatorAddrPrefix(),
139+
},
140+
},
141+
})
142+
require.NoError(b, err)
143+
144+
cdc := codec.NewProtoCodec(interfaceRegistry)
145+
std.RegisterInterfaces(interfaceRegistry)
146+
147+
mustCreateAny := func(b *testing.B, v proto.Message) *codectypes.Any {
148+
b.Helper()
149+
any, err := codectypes.NewAnyWithValue(v)
150+
require.NoError(b, err)
151+
return any
152+
}
153+
154+
createNested := func(b *testing.B, depth int) *codectypes.Any {
155+
b.Helper()
156+
// create nested MsgExecs
157+
nested := authz.NewMsgExec(sdk.AccAddress{}, []sdk.Msg{})
158+
for i := 0; i < depth; i++ {
159+
nested = authz.NewMsgExec(sdk.AccAddress{}, []sdk.Msg{&nested})
160+
}
161+
162+
return mustCreateAny(b, &nested)
163+
}
164+
165+
cases := map[string]struct {
166+
msg *codectypes.Any
167+
expErr bool
168+
}{
169+
"garbage any": {
170+
msg: &codectypes.Any{
171+
TypeUrl: "aslasdf",
172+
Value: []byte("oiuwurjtlwerlwmt032498u50j3oehr943q;l348u58q=-afvu89 290i32-1[1]"),
173+
},
174+
expErr: true,
175+
},
176+
"single MsgExec": {
177+
msg: createNested(b, 1),
178+
},
179+
"10000 MsgExec": {
180+
msg: createNested(b, 10000),
181+
},
182+
"100000 MsgExec": {
183+
msg: createNested(b, 100000),
184+
},
185+
}
186+
187+
for name, tc := range cases {
188+
b.Run(name, func(b *testing.B) {
189+
b.Logf("%s msg size %v", name, len(tc.msg.Value))
190+
b.ResetTimer()
191+
for i := 0; i < b.N; i++ {
192+
var msg sdk.Msg
193+
err := cdc.UnpackAny(tc.msg, &msg)
194+
if tc.expErr {
195+
require.Error(b, err)
196+
} else {
197+
require.NoError(b, err)
198+
}
199+
}
200+
})
201+
}
202+
}
203+
122204
func bankSendMsg(info *AppInfo) ([]sdk.Msg, error) {
123205
// Precompute all txs
124206
rcpt := sdk.AccAddress(secp256k1.GenPrivKey().PubKey().Address())

x/wasm/keeper/handler_plugin_encoders.go

Lines changed: 10 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -24,12 +24,16 @@ import (
2424
"github.com/CosmWasm/wasmd/x/wasm/types"
2525
)
2626

27+
// anyMsgGasCost is the gas cost for unpacking an AnyMsg, in CosmWasm gas units (not SDK gas units).
28+
// With the default gas multiplier, this amounts to 5 SDK gas.
29+
const anyMsgGasCost = 700000
30+
2731
type (
2832
BankEncoder func(sender sdk.AccAddress, msg *wasmvmtypes.BankMsg) ([]sdk.Msg, error)
2933
CustomEncoder func(sender sdk.AccAddress, msg json.RawMessage) ([]sdk.Msg, error)
3034
DistributionEncoder func(sender sdk.AccAddress, msg *wasmvmtypes.DistributionMsg) ([]sdk.Msg, error)
3135
StakingEncoder func(sender sdk.AccAddress, msg *wasmvmtypes.StakingMsg) ([]sdk.Msg, error)
32-
AnyEncoder func(sender sdk.AccAddress, msg *wasmvmtypes.AnyMsg) ([]sdk.Msg, error)
36+
AnyEncoder func(ctx sdk.Context, sender sdk.AccAddress, msg *wasmvmtypes.AnyMsg) ([]sdk.Msg, error)
3337
WasmEncoder func(sender sdk.AccAddress, msg *wasmvmtypes.WasmMsg) ([]sdk.Msg, error)
3438
IBCEncoder func(ctx sdk.Context, sender sdk.AccAddress, contractIBCPortID string, msg *wasmvmtypes.IBCMsg) ([]sdk.Msg, error)
3539
)
@@ -40,7 +44,7 @@ type MessageEncoders struct {
4044
Distribution func(sender sdk.AccAddress, msg *wasmvmtypes.DistributionMsg) ([]sdk.Msg, error)
4145
IBC func(ctx sdk.Context, sender sdk.AccAddress, contractIBCPortID string, msg *wasmvmtypes.IBCMsg) ([]sdk.Msg, error)
4246
Staking func(sender sdk.AccAddress, msg *wasmvmtypes.StakingMsg) ([]sdk.Msg, error)
43-
Any func(sender sdk.AccAddress, msg *wasmvmtypes.AnyMsg) ([]sdk.Msg, error)
47+
Any func(ctx sdk.Context, sender sdk.AccAddress, msg *wasmvmtypes.AnyMsg) ([]sdk.Msg, error)
4448
Wasm func(sender sdk.AccAddress, msg *wasmvmtypes.WasmMsg) ([]sdk.Msg, error)
4549
Gov func(sender sdk.AccAddress, msg *wasmvmtypes.GovMsg) ([]sdk.Msg, error)
4650
}
@@ -102,7 +106,7 @@ func (e MessageEncoders) Encode(ctx sdk.Context, contractAddr sdk.AccAddress, co
102106
case msg.Staking != nil:
103107
return e.Staking(contractAddr, msg.Staking)
104108
case msg.Any != nil:
105-
return e.Any(contractAddr, msg.Any)
109+
return e.Any(ctx, contractAddr, msg.Any)
106110
case msg.Wasm != nil:
107111
return e.Wasm(contractAddr, msg.Wasm)
108112
case msg.Gov != nil:
@@ -206,12 +210,14 @@ func EncodeStakingMsg(sender sdk.AccAddress, msg *wasmvmtypes.StakingMsg) ([]sdk
206210
}
207211

208212
func EncodeAnyMsg(unpacker codectypes.AnyUnpacker) AnyEncoder {
209-
return func(sender sdk.AccAddress, msg *wasmvmtypes.AnyMsg) ([]sdk.Msg, error) {
213+
return func(ctx sdk.Context, sender sdk.AccAddress, msg *wasmvmtypes.AnyMsg) ([]sdk.Msg, error) {
210214
codecAny := codectypes.Any{
211215
TypeUrl: msg.TypeURL,
212216
Value: msg.Value,
213217
}
214218
var sdkMsg sdk.Msg
219+
220+
ctx.GasMeter().ConsumeGas(anyMsgGasCost/types.DefaultGasMultiplier, "unpacking AnyMsg")
215221
if err := unpacker.UnpackAny(&codecAny, &sdkMsg); err != nil {
216222
return nil, errorsmod.Wrap(types.ErrInvalidMsg, fmt.Sprintf("Cannot unpack proto message with type URL: %s", msg.TypeURL))
217223
}

x/wasm/keeper/handler_plugin_encoders_test.go

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@ import (
1313
"github.com/stretchr/testify/require"
1414

1515
sdkmath "cosmossdk.io/math"
16+
storetypes "cosmossdk.io/store/types"
1617

1718
codectypes "github.com/cosmos/cosmos-sdk/codec/types"
1819
sdk "github.com/cosmos/cosmos-sdk/types"
@@ -432,7 +433,8 @@ func TestEncoding(t *testing.T) {
432433
for name, tc := range cases {
433434
t.Run(name, func(t *testing.T) {
434435
encoder := DefaultEncoders(encodingConfig.Codec, wasmtesting.MockIBCTransferKeeper{})
435-
res, err := encoder.Encode(sdk.Context{}, tc.sender, "", tc.srcMsg)
436+
gm := storetypes.NewInfiniteGasMeter()
437+
res, err := encoder.Encode(sdk.Context{}.WithGasMeter(gm), tc.sender, "", tc.srcMsg)
436438
if tc.expError {
437439
assert.Error(t, err)
438440
return

0 commit comments

Comments
 (0)