Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add customizable WasmLimits #1989

Merged
merged 11 commits into from
Nov 8, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 3 additions & 3 deletions app/ante.go
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ type HandlerOptions struct {
ante.HandlerOptions

IBCKeeper *keeper.Keeper
WasmConfig *wasmTypes.WasmConfig
NodeConfig *wasmTypes.NodeConfig
WasmKeeper *wasmkeeper.Keeper
TXCounterStoreService corestoretypes.KVStoreService
CircuitKeeper *circuitkeeper.Keeper
Expand All @@ -40,7 +40,7 @@ func NewAnteHandler(options HandlerOptions) (sdk.AnteHandler, error) {
if options.SignModeHandler == nil {
return nil, errors.New("sign mode handler is required for ante builder")
}
if options.WasmConfig == nil {
if options.NodeConfig == nil {
return nil, errors.New("wasm config is required for ante builder")
}
if options.TXCounterStoreService == nil {
Expand All @@ -52,7 +52,7 @@ func NewAnteHandler(options HandlerOptions) (sdk.AnteHandler, error) {

anteDecorators := []sdk.AnteDecorator{
ante.NewSetUpContextDecorator(), // outermost AnteDecorator. SetUpContext must be called first
wasmkeeper.NewLimitSimulationGasDecorator(options.WasmConfig.SimulationGasLimit), // after setup context to enforce limits early
wasmkeeper.NewLimitSimulationGasDecorator(options.NodeConfig.SimulationGasLimit), // after setup context to enforce limits early
wasmkeeper.NewCountTXDecorator(options.TXCounterStoreService),
wasmkeeper.NewGasRegisterDecorator(options.WasmKeeper.GetGasRegister()),
wasmkeeper.NewTxContractsDecorator(),
Expand Down
11 changes: 6 additions & 5 deletions app/app.go
Original file line number Diff line number Diff line change
Expand Up @@ -623,7 +623,7 @@ func NewWasmApp(
)

wasmDir := filepath.Join(homePath, "wasm")
wasmConfig, err := wasm.ReadWasmConfig(appOpts)
nodeConfig, err := wasm.ReadNodeConfig(appOpts)
if err != nil {
panic(fmt.Sprintf("error while reading wasm config: %s", err))
}
Expand All @@ -645,7 +645,8 @@ func NewWasmApp(
app.MsgServiceRouter(),
app.GRPCQueryRouter(),
wasmDir,
wasmConfig,
nodeConfig,
wasmtypes.VMConfig{},
wasmkeeper.BuiltInCapabilities(),
authtypes.NewModuleAddress(govtypes.ModuleName).String(),
wasmOpts...,
Expand Down Expand Up @@ -871,7 +872,7 @@ func NewWasmApp(
app.SetPreBlocker(app.PreBlocker)
app.SetBeginBlocker(app.BeginBlocker)
app.SetEndBlocker(app.EndBlocker)
app.setAnteHandler(txConfig, wasmConfig, keys[wasmtypes.StoreKey])
app.setAnteHandler(txConfig, nodeConfig, keys[wasmtypes.StoreKey])

// must be before Loading version
// requires the snapshot store to be created and registered as a BaseAppOption
Expand Down Expand Up @@ -934,7 +935,7 @@ func NewWasmApp(
return app
}

func (app *WasmApp) setAnteHandler(txConfig client.TxConfig, wasmConfig wasmtypes.WasmConfig, txCounterStoreKey *storetypes.KVStoreKey) {
func (app *WasmApp) setAnteHandler(txConfig client.TxConfig, nodeConfig wasmtypes.NodeConfig, txCounterStoreKey *storetypes.KVStoreKey) {
anteHandler, err := NewAnteHandler(
HandlerOptions{
HandlerOptions: ante.HandlerOptions{
Expand All @@ -945,7 +946,7 @@ func (app *WasmApp) setAnteHandler(txConfig client.TxConfig, wasmConfig wasmtype
SigGasConsumer: ante.DefaultSigVerificationGasConsumer,
},
IBCKeeper: app.IBCKeeper,
WasmConfig: &wasmConfig,
NodeConfig: &nodeConfig,
WasmKeeper: &app.WasmKeeper,
TXCounterStoreService: runtime.NewKVStoreService(txCounterStoreKey),
CircuitKeeper: &app.CircuitKeeper,
Expand Down
4 changes: 2 additions & 2 deletions cmd/wasmd/commands.go
Original file line number Diff line number Diff line change
Expand Up @@ -61,7 +61,7 @@ func initAppConfig() (string, interface{}) {
type CustomAppConfig struct {
serverconfig.Config

Wasm wasmtypes.WasmConfig `mapstructure:"wasm"`
Wasm wasmtypes.NodeConfig `mapstructure:"wasm"`
}

// Optionally allow the chain developer to overwrite the SDK's default
Expand All @@ -84,7 +84,7 @@ func initAppConfig() (string, interface{}) {

customAppConfig := CustomAppConfig{
Config: *srvCfg,
Wasm: wasmtypes.DefaultWasmConfig(),
Wasm: wasmtypes.DefaultNodeConfig(),
}

customAppTemplate := serverconfig.DefaultConfigTemplate +
Expand Down
31 changes: 31 additions & 0 deletions docs/proto/proto-docs.md
Original file line number Diff line number Diff line change
Expand Up @@ -85,6 +85,8 @@
- [QueryRawContractStateResponse](#cosmwasm.wasm.v1.QueryRawContractStateResponse)
- [QuerySmartContractStateRequest](#cosmwasm.wasm.v1.QuerySmartContractStateRequest)
- [QuerySmartContractStateResponse](#cosmwasm.wasm.v1.QuerySmartContractStateResponse)
- [QueryWasmLimitsConfigRequest](#cosmwasm.wasm.v1.QueryWasmLimitsConfigRequest)
- [QueryWasmLimitsConfigResponse](#cosmwasm.wasm.v1.QueryWasmLimitsConfigResponse)

- [Query](#cosmwasm.wasm.v1.Query)

Expand Down Expand Up @@ -1421,6 +1423,34 @@ Query/SmartContractState RPC method




<a name="cosmwasm.wasm.v1.QueryWasmLimitsConfigRequest"></a>

### QueryWasmLimitsConfigRequest
QueryWasmLimitsConfigRequest is the request type for the
Query/WasmLimitsConfig RPC method.






<a name="cosmwasm.wasm.v1.QueryWasmLimitsConfigResponse"></a>

### QueryWasmLimitsConfigResponse
QueryWasmLimitsConfigResponse is the response type for the
Query/WasmLimitsConfig RPC method. It contains the JSON encoded limits for
static validation of Wasm files.


| Field | Type | Label | Description |
| ----- | ---- | ----- | ----------- |
| `config` | [string](#string) | | |





<!-- end messages -->

<!-- end enums -->
Expand All @@ -1447,6 +1477,7 @@ Query provides defines the gRPC querier service
| `PinnedCodes` | [QueryPinnedCodesRequest](#cosmwasm.wasm.v1.QueryPinnedCodesRequest) | [QueryPinnedCodesResponse](#cosmwasm.wasm.v1.QueryPinnedCodesResponse) | PinnedCodes gets the pinned code ids | GET|/cosmwasm/wasm/v1/codes/pinned|
| `Params` | [QueryParamsRequest](#cosmwasm.wasm.v1.QueryParamsRequest) | [QueryParamsResponse](#cosmwasm.wasm.v1.QueryParamsResponse) | Params gets the module params | GET|/cosmwasm/wasm/v1/codes/params|
| `ContractsByCreator` | [QueryContractsByCreatorRequest](#cosmwasm.wasm.v1.QueryContractsByCreatorRequest) | [QueryContractsByCreatorResponse](#cosmwasm.wasm.v1.QueryContractsByCreatorResponse) | ContractsByCreator gets the contracts by creator | GET|/cosmwasm/wasm/v1/contracts/creator/{creator_address}|
| `WasmLimitsConfig` | [QueryWasmLimitsConfigRequest](#cosmwasm.wasm.v1.QueryWasmLimitsConfigRequest) | [QueryWasmLimitsConfigResponse](#cosmwasm.wasm.v1.QueryWasmLimitsConfigResponse) | WasmLimitsConfig gets the configured limits for static validation of Wasm files, encoded in JSON. | GET|/cosmwasm/wasm/v1/wasm-limits-config|
| `BuildAddress` | [QueryBuildAddressRequest](#cosmwasm.wasm.v1.QueryBuildAddressRequest) | [QueryBuildAddressResponse](#cosmwasm.wasm.v1.QueryBuildAddressResponse) | BuildAddress builds a contract address | GET|/cosmwasm/wasm/v1/contract/build_address|

<!-- end services -->
Expand Down
16 changes: 16 additions & 0 deletions proto/cosmwasm/wasm/v1/query.proto
Original file line number Diff line number Diff line change
Expand Up @@ -90,6 +90,13 @@ service Query {
"/cosmwasm/wasm/v1/contracts/creator/{creator_address}";
}

// WasmLimitsConfig gets the configured limits for static validation of Wasm
// files, encoded in JSON.
rpc WasmLimitsConfig(QueryWasmLimitsConfigRequest)
returns (QueryWasmLimitsConfigResponse) {
option (google.api.http).get = "/cosmwasm/wasm/v1/wasm-limits-config";
}

// BuildAddress builds a contract address
rpc BuildAddress(QueryBuildAddressRequest)
returns (QueryBuildAddressResponse) {
Expand Down Expand Up @@ -317,6 +324,15 @@ message QueryContractsByCreatorResponse {
cosmos.base.query.v1beta1.PageResponse pagination = 2;
}

// QueryWasmLimitsConfigRequest is the request type for the
// Query/WasmLimitsConfig RPC method.
message QueryWasmLimitsConfigRequest {}

// QueryWasmLimitsConfigResponse is the response type for the
// Query/WasmLimitsConfig RPC method. It contains the JSON encoded limits for
// static validation of Wasm files.
message QueryWasmLimitsConfigResponse { string config = 1; }
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Do we have a specific struct that we can define for config or we want to keep it flexible?
In that case, we could evaluate using bytes instead of string. WDYT?

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

As mentioned in our chat, I want to keep it flexible. The reason for string instead of bytes is that I want to make it easy for contract devs to copy and paste the limits. They need pass them into cosmwasm-check. See here: https://github.com/CosmWasm/cosmwasm/blob/cf413c5ad6a58a87e0be894584f01506f3b2e0af/packages/check/src/main.rs#L41-L50


// QueryBuildAddressRequest is the request type for the Query/BuildAddress RPC
// method.
message QueryBuildAddressRequest {
Expand Down
18 changes: 9 additions & 9 deletions tests/integration/module_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -446,25 +446,25 @@ func TestHandleExecuteEscrow(t *testing.T) {
assert.Equal(t, sdk.Coins{}, data.bankKeeper.GetAllBalances(data.ctx, contractAcct.GetAddress()))
}

func TestReadWasmConfig(t *testing.T) {
func TestReadNodeConfig(t *testing.T) {
withViper := func(s string) *viper.Viper {
v := viper.New()
v.SetConfigType("toml")
require.NoError(t, v.ReadConfig(strings.NewReader(s)))
return v
}
var one uint64 = 1
defaults := types.DefaultWasmConfig()
defaults := types.DefaultNodeConfig()

specs := map[string]struct {
src servertypes.AppOptions
exp types.WasmConfig
exp types.NodeConfig
}{
"set query gas limit via opts": {
src: AppOptionsMock{
"wasm.query_gas_limit": 1,
},
exp: types.WasmConfig{
exp: types.NodeConfig{
SmartQueryGasLimit: 1,
MemoryCacheSize: defaults.MemoryCacheSize,
},
Expand All @@ -473,7 +473,7 @@ func TestReadWasmConfig(t *testing.T) {
src: AppOptionsMock{
"wasm.memory_cache_size": 2,
},
exp: types.WasmConfig{
exp: types.NodeConfig{
MemoryCacheSize: 2,
SmartQueryGasLimit: defaults.SmartQueryGasLimit,
},
Expand All @@ -482,7 +482,7 @@ func TestReadWasmConfig(t *testing.T) {
src: AppOptionsMock{
"trace": true,
},
exp: types.WasmConfig{
exp: types.NodeConfig{
SmartQueryGasLimit: defaults.SmartQueryGasLimit,
MemoryCacheSize: defaults.MemoryCacheSize,
ContractDebugMode: true,
Expand All @@ -497,12 +497,12 @@ func TestReadWasmConfig(t *testing.T) {
exp: defaults,
},
"custom config template values": {
src: withViper(types.ConfigTemplate(types.WasmConfig{
src: withViper(types.ConfigTemplate(types.NodeConfig{
SimulationGasLimit: &one,
SmartQueryGasLimit: 2,
MemoryCacheSize: 3,
})),
exp: types.WasmConfig{
exp: types.NodeConfig{
SimulationGasLimit: &one,
SmartQueryGasLimit: 2,
MemoryCacheSize: 3,
Expand All @@ -512,7 +512,7 @@ func TestReadWasmConfig(t *testing.T) {
}
for msg, spec := range specs {
t.Run(msg, func(t *testing.T) {
got, err := wasm.ReadWasmConfig(spec.src)
got, err := wasm.ReadNodeConfig(spec.src)
require.NoError(t, err)
assert.Equal(t, spec.exp, got)
})
Expand Down
4 changes: 2 additions & 2 deletions x/wasm/alias.go
Original file line number Diff line number Diff line change
Expand Up @@ -51,7 +51,7 @@ var (
// Deprecated: Do not use.
NewWasmCoins = types.NewWasmCoins
// Deprecated: Do not use.
DefaultWasmConfig = types.DefaultWasmConfig
DefaultNodeConfig = types.DefaultNodeConfig
// Deprecated: Do not use.
DefaultParams = types.DefaultParams
// Deprecated: Do not use.
Expand Down Expand Up @@ -174,7 +174,7 @@ type (
// Deprecated: Do not use.
CreatedAt = types.AbsoluteTxPosition
// Deprecated: Do not use.
Config = types.WasmConfig
Config = types.NodeConfig
// Deprecated: Do not use.
CodeInfoResponse = types.CodeInfoResponse
// Deprecated: Do not use.
Expand Down
8 changes: 4 additions & 4 deletions x/wasm/keeper/bench_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -51,8 +51,8 @@ func BenchmarkInstantiationOverhead(b *testing.B) {
}
for name, spec := range specs {
b.Run(name, func(b *testing.B) {
wasmConfig := types.WasmConfig{MemoryCacheSize: 0}
ctx, keepers := createTestInput(b, false, AvailableCapabilities, wasmConfig, spec.db())
nodeConfig := types.NodeConfig{MemoryCacheSize: 0}
ctx, keepers := createTestInput(b, false, AvailableCapabilities, nodeConfig, types.VMConfig{}, spec.db())
example := InstantiateHackatomExampleContract(b, ctx, keepers)
if spec.pinned {
require.NoError(b, keepers.ContractKeeper.PinCode(ctx, example.CodeID))
Expand Down Expand Up @@ -85,9 +85,9 @@ func BenchmarkCompilation(b *testing.B) {

for name, spec := range specs {
b.Run(name, func(b *testing.B) {
wasmConfig := types.WasmConfig{MemoryCacheSize: 0}
nodeConfig := types.NodeConfig{MemoryCacheSize: 0}
db := dbm.NewMemDB()
ctx, keepers := createTestInput(b, false, AvailableCapabilities, wasmConfig, db)
ctx, keepers := createTestInput(b, false, AvailableCapabilities, nodeConfig, types.VMConfig{}, db)

// print out code size for comparisons
code, err := os.ReadFile(spec.wasmFile)
Expand Down
6 changes: 4 additions & 2 deletions x/wasm/keeper/genesis_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@ import (
stakingkeeper "github.com/cosmos/cosmos-sdk/x/staking/keeper"

"github.com/CosmWasm/wasmd/x/wasm/types"
wasmtypes "github.com/CosmWasm/wasmd/x/wasm/types"
)

func TestGenesisExportImport(t *testing.T) {
Expand Down Expand Up @@ -680,7 +681,7 @@ func setupKeeper(t *testing.T) (*Keeper, sdk.Context) {
// also registering gov interfaces for nested Any type
v1beta1.RegisterInterfaces(encodingConfig.InterfaceRegistry)

wasmConfig := types.DefaultWasmConfig()
nodeConfig := types.DefaultNodeConfig()

srcKeeper := NewKeeper(
encodingConfig.Codec,
Expand All @@ -697,7 +698,8 @@ func setupKeeper(t *testing.T) (*Keeper, sdk.Context) {
nil,
nil,
tempDir,
wasmConfig,
nodeConfig,
wasmtypes.VMConfig{},
AvailableCapabilities,
authtypes.NewModuleAddress(govtypes.ModuleName).String(),
)
Expand Down
7 changes: 7 additions & 0 deletions x/wasm/keeper/keeper.go
Original file line number Diff line number Diff line change
Expand Up @@ -109,6 +109,9 @@ type Keeper struct {
// the address capable of executing a MsgUpdateParams message. Typically, this
// should be the x/gov module account.
authority string

// wasmLimits contains the limits sent to wasmvm on init
wasmLimits wasmvmtypes.WasmLimits
}

func (k Keeper) getUploadAccessConfig(ctx context.Context) types.AccessConfig {
Expand All @@ -119,6 +122,10 @@ func (k Keeper) getInstantiateAccessConfig(ctx context.Context) types.AccessType
return k.GetParams(ctx).InstantiateDefaultPermission
}

func (k Keeper) GetWasmLimits() wasmvmtypes.WasmLimits {
return k.wasmLimits
}

// GetParams returns the total set of wasm parameters.
func (k Keeper) GetParams(ctx context.Context) types.Params {
p, err := k.params.Get(ctx)
Expand Down
19 changes: 15 additions & 4 deletions x/wasm/keeper/keeper_cgo.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import (
"path/filepath"

wasmvm "github.com/CosmWasm/wasmvm/v2"
wasmvmtypes "github.com/CosmWasm/wasmvm/v2/types"

"cosmossdk.io/collections"
corestoretypes "cosmossdk.io/core/store"
Expand All @@ -32,7 +33,8 @@ func NewKeeper(
router MessageRouter,
_ GRPCQueryRouter,
homeDir string,
wasmConfig types.WasmConfig,
nodeConfig types.NodeConfig,
vmConfig types.VMConfig,
availableCapabilities []string,
authority string,
opts ...Option,
Expand All @@ -47,7 +49,7 @@ func NewKeeper(
accountPruner: NewVestingCoinBurner(bankKeeper),
portKeeper: portKeeper,
capabilityKeeper: capabilityKeeper,
queryGasLimit: wasmConfig.SmartQueryGasLimit,
queryGasLimit: nodeConfig.SmartQueryGasLimit,
gasRegister: types.NewDefaultWasmGasRegister(),
maxQueryStackSize: types.DefaultMaxQueryStackSize,
maxCallDepth: types.DefaultMaxCallDepth,
Expand All @@ -56,7 +58,8 @@ func NewKeeper(
propagateGovAuthorization: map[types.AuthorizationPolicyAction]struct{}{
types.AuthZActionInstantiate: {},
},
authority: authority,
authority: authority,
wasmLimits: vmConfig.WasmLimits,
}
keeper.messenger = NewDefaultMessageHandler(keeper, router, ics4Wrapper, channelKeeper, capabilityKeeper, bankKeeper, cdc, portSource)
keeper.wasmVMQueryHandler = DefaultQueryPlugins(bankKeeper, stakingKeeper, distrKeeper, channelKeeper, keeper)
Expand All @@ -70,7 +73,15 @@ func NewKeeper(
// NewVM does a lot, so better not to create it and silently drop it.
if keeper.wasmVM == nil {
var err error
keeper.wasmVM, err = wasmvm.NewVM(filepath.Join(homeDir, "wasm"), availableCapabilities, contractMemoryLimit, wasmConfig.ContractDebugMode, wasmConfig.MemoryCacheSize)
keeper.wasmVM, err = wasmvm.NewVMWithConfig(wasmvmtypes.VMConfig{
Cache: wasmvmtypes.CacheOptions{
BaseDir: filepath.Join(homeDir, "wasm"),
AvailableCapabilities: availableCapabilities,
MemoryCacheSizeBytes: wasmvmtypes.NewSizeMebi(nodeConfig.MemoryCacheSize),
InstanceMemoryLimitBytes: wasmvmtypes.NewSizeMebi(contractMemoryLimit),
},
WasmLimits: vmConfig.WasmLimits,
}, nodeConfig.ContractDebugMode)
if err != nil {
panic(err)
}
Expand Down
3 changes: 2 additions & 1 deletion x/wasm/keeper/keeper_no_cgo.go
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,8 @@ func NewKeeper(
router MessageRouter,
_ GRPCQueryRouter,
homeDir string,
wasmConfig types.WasmConfig,
nodeConfig types.NodeConfig,
vmConfig types.VMConfig,
availableCapabilities string,
authority string,
opts ...Option,
Expand Down
Loading