Skip to content

Commit 65d03d3

Browse files
authored
Merge pull request #560 from CosmWasm/co/customizable-limits
Customizable limits
2 parents 4f7575a + 8d3938d commit 65d03d3

File tree

10 files changed

+371
-157
lines changed

10 files changed

+371
-157
lines changed

internal/api/bindings.h

Lines changed: 1 addition & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -412,11 +412,7 @@ typedef struct GasReport {
412412
uint64_t used_internally;
413413
} GasReport;
414414

415-
struct cache_t *init_cache(struct ByteSliceView data_dir,
416-
struct ByteSliceView available_capabilities,
417-
uint32_t cache_size,
418-
uint32_t instance_memory_limit,
419-
struct UnmanagedVector *error_msg);
415+
struct cache_t *init_cache(struct ByteSliceView config, struct UnmanagedVector *error_msg);
420416

421417
struct UnmanagedVector save_wasm(struct cache_t *cache,
422418
struct ByteSliceView wasm,

internal/api/lib.go

Lines changed: 12 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -5,8 +5,10 @@ package api
55
import "C"
66

77
import (
8+
"encoding/json"
89
"fmt"
910
"os"
11+
"path/filepath"
1012
"runtime"
1113
"strings"
1214
"syscall"
@@ -41,14 +43,14 @@ type Cache struct {
4143

4244
type Querier = types.Querier
4345

44-
func InitCache(dataDir string, supportedCapabilities []string, cacheSize uint32, instanceMemoryLimit uint32) (Cache, error) {
46+
func InitCache(config types.VMConfig) (Cache, error) {
4547
// libwasmvm would create this directory too but we need it earlier for the lockfile
46-
err := os.MkdirAll(dataDir, 0o755)
48+
err := os.MkdirAll(config.Cache.BaseDir, 0o755)
4749
if err != nil {
4850
return Cache{}, fmt.Errorf("Could not create base directory")
4951
}
5052

51-
lockfile, err := os.OpenFile(dataDir+"/exclusive.lock", os.O_WRONLY|os.O_CREATE, 0o666)
53+
lockfile, err := os.OpenFile(filepath.Join(config.Cache.BaseDir, "exclusive.lock"), os.O_WRONLY|os.O_CREATE, 0o666)
5254
if err != nil {
5355
return Cache{}, fmt.Errorf("Could not open exclusive.lock")
5456
}
@@ -62,17 +64,16 @@ func InitCache(dataDir string, supportedCapabilities []string, cacheSize uint32,
6264
return Cache{}, fmt.Errorf("Could not lock exclusive.lock. Is a different VM running in the same directory already?")
6365
}
6466

65-
dataDirBytes := []byte(dataDir)
66-
supportedCapabilitiesBytes := []byte(strings.Join(supportedCapabilities, ","))
67-
68-
d := makeView(dataDirBytes)
69-
defer runtime.KeepAlive(dataDirBytes)
70-
capabilitiesView := makeView(supportedCapabilitiesBytes)
71-
defer runtime.KeepAlive(supportedCapabilitiesBytes)
67+
configBytes, err := json.Marshal(config)
68+
if err != nil {
69+
return Cache{}, fmt.Errorf("Could not serialize config")
70+
}
71+
configView := makeView(configBytes)
72+
defer runtime.KeepAlive(configBytes)
7273

7374
errmsg := uninitializedUnmanagedVector()
7475

75-
ptr, err := C.init_cache(d, capabilitiesView, cu32(cacheSize), cu32(instanceMemoryLimit), &errmsg)
76+
ptr, err := C.init_cache(configView, &errmsg)
7677
if err != nil {
7778
return Cache{}, errorWithMessage(err, errmsg)
7879
}

internal/api/lib_test.go

Lines changed: 99 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -33,7 +33,15 @@ func TestInitAndReleaseCache(t *testing.T) {
3333
require.NoError(t, err)
3434
defer os.RemoveAll(tmpdir)
3535

36-
cache, err := InitCache(tmpdir, TESTING_CAPABILITIES, TESTING_CACHE_SIZE, TESTING_MEMORY_LIMIT)
36+
config := types.VMConfig{
37+
Cache: types.CacheOptions{
38+
BaseDir: tmpdir,
39+
AvailableCapabilities: TESTING_CAPABILITIES,
40+
MemoryCacheSizeBytes: types.NewSizeMebi(TESTING_CACHE_SIZE),
41+
InstanceMemoryLimitBytes: types.NewSizeMebi(TESTING_MEMORY_LIMIT),
42+
},
43+
}
44+
cache, err := InitCache(config)
3745
require.NoError(t, err)
3846
ReleaseCache(cache)
3947
}
@@ -46,7 +54,15 @@ func TestInitCacheWorksForNonExistentDir(t *testing.T) {
4654
defer os.RemoveAll(tmpdir)
4755

4856
createMe := filepath.Join(tmpdir, "does-not-yet-exist")
49-
cache, err := InitCache(createMe, TESTING_CAPABILITIES, TESTING_CACHE_SIZE, TESTING_MEMORY_LIMIT)
57+
config := types.VMConfig{
58+
Cache: types.CacheOptions{
59+
BaseDir: createMe,
60+
AvailableCapabilities: TESTING_CAPABILITIES,
61+
MemoryCacheSizeBytes: types.NewSizeMebi(TESTING_CACHE_SIZE),
62+
InstanceMemoryLimitBytes: types.NewSizeMebi(TESTING_MEMORY_LIMIT),
63+
},
64+
}
65+
cache, err := InitCache(config)
5066
require.NoError(t, err)
5167
ReleaseCache(cache)
5268
}
@@ -56,7 +72,15 @@ func TestInitCacheErrorsForBrokenDir(t *testing.T) {
5672
// https://gist.github.com/doctaphred/d01d05291546186941e1b7ddc02034d3
5773
// On Unix we should not have permission to create this.
5874
cannotBeCreated := "/foo:bar"
59-
_, err := InitCache(cannotBeCreated, TESTING_CAPABILITIES, TESTING_CACHE_SIZE, TESTING_MEMORY_LIMIT)
75+
config := types.VMConfig{
76+
Cache: types.CacheOptions{
77+
BaseDir: cannotBeCreated,
78+
AvailableCapabilities: TESTING_CAPABILITIES,
79+
MemoryCacheSizeBytes: types.NewSizeMebi(TESTING_CACHE_SIZE),
80+
InstanceMemoryLimitBytes: types.NewSizeMebi(TESTING_MEMORY_LIMIT),
81+
},
82+
}
83+
_, err := InitCache(config)
6084
require.ErrorContains(t, err, "Could not create base directory")
6185
}
6286

@@ -65,16 +89,40 @@ func TestInitLockingPreventsConcurrentAccess(t *testing.T) {
6589
require.NoError(t, err)
6690
defer os.RemoveAll(tmpdir)
6791

68-
cache1, err1 := InitCache(tmpdir, TESTING_CAPABILITIES, TESTING_CACHE_SIZE, TESTING_MEMORY_LIMIT)
92+
config1 := types.VMConfig{
93+
Cache: types.CacheOptions{
94+
BaseDir: tmpdir,
95+
AvailableCapabilities: TESTING_CAPABILITIES,
96+
MemoryCacheSizeBytes: types.NewSizeMebi(TESTING_CACHE_SIZE),
97+
InstanceMemoryLimitBytes: types.NewSizeMebi(TESTING_MEMORY_LIMIT),
98+
},
99+
}
100+
cache1, err1 := InitCache(config1)
69101
require.NoError(t, err1)
70102

71-
_, err2 := InitCache(tmpdir, TESTING_CAPABILITIES, TESTING_CACHE_SIZE, TESTING_MEMORY_LIMIT)
103+
config2 := types.VMConfig{
104+
Cache: types.CacheOptions{
105+
BaseDir: tmpdir,
106+
AvailableCapabilities: TESTING_CAPABILITIES,
107+
MemoryCacheSizeBytes: types.NewSizeMebi(TESTING_CACHE_SIZE),
108+
InstanceMemoryLimitBytes: types.NewSizeMebi(TESTING_MEMORY_LIMIT),
109+
},
110+
}
111+
_, err2 := InitCache(config2)
72112
require.ErrorContains(t, err2, "Could not lock exclusive.lock")
73113

74114
ReleaseCache(cache1)
75115

76116
// Now we can try again
77-
cache3, err3 := InitCache(tmpdir, TESTING_CAPABILITIES, TESTING_CACHE_SIZE, TESTING_MEMORY_LIMIT)
117+
config3 := types.VMConfig{
118+
Cache: types.CacheOptions{
119+
BaseDir: tmpdir,
120+
AvailableCapabilities: TESTING_CAPABILITIES,
121+
MemoryCacheSizeBytes: types.NewSizeMebi(TESTING_CACHE_SIZE),
122+
InstanceMemoryLimitBytes: types.NewSizeMebi(TESTING_MEMORY_LIMIT),
123+
},
124+
}
125+
cache3, err3 := InitCache(config3)
78126
require.NoError(t, err3)
79127
ReleaseCache(cache3)
80128
}
@@ -90,11 +138,35 @@ func TestInitLockingAllowsMultipleInstancesInDifferentDirs(t *testing.T) {
90138
defer os.RemoveAll(tmpdir2)
91139
defer os.RemoveAll(tmpdir3)
92140

93-
cache1, err1 := InitCache(tmpdir1, TESTING_CAPABILITIES, TESTING_CACHE_SIZE, TESTING_MEMORY_LIMIT)
141+
config1 := types.VMConfig{
142+
Cache: types.CacheOptions{
143+
BaseDir: tmpdir1,
144+
AvailableCapabilities: TESTING_CAPABILITIES,
145+
MemoryCacheSizeBytes: types.NewSizeMebi(TESTING_CACHE_SIZE),
146+
InstanceMemoryLimitBytes: types.NewSizeMebi(TESTING_MEMORY_LIMIT),
147+
},
148+
}
149+
cache1, err1 := InitCache(config1)
94150
require.NoError(t, err1)
95-
cache2, err2 := InitCache(tmpdir2, TESTING_CAPABILITIES, TESTING_CACHE_SIZE, TESTING_MEMORY_LIMIT)
151+
config2 := types.VMConfig{
152+
Cache: types.CacheOptions{
153+
BaseDir: tmpdir2,
154+
AvailableCapabilities: TESTING_CAPABILITIES,
155+
MemoryCacheSizeBytes: types.NewSizeMebi(TESTING_CACHE_SIZE),
156+
InstanceMemoryLimitBytes: types.NewSizeMebi(TESTING_MEMORY_LIMIT),
157+
},
158+
}
159+
cache2, err2 := InitCache(config2)
96160
require.NoError(t, err2)
97-
cache3, err3 := InitCache(tmpdir3, TESTING_CAPABILITIES, TESTING_CACHE_SIZE, TESTING_MEMORY_LIMIT)
161+
config3 := types.VMConfig{
162+
Cache: types.CacheOptions{
163+
BaseDir: tmpdir3,
164+
AvailableCapabilities: TESTING_CAPABILITIES,
165+
MemoryCacheSizeBytes: types.NewSizeMebi(TESTING_CACHE_SIZE),
166+
InstanceMemoryLimitBytes: types.NewSizeMebi(TESTING_MEMORY_LIMIT),
167+
},
168+
}
169+
cache3, err3 := InitCache(config3)
98170
require.NoError(t, err3)
99171

100172
ReleaseCache(cache1)
@@ -106,15 +178,31 @@ func TestInitCacheEmptyCapabilities(t *testing.T) {
106178
tmpdir, err := os.MkdirTemp("", "wasmvm-testing")
107179
require.NoError(t, err)
108180
defer os.RemoveAll(tmpdir)
109-
cache, err := InitCache(tmpdir, []string{}, TESTING_CACHE_SIZE, TESTING_MEMORY_LIMIT)
181+
config := types.VMConfig{
182+
Cache: types.CacheOptions{
183+
BaseDir: tmpdir,
184+
AvailableCapabilities: []string{},
185+
MemoryCacheSizeBytes: types.NewSizeMebi(TESTING_CACHE_SIZE),
186+
InstanceMemoryLimitBytes: types.NewSizeMebi(TESTING_MEMORY_LIMIT),
187+
},
188+
}
189+
cache, err := InitCache(config)
110190
require.NoError(t, err)
111191
ReleaseCache(cache)
112192
}
113193

114194
func withCache(t testing.TB) (Cache, func()) {
115195
tmpdir, err := os.MkdirTemp("", "wasmvm-testing")
116196
require.NoError(t, err)
117-
cache, err := InitCache(tmpdir, TESTING_CAPABILITIES, TESTING_CACHE_SIZE, TESTING_MEMORY_LIMIT)
197+
config := types.VMConfig{
198+
Cache: types.CacheOptions{
199+
BaseDir: tmpdir,
200+
AvailableCapabilities: TESTING_CAPABILITIES,
201+
MemoryCacheSizeBytes: types.NewSizeMebi(TESTING_CACHE_SIZE),
202+
InstanceMemoryLimitBytes: types.NewSizeMebi(TESTING_MEMORY_LIMIT),
203+
},
204+
}
205+
cache, err := InitCache(config)
118206
require.NoError(t, err)
119207

120208
cleanup := func() {

lib_libwasmvm.go

Lines changed: 15 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,21 @@ type VM struct {
3030
// `cacheSize` sets the size in MiB of an in-memory cache for e.g. module caching. Set to 0 to disable.
3131
// `deserCost` sets the gas cost of deserializing one byte of data.
3232
func NewVM(dataDir string, supportedCapabilities []string, memoryLimit uint32, printDebug bool, cacheSize uint32) (*VM, error) {
33-
cache, err := api.InitCache(dataDir, supportedCapabilities, cacheSize, memoryLimit)
33+
return NewVMWithConfig(types.VMConfig{
34+
Cache: types.CacheOptions{
35+
BaseDir: dataDir,
36+
AvailableCapabilities: supportedCapabilities,
37+
MemoryCacheSizeBytes: types.NewSizeMebi(cacheSize),
38+
InstanceMemoryLimitBytes: types.NewSizeMebi(memoryLimit),
39+
},
40+
}, printDebug)
41+
}
42+
43+
// NewVMWithConfig creates a new VM with a custom configuration.
44+
// This allows for more fine-grained control over the VM's behavior compared to NewVM and
45+
// can be extended more easily in the future.
46+
func NewVMWithConfig(config types.VMConfig, printDebug bool) (*VM, error) {
47+
cache, err := api.InitCache(config)
3448
if err != nil {
3549
return nil, err
3650
}

libwasmvm/bindings.h

Lines changed: 1 addition & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -412,11 +412,7 @@ typedef struct GasReport {
412412
uint64_t used_internally;
413413
} GasReport;
414414

415-
struct cache_t *init_cache(struct ByteSliceView data_dir,
416-
struct ByteSliceView available_capabilities,
417-
uint32_t cache_size,
418-
uint32_t instance_memory_limit,
419-
struct UnmanagedVector *error_msg);
415+
struct cache_t *init_cache(struct ByteSliceView config, struct UnmanagedVector *error_msg);
420416

421417
struct UnmanagedVector save_wasm(struct cache_t *cache,
422418
struct ByteSliceView wasm,

libwasmvm/src/args.rs

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,5 @@
11
// store some common string for argument names
2-
pub const DATA_DIR_ARG: &str = "data_dir";
3-
pub const AVAILABLE_CAPABILITIES_ARG: &str = "available_capabilities";
2+
pub const CONFIG_ARG: &str = "config";
43
pub const CACHE_ARG: &str = "cache";
54
pub const WASM_ARG: &str = "wasm";
65
pub const CHECKSUM_ARG: &str = "checksum";

0 commit comments

Comments
 (0)