2018年5月23日晚,Qtum x86虛擬機器及Qtum企業版的開發進展釋出會於韓國首爾順利舉行。Qtum研發團隊現場演示了用c語言編寫的“Hello world”智慧合約,從編寫、編譯、部署到呼叫的全套流程,這也是Qtum區塊鏈(內部測試網路)上執行的首個用 C 語言編寫的智慧合約。
詳情:
支援C/C++/Rust/Swift的Qtum X86虛擬機器如何打造更豐富的智慧合約生態
每週專案進展報告都有涉及 Qtum x86 技術進展,本系列文章主要為整合與實踐操作指導,幫助更多的主流語言開發者加入區塊鏈開發的大潮中來。本篇連載文章主要為“Hello World”合約的建立和除錯。
Hello World
工具鏈設定完畢之後,我們終於可以使用一個簡單的 Hello World 合約對它進行測試了。
這是一個非常簡單的 Hello World 合約原始碼:
#include <qtum.h>
int onCreate(){
qtumEventStringString("Hello World", "Contract creation");
return 0;
}
int main(){
qtumEventStringString("Hello World", "Execution Success!");
return 0;
}
在這裡 onCreate 函式在最初使用 createcontract 或 qx86deploy 在區塊鏈上部署智慧合約時被呼叫。之後無論是執行 callcontract 、sendtocontract 或是其他合約呼叫時,都將呼叫 main 函式 。
qtumEventStringString 函式可在執行時生成一個新事件(event),StringString 字尾意味著事件的 “Key”和“Value” 都是一串字元。還有類似qtumEventStringInt64 這樣的函式,用於指定的64位整數“Key”而不是字串。使用 qx86cli searchevents 我們可以對該事件進行檢索。
這個智慧合約的編譯過程稍微複雜一些。我們使用工具鏈docker 容器來進行實際的處理。這能簡化在任何作業系統上編譯 qtumx86 智慧合約的過程,而不僅限於 Linux 或 OSX。
首先,我們編寫一個 makefile。這個 makefile 將在 docker容器上執行,以確保所有 Qtum 工具都可用,下面是 hello world 的模板:
# files to be built
# fill this in as a template
HDRS =
C_SRC = helloworld.c
OUTPUT = helloworld.elf
LIBS =
BYTECODE = helloworld.qbit
C_OBJS = $(subst .c,.o,$(C_SRC))
#these default flags will just remove dead code and give warnings
CFLAGS += -Wall -ffunction-sections -f>LDFLAGS += -Wl,--gc-section
default: $(BYTECODE)
$(BYTECODE): $(OUTPUT)
x86testbench -assemble -raw $(OUTPUT) > $(BYTECODE)
$(OUTPUT): $(C_OBJS)
$(CC) $(LDFLAGS) -o $(OUTPUT) $(C_OBJS) $(LIBS)
$(C_OBJS): $(HDRS) $(C_SRC)
$(CC) $(CFLAGS) -c $*.c -o $@
clean:
rm -f $(C_OBJS) $(OUTPUT) $(BYTECODE)
我們把它的變數分解如下:
HDRS =
這是為了跟蹤合約中的任何標頭檔案。雖然標頭檔案不是直接編譯的,但是跟蹤這些檔案,可以在對標頭檔案進行更改時重新編譯程式碼。
C_SRC = helloworld.c
這些是要編譯的C檔案,可以通過在附加檔名後面加上空格分隔符將其擴充套件到多個檔案。
OUTPUT = helloworld.elf
這是GCC編譯器的輸出,是一個標準的ELF檔案,非常適合於後編譯分析。大多數現有的逆向工程和分析工具都支援這種格式。因此,如果需要對編譯器的二進位制檔案進行分析,那麼可以使用這個檔案。
LIBS =
這項操作是為了向合約中新增靜態庫。
BYTECODE = helloworld.qbit
這是實際用於部署在 Qtum 區塊鏈上的位元組碼檔案。它由 ELF 檔案簡化而來, 非常容易解析和使用,但由於存在較多限制,暫時沒有工具支援。當使用 qx86deploy 將其部署到區塊鏈時,將使用 Qtum RPC 命令 “createcontract” ,引數是這個檔案,它被轉儲到十六進位制字串中。
關於修改 Makefile,對於大多數簡單的合約,這就足夠了。對於涉及許多庫等的更復雜的檔案,使用它來編寫自定義 makefile 可能更理想。為了真正部署此合約,你可以在本地 shell 中使用此指令碼(假設你已從工具鏈設定中檢索了 helpers.sh 指令碼”)。
qx86start
qx86cli generate 600 # this will generate 600 blocks. This will start the chain and give us some coins to work with
qx86deploy helloworld.qbit
qx86cli generate 1 # generate 1 block so that we can mine our contract and ensure its processed
在這步操作之後你會看到以下輸出:
Jordans-MacBook-Pro:helloworld earlz$ qx86deploy helloworld.qbit
{
"txid": "02b28cfcc7d1fdcb5963ee2ff9024a045ac6fb4d8d66683b027e47fd5973ed0b",
"sender": "qUJfCTe5LacTUBjC7djrEfoMtfZGXD7J4L",
"hash160": "75e089080145b639bf496e27cc3ed655e13377d0",
"hexaddress": "85840fafe5b51343f58259de8b48fe6b001cce57",
"address": "xLUbyAmNUTRxLt67x5gDtDxBzWpLrH92Zn"
}
Jordans-MacBook-Pro:helloworld earlz$ qx86cli generate 1
[
"300b9d8d9e5d05c22d09ff91335766e559af21ab70ee6f37daf280220eecc06d"
]
許多不同的欄位將從部署命令中返回,其中很重要的一個是帶有 xLUbyAmNUTRxLt67x5gDtDxBzWpLrH92Zn 值的address,所以會根據區塊鏈上實際情況的不同而改變。txid 欄位表示的是合約所屬的交易ID 。
接下來你可以繼續以下操作:
qx86cli searchevents
之後將會出現一組相當大的 JSON 輸出。無論合約的執行是否成功,每一份合約的執行都有一份 JSON 輸出。下面是 JSON 中各欄位的含義:
block hash——執行合約時的區塊雜湊
tx-hash——待定
tx-n——待定
address——被執行的根合約地址,可能是執行createcontract 或是呼叫 sendtocontract 時的地址
used-gas——執行合約時所花費的 gas
sender-refund——退還給 sender 的 QTUM 數量
如果合約執行中出現的錯誤或恢復,所有在執行中傳送的 QTUM 將被退還給 sender
status——合約執行狀態的描述字串
status-code——合約執行狀態的狀態碼
transfer-txid——待定
commit-state——顯示該合約執行是否已經是提交狀態
deltas——顯示該合約執行過程中發生的所有狀態變化。它會試圖自動解析字串或數字,並以更友好的方式顯示
deltas-raw——與 deltas 一樣,但總是以原始十六進位制形式顯示
modified-balances——顯示由於該合約的執行引起餘額變動的所有地址的餘額
spent-vins——顯示所有該合約執行時消耗的 UTXO
events——顯示實際執行該合約時發生的事件,是一個 key-value 鍵值對
calls——顯示其他合約執行結果的遞迴結構。在整個合約執行過程中,每個合約呼叫都有一個結果。
你將在 JSON 輸出的底部看到如下內容:
"modified-balances": {
},
"spent-vins": [
]
},
"events": {
"Hello World": "Contract creation"
},
"calls": [
]
}
]
可以看到 hello world 合約已經生成。
為了呼叫該合約以及對它進行測試(這裡請將地址換成你自己的),執行以下操作:
qx86cli callcontract xLUbyAmNUTRxLt67x5gDtDxBzWpLrH92Zn 00
這將立即返回 JSON 結果。callcontract 只是在本地呼叫合約,並不建立區塊鏈交易。因此,沒有與 callcontract 相關的費用產生。在 JSON 結果中,你現在應該能在 events 陣列中看到"Hello World": "Execution Success!"
如要在區塊鏈上中實際交易中執行同樣的操作,你可以根據以下步驟:
qx86cli sendtocontract xLUbyAmNUTRxLt67x5gDtDxBzWpLrH92Zn 00
qx86cli generate 1 #create one block to confirm the transaction
執行後,不會有 JSON 結果出現,但你可以通過 searchevents 檢視。