In addition to Weibo, there is also WeChat
Please pay attention
WeChat public account
Shulou
2025-03-29 Update From: SLTechnology News&Howtos shulou NAV: SLTechnology News&Howtos > Internet Technology >
Share
Shulou(Shulou.com)06/01 Report--
In order to solve the problem of how to implement WebAssembly on CKB in Nervos CKB script programming, this article introduces the corresponding analysis and solution in detail, hoping to help more partners who want to solve this problem to find a more simple and feasible method.
Implementing WebAssembly on CKB
Since we chose to use RISC-V to build CKB-VM (Virtual Machine virtual machine), we have been asked this question almost every day: why not build your virtual machine on WebAssembly like everyone else?
There are actually many reasons behind this choice, and it may take another article or a speech to explain why. Fundamentally, there is a very important reason: the most important thing to build software is to find the right abstract concept, and we believe that RISC-V is a better abstract concept than WebAssembly for unlicensed blockchains.
Of course, WebAssembly is a huge step forward over other more advanced programming languages and the first generation of blockchain virtual machines, but RISC-V runs at a much lower level than WebAssembly, which makes it ideal for public chains that want to run for decades in the future.
But one question remains unanswered: at present, a large part of the blockchain industry is betting on WebAssembly, and dapps based on WebAssembly has built a good ecosystem. So how does CKB compete with it? As mentioned above, RISC-V is actually at a lower level of abstraction than WebAssembly, and we can migrate existing WebAssembly programs and run them directly on CKB-VM. In this way, we can enjoy the flexibility and stability provided by RISC-V while embracing the ecosystem of WebAssembly.
In this article, we'll show how to run a WebAssembly program in CKB-VM, and we'll show that running it this way has more advantages than using WebAssembly VM directly.
Personally, while I believe that WebAssembly will have some interesting features to support different use cases, I don't believe that WebAssembly will create a better ecology in the blockchain area. Looking around, there may be only two mature options for building DApp in a WebAssembly-based blockchain: Rust and AssemblyScript.
People have been boasting about WebAssembly's ability to support any language in a single abstract VM (I personally refuse to call WebAssembly a virtual machine for low-level), but to create a real DApp here, you can only choose between the two languages. I think if a virtual machine that supports only two programming languages is called a good VM ecosystem, then we might have a different definition. Of course, there are other languages that are catching up, but they are not yet stable enough to be considered a prosperous ecosystem. Although some interesting languages have potential in WebAssembly-based environments, no one has noticed and supported them.
If you look closely, it is still a question whether two different blockchain projects using WebAssembly can share contracts with each other. Of course, someone might say, "well, it's only a matter of time, and over time, a more dynamic WebAssembly ecosystem will sprout." But the same argument applies everywhere: why won't RISC-V 's ecosystem get better over time?
So much for the roar, and now we just assume that WebAssembly does have a blockchain ecosystem, and we can prove that two of the widely used languages, AssemblyScript and Rust, are supported in the CKB-VM environment.
AssemblyScript
I believe there is nothing more illustrative than a demonstration. So let's try the official AssemblyScript and run the compiled program on CKB. We will use only the official examples from the AssemblyScript introduction page:
$cat fib.tsexport function fib (n: i32): i32 {var a = 0, b = 1; for (let I = 0; I < n; ilevels +) {let t = a + b; a = b; b = t;} return b;}
For information about how to install, please refer to the documentation of AssemblyScripts. For convenience, I have provided some steps that you can copy and paste here.
$git clone https://github.com/AssemblyScript/assemblyscript.git$ cd assemblyscript$ npm install$ bin/asc.. / fib.ts-b.. / fib.wasm-O3 $cd.
So we have a compiled WebAssembly program, we can call a program named wasm2c to compile it into a C language source file, and then compile it into a RISC-V program through the RISC-V compiler and run it on CKB-VM.
I'm sure you'll say: this is a hacker! It decompiled the WASM program here and then made it work. You are cheating. The answer to this question is yes but no:
On the one hand, I am cheating, but the question I would like to ask is: what we should care about is the final result. If the result is good enough, why should we care if it is cheating? In addition, the modern compiler is complex enough, like a complete black box, how can we be sure that this decompilation will get a worse result?
On the other hand, this is just one way to convert WebAssembly to RISC-V. There are many other ways to achieve the same result. We will discuss this again in a later restatement section.
Start wasm2c and convert the WebAssembly program:
$git clone-- recursive https://github.com/WebAssembly/wabt$ cd wabt$ mkdir build$ cd build$ cmake. $cmake-- build. $cd.. /.. $wabt/bin/wasm2c fib.wasm-o fib.c
You will see a pair of fib.c and fib.h files in the current directory that contain the results of the transformation of the WebAssembly program, and when compiled and invoked correctly, they will perform the same functions as the WebAssembly program.
We can use a small wrapper C file to call the WebAssembly program:
$cat main.c#include # include # include "fib.h" int main (int argc, char** argv) {if (argc < 2) return 2; U8 x = atoi (argv [1]); init (); U8 result = Z_fibZ_ii (x); return result;}
This simply reads an integer from the CLI parameter, calls the Fibonacci function in the WebAssembly program, and returns the result. Let's compile it first:
$sudo docker run-- rm-it-v `pwd`: / code nervos/ckb-riscv-gnu-toolchain:xenial bash (docker) $cd / code (docker) $riscv64-unknown-elf-gcc-o fib_riscv64-O3-g main.c fib.c / code/wabt/wasm2c/wasm-rt-impl.c-I / code/wabt/wasm2c/riscv/lib/gcc/riscv64-unknown-elf/8.3.0/../riscv64-unknown-elf/bin / ld: / tmp/ccfUDYhE.o: in function `_ _ retain':/code/fib.c:1602: undefined reference to `Z_envZ_abortZ_viiii'/riscv/lib/gcc/riscv64-unknown-elf/8.3.0/../riscv64-unknown-elf/bin/ld: / tmp/ccfUDYhE.o: in function `i32_load':/code/fib.c:42: undefined reference to `Z_envZ_abortZ_viiii'/riscv/lib/ Gcc/riscv64-unknown-elf/8.3.0/../riscv64-unknown-elf/bin/ld: / tmp/ccfUDYhE.o: in function `f17':/code/fib.c:1564: undefined reference to `Z_envZ_abortZ_viiii'/riscv/lib/gcc/riscv64-unknown-elf/8.3.0/../riscv64-unknown-elf/bin/ld: / code/fib.c:1564: Undefined reference to `Z_envZ_abortZ_viiii'/riscv/lib/gcc/riscv64-unknown-elf/8.3.0/../riscv64-unknown-elf/bin/ld: / tmp/ccfUDYhE.o: in function `f6':/code/fib.c:1011: undefined reference to `ZanzenvZabortZobliviiAccording to Riscv, LIBG, GCC, Riscv64, Riscv64, UnknownMuelf, 8.3.0... Elf/bin/ld: / tmp/ccfUDYhE.o:/code/fib.c:1012: more undefined references to `ZanzenvZodii'followcollect2: error: ld returned 1 exit status (docker) $exit
As shown above, there is an error. It tells us that there is an undefined Z_ENVZ_ABORTZ_VIII function. Let's take a closer look at why this happened.
First, let's convert the original WebAssembly file to a readable form:
$wabt/bin/wasm2wat fib.wasm-o fib.wast$ cat fib.wast | grep "(import" (import "env"abort" (func (; 0;) (type 2)
So the problem is that WebAssembly can import external functions and provide additional functions when called. In fact, the famous WASI is based on the import function. Later, we will see that import can be used to implement more interesting functions that are impossible for WebAssembly-based blockchain virtual machines.
Now, let's try an abort execution to fix the error:
$cat main.c#include # include # include "fib.h" void (* Z_envZ_abortZ_viiii) (U32, U32); void env_abort (U32 a, U32 b, U32 c, U32 d) {abort ();} int main (int argc, char** argv) {if (argc < 2) return 2; U8 x = atoi (argv [1]); Z_envZ_abortZ_viiii = & env_abort; init (); U8 result = Z_fibZ_ii (x) Return result;} $sudo docker run-- rm-it-v `pwd`: / code nervos/ckb-riscv-gnu-toolchain:xenial bash (docker) $cd / code (docker) $riscv64-unknown-elf-gcc-o fib_riscv64-O3-g main.c fib.c / code/wabt/wasm2c/wasm-rt-impl.c-I / code/wabt/wasm2c (docker) $exit
Of course, you can test the compiled fib_riscv64 program on CKB. One trick, however, is that there is a simple CKB-VM binary in the test suite that we can use to run this particular program. It is worth mentioning that this CKB-VM binary works slightly differently from VM in CKB. Testing the WebAssembly program in the current example is sufficient. But to test the correct CKB script, you may want to use a newly built stand-alone debugger that follows the semantics of all CKB. Later articles will explain how the debugger works.
Let's compile the binaries in the test suite and run the program:
$git clone-- recursive https://github.com/nervosnetwork/ckb-vm-test-suite$ cd ckb-vm-test-suite$ git clone https://github.com/nervosnetwork/ckb-vm$ cd binary$ cargo build-- release$ cd.. /.. $ckb-vm-test-suite/binary/target/release/asm64 fib_riscv64 5Error result: Ok (8) $ckb-vm-test-suite/binary/target/release/asm64 fib_riscv64 10Error result: Ok (89)
The error report here is slightly misleading, and the binary will treat any non-zero result in the program as an error. Because the tested program returns the Fibonacci calculation as the return value, the binary treats the return value (probably not zero) as an error, but we can see that the actual error value contains the correct Fibonacci value.
Now we prove that the AssemblyScript program does work on CKB-VM! I'm sure more complex programs may encounter errors that need to be adjusted separately, but you've learned the whole process and know where to look when an error occurs:)
Rust
We have seen some simple examples in the AssemblyScript section. Let's try something more interesting in the Rust section: can we implement a complete signature verification in the Rust code?
It turns out we can! But this is far more than we can include in this blog post. I have prepared a demonstration project to show this. It implements the process of signature verification using secp256k1 library in pure Rust language. If you follow the instructions in the file, you should be able to reproduce the following specific steps:
Compile complex Rust programs into WebAssembly
Convert WebAssembly programs to RISC-V
Run the generated RISC-V program on the CKB virtual machine
Better than WebAssembly
One more thing we need to mention: if you check the Bindgen branch of the Rust secp256k1 presentation library and try the same steps, you will encounter the following error:
/ riscv/lib/gcc/riscv64-unknown-elf/8.3.0/../riscv64-unknown-elf/bin/ld: / tmp/ccYMiL3C.o: in function `core::result::unwrap_failed':/code/secp.c:342: undefined reference to `Zbindgenetics placeholderbank Zdestroy WBINDGen describeZonal visionary RiscvUniverse Riscv64 Muffle unknownMuffle 8.3.0... /.. / riscv64-unknown-elf/bin/ld: / code/secp.c:344: undefined reference to `Z___wbindgen_placeholder__Z___wbindgen_describeZ_vi'/riscv/lib/gcc/riscv64-unknown-elf/8.3.0/../riscv64-unknown-elf/bin/ld: / code/secp.c:344: undefined reference to `Z___wbindgen_placeholder__Z___wbindgen_describeZ_vi'/ Riscv/lib/gcc/riscv64-unknown-elf/8.3.0/../riscv64-unknown-elf/bin/ld: / code/secp.c:347: undefined reference to `Z___wbindgen_placeholder__Z___wbindgen_describeZ_vi'/riscv/lib/gcc/riscv64-unknown-elf/8.3.0/../riscv64-unknown-elf/bin/ld: / code/secp.c : 3505: undefined reference to `Z___wbindgen_placeholder__Z___wbindgen_describeZ_vi'/riscv/lib/gcc/riscv64-unknown-elf/8.3.0/../riscv64-unknown-elf/bin/ld: / tmp/ccYMiL3C.o:/code/secp.c:353: more undefined references to `ZBINDGen from wbindgenetics placeholderplaceholderplaceholderplaceholderplaceholdersZBINDgenDescribeZyogvi' follow/riscv/lib/gcc/riscv64-unknown-elf/ 8.3.0/../riscv64-unknown-elf/bin/ld: / tmp/ccYMiL3C.o: in function `i32_store':/code/secp.c:56: undefined reference to `Z___wbindgen_anyref_xform__Z___wbindgen_anyref_table_set_nullZ_vi'/riscv/lib/gcc/riscv64-unknown-elf/8.3.0/../riscv64-unknown-elf/bin / ld: / tmp/ccYMiL3C.o: in function `i32_load':/code/secp.c:42: undefined reference to `Z___wbindgen_anyref_xform__Z___wbindgen_anyref_table_set_nullZ_vi'/riscv/lib/gcc/riscv64-unknown-elf/8.3.0/../riscv64-unknown-elf/bin/ld: / tmp/ccYMiL3C.o: in function `i32_store':/code/secp.c: 56: undefined reference to `Z___wbindgen_anyref_xform__Z___wbindgen_anyref_table_set_nullZ_vi'/riscv/lib/gcc/riscv64-unknown-elf/8.3.0/../riscv64-unknown-elf/bin/ld: / code/secp.c:56: undefined reference to `Z___wbindgen_anyref_xform__Z___wbindgen_anyref_table_set_nullZ_vi'/riscv/lib/gcc/ Riscv64-unknown-elf/8.3.0/../riscv64-unknown-elf/bin/ld: / tmp/ccYMiL3C.o: in function `i32_load':/code/secp.c:42: undefined reference to `Z___wbindgen_anyref_xform__Z___wbindgen_anyref_table_growZ_ii'/riscv/lib/gcc/riscv64-unknown-elf/8.3.0/../riscv64-unknown -elf/bin/ld: / code/secp.c:42: undefined reference to `Z___wbindgen_anyref_xform__Z___wbindgen_anyref_table_growZ_ii'collect2: error: ld returned 1 exit status
Following the same steps in the AssemblyScript example, we can do some imports in the WebAssembly file:
$wabt/bin/wasm2wat wasm_secp256k1_test.wasm-o secp.wat$ cat secp.wat | grep "(import" (import "_ wbindgen_placeholder__"_ wbindgen_describe" (func $_ wbindgen_describe (type 3) (import "_ wbindgen_anyref_xform__"_ wbindgen_anyref_table_grow" (func $_ wbindgen_anyref_table_grow (type 4) (import "_ wbindgen_anyref_xform__" "_ wbindgen_anyref_table_set_null" (func $_ wbindgen_anyref_table_set_null (type 3)
These are actually functions of the binding environment required in Rust wasm-bindgen. We will continue our efforts to provide bindings that are compatible with the CKB environment. But now let's take a step back and think: the environmental functionality required here is not part of the WebAssembly standard. What is required in the standard is that when the import entry cannot be found, WebAssembly VM stops execution and an error occurs. To implement different features, different WebAssembly-based blockchains may inject different imports here. It makes it difficult to write a WebAssembly program that is compatible with different block chains.
However, in the CKB environment, we can add any environment function as needed. Therefore, all WebAssembly programs for different blockchains are supported. More importantly, we can use imports to introduce new features to existing WebAssembly programs. Because the import function is provided with the WebAssembly program, CKB itself does not need to do anything to support it. All miracles happen in a CKB script. For blockchains that support WebAssembly, these environment functions are most likely to be fixed and are part of the consensus rule. You can't introduce new ones at will. Similarly, this transformation-based process on CKB will make it easier to support new WebAssembly features (such as garbage collection or threading), which is really just a matter of writing the required support features into CKB scripts, which means that when the WebAssembly virtual machine is updated, you don't have to wait six months for the next hard fork (to implement these new features).
This is easy to implement.
You may have a question: "I see, you created WebAssembly in RISC-V, but I can also reproduce RISC-V in WebAssembly!" WebAssembly is flexible! "in a sense, this is feasible, and once a language or virtual machine exceeds a certain amount of flexibility, it can be used to build a lot of (or even crazy) things. In the first version of jslinux, you can even simulate a complete x86 in pure JavaScript. But the flip side of the problem is that it is easy to implement. It feels more natural to build WebAssembly on RISC-V because WebAssembly is abstracted to a higher level and has many advanced features. For example, a higher level of control flow, garbage collection, etc. On the other hand, RISC-V simulates what a real CPU can do, which is a very thin layer on top of the actual CPU running inside the computer. So while it is true that both directions are possible, some features of the WebAssembly built on RISC-V are easier to implement. Implementing RISC-V on WebAssembly may encounter a lot of problems.
An alternative example is that EVM,EVM has been advocating Turing completeness for many years, but the sad truth is that it is almost impossible to build arbitrarily complex algorithms on EVM: either the coding part is too difficult, or the gas consumption will be unreasonable. People have to come up with various ways to introduce the latest algorithm on EVM. When Istanbul hard bifurcation is completed, we can only use Blake2b algorithm in EVM. But what about many other algorithms?
All of these are our reasons for choosing RISC-V: we want to find the smallest layer in this generation of CPU architecture, and RISC-V is the most obvious alternative model we can find in the blockchain world while ensuring security and performance. Any different model, such as WebAssembly, EVM, etc., should be a layer above the RISC-V model and can be implemented naturally through the RISC-V model. However, the other direction may not feel so smooth at all.
This is the answer to the question about how to implement WebAssembly on CKB in Nervos CKB script programming. I hope the above content can be of some help to everyone. If you still have a lot of doubts to be solved, you can follow the industry information channel to learn more about it.
Welcome to subscribe "Shulou Technology Information " to get latest news, interesting things and hot topics in the IT industry, and controls the hottest and latest Internet news, technology news and IT industry trends.
Views: 0
*The comments in the above article only represent the author's personal views and do not represent the views and positions of this website. If you have more insights, please feel free to contribute and share.
Continue with the installation of the previous hadoop.First, install zookooper1. Decompress zookoope
"Every 5-10 years, there's a rare product, a really special, very unusual product that's the most un
© 2024 shulou.com SLNews company. All rights reserved.