Home

Awesome

Substrate Runtime in AssemblyScript

License Unit Tests Integration Tests End-to-end Tests

Important!!!<br> This project was a PoC to verify that Substrate Runtimes could be implemented in AssemblyScript. As a continuation of the project, we are building a framework for AssemblyScript Runtimes - Subsembly

Account-Based Substrate PoC Runtime written in AssemblyScript.

The project is funded by Web3 Foundation via their General Grants Program 🙏 WEB3 Badge

Currently the most matured way of developing Runtimes is using the Substrate framework (in Rust). The goal of this project is to deliver an Account-Based Substrate Runtime written in AssemblyScript as PoC.

This PoC can be considered the first step towards a general framework for developing runtimes in AssemblyScript.

Demo

Makefile

We have a Makefile in the root directory, that has 3 actions that demonstrate the AssemblyScript runtime in action.

Validator 1:

curl --location --request POST 'localhost:5000' \
--header 'Content-Type: application/json' \
--data-raw '{
    "jsonrpc": "2.0",
    "method": "author_insertKey",
    "params": ["aura","dice height enter anger ahead chronic easily wave curious banana era happy","0xdcc1461cba689c60dcae053ef09bc9e9524cdceb696ce39c7ed43bf3a5fa9659"],
    "id": 1
}'

Validator 2:

curl --location --request POST 'localhost:5001' \
--header 'Content-Type: application/json' \
--data-raw '{
    "jsonrpc": "2.0",
    "method": "author_insertKey",
    "params": ["aura","spray later man depth auction tape autumn rocket bullet grunt adult flight","0x203d05ced7e80c58db6ca60ceb28041dc28be0066ce9b1d75fd92597adae124f"],
    "id": 1
}'

Roadmap

Milestone 1 - WASM API Mock :white_check_mark:

In this milestone, the communication mechanism between the Host and Runtime will be established. The runtime will be able to access input passed from the Host and will be able to return data back to the Host as response. The Polkadot WASM API entries are mocked in this milestone.

Milestone 2 - Storage Module :white_check_mark:

In this milestone the basic functionality for setting and getting storage from the AS Runtime using the Polkadot HOST API will be implemented.

Milestone 3 - Support for Aura consensus :white_check_mark:

In this milestone the Aura Module functionality will be implemented into the AS Runtime.

Milestone 4 - State Transition function :white_check_mark:

In this milestone the State transition function will be implemented into the AS Runtime. As part of the State transition function the previously mocked WASM API functions will be implemented as-well. At this point the runtime must be able to:

  1. Define genesis state and account balances
  2. Run its Aura consensus.
  3. Sync/Initialize/Execute blocks.
  4. Being able to process Account Balance transfers (Extrinsics)

Project Structure

The most important components of this project are the following:

as-substrate-runtime
│
└───runtime    <--- Runtime packages & source code
|
└───node-template <--- Substrate node with native runtime
│
└───sandbox    <--- Rust environment for testing the Runtime
│
└───e2e-tests   <--- End-to-end tests of the Runtime

Packaging

The runtime is divided into packages and src. The packages are different components that we find useful to reuse and the src is the top-level code that compiles the whole project into a runtime. The hierarchy has the following structure:

Runtime
│
└───packages
│   └───core-modules       
│   └───core-utils         
│   └───models              
│   └───modules        <--- Modules packages. Contains the top-level "pallets" used in the Runtime
│       └───balances    
│       └───aura       
│       └───timestamp       
│       ....
│
└───src

All of the packagings are done using yarn workspaces. Thus so far we have the following workspaces:

Tools

Spec-builder

In the runtime/tools folder, there is a spec-builder tool that assists developers in generating raw versions of their genesis json files.

Substrate Node

node-template
│
└───node
└───runtime

Substrate provides a template node that uses Aura consensus for block production and Granpda for block finalization. Since our AssemblyScript runtime currently does not support Grandpa, we have modified the Node-template to not use Grandpa at all.

Substrate Runtimes compile to both native executable and WASM binary, therefore we need native executable for initializing our Node. Then, we provide WASM binary generated from AssemblyScript Runtime with the chainspec file. After the intialization, with the correct execution flags, the Substrate should be able to upgrade from the native runtime to the WASM binary. To learn more about how Substrate nodes execute the runtime, please refer to this

