11 releases

0.2.6 Jun 4, 2023
0.2.5 Jun 3, 2023
0.1.3 May 22, 2023

#1419 in Command line utilities

Download history 41/week @ 2024-07-30 14/week @ 2024-09-24 2/week @ 2024-10-01

112 downloads per month

MIT license

71KB
1.5K SLoC

WARK

WebAssembly RunKit, also known as WARK, is a highly efficient tool designed to execute WebAssembly (w/ WASI) modules within a secure sandboxed environment. It can meticulously calculate and report the precise resource usage of the module, including instruction cost and memory utilization.

You can use WARK as a Command-Line Interface (CLI) tool or as a web service, depending on your needs.

Table of Contents

Installation

Docker

If you have Docker installed, you can use the following command to run WARK:

# Run the web service
docker run -it --rm -p 33000:33000 jacoblincool/wark server

Cargo

To install WARK using Cargo, use the following command:

cargo install wark

Usage

CLI

To run a WebAssembly module using the CLI, use the following command:

wark run [OPTIONS] <module>

Options

You can customize the execution with the following options:

  -m, --memory <memory>     Define memory limit in MB [default: 512]
  -c, --cost <cost>         Set computational cost limit in instruction count [default: 1000000000]
  -i, --input <input>       Specify input file path for the program [default: stdin]
      --stderr <file>       Redirect program's stderr to a file
  -n, --no-report           Suppress the report of the program's resource usage

IO

  • You can use the --input option to specify the input file path for the program. If you want to use stdin as the input, use - as the input file path.
  • The stdout of the module will be printed to the stdout of the CLI.
  • The stderr of the module will not be printed to the stderr of the CLI. Instead, use the --stderr option to redirect it to a file.
  • Unless suppressed with the --no-report option, the resource usage of the module will be printed to the stderr of the CLI.

Web Service

To start the WARK server, use the following command:

wark server

You can use the PORT environment variable to specify the port number. The default port number is 33000.

Run

To run a WebAssembly module, send a POST request with a JSON object in the body containing the following fields:

curl 'http://127.0.0.1:33000/run' \
--header 'Content-Type: application/json' \
--header 'Authorization: Bearer <JWT_TOKEN>' \
--data '{
    "cost": 10000000,
    "memory": 512,
    "input": "I am stdin input",
    "wasm": "<base64 encoded wasm module>"
  }'

The server will respond with a JSON object containing the following fields:

{
    "success": true,
    "cost": 1234567,
    "memory": 345,
    "stdout": "I am stdout output",
    "stderr": "I am stderr output",
    "message": "I am message"
}

Judge

To run the program in judge mode, send a POST request with a JSON object in the body containing the following fields:

curl --location 'http://127.0.0.1:33000/judge' \
--header 'Content-Type: application/json' \
--header 'Authorization: Bearer <JWT_TOKEN>' \
--data '{
    "wasm": "<base64 encoded wasm module>",
    "specs": [
        {
            "judger": "IOFast",
            "input": "Jacob",
            "output_hash": "128783a055c41c0a79ad7376e8e22587cdca53ed1f9c47c46d02a7768992b325",
            "cost": 1000000000,
            "memory": 1024
        },
        {
            "judger": "IOFast",
            "input": "WOJ",
            "output_hash": "75787b1df461d0c48f0229a7769cbcc37c7d96d6613f825b77e76afdd1eb790a",
            "cost": 1000000000,
            "memory": 1024
        },
        {
            "judger": "IOFast",
            "input": "WASM OJ Wonderland",
            "output_hash": "8f02d3283b88d16766cb287090bf59135c873e9175759b73f96ffe674440ff21",
            "cost": 1000000000,
            "memory": 1024
        },
        {
            "judger": "IOFast",
            "input_url": "https://link-to-input.file/input.txt",
            "output_hash": "87c215c4afeaf7ff7684ef90fd44649b2051bc4c68cf58bdad402fa304487b8w",
            "cost": 1000000000,
            "memory": 1024
        }
    ]
}'

The server will respond with a JSON object containing the following fields:

{
    "results": [
        {
            "success": true,
            "cost": 3776,
            "memory": 1,
            "message": null,
            "exception": null
        },
        {
            "success": true,
            "cost": 3692,
            "memory": 1,
            "message": null,
            "exception": null
        },
        {
            "success": true,
            "cost": 4421,
            "memory": 1,
            "message": null,
            "exception": null
        },
        {
            "success": false,
            "cost": 5848,
            "memory": 1,
            "message": null,
            "exception": {
                "type": "Output",
                "reason": "Output hash mismatch. Expected 87c215c4afeaf7ff7684ef90fd44649b2051bc4c68cf58bdad402fa304487b8w, got 87c215c4afeaf7ff7684ef90fd44649b2051bc4c68cf58bdad402fa304487b8c"
            }
        }
    ]
}

Currently, the server only supports the IOFast judger, which is a simple judger that compares the trimmed output of the program with the output_hash field. If the output of the program matches the output_hash field, indicating that the program has passed the test case. Otherwise, an Output exception will be returned.

Remote inputs will be cached in the http-cache directory, the TTL of each cache is respecting the Cache-Control header of the response.

Cost Table

You can find the cost of each instruction in the src/cost.rs.

If you see Penalty Instruction [Instruction Name], it means that the specific instruction was not included in the cost table. Therefore, its cost defaults to 1000 points.


Feel free to contribute to this project by submitting pull requests or reporting issues. Your help is always welcomed and appreciated!

Dependencies

~47–83MB
~1.5M SLoC