Designing and building utopian distributed computing solutions; using WebAssembly (Wasm)

Timothy McCallum
Wasm
Published in
8 min readJan 13, 2020

… and a way we go!

This article demonstrates how end-users, and machines alike, can summon up answers from Wasm functions over the web using nothing more than HTTP requests. For the more adventurous readers out there, this article also demonstrates how to write and deploy your very own Wasm executable on the same infrastructure.

Background

A recent article surmised that whilst Wasm has indeed gained popularity on the client-side, Wasm has also recently become a serious contender in relation to server-side technologies and services.

Expanding on this idea, another article suggests that the future of distributed computing will see traditional microservices being transitioned towards Wasm infrastructure. There are many reasons for this. One being that Wasm allows the logic of individual discrete functions to be written and shared amongst the most amount of source-code languages, and native hardware.

Inevitably then, this means that Wasm will be applicable to the most amount of applications, even if its presence is behind the scenes; serving each application by efficiently executing a well managed set of discrete functions.

Of course, this utopian distributed computing model requires some foundations upon which we can build our own customised business and enterprise software.

With these lofty, yet achievable goals in mind, let’s now take a look at a some new and exciting Wasm infrastructure that will help us along this path.

SecondState have recently built a suite of software that facilitates, among other things, server-side Wasm deployment and execution.

https://www.secondstate.io/

The following diagram shows a few of the components which make up this system. Namely:

  • SSVMRPC — A Remote Procedure Call (RPC) implementation (written in Rust) which facilitates both Wasm code-deployment and Wasm code-execution interactions with SecondState’s stateless Virtual Machine (SSVM)
  • SSVMContainer — A Rust application that sits between incoming requests from the network and the SSVM. This application handles the deployment of Wasm applications and manages the execution of services (callable functions inside the Wasm application). It also manages application state, given that SSVM performs stateless execution.
  • SSVM — a high performance, hardware optimised, stateless, stack-based Wasm Virtual Machine. SSVM can execute Wasm binaries, but is also highly optimised for both AI and Blockchain specific applications.

An overview of the infrastructure

https://github.com/second-state/SSVMRPC/blob/master/documentation/images/ssvmrpc.png

One of the key benefits of SecondState’s infrastructure, is that you don’t actually have to think about, or know how the internals work. In fact to execute server-side Wasm, using this system, you just need to be able to make a simple HTTP request.

We will demonstrate “Calling an application’s function” very shortly, but hang in there for a couple of minutes while we take a quick technical dive.

Technical dive

This section will show you how to create and deploy your own Wasm executable on the SecondState infrastructure. For this application creation & deployment demonstration, we will use Rust on an Ubuntu OS.

Let’s get started!

Install Rust

sudo apt-get update
sudo apt-get -y upgrade
curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh
source $HOME/.cargo/env

Create a new application

cd ~
cargo new --lib add
cd add

Set Wasm specific system configuration

Add the following to the Cargo.toml file

[lib]
name = "add_lib"
path = "src/lib.rs"
crate-type =["cdylib"]

Write the source code

Open a new file at src/lib.rs and add the following code

#[no_mangle]
pub extern fn add_two_numbers(_x: i32, _y: i32) -> i32{
_x + _y
}

Wasm system config

rustup target add wasm32-wasi
rustup override set nightly

Compile to Wasm

cargo build --release --target=wasm32-wasi

The above compilation will create a new Wasm file at target/wasm32-wasi/release/add_lib.wasm . This is the file that we will deploy on SecondState’s Wasm infrastructure.

As you will see in a minute, we will be following this particular HTTP POST specification when deploying this application.

A quick word about compiled Wasm files

WAT

If you would like to see the textual representation (known as “WebAssembly Text format” or “WAT” for short) of your (newly created) Wasm application, you can install the incredibly useful wabt toolkit.

Simply run the following command; converting from wasm to wat.

./wasm2wat ~/add/target/wasm32-wasi/release/add_lib.wasm -o ~/add/target/wasm32-wasi/release/add_lib.wat

The textual representation (WAT) will look like this.

(module
(type (;0;) (func (param i32 i32) (result i32)))
(func $add_two_numbers (type 0) (param i32 i32) (result i32)
local.get 1
local.get 0
i32.add)
(table (;0;) 1 1 funcref)
(memory (;0;) 16)
(global (;0;) (mut i32) (i32.const 1048576))
(global (;1;) i32 (i32.const 1048576))
(global (;2;) i32 (i32.const 1048576))
(export "memory" (memory 0))
(export "__data_end" (global 1))
(export "__heap_base" (global 2))
(export "add_two_numbers" (func $add_two_numbers)))

Wasm

You will notice that the original add_lib.wasm file is not able to be easily viewed, as it is an executable binary file. You will also notice that without any optimisations, the Wasm file (generated by default Rust compilation) is around 1800000 bytes. This is large in terms of Wasm.

We will be a xxd command to convert the Wasm file to hex (for use in the HTTP POST’s JSON data). But, before you do that, I highly recommend shrinking the original Wasm file.

xxd -p target/wasm32-wasi/release/add_lib.wasm | tr -d $'\n'

One very easy way to shrink the Wasm executable is to use the awesome wabt toolkit again. Except this time we will convert back the other way i.e. convert the wat file (that we just created) back to wasm like this.

./wat2wasm ~/add/target/wasm32-wasi/release/add_lib.wat -o ~/add/target/wasm32-wasi/release/add_lib.wasm

It is now safe to perform the above xxd command :)

Just for your interest, the overall result of these wabt conversions sees the Wasm executable size go from the original 1800000 bytes to just 4000 bytes. The new hexadecimal representation of the Wasm executable file (after the xxd command) now looks, literally, like this …

