TLDR
I would like to propose that the Internet Computer System API be changed to enable better support for interpreted languages.
The protocol should be upgraded with System APIs that do the following:
- Dynamic registration of canister methods
- Reading of the custom Wasm metadata section
This would allow interpreted language CDKs to forego shipping a Rust/C++/etc environment to the end-developer’s machine, as canister methods could be registered at runtime and the interpreted source code could be read during init/post_upgrade from the custom metadata section.
All of this is to avoid having to compile a Wasm binary on the end-developer’s machine, which is the source of many complications for the end-developer and the CDK team.
Background Information
Demergent Labs is developing Azle (TypeScript and JavaScript CDK) and Kybra (Python CDK). Because these languages are generally enabled by interpreters, a lot of our work is dealing with enabling interpreters to function on the IC. The IC is lacking certain functionality to enable interpreted language CDKs to run at their simplest.
Two of the biggest problems we are facing with Azle and Kybra are long compile times and complicated automated environment setups.
The current architectures of Azle and Kybra essentially take an existing JavaScript or Python interpreter and compile them into Wasm, currently using a Rust canister to enable this. Shipping a Rust environment to the developers’ computers is thus necessary. This causes a large amount of complication and headache for developers and ourselves, as we must deal with the complexities of installing Rust across various operating systems and OS architectures.
Unfortunately there is no way that I know of to get around shipping this Rust environment to the developers’ machines. And Rust is not the important piece, it’s the fact that the Wasm binary requires the canister methods to be exported in the binary. This requires a Wasm compilation.
There are a few things I’ve tried to get around this. I’ve tried manipulating the binary with tooling to add the exported methods after the binary has been compiled. This is complicated, inelegant, and error-prone. I’ve thought about sending the source code in the init/post_upgrade params, but the code could easily be bigger than 2MiB (I suppose gzipping could help), and we would also be permanently changing the init/post_upgrade params for developers, possibly causing confusion and making deployments difficult.
We could also consider not using init/post_upgrade and using some kind of custom initialization process (just a canister update method), but this is not desirable as then Azle/Kybra deploy semantics would deviate from all other CDKs. Kybra already does something similar to chunk-upload its Wasm binaries, and we have to explain to devs these differences, which doesn’t seem desirable.
The goal is to be able to ship an already-compiled Wasm binary with the interpreter and all necessary initialization code in it. Then we would allow the JavaScript or Python code to dynamically register its methods during init/post_upgrade. We also need a way to load the static JavaScript and Python code during the init and post_upgrade method execution, as that’s where the interpreters are initialized and the source code executed.
I would like to propose a solution to this problem at a high level, and I would like to solicit feedback. I would love to know if anyone can think of a simpler way to accomplish this, because there is none that I know of. The Wasm binary must be compiled to get the canister methods exported. This requires a compiler toolchain like Rust/C++. This is to be avoided because of the complications it brings.
The protocol should be upgraded with System APIs that do the following:
- Dynamic registration of canister methods
- Reading of the custom Wasm metadata section
For example, imagine methods such as ic0.register_query_method
, ic0.register_update_method
, ic0.register_heartbeat_method
, ic0.custom_metadata_read
.
If we had access to these System APIs, we could ship a pre-compiled Wasm binary. This wouldn’t require shipping a Rust environment to the developers’ machines, and compilation should become extremely fast. In Azle’s case, we would only need to transpile their TypeScript/JavaScript, write to the custom metadata section, and deploy the binary again. For Kybra this would be even faster.
After implementing these new System APIs interpreted language CDKs should be much simpler for developers to install, and compilation would be almost instant…perhaps we could even then enable hot module swapping.
@ulan @roman-kashitsyn @ielashi @Manu @dsarlis @skilesare @bogwar