Playing with the Runtime

The runtime has 3 types of tests so far -> Integration, Unit and End-to-End tests. The Unit tests are written in AssemblyScript and are testing f.e the instantiation or encoding of a Block from a SCALE encoded Byte Array.

The Integration tests are written in Rust. They are calling into the WASM code and are validating:

  1. Whether the WASM code exposes the required API functions.
  2. Whether the API functions are returning the correct responses.

0. Prerequisite

1. Build the Runtime

  1. Go to ./runtime
  2. Execute yarn install
  3. Execute yarn run build New wasm-code binary file will be generated in the runtime folder.

2. Run the Unit Tests for Runtime

  1. Go to ./runtime
  2. Execute yarn run test

3. Compile the Rust Environment (Sandbox)

  1. Go to ./sandbox
  2. Execute cargo build

4. Run the Integration Tests (Option 1)

  1. Build the AS Runtime using the instructions above
  2. Go to ./sandbox
  3. Execute cargo test

*To see the results of the called methods, execute the command with cargo test -- --nocapture

4. Run the Integration Tests (Option 2)

  1. Go to ./sandbox
  2. Execute bash run-it.sh

5. Run the Unit Tests for Spec-Builder

  1. Go to ./runtime/tools/spec-builder
  2. Build wasm module by executing yarn run asbuild
  3. Execute yarn run test

6. Build and Run the node with WASM code

  1. Go to ./node-template
  2. Build WASM module and generate chain spec by executing:
yarn --cwd=../runtime build-spec -f ../spec-files/customSpec.json -o ../spec-files/customSpecRaw.json -c ../runtime/wasm-code
  1. Substrate node

    1. (Option 1) Build the node cargo build --release (may take a while)
    2. (Option 2) Pull the Docker image of the Substrate node (see Running in Docker section)
  2. (Optional) Purge the existing db with the following command:

rm -rf /tmp/node0*
  1. Run the node with the generated chain spec:
./target/release/node-template \
    --chain=../spec-files/customSpecRaw.json \
    --port 30333 \
    --ws-port 9944 \
    --rpc-port 9933 \
    --validator \
    --rpc-methods=Unsafe \
    --name Node01 \
    --base-path /tmp/node01 \
    --execution Wasm

The Node should start, but no blocks will be produced. For activating block production see the Block Production section.

7. Run End-to-End tests

End-to-end tests are designed to test the account transactions.

  1. Execute docker-compose up which runs 4 instances of Substrate nodes
  2. Go to ./e2e-tests
  3. Run npm install to load all dependencies
  4. Run npm test

Running in Docker

You should have Docker installed.

Docker image

We have a Docker Hub repository where we host the latest stable image of the Substrate node. This is the easiest and fastest way to run the Substrate node with Assemblyscript Runtime.

Run the executable:

docker run -p 9933:9933 -p 9944:9944 -p 30333:30333 -v {path-to-chain-spec-raw}/customSpecRaw.json:/customSpecRaw.json limechain/as-substrate:stable 

NOTE: Path to customSpecRaw.json must be absolute

Block production

We already have generated Aura keys for testing purposes, which is also passed to the node with chain spec file. Run this to add the keys to the node with author_insertKey RPC call:

curl --location --request POST 'localhost:9933' \
--header 'Content-Type: application/json' \
--data-raw '{
    "jsonrpc": "2.0",
    "method": "author_insertKey",
    "params": ["aura","dice height enter anger ahead chronic easily wave curious banana era happy","0xdcc1461cba689c60dcae053ef09bc9e9524cdceb696ce39c7ed43bf3a5fa9659"],
    "id": 1
}'

The response should be:

{"jsonrpc":"2.0","result":null,"id":1}

Now, node will start producing blocks.

Test Runtime modules with RPC calls

We have created a Postman collection with some useful RPC calls that access the Runtime API entries.

Follow this link to play around with the Postman collection. You need to have the a Substrate node running with the chain spec generated by our runtime and rpc-external option enabled if you are running with Docker.

License

This repository is licensed under Apache 2.0 license