Skip to content

Commit

Permalink
Merge pull request #2115 from CosmWasm/co/benchmark-unpack-any
Browse files Browse the repository at this point in the history
Add gas cost for `UnpackAny`
  • Loading branch information
chipshort authored Feb 10, 2025
2 parents 6c087f9 + f85d3f6 commit 4e7c441
Show file tree
Hide file tree
Showing 3 changed files with 95 additions and 5 deletions.
82 changes: 82 additions & 0 deletions benchmarks/bench_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,11 +7,19 @@ import (

abci "github.com/cometbft/cometbft/abci/types"
dbm "github.com/cosmos/cosmos-db"
"github.com/cosmos/gogoproto/proto"
"github.com/stretchr/testify/require"
"github.com/syndtr/goleveldb/leveldb/opt"

"cosmossdk.io/x/tx/signing"

"github.com/cosmos/cosmos-sdk/codec"
"github.com/cosmos/cosmos-sdk/codec/address"
codectypes "github.com/cosmos/cosmos-sdk/codec/types"
"github.com/cosmos/cosmos-sdk/crypto/keys/secp256k1"
"github.com/cosmos/cosmos-sdk/std"
sdk "github.com/cosmos/cosmos-sdk/types"
"github.com/cosmos/cosmos-sdk/x/authz"
banktypes "github.com/cosmos/cosmos-sdk/x/bank/types"

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

func BenchmarkUnpackAny(b *testing.B) {
interfaceRegistry, err := codectypes.NewInterfaceRegistryWithOptions(codectypes.InterfaceRegistryOptions{
ProtoFiles: proto.HybridResolver,
SigningOptions: signing.Options{
AddressCodec: address.Bech32Codec{
Bech32Prefix: sdk.GetConfig().GetBech32AccountAddrPrefix(),
},
ValidatorAddressCodec: address.Bech32Codec{
Bech32Prefix: sdk.GetConfig().GetBech32ValidatorAddrPrefix(),
},
},
})
require.NoError(b, err)

cdc := codec.NewProtoCodec(interfaceRegistry)
std.RegisterInterfaces(interfaceRegistry)

mustCreateAny := func(b *testing.B, v proto.Message) *codectypes.Any {
b.Helper()
any, err := codectypes.NewAnyWithValue(v)
require.NoError(b, err)
return any
}

createNested := func(b *testing.B, depth int) *codectypes.Any {
b.Helper()
// create nested MsgExecs
nested := authz.NewMsgExec(sdk.AccAddress{}, []sdk.Msg{})
for i := 0; i < depth; i++ {
nested = authz.NewMsgExec(sdk.AccAddress{}, []sdk.Msg{&nested})
}

return mustCreateAny(b, &nested)
}

cases := map[string]struct {
msg *codectypes.Any
expErr bool
}{
"garbage any": {
msg: &codectypes.Any{
TypeUrl: "aslasdf",
Value: []byte("oiuwurjtlwerlwmt032498u50j3oehr943q;l348u58q=-afvu89 290i32-1[1]"),
},
expErr: true,
},
"single MsgExec": {
msg: createNested(b, 1),
},
"10000 MsgExec": {
msg: createNested(b, 10000),
},
"100000 MsgExec": {
msg: createNested(b, 100000),
},
}

for name, tc := range cases {
b.Run(name, func(b *testing.B) {
b.Logf("%s msg size %v", name, len(tc.msg.Value))
b.ResetTimer()
for i := 0; i < b.N; i++ {
var msg sdk.Msg
err := cdc.UnpackAny(tc.msg, &msg)
if tc.expErr {
require.Error(b, err)
} else {
require.NoError(b, err)
}
}
})
}
}

func bankSendMsg(info *AppInfo) ([]sdk.Msg, error) {
// Precompute all txs
rcpt := sdk.AccAddress(secp256k1.GenPrivKey().PubKey().Address())
Expand Down
14 changes: 10 additions & 4 deletions x/wasm/keeper/handler_plugin_encoders.go
Original file line number Diff line number Diff line change
Expand Up @@ -24,12 +24,16 @@ import (
"github.com/CosmWasm/wasmd/x/wasm/types"
)

// anyMsgGasCost is the gas cost for unpacking an AnyMsg, in CosmWasm gas units (not SDK gas units).
// With the default gas multiplier, this amounts to 5 SDK gas.
const anyMsgGasCost = 700000

type (
BankEncoder func(sender sdk.AccAddress, msg *wasmvmtypes.BankMsg) ([]sdk.Msg, error)
CustomEncoder func(sender sdk.AccAddress, msg json.RawMessage) ([]sdk.Msg, error)
DistributionEncoder func(sender sdk.AccAddress, msg *wasmvmtypes.DistributionMsg) ([]sdk.Msg, error)
StakingEncoder func(sender sdk.AccAddress, msg *wasmvmtypes.StakingMsg) ([]sdk.Msg, error)
AnyEncoder func(sender sdk.AccAddress, msg *wasmvmtypes.AnyMsg) ([]sdk.Msg, error)
AnyEncoder func(ctx sdk.Context, sender sdk.AccAddress, msg *wasmvmtypes.AnyMsg) ([]sdk.Msg, error)
WasmEncoder func(sender sdk.AccAddress, msg *wasmvmtypes.WasmMsg) ([]sdk.Msg, error)
IBCEncoder func(ctx sdk.Context, sender sdk.AccAddress, contractIBCPortID string, msg *wasmvmtypes.IBCMsg) ([]sdk.Msg, error)
)
Expand All @@ -40,7 +44,7 @@ type MessageEncoders struct {
Distribution func(sender sdk.AccAddress, msg *wasmvmtypes.DistributionMsg) ([]sdk.Msg, error)
IBC func(ctx sdk.Context, sender sdk.AccAddress, contractIBCPortID string, msg *wasmvmtypes.IBCMsg) ([]sdk.Msg, error)
Staking func(sender sdk.AccAddress, msg *wasmvmtypes.StakingMsg) ([]sdk.Msg, error)
Any func(sender sdk.AccAddress, msg *wasmvmtypes.AnyMsg) ([]sdk.Msg, error)
Any func(ctx sdk.Context, sender sdk.AccAddress, msg *wasmvmtypes.AnyMsg) ([]sdk.Msg, error)
Wasm func(sender sdk.AccAddress, msg *wasmvmtypes.WasmMsg) ([]sdk.Msg, error)
Gov func(sender sdk.AccAddress, msg *wasmvmtypes.GovMsg) ([]sdk.Msg, error)
}
Expand Down Expand Up @@ -102,7 +106,7 @@ func (e MessageEncoders) Encode(ctx sdk.Context, contractAddr sdk.AccAddress, co
case msg.Staking != nil:
return e.Staking(contractAddr, msg.Staking)
case msg.Any != nil:
return e.Any(contractAddr, msg.Any)
return e.Any(ctx, contractAddr, msg.Any)
case msg.Wasm != nil:
return e.Wasm(contractAddr, msg.Wasm)
case msg.Gov != nil:
Expand Down Expand Up @@ -206,12 +210,14 @@ func EncodeStakingMsg(sender sdk.AccAddress, msg *wasmvmtypes.StakingMsg) ([]sdk
}

func EncodeAnyMsg(unpacker codectypes.AnyUnpacker) AnyEncoder {
return func(sender sdk.AccAddress, msg *wasmvmtypes.AnyMsg) ([]sdk.Msg, error) {
return func(ctx sdk.Context, sender sdk.AccAddress, msg *wasmvmtypes.AnyMsg) ([]sdk.Msg, error) {
codecAny := codectypes.Any{
TypeUrl: msg.TypeURL,
Value: msg.Value,
}
var sdkMsg sdk.Msg

ctx.GasMeter().ConsumeGas(anyMsgGasCost/types.DefaultGasMultiplier, "unpacking AnyMsg")
if err := unpacker.UnpackAny(&codecAny, &sdkMsg); err != nil {
return nil, errorsmod.Wrap(types.ErrInvalidMsg, fmt.Sprintf("Cannot unpack proto message with type URL: %s", msg.TypeURL))
}
Expand Down
4 changes: 3 additions & 1 deletion x/wasm/keeper/handler_plugin_encoders_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ import (
"github.com/stretchr/testify/require"

sdkmath "cosmossdk.io/math"
storetypes "cosmossdk.io/store/types"

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

0 comments on commit 4e7c441

Please sign in to comment.