5?月?16?日,迅雷發(fā)布了星域云和迅雷鏈開放平臺。關(guān)于迅雷鏈開放平臺、如何基于迅雷鏈開發(fā)智能合約,以及開發(fā)合約的注意事項(xiàng),來鑫有著最直接和專業(yè)的理解。
迅雷鏈的優(yōu)勢
目前,迅雷區(qū)塊鏈已實(shí)現(xiàn)智能合約每秒百萬次調(diào)用。在迅雷鏈基礎(chǔ)上,已搭建起了區(qū)塊鏈技術(shù)應(yīng)用的開放平臺,企業(yè)和個人開發(fā)者可以輕松將業(yè)務(wù)上鏈。作為區(qū)塊鏈?3.0?的代表,迅雷鏈開放平臺相比于其他主鏈具備很多優(yōu)勢:
1.技術(shù)優(yōu)勢:百萬級并發(fā)處理能力、秒級確認(rèn)快速可靠,適合企業(yè)?ToC?應(yīng)用的大規(guī)模使用;
2.成本優(yōu)勢:成功接入的應(yīng)用首年?gas?成本將全部由迅雷網(wǎng)心承擔(dān),從根本上解決開發(fā)者的成本之憂;
3.流量優(yōu)勢:共享?4?億?+?用戶基礎(chǔ),共享鏈克生態(tài)的百萬量級活躍人群,塑造標(biāo)桿產(chǎn)品對接迅雷核心推廣資源;
4.投融資優(yōu)勢:聯(lián)手知名投資機(jī)構(gòu),投資孵化。
迅雷鏈開放平臺運(yùn)行流程和接入
為了方便開發(fā)者調(diào)試,迅雷鏈提供沙盒環(huán)境,開發(fā)者在完成本地測試后,先在沙盒環(huán)境測試,在沙盒環(huán)境開發(fā)者可以申請給測試賬號充值,調(diào)用接口部署合約,并執(zhí)行合約進(jìn)行邏輯測試。測試完成后使用沙盒環(huán)境中的合約地址到迅雷鏈開放平臺提交發(fā)布申請。開發(fā)者在開放平臺提交的合約代碼必須和測試環(huán)境一致。
迅雷鏈官方審核開發(fā)者應(yīng)用合規(guī)后,反饋開發(fā)者審核通過,開發(fā)者手動執(zhí)行發(fā)布到鏈上,將區(qū)塊鏈應(yīng)用邏輯里使用的合約地址替換為合約在線上區(qū)塊鏈發(fā)布后的地址。
關(guān)于合約的開發(fā)有哪些注意事項(xiàng)
迅雷鏈底層兼容?EVM,所以推薦開發(fā)者使用S????ty?語言開發(fā)智能合約。智能合約,實(shí)際上就是存儲了代碼的區(qū)塊鏈賬戶,其他賬戶都可以通過給這個賬戶發(fā)送交易實(shí)現(xiàn)合約調(diào)用,以改變合約內(nèi)存儲的狀態(tài)變量。下面是一個簡單的商品買賣合約代碼。
上面的合約,實(shí)現(xiàn)了一個簡單的商品買賣合約,賣家部署合約并放入雙倍商品價格的保證金,買家通過向合約發(fā)送交易調(diào)用?confirmPurchase?方法,并轉(zhuǎn)入雙倍商品價格的鏈克,來鎖定交易,買賣雙方在交易確認(rèn)后,買家再次通過向合約發(fā)送交易調(diào)用?confirmReceived?方法,確認(rèn)交易狀態(tài),合約向買家轉(zhuǎn)入一倍商品價格的鏈克,向賣家轉(zhuǎn)入剩余的全部鏈克,交易結(jié)束。
合約中限定了狀態(tài)、調(diào)用者等?modifier,保證交易流程的正確。合約的狀態(tài)變量記錄了買賣雙方的賬戶、商品的價格、交易的狀態(tài)等信息,通過向合約發(fā)送交易調(diào)用合約內(nèi)方法,來改變合約內(nèi)部的狀態(tài)變量值,最后這些交易在區(qū)塊鏈同步出去,實(shí)現(xiàn)了合約代表的交易需求的去中心化。
合約通過?Solidity?語言編寫,是當(dāng)前的合約編寫最流行的語言之一。這門語言受?C++,Python?和Javascript?語言的影響,設(shè)計的目的是能在以太坊虛擬機(jī)(EVM)上運(yùn)行。Solidity?是靜態(tài)類型語言,支持繼承、庫和復(fù)雜的用戶定義類型等特性。詳細(xì)?API?可參考
http://solidity.readthedocs.io/en/develop/index.html
通過truffle的智能合約的開發(fā)流程
truffle?是一套?Solidity?開發(fā)框架,集成了本地區(qū)塊鏈環(huán)境,可快速編譯、部署、調(diào)試合約代碼。詳情可參考?http://truffleframework.com/docs/
1.首先安裝?truffle,依賴?nodejs,使用?npm -g truffle?命令安裝。新建合約項(xiàng)目文件目錄,使用truffle init命令初始化合約工程。
2.新建合約文件?contract/SimpleStorage.sol
3.添加?migrate?代碼,新建文件?migrations/2_deploy_contract.js。后面會介紹這段代碼的作用。
4.執(zhí)行?truffle compile?編譯合約,編譯后的合約在?build?文件夾下。每個合約有一個對應(yīng)的?json?文件,內(nèi)含部署所需的?bytecode,abiCode
5.執(zhí)行?truffle migrate?移植部署合約
6.執(zhí)行?truffle develop,開啟本地區(qū)塊鏈環(huán)境,對已部署的合約進(jìn)行測試
合約是通過?EVM(以太坊虛擬機(jī))?來運(yùn)行的,最終部署在區(qū)塊鏈上,同步到區(qū)塊鏈的交易中,生成合約賬戶。
truffle develop?命令可以生成一個本地區(qū)塊鏈,并生成?10?個區(qū)塊鏈賬戶,每個賬戶有?100?的余額。migrate?是?truffle?命令,可以通過執(zhí)行?migrations?下的腳本,將合約部署到指定的區(qū)塊鏈上。truffle.js可以配置部署和連接的區(qū)塊鏈。上面第三步腳本實(shí)現(xiàn)的功能就是將?SimpleStorage?合約部署到區(qū)塊鏈上,依賴的是?truffle?封裝的功能。
truffle develop?生成的控制臺環(huán)境,是本地區(qū)塊鏈環(huán)境,內(nèi)置?web3,并將?migration?里部署的合約實(shí)例化到上下文中,可以直接調(diào)用。
以太坊remix實(shí)現(xiàn)合約的部署和調(diào)用
除了使用?truffle?框架開發(fā)智能合約,還可以通過以太坊提供的?[remix](http://remix.ethereum.org/)快速實(shí)現(xiàn)合約的部署和調(diào)用。(由于某些網(wǎng)絡(luò)原因,可能出現(xiàn)頁面部分?js?不能完全加載)
remix?提供了合約的編譯運(yùn)行環(huán)境,并可以再控制臺看到合約每條交易的詳細(xì)信息,如輸入輸出參數(shù),簽名后的方法?data,交易?hash?等信息。支持調(diào)試。
1.使用?compile detail,可以看到合約編譯詳情。包括?bytecode,abi?和使用?web3.js?快速部署的方法。
2.使用run來create合約,控制臺可查看創(chuàng)建合約的交易。
remix功能豐富,提供有本地區(qū)塊鏈環(huán)境和線上etherum連接選擇,支持單步調(diào)試,并可以看到詳細(xì)的堆棧內(nèi)容和assembly code。簡單的合約直接通過remix部署和測試十分便捷。但是如果有依賴合約需要導(dǎo)入等方式實(shí)現(xiàn)的,不能很好的支持。也可以支持通過websocket連接本地項(xiàng)目。
智能合約有哪些安全注意事項(xiàng)?
由于智能合約是通過發(fā)送交易部署在區(qū)塊鏈上的去中心化應(yīng)用,這種性質(zhì)就決定了合約一旦部署和調(diào)用操作成功,就不能回退。而合約中所保存狀態(tài)和轉(zhuǎn)移的資產(chǎn),都具有重要的價值和意義,所以如果合約代碼出現(xiàn)?bug,往往都會產(chǎn)生十分嚴(yán)重的后果。下面介紹一些合約開發(fā)過程中需要注意到的部分安全事項(xiàng)。
1.設(shè)置函數(shù)可視性和合理的?modifier?權(quán)限
有對外交互的函數(shù)通常設(shè)置為?public?或?external,內(nèi)部函數(shù)設(shè)置為?private?或?internal。另外,一般使用相應(yīng)的?modifier?限制函數(shù)操作的角色權(quán)限。這些都可以有效減少安全問題。
2. send?調(diào)用可能失敗,需要檢測?send?結(jié)果然后再確定是否進(jìn)行下面的狀態(tài)改變。
通常的操作邏輯可能會使,向某個賬戶發(fā)送一筆交易,然后改變合約內(nèi)的某些數(shù)據(jù)狀態(tài)。但是如果未對?send?函數(shù)調(diào)用的結(jié)果做檢測,可能會出現(xiàn)?send?失敗,但是后續(xù)狀態(tài)依然被改變的結(jié)果,導(dǎo)致狀態(tài)不一致。
下面例子展示(但并不是一個安全的合約例子):
如果msg.sender.send失敗,但合約并未拋出異常繼續(xù)執(zhí)行,將導(dǎo)致?balances[msg.sender]?為?0,但msg.sender?并沒有轉(zhuǎn)入對應(yīng)的?balance。所以需要對?send?的結(jié)果檢測,并使用?throw?異常的方法,回滾已改變的狀態(tài)值。
3.循環(huán)可能導(dǎo)致?gas?被消耗完而引起合約執(zhí)行失敗
循環(huán)變量可能依賴外部輸入,如果循環(huán)的次數(shù)過多,將會導(dǎo)致?gas?消耗遞增,直至超過?gasLimit,從而使得合約執(zhí)行失敗,回滾狀態(tài)值,但是對應(yīng)的?gas?卻已經(jīng)消耗不能退回。
4.調(diào)用堆棧深度限制
EVM?調(diào)用堆棧限制最深?1024?層,從資源交易占用角度看這是必須的。同時也意味著,如果嵌套調(diào)用的數(shù)量達(dá)到?1024,合約執(zhí)行將會失敗。攻擊者可以遞歸調(diào)用一個合約?1023?次,然后再調(diào)用合約函數(shù),造成失敗一些?send?之類的失敗,如上述第一條。
5.溢出漏洞
溢出,就是一個數(shù)字增加到它的最大值以上。Solidity?可以處理多達(dá)?256?位的數(shù)字(高達(dá)?2的256次方-1),所以遞增?1?會得?0。最佳實(shí)踐是通過?zeppelin-solidity?提供的?safeMath?來處理數(shù)值計算。
上面是?openzeppelin?實(shí)現(xiàn)的?safeMath?的乘法運(yùn)算。如果乘法運(yùn)算溢出,則?c/a?的結(jié)果不會等于b。以此保證運(yùn)算的正確性。
6.可重入攻擊?(DAO)
在使用?call?來發(fā)送?value?時,檢測外部條件順序的不合理或調(diào)用者設(shè)置?call?或?send?對應(yīng)?fallback惡意轉(zhuǎn)賬,都可能導(dǎo)致狀態(tài)不一致和金額的損失。
避免?DAO?攻擊最佳實(shí)踐就是使用?transfer?來實(shí)現(xiàn)轉(zhuǎn)賬,并使用?require?檢測結(jié)果。
在合約?A?執(zhí)行?to.call.value?時,如果?to?地址是合約地址,將會觸發(fā)?to?的?fallback?函數(shù)來接收value。如果在?to?合約的?fallback?里遞歸調(diào)用了?A?合約的?withdraw?時,就是?DAO?攻擊。
7. selfdestruct?的執(zhí)行參數(shù)如果是合約地址,將不會執(zhí)行合約的?fallback
如果一個合約?A?的?selfdestrcut(sender)?的?sender?是一個合約地址?B,B?合約將不會使用?fallback?來接收?A?的?selfdestruct?帶來的轉(zhuǎn)賬。由此可能產(chǎn)生繞過合約邏輯的風(fēng)險。
8.短地址攻擊
短地址攻擊是針對基于?ERC20?類型的?token transfer?時的問題。在調(diào)用?transfer (address addr, uint amount)?時,實(shí)際發(fā)送交易的是?abi?編碼后的16進(jìn)制代碼,其中每個參數(shù)長度是固定的,如果長度不足會自動補(bǔ)?0。漏洞即源于此,如果?addr?的最后是以?0?結(jié)尾的,而攻擊者少輸入最后的?0,amount?編碼高位補(bǔ)?0,導(dǎo)致?amount?編譯值比實(shí)際輸入值大。從而實(shí)現(xiàn)轉(zhuǎn)移超出實(shí)際應(yīng)該?transfer?的數(shù)量的?token。實(shí)踐中,需要在?transfer?方法檢查長度來限制此類問題。
合約的安全實(shí)踐需要持續(xù)的關(guān)注和更新,并做好合約的審計和升級,必要情況下可設(shè)置一些緊急停止或轉(zhuǎn)移合約功能的方法,以備不時之需。