因預編譯合約的使用方式與普通Solidity合約使用方式完全相同,該框架能做到在不改變客戶端開發者體驗的情況下,獲得極高的運行速度,這對邏輯相對確定、追求高速度和併發能力的場景來說,可謂是屠龍刀一樣的存在。
今天,我將以HelloWorld合約爲例,爲大家介紹如何使用預編譯合約版本的HelloWorld。注意,本章內容需要你具備一定的C++開發經驗,且詳細閱讀了《FISCO BCOS 2.0原理解析: 分佈式存儲架構設計》。
下圖所示5個步驟是開發預編譯合約的必經之路,我將按步驟實現HelloWorld預編譯合約,然後分別使用控制檯、Solidity合約兩種方式來調用HelloWorld預編譯合約。
HelloWorld預編譯合約開發
先來看一下我們想要實現的HelloWorld合約的Solidity版本。Solidity版本的HelloWorld,有一個成員name用於存儲數據,兩個接口get(),set(string)分別用於讀取和設置該成員變量。
#step1#
定義HelloWorld接口
Solidity的接口調用都會被封裝爲一筆交易,其中,調用只讀接口的交易不會被打包進區塊,而寫接口交易會被打包進區塊中。由於底層需要根據交易數據中的ABI編碼來判斷調用的接口並解析參數,所以需要先把接口定義出來。
預編譯合約的ABI接口規則與Solidity完全相同,定義預編譯合約接口時,通常需要定義一個有相同接口的Solidity合約,這個合約稱爲預編譯合約的接口合約。接口合約在調用預編譯合約時需要使用。
#step2#
設計存儲結構
預編譯合約涉及存儲操作時,需要確定存儲的表信息(表名與表結構,存儲數據在FISCO BCOS中會統一抽象爲表結構)。這在之前的文章分佈式存儲架構設計有介紹。如果合約中不涉及變量存儲,可以忽略該步驟。
對於HelloWorld,我們設計如下的表。該表只存儲一對鍵值對,key字段爲hello_key,value字段爲hello_value 存儲對應的字符串值,可以通過set(string)接口修改,通過get()接口獲取。
#step3#
實現合約邏輯
實現新增合約的調用邏輯,需要新實現一個C++類,該類需要繼承Precompiled類, 重載call函數, 在call函數中實現各個接口的調用行爲。
call函數有三個參數,_context保存交易執行的上下文,_param是調用合約的參數信息,本次調用對應合約接口以及接口的參數可以從_param解析獲取,_origin是交易發送者,用於權限控制。
接下來,我們在源碼FISCO-BCOS/libprecompiled/extension目錄下實現HelloWorldPrecompiled類,重載call函數,實現get()/set(string)兩個接口。
接口註冊:
創建表:
在call函數中添加打開表的邏輯
區分調用接口:
參數解析與返回:
調用合約時的參數包含在call函數的_param參數中,是按照Solidity ABI格式進行編碼,使用dev::eth::ContractABI工具類可以進行參數的解析,同樣接口返回時返回值也需要按照該編碼格編碼。
dev::eth::ContractABI類中我們需要使用abiIn/abiOut兩個接口,前者用戶參數的序列化,後者可以從序列化的數據中解析參數。
HelloWorldPrecompiled實現:
考慮手機上的閱讀體驗,我們分塊介紹call接口內部實現並省略部分錯誤處理邏輯,詳細代碼實現可以參考FISCO BCOS 2.0文檔使用手冊->智能合約開發->預編譯合約開發。可複製下列鏈接到網頁中查看:
https://fisco-bcos-documentation.readthedocs.io/zh_CN/latest/docs/manual/smart_contract.html#id2
get()接口實現
set接口實現
#step4#
分配並註冊合約地址
FSICO BCOS 2.0執行交易時,根據合約地址區分是不是預編譯合約,所以開發完預編譯合約後,需要在底層註冊爲預編譯合約註冊地址。2.0版本地址空間劃分如下:
用戶分配地址空間爲0x5001-0xffff,用戶需要爲新添加的預編譯合約分配一個未使用的地址,預編譯合約地址必須唯一, 不可衝突。
開發者需要修改
FISCO-BCOS/cmake/templates/UserPrecompiled.h.in文件,在registerUserPrecompiled函數中註冊HelloWorldPrecompiled合約的地址(要求v2.0.0-rc2以上版本),如下注冊HelloWorldPrecompiled合約:
#step5#
編譯源碼
參考FISCO BCOS 2.0使用手冊->獲取可執行程序->源碼編譯。
https://fisco-bcos-documentation.readthedocs.io/zh_CN/latest/docs/manual/get_executable.html
需要注意的是,實現的
HelloWorldPrecompiled.cpp
和HelloWorldPrecompiled.h
需要放置於
FISCO-BCOS/libprecompiled/extension目錄下。
HelloWorld預編譯合約調用
使用控制檯調用HelloWorld預編譯合約
在控制檯solidity/contracts創建HelloWorldPrecompiled.sol文件,文件內容是HelloWorld預編譯合約的接口聲明,如下
pragma solidity ^0.4.24;
contract HelloWorldPrecompiled{
function get() public constant returns(string);
function set(string n);
}
使用編譯出的二進制搭建節點後,部署控制檯v1.0.2以上版本,然後執行下面語句即可調用
在Solidity中調用HelloWorld預編譯合約
我們嘗試在Solidity合約中創建預編譯合約對象並調用其接口。在控制檯solidity/contracts創建HelloWorldHelper.sol文件,文件內容如下
pragma solidity ^0.4.24;
import "./HelloWorldPrecompiled.sol";
contract HelloWorldHelper {
HelloWorldPrecompiled hello;
function HelloWorldHelper() {
// 調用HelloWorld預編譯合約
hello = HelloWorldPrecompiled(0x5001);
}
function get() public constant returns(string) {
return hello.get();
}
function set(string m) {
hello.set(m);
}
}
部署HelloWorldHelper合約,然後調用HelloWorldHelper合約的接口,結果如下
到這裏,就可以恭喜你順滑地完成了HelloWorld預編譯合約的開發,其他預編譯合約的開發流程道理相通。
我們鼓勵機構成員、開發者等社區夥伴參與開源共建事業,有你在一起,會更了不起。多樣參與方式:
1 進入微信社羣,隨時隨地與圈內最活躍、最頂尖的團隊暢聊技術話題(進羣請添加小助手微信,微信ID:fiscobcosfan);
2 訂閱我們的公衆號:“FISCO BCOS開源社區”,我們爲你準備了開發資料庫、最新FISCO BCOS動態、活動、大賽等信息;
3 來Meetup與開發團隊面對面交流,FISCO BCOS正在全國舉辦巡迴Meetup,深圳、北京、上海、成都……歡迎您公衆號在菜單欄【找活動】中找到附近的Meetup,前往結識技術大咖,暢聊硬核技術;
4 參與代碼貢獻,您可以在Github提交Issue進行問題交流,歡迎向FISCO BCOS提交Pull Request,包括但不限於文檔修改、修復發現的bug、提交新的功能特性。
代碼貢獻指引:
https://github.com/FISCO-BCOS/FISCO-BCOS/blob/master/docs/CONTRIBUTING_CN.md
本文首發於公衆號【FISCO BCOS開源社區】,如轉載請註明出處,原創不易,謝謝珍惜