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

Using metering middleware via c-api #2025

Closed
satrobit opened this issue Jan 15, 2021 · 4 comments · Fixed by #2103
Closed

Using metering middleware via c-api #2025

satrobit opened this issue Jan 15, 2021 · 4 comments · Fixed by #2103
Labels
📦 lib-c-api About wasmer-c-api ⏱ metering ❓ question I've a question!

Comments

@satrobit
Copy link
Contributor

Summary

I'm trying to add metering to wasm modules using wasmer c-api but I'm not able to find the necessary headers for it. Is it even exposed to the c-api? If it is, can you point me in the right direction?

@satrobit satrobit added the ❓ question I've a question! label Jan 15, 2021
@MarkMcCaskey
Copy link
Contributor

Hello!

That's a good question! We currently do not have a metering API available to the C API.

It's certainly a possibility -- the hard part would be designing what that API would look like in a wasm-c-api style.

@satrobit
Copy link
Contributor Author

It'd be awesome to have this feature in the C API. It's indeed challenging to come up with an elegant design that is compatible with wasm-c-api but I think it's worth the effort. I'll probably hack something together for now but I'll share my findings if any clean design comes to my mind.

@Hywan
Copy link
Contributor

Hywan commented Mar 5, 2021

Hello @satrobit,

It took a little bit of time, but here is the metering C API, https://wasmerio.github.io/wasmer/crates/wasmer_c_api/wasm_c_api/unstable/middlewares/metering/index.html. I'm copy pasting the example for the record:

// Define our “cost function”.
uint64_t cost_function(wasmer_parser_operator_t wasm_operator) {
    switch(wasm_operator) {
        // `local.get` and `i32.const` cost 1 unit.
        case LocalGet:
        case I32Const:
            return 1;

        // `i32.add` costs 2 units.
        case I32Add:
            return 2;

        // The other operations are free.
        default:
            return 0;
    }
}

int main() {
    // Create a new metering middleware, with our cost function.
    wasmer_metering_t* metering = wasmer_metering_new(10, cost_function);

    // Consume `metering` to produce a generic `wasmer_middleware_t` value.
    wasmer_middleware_t* middleware = wasmer_metering_as_middleware(metering);
     
    // Create a new configuration, and push the middleware in it.
    wasm_config_t* config = wasm_config_new();
    wasm_config_push_middleware(config, middleware);
     
    // Create the engine and the store based on the configuration.
    wasm_engine_t* engine = wasm_engine_new_with_config(config);
    wasm_store_t* store = wasm_store_new(engine);
     
    // Create the new WebAssembly module.
    wasm_byte_vec_t wat;
    wasmer_byte_vec_new_from_string(
        &wat,
        "(module\n"
        "  (type $add_t (func (param i32) (result i32)))\n"
        "  (func $add_two_f (type $add_t) (param $value i32) (result i32)\n"
        "    local.get $value\n"
        "    i32.const 1\n"
        "    i32.add)\n"
        "  (export \"add_two\" (func $add_two_f)))"
    );
    wasm_byte_vec_t wasm;
    wat2wasm(&wat, &wasm);

    wasm_module_t* module = wasm_module_new(store, &wasm);
    assert(module);
     
    // Instantiate the module.
    wasm_extern_vec_t imports = WASM_EMPTY_VEC;
    wasm_trap_t* traps = NULL;
    wasm_instance_t* instance = wasm_instance_new(store, module, &imports, &traps);
    assert(instance);
     
    // Here we go. At this step, we will get the `add_two` exported function, and
    // call it.
    wasm_extern_vec_t exports;
    wasm_instance_exports(instance, &exports);
    assert(exports.size >= 1);
    assert(wasm_extern_kind(exports.data[0]) == WASM_EXTERN_FUNC);

    const wasm_func_t* add_two = wasm_extern_as_func(exports.data[0]);
    assert(add_two);

    wasm_val_t arguments[1] = { WASM_I32_VAL(41) };
    wasm_val_t results[1] = { WASM_INIT_VAL };

    wasm_val_vec_t arguments_as_array = WASM_ARRAY_VEC(arguments);
    wasm_val_vec_t results_as_array = WASM_ARRAY_VEC(results);

    // Let's call `add_two` for the first time!
    {
        wasm_trap_t* trap = wasm_func_call(add_two, &arguments_as_array, &results_as_array);
        assert(trap == NULL);
        assert(results[0].of.i32 == 42);

        // There is 6 points left!
        assert(wasmer_metering_get_remaining_points(instance) == 6);
        assert(wasmer_metering_points_are_exhausted(instance) == false);
    }

    // Let's call `add_two` for the second time!
    {
        wasm_trap_t* trap = wasm_func_call(add_two, &arguments_as_array, &results_as_array);
        assert(trap == NULL);
        assert(results[0].of.i32 == 42);

        // There is 2 points left!
        assert(wasmer_metering_get_remaining_points(instance) == 2);
        assert(wasmer_metering_points_are_exhausted(instance) == false);
    }

    // Let's call `add_two` for the third time!
    {
        wasm_trap_t* trap = wasm_func_call(add_two, &arguments_as_array, &results_as_array);
        // Oh, it failed!
        assert(trap != NULL);

        // There is 0 point left… they are exhausted.
        assert(wasmer_metering_points_are_exhausted(instance) == true);
    }
     
    wasm_instance_delete(instance);
    wasm_module_delete(module);
    wasm_store_delete(store);
    wasm_engine_delete(engine);

    return 0;
}

@satrobit
Copy link
Contributor Author

satrobit commented Mar 5, 2021

Hi! This is awesome. Thank you.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
📦 lib-c-api About wasmer-c-api ⏱ metering ❓ question I've a question!
Projects
None yet
Development

Successfully merging a pull request may close this issue.

3 participants