2019-07-19 使用c语言编写ewasm

以太坊ewasm测试链下使用c语言编写ewasm合约

1、 合约的创建

a) 搭建开发环境(ubuntu18)

i. llvm安装

这个不要自己编译,耗时太久,虚拟机上可能编译不过,直接下载安装
打开网站llvm ,选择最新版安装,本文安装8.0

$ wget -c http://releases.llvm.org/8.0.0/clang+llvm-8.0.0-x86_64-linux-gnu-ubuntu-18.04.tar.xz
$ tar xJvf clang+llvm-8.0.0-x86_64-linux-gnu-ubuntu-18.04.tar.xz
$ pwd
$ vim ~/.bashrc
export PATH=$PATH:..clang+llvm-8.0.0-x86_64-linux-gnu-ubuntu-18.04/bin
$ source ~/.bashrc
$ clang --version

ii. wabt安装

    git clone https://github.com/webassembly/wabt.git
    mkdir wabt/build
    cd wabt/build
    cmake .. -DBUILD_TESTS=OFF
    make -j4

iii. pywebassembly安装

    git clone https://github.com/poemm/pywebassembly.git

iv. binaryen安装

    git clone https://github.com/WebAssembly/binaryen.git
    cd binaryen
    mkdir build
    cd build
    cmake ..
    make -j4
    sudo make install

v. rust安装

curl https://sh.rustup.rs -sSf | sh
source $HOME/.cargo/env
cargo install chisel

b) 编写合约

i. 参考代码

C代码:https://github.com/poemm/C_ewasm_contracts
Rust代码:https://github.com/ewasm/rust-ewasm.git
Nim代码:https://github.com/status-im/nimplay

ii. 编写c代码

首先需要获取代码:

git clone https://github.com/poemm/C_ewasm_contracts.git

目的只是为了复制其中的几个文件
新建目录evmc,复制两个文件到这里

mkdir evmc
cd evmc
cp ../C_ewasm_contracts/src/ewasm.h .
cp ../C_ewasm_contracts/src/ewasm.syms .

在当前目录下编写hello.c:

#include "ewasm.h"
typedef unsigned char BYTE;             // 8-bit byte

void main()
{
    char hello[] = "hello world!";
    BYTE buf[32];
    memcpy(buf,hello,sizeof(hello));
    finish((i32ptr*)buf,32);
}

由于以太坊环境无法printf,这里只能通过finish返回给调用者,其中的ewasm.h文件是从https://github.com/poemm/C_ewasm_contracts里面复制出来的

iii. 编译

clang -cc1 -O3 -emit-llvm -triple=wasm32-unknown-unknown-wasm hello.c -o hello.ll
opt -O3 hello.ll -o hello.ll
llc -O3 -filetype=obj hello.ll -o hello.o
wasm-ld hello.o -o hello.wasm --no-entry -allow-undefined-file=ewasm.syms -export=main

这个时候获取的wasm不符合以太坊ewasm的两个规则,只能导入ethereum库,只能导出main和malloc两个函数,因此无法使用,我们需要手动修改一下

iv. 修改wasm

先转换wasm为wast,修改后,再改为wasm

wasm-dis hello.wasm -o hello.wast

打开文件hello.wast:
修改:

(import "env" "finish" (func $finish (param i32 i32)))

为:

(import " ethereum" "finish" (func $finish (param i32 i32)))

找到:

(export "__heap_base" (global $global$1))
(export "__data_end" (global $global$2))

删除这两行
然后把wasm转换为wast

wasm-as hello.wast -o hello.wasm

这个过程太麻烦,写个脚本test.sh搞定:

wasmfile=$1
filename=${wasmfile%.*}
wastfile=${filename}".wast"
wasm-dis $wasmfile -o $wastfile
# generate file.wat with Wabt's wasm2wat, then:
sed -i -e 's/"env"/"ethereum"/g' $wastfile
sed -i -e 's/"_main"/"main"/g' $wastfile
sed -i '/_heap_base/d' $wastfile
sed -i '/_data_end/d' $wastfile
wasm-as $wastfile -o $wasmfile

调用:

./test.sh hello.wasm

c) 合约后期处理

这个时候的wasm还是不能直接使用,需要通过哨兵合约的检测,就必须使用chisel,编写chisel.yml,内容如下:

ewasm:
        file: "hello.wasm"
        output: "hello_deployer.wasm"
        trimexports:
                preset: "ewasm"
        verifyimports:
                preset: "ewasm"
        verifyexports:
                preset: "ewasm"
        repack:
                preset: "ewasm"
        deployer:
                preset: "memory"

然后执行:
chisel run
获得文件hello_deployer.wasm,这个文件就是用来发布的合约

d) 合约转化为16进制数据

执行命令:

hexdump -v -e '"" 1/1 "%02x" ""' hello_deployer.wasm

就可以转换成功

复制内容,制作发布合约的rpc:

{
    "jsonrpc": "2.0",
    "id": 171,
    "method": "eth_sendTransaction",
    "params": [
        {
            "data": "0x0061736d0100000001090260027f7f0060000002130108657468657265756d0666696e697368000003030200010503010001071102046d61696e0002066d656d6f727902000a0e0202000b0900410041b10110000b0bb801010041000bb1010061736d0100000001090260027f7f0060000002130108657468657265756d0666696e697368000003030201010405017001010105030100020615037f01419088040b7f00419088040b7f00418d080b071102066d656d6f72790200046d61696e00020a36020300010b3001017f230041206b2200240020004100290085083700052000410029008008370300200041201000200041206a24000b0b1401004180080b0d68656c6c6f20776f726c642100",
            "from": "1AdrP7vxBYFVW27rrscPbwoziSr3WtPNin",
            "gas": "0x47b760"
        }
    ]
}

其中data数据就是hexdump得到的内容,注意前面多加了个0x

你可能感兴趣的:(2019-07-19 使用c语言编写ewasm)