摘要:所以,在設(shè)計時,要了解區(qū)塊鏈相關(guān)知識,這些是出于安全考慮。通過一個智能合約能夠管理所有模塊,這個是不變的,相當(dāng)于一個不變的點,用來鏈接各個模塊,保證穩(wěn)定,相當(dāng)于在區(qū)塊鏈上一直會有一個穩(wěn)定的地址長期進行服務(wù)。
智能合約的設(shè)計和傳統(tǒng)的應(yīng)用設(shè)計有點不同。傳統(tǒng)應(yīng)用一般為了快速迭代是在產(chǎn)品之后考慮安全,但是 DApp 則需要在產(chǎn)品出來之前就考慮安全問題,它將會關(guān)系到賬戶資產(chǎn)、用戶數(shù)據(jù)等問題,而且對 DApp 來講,升級是個比較麻煩的事情,因此在智能合約設(shè)計時,結(jié)構(gòu)是非常重要的部分。本文將為大家闡釋如何來設(shè)計這個結(jié)構(gòu)。目前 DApp 面臨問題
首先,是關(guān)于 DApp 和 App。事物發(fā)展將會遵循技術(shù)為王、產(chǎn)品為王、最后到運營為王三個發(fā)展階段?,F(xiàn)在,區(qū)塊鏈和 DApp 正處于技術(shù)為王階段。整個市場上的 DApp,在性能和用戶友好性上,都不如 App。DApp 的優(yōu)勢顯而易見:去中心化,它是依附區(qū)塊鏈的應(yīng)用。但是我們認為很多 DApp 的短板,其實是因為底層區(qū)塊鏈的限制。
其次,是關(guān)于安全。現(xiàn)在 DApp 爆發(fā)的安全漏洞很多,主要原因是區(qū)塊鏈仍處于發(fā)展早期。開發(fā) DApp 的基礎(chǔ)設(shè)施和相關(guān)工具都很不成熟,但是黑客是很成熟的,在互聯(lián)網(wǎng)上久經(jīng)沙場,對 DApp 世界影響很大。所以,在設(shè)計 DApp 時,要了解區(qū)塊鏈相關(guān)知識,這些是出于安全考慮。
最后,是關(guān)于成本。在以太坊中就是 Gas,部署智能合約將消耗一定 Gas。這是因為 DApp 很消耗 Gas,特別是部署一個大型 DApp(包括后面的維護、升級)。Gas 是什么?是資金。那么,有沒有一種結(jié)構(gòu)能夠暫時忽略 Gas。這就分成兩種方向,一是思考節(jié)約 gas 到細微處,用一種怪異不太舒服的寫法來節(jié)約 Gas;第二種是走向宏觀,整個結(jié)構(gòu)是清晰明了的,但是可能會存在浪費 Gas 的行為。
解決辦法第一,是優(yōu)美結(jié)構(gòu)。一個優(yōu)美的結(jié)構(gòu)會帶來 Gas 的節(jié)約,這是我一直相信的。那整個結(jié)構(gòu)是包含哪些方面呢?最宏觀的說指分層。這里分層和一般的 app 分層是相通的,比如應(yīng)用層、邏輯層、數(shù)據(jù)層。
第二,是友好。因為現(xiàn)在一個大型的 DApp,如果有很好的模塊化,可能會有十幾個智能合約,他們中間可能還有依賴。那就要求你在部署時,需要格外小心。(友好就是說能夠一鍵部署。 )
第三,是支持升級。這個是在 App 上很常見的,因為我們在開發(fā)一個 App 時,必須要進行版本迭代,新功能的增加,Bug fix...這個就是升級。而我們知道 DApp 在區(qū)塊鏈上,由于區(qū)塊鏈的不可篡改性,部署的合約就在那里了。這里面涉及升級的問題就比較復(fù)雜。簡而言之,我們這個結(jié)構(gòu)采取了支持升級的方式,升級比較簡單的部分是算法部分,算法部分是純粹的邏輯,替換可以做到無感知,只需要修改邏輯合約的地址即可。比較麻煩的是對數(shù)據(jù)結(jié)構(gòu)的升級,數(shù)據(jù)結(jié)構(gòu)涉及到實際數(shù)據(jù),如果輕易改動就要兼容以前的數(shù)據(jù)(這種需求很常見)。數(shù)據(jù)遷移是一個比較麻煩的事情,在設(shè)計數(shù)據(jù)結(jié)構(gòu)之初盡量確定數(shù)據(jù)結(jié)構(gòu),避免頻繁的變動。數(shù)據(jù)結(jié)構(gòu)確定之后,包括 CURD 以及一些 Check 的接口其實也可以確定。這些可以作為一個最小的數(shù)據(jù)合約單元。
第四,是訪問控制。要對整個結(jié)構(gòu)中的數(shù)據(jù)流轉(zhuǎn)進行控制,這是出于安全性的考慮。
第五,是模塊化。一方面,是出于安全考慮,所有東西在一個合約里會增加合約的復(fù)雜性,會對安全造成隱患。畢竟復(fù)雜是安全的天敵,越簡單越安全,這是軟件開發(fā)中的常識。所以我們要保證合約的簡潔,一眼看過去就知道這個合約是干什么。另一方面,是保證函數(shù)的簡單。一樣的道理,函數(shù)簡單意味著組成的合約也是簡單的。
整個分層就是應(yīng)用層、邏輯層和數(shù)據(jù)層,這個結(jié)構(gòu)里面的三層,整個 DApp 是偏向后端的,這里三層是智能合約里面的三層。
結(jié)構(gòu)設(shè)計根據(jù)之前 hackathon 上做的項目,叫做 summerWar(區(qū)塊鏈沙盒游戲),這個項目里的結(jié)構(gòu)基本上遵循這種設(shè)計。
summer War GitHub 倉庫地址:
https://github.com/CryptapeHa...
an Arch : layer
這個是我們整個游戲的結(jié)構(gòu)圖,最左邊的是 off-chain,是關(guān)于鏈下用戶操作。register 是應(yīng)用層、Permission 是訪問控制、后面是邏輯層和數(shù)據(jù)層,后面是數(shù)據(jù)流轉(zhuǎn)和調(diào)用的圖 。
分層:register 是應(yīng)用層,operator 是單純邏輯 ,和數(shù)據(jù)沒有關(guān)系。后面是數(shù)據(jù)層,整個數(shù)據(jù)多帶帶和邏輯拆分。
權(quán)限剛才已經(jīng)闡述了。在整個結(jié)構(gòu)流轉(zhuǎn)中,如果 operator 是操作層的話,用戶需要先訪問操作層合約,然后由操作層訪問底層數(shù)據(jù)合約。這里限制訪問控制,一是指控制各個層之間的調(diào)用關(guān)系,比如數(shù)據(jù)類合約嚴格控制只能讓操作類合約來控制,不可能是隨便的合約就能訪問的。這里數(shù)據(jù)不僅是指數(shù)據(jù),還包括數(shù)據(jù)的簡單存取接口,相當(dāng)于一個數(shù)據(jù)庫的概念,包含存儲和查詢。 二是可以控制具體用戶的操作。
An arch: auth
auth 模塊實現(xiàn)了上述說的兩種訪問控制,在結(jié)構(gòu)上是散布在各個層級之間及整個結(jié)構(gòu)與外部用戶之間。
對用戶進行訪問控制是指:假設(shè)有 id,就會先檢查哪些地址可以操作,這里 id 是指整個 DApp 的身份,和區(qū)塊鏈身份不影響,因為區(qū)塊鏈由于去中心化原因是沒有身份的。但是開發(fā)的 DApp 里面可以定義一個用戶名,這個在 DApp 里是可行的,和區(qū)塊鏈沒有關(guān)系。所以這里可以對這個地址進行檢查,允許哪些地址進行操作。至于層之間的訪問控制,和用戶訪問控制類似,用戶 id 是Dapp 通行的身份,各層合約可以在 register 查詢到也可以把這些合約地址作為整個結(jié)構(gòu)中通行的身份。
具體在底層實現(xiàn)要用到兩種特性,modifier 和 函數(shù)的可見性。通過這兩種特性結(jié)合能夠達到以上效果:某個合約只能某些合約調(diào)用,某些合約只能由某些 sender 調(diào)用,這樣的控制。
modifier:
https://solidity.readthedocs....
函數(shù)的可見性:
https://solidity.readthedocs....
整個下來,代碼的組織結(jié)構(gòu)可能就如下圖所示:
App: register
整個結(jié)構(gòu)的分層,我們先從上往下我們開始講。首先是 App 層的 register。regitser 是什么角色?他是注冊中心,是一個 hub,我們期望它能夠保存所有 DApp 智能合約的相關(guān)信息(地址等),這也是一個用戶接入的入口。在這里,除 operator 后續(xù)升級和注冊外,它相當(dāng)于一個交互樞紐,可以進行部署、初始化、注冊和升級。這里能夠?qū)崿F(xiàn)在 regiter 部署之后,整個 DApp 的智能合約部分也就部署上去了。我們看一下 register 在整個結(jié)構(gòu)中的位置,是在 off-chain 與 后面操作、數(shù)據(jù)層之間。
為什么要這樣做呢?不能直接邏輯層+數(shù)據(jù)層?這樣一個中心化的東西會不會影響整個 DApp 的去中心化?
DApp 去中心化屬性是依靠后面區(qū)塊鏈實現(xiàn)的,有一個中心化的東西并不影響。它的一個優(yōu)點是簡單。通過一個智能合約能夠管理所有模塊,這個 register 是不變的,相當(dāng)于一個不變的點,用來鏈接各個模塊,保證穩(wěn)定,相當(dāng)于 DApp 在區(qū)塊鏈上一直會有一個穩(wěn)定的地址長期進行服務(wù)。如果,需要支持升級那么很多模塊都可改變。然而,如果所有東西可以改變,則會變得很難維護,所以使用 register,能夠隨時通過這個東西進行查詢和操作。還有一個優(yōu)點是能夠節(jié)約 Gas。只部署 register,然后就完成了整個 DApp 的部署。是怎么實現(xiàn)的?這里合約可以用 new 來生成其他智能合約。new 并不節(jié)約 Gas,節(jié)約的是交易相關(guān)的消耗。
Register 包含三類接口第一類接口:初始化
也就是 Solidity 里面的 constructor,合約的構(gòu)造函數(shù)。它的功能是在部署智能合約時,一次性執(zhí)行然后銷毀。所以初始化時,要存入什么?剛說 register 是一個穩(wěn)定的東西,那就能把整個結(jié)構(gòu)中,一些相對穩(wěn)定的東西放在這里初始化。比如多個用戶的操作層合約是固定的,而數(shù)據(jù)層的合約隨著用戶的注冊注銷而變化,那么就可以把操作層合約在這里初始化,隨著 register 的部署由其進行創(chuàng)建。
第二類接口:注冊
注冊是 web 調(diào)用,由外部用戶來使用的。在初始完之后,相當(dāng)于整個 DApp 上線了,在用戶使用時,可能就有些功能上的注冊操作。比如 identity,用戶需要注冊一個用戶名之類。在 register 部署之后,你能夠完成初始化的其他操作,類比我們現(xiàn)在的應(yīng)用運行之后提供的功能。
第三類接口:查詢
這類接口的使用者分為兩類:
外部用戶可以查詢一些 register 保存的各種模塊信息。
當(dāng)一個合約與其他模塊通信時,它只知道 register 地址,而更多模塊合約地址可能是通過 register 來生成的隨機地址,這個時候就可以通過 register 獲得其他模塊的地址進行之間的交互。
接著往下看是操作層的合約。這里可以做一些模塊化的東西,支持升級也是在這里做的,是因為簡單。我們通常講的支持升級包括兩個方面,一個是函數(shù)或者接口的升級。另外一個是數(shù)據(jù)的升級或者說遷移。接口的升級比較容易,在區(qū)塊鏈上數(shù)據(jù)升級比較困難,因為數(shù)據(jù)復(fù)制的操作很貴。存數(shù)據(jù)一字大概 2w gas。我們這里優(yōu)先考慮 operator 的升級。
升級有兩種方式,對應(yīng) evm 的智能合約里面進行交互兩種指令,分別有兩種升級方式
一個是 call,是消息調(diào)用的一種。調(diào)用 call 時,相當(dāng)于把主動權(quán)交給另一個合約了,這個合約在一個新的 evm 執(zhí)行之后返回一個結(jié)果給我。利用這個指令可以完成一個支持升級的方式,就是在 register 做一個類似 router 的東西,記錄每一個操作類合約的版本號,然后用戶就在訪問操作類合約的時候選擇版本進行下一次的調(diào)用,或者 register 幫你轉(zhuǎn)。
第二個是用 delegate call,相對于 call,用 delegate 時主動權(quán)并沒有交出去,整個智能合約代碼還是在我現(xiàn)在的執(zhí)行環(huán)境中執(zhí)行,這是智能合約庫使用的基本指令,很多庫的實現(xiàn)都是基于 delegate call 的方式來做的。支持升級就是用一個代理類的合約,用戶調(diào)用時幫你進行轉(zhuǎn)發(fā)。這里會有一個副作用,必須把操作的數(shù)據(jù)留在 proxy 里面,這是 delegate 的屬性。因為這個屬性就需要支持升級的合約。有兩個要求,一個是純邏輯的,沒有對狀態(tài)的改變,第二個是沒有在對數(shù)據(jù)留存在外面的要求,沒有對數(shù)據(jù)進行分開的要求,所有版本的數(shù)據(jù)在 proxy 保存 。
我更推薦前者。后者把數(shù)據(jù)都存在 proxy 里面,前者是把數(shù)據(jù)也分開了,更模塊化。我個人覺得是比較清晰的用法,這里用的也是這個。
DATA: data
關(guān)于數(shù)據(jù),這方面的升級其實比較麻煩,會有一些問題。所以我們設(shè)計數(shù)據(jù)結(jié)構(gòu)時盡量穩(wěn)定一點,變動小一些,提前預(yù)留好以后要用的字段,避免以后的升級。要升級的話也有兩種方法
一種方法是類似于插件的東西,舊的比如是 map 結(jié)構(gòu),是地址結(jié)構(gòu)體,后面要多加一個字段。那么涉及舊數(shù)據(jù)怎么辦?我可以定義一個插件類的合約,定義一個多余字段加一個指針指回原來的地方,相當(dāng)于數(shù)據(jù)分開存。,但是保存一個指針指向舊數(shù)據(jù)并且能夠找到他,能夠做一些操作,這樣的好處是不會變動數(shù)據(jù),但是會增加操作的邏輯,比較復(fù)雜,而且不是所有的數(shù)據(jù)結(jié)構(gòu)都能做的。
第二個是遷移,如果很有錢的話,可以直接拷貝過來,如果不在乎錢這是最簡單的方式。
整個結(jié)構(gòu)大概是這樣。
對于升級的一點建議:升級時 copy 數(shù)據(jù)很貴,所以我們盡量避免這樣的消耗,前期 gas 消耗也是注意的一個點。第二個是使用庫來封裝這些邏輯,就是說模塊化。盡可能邏輯都能成庫,可以找比較好的庫來用。就是說很多模塊交互需要用接口,讓合約不依賴模塊本身實現(xiàn)而依賴接口,這樣保持接口不變的前提下就能升級合約。
文章版權(quán)歸作者所有,未經(jīng)允許請勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。
轉(zhuǎn)載請注明本文地址:http://www.ezyhdfw.cn/yun/24454.html
摘要:比特幣和以太幣屬于一類區(qū)塊鏈,我們將其歸類為公共無許可的區(qū)塊鏈技術(shù)。例如,在單個企業(yè)中部署時,或由受信任的權(quán)威機構(gòu)運作,完全拜占庭容錯的共識可能被認為是不必要的,并且對性能和吞吐量造成過度的拖累。 介紹 一般而言,區(qū)塊鏈是一個不可變的交易分類賬,維護在一個分布式對等節(jié)點網(wǎng)絡(luò)中。這些節(jié)點通過應(yīng)用已經(jīng)由共識協(xié)議驗證的交易來維護分類帳的副本,該交易被分組為包括將每個塊綁定到前一個塊的散列的塊...
摘要:年,包括分層的網(wǎng)絡(luò)以及一個作為共同知識庫的區(qū)塊鏈,都已經(jīng)成熟。是一個在設(shè)計上非常不同的公有鏈協(xié)議,也是網(wǎng)絡(luò)中的基礎(chǔ)層,是整個加密經(jīng)濟網(wǎng)絡(luò)的信任引擎。主要指責(zé)是記錄和更新本地累計工作量最高的鏈,并維護鏈上數(shù)據(jù)的索引。 說到猿起,這些心里的想法能追溯到 2016 年,甚至更早。2017 年,包括分層的網(wǎng)絡(luò)以及一個作為共同知識庫(Common Knowledge Base)的區(qū)塊鏈,都已經(jīng)成...
摘要:我們目前正處于一個新興的區(qū)塊鏈開發(fā)行業(yè)中。,一種在以太坊開發(fā)人員中流行的新的簡單編程語言,因為它是用于開發(fā)以太坊智能合約的語言。它是全球至少萬開發(fā)人員使用的世界上最流行的編程語言之一。以太坊,主要是針對工程師使用進行區(qū)塊鏈以太坊開發(fā)的詳解。 我們目前正處于一個新興的區(qū)塊鏈開發(fā)行業(yè)中。區(qū)塊鏈技術(shù)處于初期階段,然而這種顛覆性技術(shù)已經(jīng)成功地風(fēng)靡全球,并且最近經(jīng)歷了一場與眾不同的繁榮。由于許多...
摘要:使用模型的代表是比特幣。每一個比特幣全節(jié)點都會維護當(dāng)前所有的集合,這個集合我們就稱為比特幣賬本的當(dāng)前狀態(tài)即當(dāng)前的賬本。每一次比特幣轉(zhuǎn)賬都是一個從集合中刪除幾個硬幣屬于付款方然后又增加幾個新硬幣屬于收款方和或付款方的過程。 showImg(https://segmentfault.com/img/bVblzCB?w=1219&h=803); 本篇文章的作者是 Jan,文章闡述了 Cell...
摘要:以后的邏輯合約可以升級現(xiàn)有的方法或者創(chuàng)造新的方法,但是不能引入新的狀態(tài)變量。使用非結(jié)構(gòu)化存儲升級非結(jié)構(gòu)化存儲模式和繼承存儲類似,但是不要求邏輯合約繼承任何和升級相關(guān)的狀態(tài)變量。 以太坊最大的優(yōu)勢就是,每一筆用來轉(zhuǎn)賬、部署合約或者和合約交互的交易(事務(wù))都被存在一個叫做區(qū)塊鏈的公共賬本上。一旦交易發(fā)生,就再也無法隱藏或者改變。這帶來一個巨大的好處,就是在以太坊中的每一個節(jié)點都可以去驗證任...
閱讀 529·2023-04-25 23:00
閱讀 3538·2021-11-22 13:54
閱讀 1962·2021-10-27 14:14
閱讀 1531·2019-08-30 13:59
閱讀 3568·2019-08-23 16:15
閱讀 2019·2019-08-23 16:06
閱讀 3402·2019-08-23 15:26
閱讀 1314·2019-08-23 13:48