Qtum x86 虛擬機器技術文件連載(二)

QTUM量子鏈開發團隊發表於2019-01-28

Qtum x86 虛擬機器技術文件連載(二)


本篇為Qtum x86虛擬機器的第二篇技術分析連載,本篇逐漸進入實際程式碼操作實操階段,想要了解什麼是虛擬機器Qtum x86虛擬機器獨特優勢見

Qtum x86 虛擬機器技術文件連載(一)

Qtum x86 虛擬機器技術文件連載(二)

2018年5月23日晚,Qtum x86虛擬機器及Qtum企業版的開發進展釋出會於韓國首爾順利舉行。Qtum研發團隊現場演示了用c語言編寫的“Hello world”智慧合約,從編寫、編譯、部署到呼叫的全套流程,這也是Qtum區塊鏈(內部測試網路)上執行的首個用 C 語言編寫的智慧合約。


詳情:

Qtum X86虛擬機器及Qtum企業版原型於韓國發布

支援C/C++/Rust/Swift的Qtum X86虛擬機器如何打造更豐富的智慧合約生態


每週專案進展報告都有涉及 Qtum x86 技術進展,本系列文章主要為整合與實踐操作指導,幫助更多的主流語言開發者加入區塊鏈開發的大潮中來。本篇連載文章主要為“Hello World”合約的建立和除錯。


Qtum x86 虛擬機器技術文件連載(二)

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 中各欄位的含義:

  1. block hash——執行合約時的區塊雜湊

  2. tx-hash——待定

  3. tx-n——待定

  4. address——被執行的根合約地址,可能是執行createcontract 或是呼叫 sendtocontract 時的地址

  5. used-gas——執行合約時所花費的 gas

  6. sender-refund——退還給 sender 的 QTUM 數量


如果合約執行中出現的錯誤或恢復,所有在執行中傳送的 QTUM 將被退還給 sender

  1. status——合約執行狀態的描述字串

  2. status-code——合約執行狀態的狀態碼

  3. transfer-txid——待定

  4. commit-state——顯示該合約執行是否已經是提交狀態

  5. deltas——顯示該合約執行過程中發生的所有狀態變化。它會試圖自動解析字串或數字,並以更友好的方式顯示

  6. deltas-raw——與 deltas 一樣,但總是以原始十六進位制形式顯示

  7. modified-balances——顯示由於該合約的執行引起餘額變動的所有地址的餘額

  8. spent-vins——顯示所有該合約執行時消耗的 UTXO

  9. events——顯示實際執行該合約時發生的事件,是一個 key-value 鍵值對

  10. 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 檢視。



相關文章