0061736d0100000001070160027f7f017f030201000405017001010105030100100619037f01418080c0000b7f00418080c0000b7f00418080c0000b073704066d656d6f727902000a5f5f646174615f656e6403010b5f5f686561705f6261736503020f6164645f74776f5f6e756d6265727300000a09010700200120006a0b

Pretty manageable in terms of cut and paste now, right?

Deploying your application

This hexadecimal dump of the Wasm file needs a quick tweak. We need to add a 0x to the beginning of the Wasm hex string before we deploy our application.

Here is an example of how we deploy the above Wasm application via Curl.

Curl

Note the 0x, that we manually added, at the start of the bytecode!

curl --header "Content-Type: application/json" \
--request POST \
--data '{
"request": {
"application": {
"storage": "file_system",
"bytecode": "0x0061736d0100000001070160027f7f017f030201000405017001010105030100100619037f01418080c0000b7f00418080c0000b7f00418080c0000b073704066d656d6f727902000a5f5f646174615f656e6403010b5f5f686561705f6261736503020f6164645f74776f5f6e756d6265727300000a09010700200120006a0b","name": "Add"}}}' \
http://13.54.168.1:8080/deploy_wasm_application

Postman — GUI HTTP client

https://www.getpostman.com/

Here is the equivalent JSON that you would pass in, if you were using a GUI HTTP client to make the POST request.

Again, note the 0x, that we manually added, at the start of the bytecode!

{
"request": {
"application": {
"storage": "file_system",
"bytecode": "0x0061736d0100000001070160027f7f017f030201000405017001010105030100100619037f01418080c0000b7f00418080c0000b7f00418080c0000b073704066d656d6f727902000a5f5f646174615f656e6403010b5f5f686561705f6261736503020f6164645f74776f5f6e756d6265727300000a09010700200120006a0b",
"name": "Add"
}
}
}

Response

{"response":{"application":{"name":"Add","uuid":"0xa9d57ac0f5046512"},"status":"success"}}

Application successfully deployed

When the application deploys, it will return a unique identifier i.e. 0xa9d57ac0f5046512 . You will need to remember/save this identifier for when you are calling an application’s function, in the future.

That wraps up the technical dive section, let’s take a look at how we can call an application’s functions over HTTP.

Calling an application’s function

The calling of an application’s function is not limited to just users. This article explains how to call Wasm functions via Curl etc. because this is a great way to roll up your sleeves and understand the details of the requests and responses.

The reality is that most of the time these functions will be called programatically by machines. At the very least, they will be constructed programatically behind a web browser or phone app and will be executed via end user “clicks”.

Let’s now have a go at calling an application’s function.

Copy and paste the following curl command into your terminal (or if you prefer, you can use a Graphical User Interface like Postman to perform this HTTP request for you).

Command line — Curl syntax example

Don’t be overwhelmed by the --data below. It is actually pretty straight forward (see the HTTP POST specification for more information). Essentially, we are just calling the function add_two_numbers and passing in two numbers ["2", "2"] ; expecting a return value of "4"

curl --header "Content-Type: application/json" \
--request POST \
--data '{"request": {"application": {"storage": "file_system", "uuid": "0xa9d57ac0f5046512"},"function": {"name": "add_two_numbers", "arguments": ["2", "2"],"argument_types": ["i32", "i32"], "return_types": ["i32"]},"modules": ["rust"] }}' \
http://13.54.168.1:8080/execute_wasm_function

GUI — Postman JSON example

{
"request": {
"application": {
"storage": "file_system",
"uuid": "0xa9d57ac0f5046512"
},
"function": {
"name": "add_two_numbers",
"arguments": ["2", "2"],
"argument_types": ["i32", "i32"],
"return_types": ["i32"]
},
"modules": ["rust"]
}
}

Response

Either of the above methods will produce a result object, as shown below. You will notice the return value "return_value":["4"] which is correct.

{
"result": {
"error_message": "",
"gas": 0,
"gas_used": 6,
"return_value": [
"4"
],
"status": "Succeeded",
"vm_snapshot": {
"global": [
[
0,
"0x0000000000100000"
],
[
1,
"0x0000000000100000"
],
[
2,
"0x0000000000100000"
]
]
}
},
"service_name": "0xa9d57ac0f5046512_1578786333_add_two_numbers",
"uuid": "0xa9d57ac0f5046512"
}

You may have also noticed that there is a vm_snapshot section in the return data. What is this vm_snapshot ?

VM Snapshot

VM Snapshot is data which is produced by SecondState’s Virtual Machine(SSVM), itself.

It is important to remember that the SSVM itself is stateless. Each call to this system invokes a new clean SSVM instance.

The vm_snapshot data allows the overarching system to store the last known state of the SSVM. By storing this vm_snapshot information, we are able to ensure that SSVM can pick up where it last left off. Using this approach, the last known state of SSVM can be restored during the next execution.

We mentioned at the beginning of this article that an end-user does not really need to understand the inner workings of the system. Simply put, if an end-user repeatedly calls a function, all of the vm_snapshot (VM state) will be handled by the system on their behalf.

Stateful Wasm execution as a service

This article has demonstrated a simple stateful Wasm execution environment; one where human callers or machines can interact, with the logic of each discrete Wasm function. Simply using HTTP POST requests via the web.

Naturally, this demonstration only used simple application functions line add_two_numbers but of course you are free to write any logic to suit your needs.

If you have any questions or would like any assistance in relation to the technology in this article please get in touch with SecondState via the web site or GitHub.

contact@secondstate.io

--

--

Timothy McCallum
Wasm
Editor for

I'm a technical writer and copy editor exploring WebAssembly (Wasm), software automation, and Artificial Intelligence (AI) while mastering Rust, Python, & Bash.