1. Neo核心開發(fā)者:我為N3開發(fā)的第一個智能合約|Neo專欄

        共 4288字,需瀏覽 9分鐘

         ·

        2021-09-10 20:38

        上一篇Neo專欄中

        作者為我們揭秘了引入隨機數(shù)的具體困難有哪些

        以及Neo在隨機數(shù)算法領(lǐng)域究竟有何發(fā)展目標??


        本篇Neo專欄,

        Neo核心開發(fā)者廖京輝???♂?

        帶您走近他「為N3開發(fā)的第一個智能合約」

        在此過程中遇到的困難和解決方案

        及對N3區(qū)塊鏈開發(fā)平臺的理解與想法??


        快來一起看看吧??

        前兩篇文章里介紹了為N3引入安全隨機數(shù)的事情,雖然最終版本的隨機數(shù)算法還在不斷的開發(fā)迭代中,但是現(xiàn)有的N3的區(qū)塊內(nèi)已經(jīng)引入了一個由議長生成的隨機數(shù),可以用來測試相關(guān)合約。因此,我開發(fā)了一個剪刀石頭布的游戲。一是用來學習N3的合約開發(fā),二來是測試一下運行時隨機數(shù)。合約源碼地??https://github.com/Liaojinghui/RPC

        這個剪刀石頭布的游戲很簡單,設(shè)計如下:

        剪刀石頭布

        用戶轉(zhuǎn)GAS給RPC合約,同時傳入一個手勢(以0,1,2 來代表)。


        RPC合約在收到GAS之后就會觸發(fā)OnNEP17Payment 方法并將手勢傳進來。


        在OnNEP17Payment 中,RPC會調(diào)用運行時的隨機數(shù)算法來生成一個隨機數(shù),并將其值約束在0、1、2的范圍內(nèi),之后與用戶手勢進行比較。


        如果用戶獲勝,則合約給用戶反向轉(zhuǎn)賬,如果合約獲勝,合約拿走用戶的轉(zhuǎn)賬,如果平手,則交易FAULT。

        用戶每輪的投注需要大于1個GAS,同時需要小于之前合約從用戶那里贏走的錢。也就是說用戶不能期待一把回本,否則合約幾乎永遠都是輸家。

        在別的平臺如果開發(fā)這樣的合約,在沒有可靠的運行時隨機數(shù)的前提下,用戶需要先將手勢的摘要信息發(fā)送到合約里,然后等待下一個區(qū)塊取某種線上數(shù)據(jù)作為隨機數(shù),再等待一個區(qū)塊才能將用戶手勢的明文發(fā)送到合約里。為了完成一個簡單的小游戲,這樣的操作不可謂不繁瑣復雜。而在N3里,只需要一筆交易,所有的過程都可以直接在一個區(qū)塊內(nèi)完成。

        工具方法

        為了方便合約開發(fā),我把常用的權(quán)限控制整理成了OwnerOnly()方法,將條件控制邏輯整理成了Require()方法。

        OwnerOnly()方法是為了對合約接口的調(diào)用權(quán)限進行約束。我們把只允許管理員進行調(diào)用的接口稱為管理員接口,標記為***I_owner***。通常,我們需要對合約調(diào)用的交易的簽名進行驗證,只有來自合約擁有者,也就是在合約里標記的Owner賬戶的簽名才能合法調(diào)用I_owner接口。這樣的驗證邏輯通常是一致的代碼邏輯,因此,為了方便合約開發(fā),對其進行代碼進行歸納整理為:

        private static void OwnerOnly() { if (!Verify()) throw new Exception("No authorization."); }

        Require() 方法則是因為各種合約方法內(nèi)部都需要對條件進行非常繁瑣的驗證,為了合約安全,我們通常希望合約的驗證越完善越好。但是驗證的過程一般需要引入if語句,而為了邏輯清晰,我們又不能將所有的條件整理成一種。當大量的if語句堆疊到一起的時候,代碼就會變得臃腫。

        因此,為了讓合約在進行邏輯和條件檢查的時候能更加“優(yōu)雅”,我定義了private static void Require(bool isTrue, string msg = "Invalid")(后文稱Require())。Require() 接收兩個參數(shù),第一個參數(shù)為條件或者條件語句,第二個為可選的錯誤信息。當?shù)谝粋€參數(shù)的結(jié)果不是true的時候,Require()就會拋出異常,F(xiàn)AULT這筆交易。同時用戶可以通過第二個參數(shù)來自定義異常信息。方法實現(xiàn)為:

        private static void Require(bool isTrue, string msg = "Invalid") { if (!isTrue) throw new Exception($"RPC::{msg}"); }

        此外,為了減少由方法調(diào)用而增加的額外開銷,我將這兩個方法都設(shè)置為了內(nèi)聯(lián)函數(shù)。因此兩個方法的最終實現(xiàn)版本為:

        [MethodImpl(MethodImplOptions.AggressiveInlining)]private static void Require(bool isTrue, string msg = "Invalid") { if (!isTrue) throw new Exception($"RPC::{msg}"); } 


        [MethodImpl(MethodImplOptions.AggressiveInlining)]private static void OwnerOnly() { if (!Verify()) throw new Exception("No authorization."); }

        細粒度安全要求與嚴格的安全校驗

        雖然開發(fā)這個小游戲的代碼量并不大,邏輯更是非常簡單,但是為了給以后的合約開發(fā)者積累更多的經(jīng)驗,我還是按照最高標準來去實現(xiàn)了這個合約的每一個功能。對于合約來說,最高的標準就是安全標準——這一點是毫無爭議的。我始終認為合約的開發(fā)應該在最小的單位——方法里,就對安全要求進行定義并且驗證。并且每個單位應該有自己完全獨立的安全邏輯,比如參數(shù)的驗證一定要在方法內(nèi)部獨立完成,不能對上層的calling方法傳入的參數(shù)進行任何形式的假設(shè),否則肯定會增加的重復驗證的開銷。但是,對于合約來說,安全大過天,為了保證安全,合約有時不得不“臃腫”。搭乘過飛機的小伙伴肯定都知道坐飛機有非常繁瑣的安檢流程,尤其是跨國轉(zhuǎn)機,幾乎每次中轉(zhuǎn)都要重新安檢。這就是為了排除各種風險。而合約的開發(fā)就需要這樣對安全認真嚴謹?shù)膽B(tài)度,在每一個最小節(jié)點里定義安全行為,引入安全檢查。

        在該合約里,我是在每個方法的注釋里加入Security Requirements 內(nèi)容來對方法的安全進行文字層面的約束,主要就是定義一下參數(shù)的范圍,方法權(quán)限等等。然后在開發(fā)的時候逐一對安全要求進行確認。再在合約部署在測試網(wǎng)之后對每一個安全要求進行測試網(wǎng)上實際交易的檢驗,當檢驗通過時再進行最終的確認標記。也就是在功能測試之外,獨立進行安全測試。舉個例子,合約里的OnNEP17Payment回調(diào)方法:

        OnNEP17Payment回調(diào)方法

        方法的注釋里有四條安全約束,這四條安全約束都在代碼中進行了體現(xiàn),具體到代碼所在的行:

        // <2> -- confirmed by jinghuiRequire(!Paused());


         // <3> -- yet to confirmRequire(Runtime.CallingScriptHash == GAS.Hash, "Script format error.");//Require(Runtime.EntryScriptHash == GAS.Hash, "Runtime.EntryScriptHash == ((Transaction)Runtime.ScriptContainer).Hash");if (((Transaction)Runtime.ScriptContainer).Script.Length > 96)    throw new Exception("RPC::Transaction script length error. No wrapper contract or extra script allowed.");// should not be called from a contract// --confirmedRequire(ContractManagement.GetContract(from) is null, "ContractManagement.GetContract(from) is null");


         // <1> -- confirmed by jinghuiRequire(move == 0 || move == 1 || move == 2, "Invalid move."); 


         // <0> -- confirmed by jinghuiRequire(amount >= 1_0000_0000, "Please at least bet 1 GAS.");

        雖然這樣的方式不能排除合約存在漏洞的可能,但是卻可以強制合約開發(fā)者對合約安全進行思考并予以約束,進而為合約提供最低限度的安全保障。

        最后,特別感謝NGD的陳志同同學和鴨脖小朋友提供的大量幫助和指點。這個合約部署在N3的測試網(wǎng)上??https://neo3.testnet.neotube.io/contract/0x9c01a8640dff7c086dca99758d71645f57164d7c。感興趣的朋友可以去試試。不過調(diào)用合約最好不要用Neo-cli,這個里面的send命令有點問題,必須傳from字段才能傳data,而且data還只能是string類型。建議大家用別的工具來進行調(diào)用。

        合約代碼開源且完全授權(quán),任何同學都可以對其進行任何形式的更改,進行任何方式的使用。希望能夠幫助到想要進行N3合約開發(fā)的同學。

        - 推薦閱讀 -

        All in One · All in Neo

        Neo是一個由社區(qū)驅(qū)動的開源平臺。利用區(qū)塊鏈技術(shù)與數(shù)字身份,開發(fā)者可以通過智能合約實現(xiàn)資產(chǎn)管理數(shù)字化與自動化。Neo致力于通過分布式網(wǎng)絡(luò)建設(shè)下一代互聯(lián)網(wǎng)基礎(chǔ)設(shè)施,為區(qū)塊鏈技術(shù)大規(guī)模落地奠定基礎(chǔ),以實現(xiàn)智能經(jīng)濟的宏大愿景。

        自2016年上線至今,Neo主網(wǎng)已穩(wěn)定運行超過四年。全新版本Neo N3已于2021年發(fā)布,能夠提供更高吞吐量、更強穩(wěn)定性與安全性,帶來優(yōu)化的智能合約系統(tǒng)及功能豐富的基礎(chǔ)設(shè)施集合,賦能開發(fā)者并加速企業(yè)級區(qū)塊鏈創(chuàng)新。

        瀏覽 53
        點贊
        評論
        收藏
        分享

        手機掃一掃分享

        分享
        舉報
        評論
        圖片
        表情
        推薦
        點贊
        評論
        收藏
        分享

        手機掃一掃分享

        分享
        舉報
          
          

            1. 免费一级A片毛一女多男 | 超碰在线人人 | 精品人妇一区二区三区 | 青青草无码在线 | 欧美久久网 |