第四,是訪問控制。要對整個結構中的資料流轉進行控制,這是出於安全性的考慮。
第五,是模組化。一方面,是出於安全考慮,所有東西在乙個合約裡會增加合約的複雜性,會對安全造成隱患。畢竟複雜是安全的天敵,越簡單越安全,這是軟體開發中的常識。所以我們要保證合約的簡潔,一眼看過去就知道這個合約是幹什麼。另一方面,是保證函式的簡單。一樣的道理,函式簡單意味著組成的合約也是簡單的。
根據之前 hackathon 上做的專案,叫做 summerwar(區塊鏈沙盒遊戲),這個專案裡的結構基本上遵循這種設計。
an arch : layer
這個是我們整個遊戲的結構圖,最左邊的是 off-chain,是關於鏈下使用者操作。register 是應用層、permission 是訪問控制、後面是邏輯層和資料層,後面是資料流轉和呼叫的圖 。
分層:register 是應用層,operator 是單純邏輯 ,和資料沒有關係。後面是資料層,整個資料單獨和邏輯拆分。
許可權剛才已經闡述了。在整個結構流轉中,如果 operator 是操作層的話,使用者需要先訪問操作層合約,然後由操作層訪問底層資料合約。這裡限制訪問控制,一是指控制各個層之間的呼叫關係,比如資料類合約嚴格控制只能讓操作類合約來控制,不可能是隨便的合約就能訪問的。這裡資料不僅是指資料,還包括資料的簡單訪問介面,相當於乙個資料庫的概念,包含儲存和查詢。 二是可以控制具體使用者的操作。
an arch: auth
auth 模組實現了上述說的兩種訪問控制,在結構上是散布在各個層級之間及整個結構與外部使用者之間。
具體在底層實現要用到兩種特性,modifier 和 函式的可見性。通過這兩種特性結合能夠達到以上效果:某個合約只能某些合約呼叫,某些合約只能由某些 sender 呼叫,這樣的控制。
modifier:
函式的可見性:
整個下來,**的組織結構可能就如下圖所示:
第一類介面:初始化
也就是 solidity 裡面的 constructor,合約的建構函式。它的功能是在部署智慧型合約時,一次性執行然後銷毀。所以初始化時,要存入什麼?剛說 register 是乙個穩定的東西,那就能把整個結構中,一些相對穩定的東西放在這裡初始化。比如多個使用者的操作層合約是固定的,而資料層的合約隨著使用者的註冊登出而變化,那麼就可以把操作層合約在這裡初始化,隨著 register 的部署由其進行建立。
第二類介面:註冊第三類介面:查詢
這類介面的使用者分為兩類:
外部使用者可以查詢一些 register 儲存的各種模組資訊。
當乙個合約與其他模組通訊時,它只知道 register 位址,而更多模組合約位址可能是通過 register 來生成的隨機位址,這個時候就可以通過 register 獲得其他模組的位址進行之間的互動。
接著往下看是操作層的合約。這裡可以做一些模組化的東西,支援公升級也是在這裡做的,是因為簡單。我們通常講的支援公升級包括兩個方面,乙個是函式或者介面的公升級。另外乙個是資料的公升級或者說遷移。介面的公升級比較容易,在區塊鏈上資料公升級比較困難,因為資料複製的操作很貴。存資料一字大概 2w gas。我們這裡優先考慮 operator 的公升級。
公升級有兩種方式,對應 evm 的智慧型合約裡面進行互動兩種指令,分別有兩種公升級方式
乙個是 call,是訊息呼叫的一種。呼叫 call 時,相當於把主動權交給另乙個合約了,這個合約在乙個新的 evm 執行之後返回乙個結果給我。利用這個指令可以完成乙個支援公升級的方式,就是在 register 做乙個類似 router 的東西,記錄每乙個操作類合約的版本號,然後使用者就在訪問操作類合約的時候選擇版本進行下一次的呼叫,或者 register 幫你轉。
第二個是用 delegate call,相對於 call,用 delegate 時主動權並沒有交出去,整個智慧型合約**還是在我現在的執行環境中執行,這是智慧型合約庫使用的基本指令,很多庫的實現都是基於 delegate call 的方式來做的。支援公升級就是用乙個**類的合約,使用者呼叫時幫你進行**。這裡會有乙個***,必須把操作的資料留在 proxy 裡面,這是 delegate 的屬性。因為這個屬性就需要支援公升級的合約。有兩個要求,乙個是純邏輯的,沒有對狀態的改變,第二個是沒有在對資料留存在外面的要求,沒有對資料進行分開的要求,所有版本的資料在 proxy 儲存 。
我更推薦前者。後者把資料都存在 proxy 裡面,前者是把資料也分開了,更模組化。我個人覺得是比較清晰的用法,這裡用的也是這個。
data: data
關於資料,這方面的公升級其實比較麻煩,會有一些問題。所以我們設計資料結構時盡量穩定一點,變動小一些,提前預留好以後要用的字段,避免以後的公升級。要公升級的話也有兩種方法
一種方法是類似於外掛程式的東西,舊的比如是 map 結構,是位址結構體,後面要多加乙個字段。那麼涉及舊資料怎麼辦?我可以定義乙個外掛程式類的合約,定義乙個多餘欄位加乙個指標指回原來的地方,相當於資料分開存。,但是儲存乙個指標指向舊資料並且能夠找到他,能夠做一些操作,這樣的好處是不會變動資料,但是會增加操作的邏輯,比較複雜,而且不是所有的資料結構都能做的。
第二個是遷移,如果很有錢的話,可以直接拷貝過來,如果不在乎錢這是最簡單的方式。
整個結構大概是這樣。
對於公升級的一點建議:公升級時 copy 資料很貴,所以我們盡量避免這樣的消耗,前期 gas 消耗也是注意的乙個點。第二個是使用庫來封裝這些邏輯,就是說模組化。盡可能邏輯都能成庫,可以找比較好的庫來用。就是說很多模組互動需要用介面,讓合約不依賴模組本身實現而依賴介面,這樣保持介面不變的前提下就能公升級合約。
3 2 智慧型合約的結構
合約就像乙個類 class 其中包含狀態變數 state variable 函式 function 函式修改器 function modifier 事件 event 結構 structure 和列舉 enum 合約還支援繼承,通過在編譯時備份 來實現。最後,合約還支 持多型。下面來看乙個智慧型合約的...
人生的一種智慧型
很多時候,原本生活很美的,只因我們想得太多,顧慮自然就會接踵而至。別想太多,即使是心情很糟糕,工作不順心,或是和朋友火藥味很濃地爭論,但這一切都會成為過眼雲煙,一切都會有撥開雲霧見天日的那一天。別想太多,我們的生活就不會平添累贅,人生就會暢快一些。有時候,一首老歌,一段熟悉的旋律,在適當的時候,緩緩...
豁達是一種智慧型
張立濤 字型大小 大 中小 我要列印 我要糾錯 email推薦 有的人一輩子悲悲戚戚 鬱鬱寡歡 房子不如人家的大 不爽,車子不如人家的好 不快,官職沒有人家高 不服 可有的人一輩子痛痛快快 高高興興,卻也不見得擁有多少財富和權力。什麼原因?筆者認為關鍵在於心境的豁達。人成天被名利纏得死死的,得與失算...