摘要: BSN智能合約開發培訓-FISCO BCOS(二)
作者:微眾銀行
作為BSN首個引入的國產聯盟鏈底層框架,FISCO BCOS將在4月份完成BSN適配並開啟公測,屆時,開發者可以免費部署一個具有三個記帳節點的應用。
目前,FISCO BCOS平台支持Solidity和Precompiled兩種類型的智能合約,同時,提供交互式控制台工具(Console),方便開發者與鏈進行交互,部署、調用智能合約。
為了讓大家快速上手智能合約,FISCO BCOS推出了智能合約系列教程,本文為系列教程精編,更多實操內容敬請關注FISCO BCOS開源社區公眾號。
1.智能合約簡介
眾所周知,智能合約的出現,使區塊鏈不僅能處理簡單的轉帳功能,還能實現複雜的業務邏輯,極大地推動了區塊鏈技術發展,加速應用落地。
目前,在眾多區塊鏈平台中,大多數集成了以太坊虛擬機,並使用Solidity作為智能合約開發語言。作為一門面向合約的高級程式語言,Solidity借鑑了C++、Python和JavaScript等語言的設計,使用靜態類型,不僅支持基礎/複雜數據類型操作、邏輯操作,同時提供高級語言的相關特性,比如繼承、重載、庫和用戶自定義類型等。
作為最大最活躍的國產開源聯盟鏈社區,FISCO BOCS無縫支持Solidity合約,並提供從開發、編譯、部署到調用的全鏈路工具和完整解決方案,使智能合約和區塊鏈應用開發變得簡單。
除此之外,基於大量探索和實踐,FISCO BCOS不僅支持Solidity合約,還支持Precompiled合約,並在用戶層提供CRUD合約接口。面向庫表開發的CRUD合約不僅更符合用戶開發習慣,進一步降低合約開發難度,提升性能,使區塊鏈應用滿足高並發場景的訴求。
2.智能合約分類
FISCO BCOS平台支持兩種類型的智能合約:Solidity合約和Precompiled合約。
2.1 Solidity合約
Solidity合約運行在EVM上,EVM為以太坊虛擬機,採用哈佛架構,指令、數據和棧完全分離。
在智能合約運行期間,首先創建一個沙盒環境(EVM實例),沙盒環境與外部環境完全隔離,無法訪問網絡、文件系統其它進程,智能合約在EVM內只允許進行有限的操作。交易執行時,EVM通過獲取合約的opcode,將opcode轉化為對應的EVM指令,並按照指令進行執行。
從應用落地的數量來看,Solidity合約使用最為廣泛,幾乎所有區塊鏈平台都支持,但Solidity也有很多缺點。如下:
合約在EVM中串行執行,性能較差;
跨合約調用會新建EVM,內存開銷較大;
合約變量和數據存在MPT數中,不便於合約升級;
邏輯和數據耦合,不便於存儲擴容。
2.2 Precompiled合約
Precompiled合約即預編譯合約。預編譯合約通過Precompiled引擎執行,採用C++編寫合約邏輯,合約編譯集成進FISCO BCOS底層節點。
調用合約不進EVM,可並行執行,突破EVM性能瓶頸;提供標準開發框架,只需繼承基類,實現call接口即可;適合於邏輯相對確定、追求高並發的場景;數據存在表中,與合約分離,可升級合約邏輯。
當然,預編譯合約的使用有一定的門檻。如下:
對於數據的存儲,需要創建FISCO BCOS特有的表結構;
編寫合約時需繼承Precompiled類,然後實現Call接口函數;
完成合約開發後,需在底層為預編譯合約註冊地址;
編寫完成合約後,需要重新編譯FISCO BCOS源碼。
為了屏蔽預編譯合約在開發和使用中的門檻,FISCO BCOS基於預編譯合約和分布式存儲設計了CRUD合約接口。用戶在編寫Solidity合約時,只需要引入抽象合約接口文件Table.sol,便可使用CRUD功能,用戶不需要關心底層的具體實現。
3.智能合約開發
本節將基於全球英文認證考試成績管理作為場景,基於FISCO BCOS平台對智能合約進行開發。全球認證考試包括GRE、TOEFL、IELTS等。為了簡化合約邏輯,所有成績統一由考試管理中心發布和管理,學生可以根據自己的帳號(地址)查詢自己的考試成績。
3.1 Solidity合約開發
在 Solidity 中,合約類似於面向對象程式語言中的類。Solidity合約有自身的代碼結構,由幾個部分組成,如下所示。
狀態變量:狀態變量是永久存儲在合約中的值
構造函數:用於部署並初始化合約
事件:事件是能方便地調用以太坊虛擬機日誌功能的接口
修飾器:函數修飾器可以用來改變函數的行為,比如自動檢查,類似Spring的AOP
函數:函數是合約中代碼的可執行單元
創建合約
首先創建一個名為StudentScoreBySol的合約,用於管理學生的成績。如下代碼所示,開頭需要引入合約版本。
定義狀態變量
狀態變量用於存儲和管理學生的考試成績。
在當前場景中定義兩個變量,其中_owner為合約的創建者,即考試管理中心;_scores用於存儲學生成績,為一個嵌套mapping類型,第一個mapping的key(address)為學生的帳戶(私鑰對應的地址),value也為一個mapping類型,對應為每一科的成績,在第二個mapping中key(bytes32)為科目名稱,如GRE、TOEFL等,value(uint8)為成績。如下所示。
定義事件
定義一個事件setScoreEvent,用於跟蹤對學生成績的新增/修改操作,可以在業務層面對事件進行監聽。事件的定義是可選的,如果沒有定義也沒關係,在業務層面可以根據方法的返回值去判斷交易是否成功,但無法做到更精細的問題定位。
定義修飾器
智能合約中的修飾器(Modifier)類似面向對象編程中的AOP,滿足條件才會執行後續操作。如下所示,修飾器要求必須是合約的Owner才能進行後續操作,其中Owner為考試管理中心。
定義構造方法
構造方法用於實例化合約,在當前構造方法中,指定Owner為合約的部署者。
編寫函數
當前合約中,定義兩個函數,setScore函數用於新增/修改/刪除(score置為0)學生成績,並使用了onlyOwner修飾器,只有Owner(考試管理中心)才能操作,並通過setScoreEvent事件跟蹤每次操作內容。getScore方法用於成績查詢,其中view修飾符表示不會修改狀態變量。
Solidity合約完整代碼如下所示。基於Solidity語言的合約開發,看似簡單,但需要對Solidity程式語言深入學習,才能編寫出高可用的合約,具備一定學習成本。
通過FISCO BCOS開源社區推出的智能合約專題,開發者可了解更多運用Solidity編寫智能合約的方法與技巧,關注「FISCO BCOS開源社區」公眾號可獲取專題。
更多細節可參考Solidity官方文檔:
3.2 CRUD合約開發
CRUD合約是CRUD功能的核心,用戶可以直接在合約中引用CRUD接口文件Table.sol,並在Solidity合約中調用CRUD接口。CRUD合約的開發完全遵從資料庫的操作習慣,更容易理解和上手。
CRUD合約更多開發細節可參考:
創建合約
CRUD創建的合約和Solidity創建的沒有太大區別,唯一區別在於需要引入CRUD接口文件Table.sol,如下所示。修飾器和構造方法的作用與Solidity合約相同。
事件定義
在Solidity合約中可以通過setScore完成成績的新增/修改/刪除,但在CRUD合約中,需要藉助CRUD接口文件的不同接口,通過不同函數實現,所以需要針對不同的函數定義不同時間,如下所示。
createEvent:用於跟蹤創建表操作;
insertEvent:用於跟蹤插入成績操作;
updateEvent:用於跟蹤更新成績操作;
removeEvent:用於跟蹤刪除成績操作。
創建表函數
CRUD合約實現業務功能,首先需要像資料庫操作一樣,創建一張表,用於存放數據。
FISCO BCOS底層提供了TableFactory合約,該合約的地址固定為0x1001,可以通過TableFactory對象提供的方法對表進行創建(createTable)和打開(openTable),如下所示。
createTable接口返回值為0時,說明創建成功。需要注意的是,為了讓創建的表可被多個合約共享訪問,表名必須是群組內全局可見且唯一的,無法在同一條鏈上的同一個群組中,創建多個名稱相同的表。
新增成績函數
對表進行操作時,首先需要通過TableFactory打開對應的表,獲得表對象,然後通過表對象的insert方法進行數據插入。在插入數據前,首先需要構建一個Entry對象實例,代碼如下所示。
需要注意的是,Table接口合約的insert、remove、update和select函數返回值類似資料庫,均為受影響的記錄行數,且接口中key的類型為string。
而在當前場景中,學生的studentId為address類型,所以需要在函數內部將address類型轉化為string類型,代碼如下。
更新成績函數
更新成績操作步驟包括:通過TableFactory對象打開表,然後,像資料庫一樣構造篩選條件。
在CRUD合約接口中,提供了Condition對象,該對象提供了諸如大於、等於、小於等一系列條件方法。構造完成條件對象後,可以調用table對象的udpdate接口,完成更新操作,代碼如下。
刪除成績操作
刪除操作和更新操作類似,需要調用table.remove接口完成,不再贅述,代碼如下。
查詢成績操作
查詢成績操作很簡單,需要調用table.select接口完成,代碼如下。
至此基於CRUD的合約開發完成。
從當前場景的代碼行數來看,CRUD合約比較複雜,Solidity合約相對簡單。但這只是一個幻覺,實際情況可能並非如此。而且CRUD合約的開發更符合開發者習慣,沒有多餘的學習成本,更容易理解和上手。
4.合約部署及調用
開發完智能合約後,需要對合約進行編譯和部署,然後才能調用。FISCO BCOS平台提供了交互式控制台工具(Console),可以非常方便地與鏈進行交互。下面將以上述智能合約為例,採用控制台工具進行部署和調用。
控制台安裝及使用可參考:
4.1準備工作
在對合約進行部署和調用前需要做三件事情。首先複製編寫好的合約到控制台目錄console/contracts/solidity下。如下圖所示。
其次對合約進行編譯,可以採用控制台目錄下的sol2java.sh腳本對合約進行編譯,編譯結束後會在console/contracts/sdk目錄下生成如下文件夾,如下圖所示。
其中abi中存放合約的ABI,bin存放合約的二級制編碼文件(BINARY),JAVA文件夾中為對應的JAVA合約,便於通過SDK和鏈進行交互。
需要注意的是對CRUD合約編譯時。需要將CRUD接口合約Table.sol一併放入console/contracts/solidity目錄下,不然會報錯。
最後,對合約進行部署時,依賴外部帳戶,所以首先需要生成帳戶。在控制台中提供了帳戶生成工具get_account.sh,運行該腳本會在console/accounts目錄下生成帳戶。
我們利用帳戶生成工具生成兩個帳戶。一個為考試管理中心的帳戶,用於部署和新增/修改/刪除學生成績;一個為學生帳戶,用於查看考試成績。如下所示。
4.2 Solidity合約部署和調用
首先採用考試管理中心帳戶啟動控制台,如下圖所示,即表示控制台啟動成功。
然後通過deploy命令對合約進行部署,合約部署成功之後會返回合約地址,如下圖所示。
合約部署完成之後,可以通過控制台的call命令調用合約函數。如下圖所示,新增學生的GRE成績為70(修改和刪除均可通過調用setScore方法進行操作),函數返回值為true,則表示交易成功。call命令的具體用法可以通過call -h 查看。
採用學生帳戶啟動控制台,通過getScore函數查看成績,如下圖所示,返回值為70,說明沒有問題。也可以使用學生帳戶調用setScore方法,會報錯,列印沒有權限,不再贅述。
4.3 CRUD合約部署和調用
CRUD合約的部署和調用和Solidity合約沒有區別,這裡同樣採用控制台進行。
首先採用考試管理中心帳戶啟動控制台,並對StudentScoreByCRUD合約進行部署。如下圖所示。
合約部署完成之後,調用create函數創建stu_score表,如下所示,返回結果為0,說明創建成功。
創建好表之後,就可以調用相關接口對學生成績進行操作了,首先調用insert函數新增學生成績。如下所示,返回結果為1,說明插入成績成功。
成績插入成功之後,關閉當前控制台,用學生帳戶登錄控制台,並調用select函數查詢成績,如下圖所示,返回70,說明查詢成功。剩餘函數測試可自行完成,不再贅述。
5.結束語
本文重點介紹了FISCO BCOS平台的智能合約開發。在FISCO BCOS平台中,既可以採用原生Solidity語言開發智能合約,也可以使用預編譯合約模式開發合約。Solidity合約性能差、學習成本高;預編譯合約,採用預編譯引擎,支持並行計算,性能更高,同時支持存儲擴容等。
但由於預編譯合約使用存在一定的門檻,基於此,FISCO BCOS平台開發了CRUD合約接口,用戶不需要關心底層的實現邏輯,只需要引入Table.sol合約接口文件,通過調用相關接口即可完成合約的開發。
(1、 內容來自鏈得得內容開放平台「得得號」,稿件內容僅代表作者觀點,不代表鏈得得官方立場。2、 凡「得得號」文章,原創性和內容的真實性由投稿人保證,如果稿件因抄襲、作假等行為導致的法律後果,由投稿人本人負責。3、 得得號平台發布文章,如有侵權、違規及其他不當言論內容,請廣大讀者監督,一經證實,平台會立即下線。如遇文章內容問題,請發送至郵箱:[email protected])