diff --git a/api/api_test.go b/api/api_test.go index 19efe1bc..6dd45496 100644 --- a/api/api_test.go +++ b/api/api_test.go @@ -34,7 +34,7 @@ func TestCanonicalAddressFailure(t *testing.T) { // make sure the call doesn't error, but we get a JSON-encoded error result from InitResult igasMeter := GasMeter(gasMeter) - res, _, err := Instantiate(cache, id, env, info, msg, &igasMeter, store, api, &querier, TESTING_GAS_LIMIT, TESTING_PRINT_DEBUG) + res, _, err := Instantiate(cache, id, env, info, msg, &igasMeter, store, api, &querier, TESTING_GAS_LIMIT, TESTING_MEMORY_LIMIT, TESTING_PRINT_DEBUG) require.NoError(t, err) var resp types.InitResult err = json.Unmarshal(res, &resp) @@ -67,7 +67,7 @@ func TestHumanAddressFailure(t *testing.T) { // instantiate it normally msg := []byte(`{"verifier": "short", "beneficiary": "bob"}`) igasMeter := GasMeter(gasMeter) - _, _, err = Instantiate(cache, id, env, info, msg, &igasMeter, store, api, &querier, TESTING_GAS_LIMIT, TESTING_PRINT_DEBUG) + _, _, err = Instantiate(cache, id, env, info, msg, &igasMeter, store, api, &querier, TESTING_GAS_LIMIT, TESTING_MEMORY_LIMIT, TESTING_PRINT_DEBUG) require.NoError(t, err) // call query which will call canonicalize address @@ -75,7 +75,7 @@ func TestHumanAddressFailure(t *testing.T) { gasMeter3 := NewMockGasMeter(TESTING_GAS_LIMIT) query := []byte(`{"verifier":{}}`) igasMeter3 := GasMeter(gasMeter3) - res, _, err := Query(cache, id, env, query, &igasMeter3, store, badApi, &querier, TESTING_GAS_LIMIT, TESTING_PRINT_DEBUG) + res, _, err := Query(cache, id, env, query, &igasMeter3, store, badApi, &querier, TESTING_GAS_LIMIT, TESTING_MEMORY_LIMIT, TESTING_PRINT_DEBUG) require.NoError(t, err) var resp types.QueryResponse err = json.Unmarshal(res, &resp) diff --git a/api/bindings.h b/api/bindings.h index 462d580e..1c610395 100644 --- a/api/bindings.h +++ b/api/bindings.h @@ -140,6 +140,7 @@ Buffer handle(cache_t *cache, GoApi api, GoQuerier querier, uint64_t gas_limit, + uint32_t memory_limit, bool print_debug, uint64_t *gas_used, Buffer *err); @@ -155,6 +156,7 @@ Buffer instantiate(cache_t *cache, GoApi api, GoQuerier querier, uint64_t gas_limit, + uint32_t memory_limit, bool print_debug, uint64_t *gas_used, Buffer *err); @@ -168,6 +170,7 @@ Buffer migrate(cache_t *cache, GoApi api, GoQuerier querier, uint64_t gas_limit, + uint32_t memory_limit, bool print_debug, uint64_t *gas_used, Buffer *err); @@ -180,6 +183,7 @@ Buffer query(cache_t *cache, GoApi api, GoQuerier querier, uint64_t gas_limit, + uint32_t memory_limit, bool print_debug, uint64_t *gas_used, Buffer *err); diff --git a/api/iterator_test.go b/api/iterator_test.go index a2e9a4d8..f4bdbbc9 100644 --- a/api/iterator_test.go +++ b/api/iterator_test.go @@ -36,7 +36,7 @@ func setupQueueContractWithData(t *testing.T, cache Cache, values ...int) queueD msg := []byte(`{}`) igasMeter1 := GasMeter(gasMeter1) - res, _, err := Instantiate(cache, id, env, info, msg, &igasMeter1, store, api, &querier, TESTING_GAS_LIMIT, TESTING_PRINT_DEBUG) + res, _, err := Instantiate(cache, id, env, info, msg, &igasMeter1, store, api, &querier, TESTING_GAS_LIMIT, TESTING_MEMORY_LIMIT, TESTING_PRINT_DEBUG) require.NoError(t, err) requireOkResponse(t, res, 0) @@ -44,7 +44,7 @@ func setupQueueContractWithData(t *testing.T, cache Cache, values ...int) queueD // push 17 var gasMeter2 GasMeter = NewMockGasMeter(TESTING_GAS_LIMIT) push := []byte(fmt.Sprintf(`{"enqueue":{"value":%d}}`, value)) - res, _, err = Handle(cache, id, env, info, push, &gasMeter2, store, api, &querier, TESTING_GAS_LIMIT, TESTING_PRINT_DEBUG) + res, _, err = Handle(cache, id, env, info, push, &gasMeter2, store, api, &querier, TESTING_GAS_LIMIT, TESTING_MEMORY_LIMIT, TESTING_PRINT_DEBUG) require.NoError(t, err) requireOkResponse(t, res, 0) } @@ -74,7 +74,7 @@ func TestQueueIterator(t *testing.T) { store := setup.Store(gasMeter) query := []byte(`{"sum":{}}`) env := MockEnvBin(t) - data, _, err := Query(cache, id, env, query, &igasMeter, store, api, &querier, TESTING_GAS_LIMIT, TESTING_PRINT_DEBUG) + data, _, err := Query(cache, id, env, query, &igasMeter, store, api, &querier, TESTING_GAS_LIMIT, TESTING_MEMORY_LIMIT, TESTING_PRINT_DEBUG) require.NoError(t, err) var qres types.QueryResponse err = json.Unmarshal(data, &qres) @@ -84,7 +84,7 @@ func TestQueueIterator(t *testing.T) { // query reduce (multiple iterators at once) query = []byte(`{"reducer":{}}`) - data, _, err = Query(cache, id, env, query, &igasMeter, store, api, &querier, TESTING_GAS_LIMIT, TESTING_PRINT_DEBUG) + data, _, err = Query(cache, id, env, query, &igasMeter, store, api, &querier, TESTING_GAS_LIMIT, TESTING_MEMORY_LIMIT, TESTING_PRINT_DEBUG) require.NoError(t, err) var reduced types.QueryResponse err = json.Unmarshal(data, &reduced) @@ -112,7 +112,7 @@ func TestQueueIteratorRaces(t *testing.T) { // query reduce (multiple iterators at once) query := []byte(`{"reducer":{}}`) - data, _, err := Query(cache, id, env, query, &igasMeter, store, api, &querier, TESTING_GAS_LIMIT, TESTING_PRINT_DEBUG) + data, _, err := Query(cache, id, env, query, &igasMeter, store, api, &querier, TESTING_GAS_LIMIT, TESTING_MEMORY_LIMIT, TESTING_PRINT_DEBUG) require.NoError(t, err) var reduced types.QueryResponse err = json.Unmarshal(data, &reduced) diff --git a/api/lib.go b/api/lib.go index 2610ad19..7a9523a0 100644 --- a/api/lib.go +++ b/api/lib.go @@ -82,6 +82,7 @@ func Instantiate( api *GoAPI, querier *Querier, gasLimit uint64, + memoryLimit uint32, printDebug bool, ) ([]byte, uint64, error) { id := sendSlice(code_id) @@ -104,7 +105,7 @@ func Instantiate( var gasUsed cu64 errmsg := C.Buffer{} - res, err := C.instantiate(cache.ptr, id, e, i, m, db, a, q, cu64(gasLimit), cbool(printDebug), &gasUsed, &errmsg) + res, err := C.instantiate(cache.ptr, id, e, i, m, db, a, q, cu64(gasLimit), cu32(memoryLimit), cbool(printDebug), &gasUsed, &errmsg) if err != nil && err.(syscall.Errno) != C.ErrnoValue_Success { // Depending on the nature of the error, `gasUsed` will either have a meaningful value, or just 0. return nil, uint64(gasUsed), errorWithMessage(err, errmsg) @@ -123,6 +124,7 @@ func Handle( api *GoAPI, querier *Querier, gasLimit uint64, + memoryLimit uint32, printDebug bool, ) ([]byte, uint64, error) { id := sendSlice(code_id) @@ -145,7 +147,7 @@ func Handle( var gasUsed cu64 errmsg := C.Buffer{} - res, err := C.handle(cache.ptr, id, e, i, m, db, a, q, cu64(gasLimit), cbool(printDebug), &gasUsed, &errmsg) + res, err := C.handle(cache.ptr, id, e, i, m, db, a, q, cu64(gasLimit), cu32(memoryLimit), cbool(printDebug), &gasUsed, &errmsg) if err != nil && err.(syscall.Errno) != C.ErrnoValue_Success { // Depending on the nature of the error, `gasUsed` will either have a meaningful value, or just 0. return nil, uint64(gasUsed), errorWithMessage(err, errmsg) @@ -164,6 +166,7 @@ func Migrate( api *GoAPI, querier *Querier, gasLimit uint64, + memoryLimit uint32, printDebug bool, ) ([]byte, uint64, error) { id := sendSlice(code_id) @@ -186,7 +189,7 @@ func Migrate( var gasUsed cu64 errmsg := C.Buffer{} - res, err := C.migrate(cache.ptr, id, e, i, m, db, a, q, cu64(gasLimit), cbool(printDebug), &gasUsed, &errmsg) + res, err := C.migrate(cache.ptr, id, e, i, m, db, a, q, cu64(gasLimit), cu32(memoryLimit), cbool(printDebug), &gasUsed, &errmsg) if err != nil && err.(syscall.Errno) != C.ErrnoValue_Success { // Depending on the nature of the error, `gasUsed` will either have a meaningful value, or just 0. return nil, uint64(gasUsed), errorWithMessage(err, errmsg) @@ -204,6 +207,7 @@ func Query( api *GoAPI, querier *Querier, gasLimit uint64, + memoryLimit uint32, printDebug bool, ) ([]byte, uint64, error) { id := sendSlice(code_id) @@ -224,7 +228,7 @@ func Query( var gasUsed cu64 errmsg := C.Buffer{} - res, err := C.query(cache.ptr, id, e, m, db, a, q, cu64(gasLimit), cbool(printDebug), &gasUsed, &errmsg) + res, err := C.query(cache.ptr, id, e, m, db, a, q, cu64(gasLimit), cu32(memoryLimit), cbool(printDebug), &gasUsed, &errmsg) if err != nil && err.(syscall.Errno) != C.ErrnoValue_Success { // Depending on the nature of the error, `gasUsed` will either have a meaningful value, or just 0. return nil, uint64(gasUsed), errorWithMessage(err, errmsg) diff --git a/api/lib_test.go b/api/lib_test.go index 215b48b9..72239bf4 100644 --- a/api/lib_test.go +++ b/api/lib_test.go @@ -16,7 +16,8 @@ import ( const TESTING_FEATURES = "staking" const TESTING_PRINT_DEBUG = false const TESTING_GAS_LIMIT = 100_000_000 -const TESTING_CACHE_SIZE = 100 // MiB +const TESTING_MEMORY_LIMIT = 32 // MiB +const TESTING_CACHE_SIZE = 100 // MiB func TestInitAndReleaseCache(t *testing.T) { dataDir := "/foo" @@ -89,7 +90,7 @@ func TestInstantiate(t *testing.T) { info := MockInfoBin(t, "creator") msg := []byte(`{"verifier": "fred", "beneficiary": "bob"}`) - res, cost, err := Instantiate(cache, id, env, info, msg, &igasMeter, store, api, &querier, TESTING_GAS_LIMIT, TESTING_PRINT_DEBUG) + res, cost, err := Instantiate(cache, id, env, info, msg, &igasMeter, store, api, &querier, TESTING_GAS_LIMIT, TESTING_MEMORY_LIMIT, TESTING_PRINT_DEBUG) require.NoError(t, err) requireOkResponse(t, res, 0) assert.Equal(t, uint64(0x13860), cost) @@ -119,7 +120,7 @@ func TestHandle(t *testing.T) { msg := []byte(`{"verifier": "fred", "beneficiary": "bob"}`) start := time.Now() - res, cost, err := Instantiate(cache, id, env, info, msg, &igasMeter1, store, api, &querier, TESTING_GAS_LIMIT, TESTING_PRINT_DEBUG) + res, cost, err := Instantiate(cache, id, env, info, msg, &igasMeter1, store, api, &querier, TESTING_GAS_LIMIT, TESTING_MEMORY_LIMIT, TESTING_PRINT_DEBUG) diff := time.Now().Sub(start) require.NoError(t, err) requireOkResponse(t, res, 0) @@ -133,7 +134,7 @@ func TestHandle(t *testing.T) { env = MockEnvBin(t) info = MockInfoBin(t, "fred") start = time.Now() - res, cost, err = Handle(cache, id, env, info, []byte(`{"release":{}}`), &igasMeter2, store, api, &querier, TESTING_GAS_LIMIT, TESTING_PRINT_DEBUG) + res, cost, err = Handle(cache, id, env, info, []byte(`{"release":{}}`), &igasMeter2, store, api, &querier, TESTING_GAS_LIMIT, TESTING_MEMORY_LIMIT, TESTING_PRINT_DEBUG) diff = time.Now().Sub(start) require.NoError(t, err) assert.Equal(t, uint64(0x1d663), cost) @@ -175,7 +176,7 @@ func TestHandleCpuLoop(t *testing.T) { msg := []byte(`{"verifier": "fred", "beneficiary": "bob"}`) start := time.Now() - res, cost, err := Instantiate(cache, id, env, info, msg, &igasMeter1, store, api, &querier, TESTING_GAS_LIMIT, TESTING_PRINT_DEBUG) + res, cost, err := Instantiate(cache, id, env, info, msg, &igasMeter1, store, api, &querier, TESTING_GAS_LIMIT, TESTING_MEMORY_LIMIT, TESTING_PRINT_DEBUG) diff := time.Now().Sub(start) require.NoError(t, err) requireOkResponse(t, res, 0) @@ -189,7 +190,7 @@ func TestHandleCpuLoop(t *testing.T) { store.SetGasMeter(gasMeter2) info = MockInfoBin(t, "fred") start = time.Now() - res, cost, err = Handle(cache, id, env, info, []byte(`{"cpu_loop":{}}`), &igasMeter2, store, api, &querier, maxGas, TESTING_PRINT_DEBUG) + res, cost, err = Handle(cache, id, env, info, []byte(`{"cpu_loop":{}}`), &igasMeter2, store, api, &querier, maxGas, TESTING_MEMORY_LIMIT, TESTING_PRINT_DEBUG) diff = time.Now().Sub(start) require.Error(t, err) assert.Equal(t, cost, maxGas) @@ -214,7 +215,7 @@ func TestHandleStorageLoop(t *testing.T) { msg := []byte(`{"verifier": "fred", "beneficiary": "bob"}`) - res, cost, err := Instantiate(cache, id, env, info, msg, &igasMeter1, store, api, &querier, maxGas, TESTING_PRINT_DEBUG) + res, cost, err := Instantiate(cache, id, env, info, msg, &igasMeter1, store, api, &querier, maxGas, TESTING_MEMORY_LIMIT, TESTING_PRINT_DEBUG) require.NoError(t, err) requireOkResponse(t, res, 0) @@ -224,7 +225,7 @@ func TestHandleStorageLoop(t *testing.T) { store.SetGasMeter(gasMeter2) info = MockInfoBin(t, "fred") start := time.Now() - res, cost, err = Handle(cache, id, env, info, []byte(`{"storage_loop":{}}`), &igasMeter2, store, api, &querier, maxGas, TESTING_PRINT_DEBUG) + res, cost, err = Handle(cache, id, env, info, []byte(`{"storage_loop":{}}`), &igasMeter2, store, api, &querier, maxGas, TESTING_MEMORY_LIMIT, TESTING_PRINT_DEBUG) diff := time.Now().Sub(start) require.Error(t, err) t.Logf("StorageLoop Time (%d gas): %s\n", cost, diff) @@ -253,7 +254,7 @@ func TestHandleUserErrorsInApiCalls(t *testing.T) { defaultApi := NewMockAPI() msg := []byte(`{"verifier": "fred", "beneficiary": "bob"}`) - res, _, err := Instantiate(cache, id, env, info, msg, &igasMeter1, store, defaultApi, &querier, maxGas, TESTING_PRINT_DEBUG) + res, _, err := Instantiate(cache, id, env, info, msg, &igasMeter1, store, defaultApi, &querier, maxGas, TESTING_MEMORY_LIMIT, TESTING_PRINT_DEBUG) require.NoError(t, err) requireOkResponse(t, res, 0) @@ -262,7 +263,7 @@ func TestHandleUserErrorsInApiCalls(t *testing.T) { store.SetGasMeter(gasMeter2) info = MockInfoBin(t, "fred") failingApi := NewMockFailureAPI() - res, _, err = Handle(cache, id, env, info, []byte(`{"user_errors_in_api_calls":{}}`), &igasMeter2, store, failingApi, &querier, maxGas, TESTING_PRINT_DEBUG) + res, _, err = Handle(cache, id, env, info, []byte(`{"user_errors_in_api_calls":{}}`), &igasMeter2, store, failingApi, &querier, maxGas, TESTING_MEMORY_LIMIT, TESTING_PRINT_DEBUG) require.NoError(t, err) requireOkResponse(t, res, 0) } @@ -283,13 +284,13 @@ func TestMigrate(t *testing.T) { info := MockInfoBin(t, "creator") msg := []byte(`{"verifier": "fred", "beneficiary": "bob"}`) - res, _, err := Instantiate(cache, id, env, info, msg, &igasMeter, store, api, &querier, TESTING_GAS_LIMIT, TESTING_PRINT_DEBUG) + res, _, err := Instantiate(cache, id, env, info, msg, &igasMeter, store, api, &querier, TESTING_GAS_LIMIT, TESTING_MEMORY_LIMIT, TESTING_PRINT_DEBUG) require.NoError(t, err) requireOkResponse(t, res, 0) // verifier is fred query := []byte(`{"verifier":{}}`) - data, _, err := Query(cache, id, env, query, &igasMeter, store, api, &querier, TESTING_GAS_LIMIT, TESTING_PRINT_DEBUG) + data, _, err := Query(cache, id, env, query, &igasMeter, store, api, &querier, TESTING_GAS_LIMIT, TESTING_MEMORY_LIMIT, TESTING_PRINT_DEBUG) require.NoError(t, err) var qres types.QueryResponse err = json.Unmarshal(data, &qres) @@ -300,11 +301,11 @@ func TestMigrate(t *testing.T) { // migrate to a new verifier - alice // we use the same code blob as we are testing hackatom self-migration info = MockInfoBin(t, "fred") - res, _, err = Migrate(cache, id, env, info, []byte(`{"verifier":"alice"}`), &igasMeter, store, api, &querier, TESTING_GAS_LIMIT, TESTING_PRINT_DEBUG) + res, _, err = Migrate(cache, id, env, info, []byte(`{"verifier":"alice"}`), &igasMeter, store, api, &querier, TESTING_GAS_LIMIT, TESTING_MEMORY_LIMIT, TESTING_PRINT_DEBUG) require.NoError(t, err) // should update verifier to alice - data, _, err = Query(cache, id, env, query, &igasMeter, store, api, &querier, TESTING_GAS_LIMIT, TESTING_PRINT_DEBUG) + data, _, err = Query(cache, id, env, query, &igasMeter, store, api, &querier, TESTING_GAS_LIMIT, TESTING_MEMORY_LIMIT, TESTING_PRINT_DEBUG) require.NoError(t, err) var qres2 types.QueryResponse err = json.Unmarshal(data, &qres2) @@ -327,7 +328,7 @@ func TestMultipleInstances(t *testing.T) { env := MockEnvBin(t) info := MockInfoBin(t, "regen") msg := []byte(`{"verifier": "fred", "beneficiary": "bob"}`) - res, cost, err := Instantiate(cache, id, env, info, msg, &igasMeter1, store1, api, &querier, TESTING_GAS_LIMIT, TESTING_PRINT_DEBUG) + res, cost, err := Instantiate(cache, id, env, info, msg, &igasMeter1, store1, api, &querier, TESTING_GAS_LIMIT, TESTING_MEMORY_LIMIT, TESTING_PRINT_DEBUG) require.NoError(t, err) requireOkResponse(t, res, 0) // we now count wasm gas charges and db writes @@ -339,7 +340,7 @@ func TestMultipleInstances(t *testing.T) { store2 := NewLookup(gasMeter2) info = MockInfoBin(t, "chrous") msg = []byte(`{"verifier": "mary", "beneficiary": "sue"}`) - res, cost, err = Instantiate(cache, id, env, info, msg, &igasMeter2, store2, api, &querier, TESTING_GAS_LIMIT, TESTING_PRINT_DEBUG) + res, cost, err = Instantiate(cache, id, env, info, msg, &igasMeter2, store2, api, &querier, TESTING_GAS_LIMIT, TESTING_MEMORY_LIMIT, TESTING_PRINT_DEBUG) require.NoError(t, err) requireOkResponse(t, res, 0) assert.Equal(t, uint64(0x137e1), cost) @@ -401,7 +402,7 @@ func exec(t *testing.T, cache Cache, id []byte, signer types.HumanAddress, store igasMeter := GasMeter(gasMeter) env := MockEnvBin(t) info := MockInfoBin(t, signer) - res, cost, err := Handle(cache, id, env, info, []byte(`{"release":{}}`), &igasMeter, store, api, &querier, TESTING_GAS_LIMIT, TESTING_PRINT_DEBUG) + res, cost, err := Handle(cache, id, env, info, []byte(`{"release":{}}`), &igasMeter, store, api, &querier, TESTING_GAS_LIMIT, TESTING_MEMORY_LIMIT, TESTING_PRINT_DEBUG) require.NoError(t, err) assert.Equal(t, gasExpected, cost) @@ -425,7 +426,7 @@ func TestQuery(t *testing.T) { env := MockEnvBin(t) info := MockInfoBin(t, "creator") msg := []byte(`{"verifier": "fred", "beneficiary": "bob"}`) - _, _, err := Instantiate(cache, id, env, info, msg, &igasMeter1, store, api, &querier, TESTING_GAS_LIMIT, TESTING_PRINT_DEBUG) + _, _, err := Instantiate(cache, id, env, info, msg, &igasMeter1, store, api, &querier, TESTING_GAS_LIMIT, TESTING_MEMORY_LIMIT, TESTING_PRINT_DEBUG) require.NoError(t, err) // invalid query @@ -433,7 +434,7 @@ func TestQuery(t *testing.T) { igasMeter2 := GasMeter(gasMeter2) store.SetGasMeter(gasMeter2) query := []byte(`{"Raw":{"val":"config"}}`) - data, _, err := Query(cache, id, env, query, &igasMeter2, store, api, &querier, TESTING_GAS_LIMIT, TESTING_PRINT_DEBUG) + data, _, err := Query(cache, id, env, query, &igasMeter2, store, api, &querier, TESTING_GAS_LIMIT, TESTING_MEMORY_LIMIT, TESTING_PRINT_DEBUG) require.NoError(t, err) var badResp types.QueryResponse err = json.Unmarshal(data, &badResp) @@ -445,7 +446,7 @@ func TestQuery(t *testing.T) { igasMeter3 := GasMeter(gasMeter3) store.SetGasMeter(gasMeter3) query = []byte(`{"verifier":{}}`) - data, _, err = Query(cache, id, env, query, &igasMeter3, store, api, &querier, TESTING_GAS_LIMIT, TESTING_PRINT_DEBUG) + data, _, err = Query(cache, id, env, query, &igasMeter3, store, api, &querier, TESTING_GAS_LIMIT, TESTING_MEMORY_LIMIT, TESTING_PRINT_DEBUG) require.NoError(t, err) var qres types.QueryResponse err = json.Unmarshal(data, &qres) @@ -471,7 +472,7 @@ func TestHackatomQuerier(t *testing.T) { query := []byte(`{"other_balance":{"address":"foobar"}}`) // TODO The query happens before the contract is initialized. How is this legal? env := MockEnvBin(t) - data, _, err := Query(cache, id, env, query, &igasMeter, store, api, &querier, TESTING_GAS_LIMIT, TESTING_PRINT_DEBUG) + data, _, err := Query(cache, id, env, query, &igasMeter, store, api, &querier, TESTING_GAS_LIMIT, TESTING_MEMORY_LIMIT, TESTING_PRINT_DEBUG) require.NoError(t, err) var qres types.QueryResponse err = json.Unmarshal(data, &qres) @@ -522,7 +523,7 @@ func TestCustomReflectQuerier(t *testing.T) { query, err := json.Marshal(queryMsg) require.NoError(t, err) env := MockEnvBin(t) - data, _, err := Query(cache, id, env, query, &igasMeter, store, api, &querier, TESTING_GAS_LIMIT, TESTING_PRINT_DEBUG) + data, _, err := Query(cache, id, env, query, &igasMeter, store, api, &querier, TESTING_GAS_LIMIT, TESTING_MEMORY_LIMIT, TESTING_PRINT_DEBUG) require.NoError(t, err) var qres types.QueryResponse err = json.Unmarshal(data, &qres) diff --git a/lib.go b/lib.go index c5144de8..6e4f3f38 100644 --- a/lib.go +++ b/lib.go @@ -30,22 +30,24 @@ type GasMeter = api.GasMeter // You should create an instance with its own subdirectory to manage state inside, // and call it for all cosmwasm code related actions. type VM struct { - cache api.Cache - printDebug bool + cache api.Cache + memoryLimit uint32 // memory limit of each contract execution (in MiB) + printDebug bool } // NewVM creates a new VM. // // `dataDir` is a base directory for Wasm blobs and various caches. // `supportedFeatures` is a comma separated list of features suppored by the chain. +// `memoryLimit` is the memory limit of each contract execution (in MiB) // `printDebug` is a flag to enable/disable printing debug logs from the contract to STDOUT. This should be false in production environments. // `cacheSize` sets the size in MiB of an in-memory cache for e.g. module caching. Set to 0 to disable. -func NewVM(dataDir string, supportedFeatures string, printDebug bool, cacheSize uint32) (*VM, error) { +func NewVM(dataDir string, supportedFeatures string, memoryLimit uint32, printDebug bool, cacheSize uint32) (*VM, error) { cache, err := api.InitCache(dataDir, supportedFeatures, cacheSize) if err != nil { return nil, err } - return &VM{cache: cache, printDebug: printDebug}, nil + return &VM{cache: cache, memoryLimit: memoryLimit, printDebug: printDebug}, nil } // Cleanup should be called when no longer using this to free resources on the rust-side @@ -105,7 +107,7 @@ func (vm *VM) Instantiate( if err != nil { return nil, 0, err } - data, gasUsed, err := api.Instantiate(vm.cache, code, envBin, infoBin, initMsg, &gasMeter, store, &goapi, &querier, gasLimit, vm.printDebug) + data, gasUsed, err := api.Instantiate(vm.cache, code, envBin, infoBin, initMsg, &gasMeter, store, &goapi, &querier, gasLimit, vm.memoryLimit, vm.printDebug) if err != nil { return nil, gasUsed, err } @@ -146,7 +148,7 @@ func (vm *VM) Execute( if err != nil { return nil, 0, err } - data, gasUsed, err := api.Handle(vm.cache, code, envBin, infoBin, executeMsg, &gasMeter, store, &goapi, &querier, gasLimit, vm.printDebug) + data, gasUsed, err := api.Handle(vm.cache, code, envBin, infoBin, executeMsg, &gasMeter, store, &goapi, &querier, gasLimit, vm.memoryLimit, vm.printDebug) if err != nil { return nil, gasUsed, err } @@ -179,7 +181,7 @@ func (vm *VM) Query( if err != nil { return nil, 0, err } - data, gasUsed, err := api.Query(vm.cache, code, envBin, queryMsg, &gasMeter, store, &goapi, &querier, gasLimit, vm.printDebug) + data, gasUsed, err := api.Query(vm.cache, code, envBin, queryMsg, &gasMeter, store, &goapi, &querier, gasLimit, vm.memoryLimit, vm.printDebug) if err != nil { return nil, gasUsed, err } @@ -220,7 +222,7 @@ func (vm *VM) Migrate( if err != nil { return nil, 0, err } - data, gasUsed, err := api.Migrate(vm.cache, code, envBin, infoBin, migrateMsg, &gasMeter, store, &goapi, &querier, gasLimit, vm.printDebug) + data, gasUsed, err := api.Migrate(vm.cache, code, envBin, infoBin, migrateMsg, &gasMeter, store, &goapi, &querier, gasLimit, vm.memoryLimit, vm.printDebug) if err != nil { return nil, gasUsed, err } diff --git a/src/lib.rs b/src/lib.rs index c7759d35..c87b4e44 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -30,9 +30,6 @@ use crate::args::{CACHE_ARG, CODE_ID_ARG, ENV_ARG, GAS_USED_ARG, INFO_ARG, MSG_A use crate::cache::{cache_t, to_cache}; use crate::error::{handle_c_error, Error}; -// TODO: Remove constant and make configurable by user -const MEMORY_LIMIT: Size = Size::gibi(4); - fn into_backend(db: DB, api: GoApi, querier: GoQuerier) -> Backend { Backend { api, @@ -108,10 +105,16 @@ pub extern "C" fn instantiate( api: GoApi, querier: GoQuerier, gas_limit: u64, + memory_limit: u32, // in MiB print_debug: bool, gas_used: Option<&mut u64>, err: Option<&mut Buffer>, ) -> Buffer { + let memory_limit = Size::mebi( + memory_limit + .try_into() + .expect("Cannot convert u32 to usize. What kind of system is this?"), + ); let r = match to_cache(cache) { Some(c) => catch_unwind(AssertUnwindSafe(move || { do_init( @@ -124,6 +127,7 @@ pub extern "C" fn instantiate( api, querier, gas_limit, + memory_limit, print_debug, gas_used, ) @@ -145,6 +149,7 @@ fn do_init( api: GoApi, querier: GoQuerier, gas_limit: u64, + memory_limit: Size, print_debug: bool, gas_used: Option<&mut u64>, ) -> Result, Error> { @@ -159,7 +164,7 @@ fn do_init( let backend = into_backend(db, api, querier); let options = InstanceOptions { gas_limit, - memory_limit: MEMORY_LIMIT, + memory_limit, print_debug, }; let mut instance = cache.get_instance(&code_id, backend, options)?; @@ -181,10 +186,16 @@ pub extern "C" fn handle( api: GoApi, querier: GoQuerier, gas_limit: u64, + memory_limit: u32, // in MiB print_debug: bool, gas_used: Option<&mut u64>, err: Option<&mut Buffer>, ) -> Buffer { + let memory_limit = Size::mebi( + memory_limit + .try_into() + .expect("Cannot convert u32 to usize. What kind of system is this?"), + ); let r = match to_cache(cache) { Some(c) => catch_unwind(AssertUnwindSafe(move || { do_handle( @@ -197,6 +208,7 @@ pub extern "C" fn handle( api, querier, gas_limit, + memory_limit, print_debug, gas_used, ) @@ -218,6 +230,7 @@ fn do_handle( api: GoApi, querier: GoQuerier, gas_limit: u64, + memory_limit: Size, print_debug: bool, gas_used: Option<&mut u64>, ) -> Result, Error> { @@ -232,7 +245,7 @@ fn do_handle( let backend = into_backend(db, api, querier); let options = InstanceOptions { gas_limit, - memory_limit: MEMORY_LIMIT, + memory_limit, print_debug, }; let mut instance = cache.get_instance(&code_id, backend, options)?; @@ -254,10 +267,16 @@ pub extern "C" fn migrate( api: GoApi, querier: GoQuerier, gas_limit: u64, + memory_limit: u32, // in MiB print_debug: bool, gas_used: Option<&mut u64>, err: Option<&mut Buffer>, ) -> Buffer { + let memory_limit = Size::mebi( + memory_limit + .try_into() + .expect("Cannot convert u32 to usize. What kind of system is this?"), + ); let r = match to_cache(cache) { Some(c) => catch_unwind(AssertUnwindSafe(move || { do_migrate( @@ -270,6 +289,7 @@ pub extern "C" fn migrate( api, querier, gas_limit, + memory_limit, print_debug, gas_used, ) @@ -291,6 +311,7 @@ fn do_migrate( api: GoApi, querier: GoQuerier, gas_limit: u64, + memory_limit: Size, print_debug: bool, gas_used: Option<&mut u64>, ) -> Result, Error> { @@ -305,7 +326,7 @@ fn do_migrate( let backend = into_backend(db, api, querier); let options = InstanceOptions { gas_limit, - memory_limit: MEMORY_LIMIT, + memory_limit, print_debug, }; let mut instance = cache.get_instance(&code_id, backend, options)?; @@ -326,10 +347,16 @@ pub extern "C" fn query( api: GoApi, querier: GoQuerier, gas_limit: u64, + memory_limit: u32, // in MiB print_debug: bool, gas_used: Option<&mut u64>, err: Option<&mut Buffer>, ) -> Buffer { + let memory_limit = Size::mebi( + memory_limit + .try_into() + .expect("Cannot convert u32 to usize. What kind of system is this?"), + ); let r = match to_cache(cache) { Some(c) => catch_unwind(AssertUnwindSafe(move || { do_query( @@ -341,6 +368,7 @@ pub extern "C" fn query( api, querier, gas_limit, + memory_limit, print_debug, gas_used, ) @@ -361,6 +389,7 @@ fn do_query( api: GoApi, querier: GoQuerier, gas_limit: u64, + memory_limit: Size, print_debug: bool, gas_used: Option<&mut u64>, ) -> Result, Error> { @@ -374,7 +403,7 @@ fn do_query( let backend = into_backend(db, api, querier); let options = InstanceOptions { gas_limit, - memory_limit: MEMORY_LIMIT, + memory_limit, print_debug, }; let mut instance = cache.get_instance(&code_id, backend, options)?;