智能合約調(diào)用是實現(xiàn)一個 DApp 的關(guān)鍵,一個完整的 DApp 包括前端、后端、智能合約及區(qū)塊 鏈系統(tǒng),智能合約的調(diào)用是連接區(qū)塊鏈與前后端的關(guān)鍵。
10年的鐵東網(wǎng)站建設經(jīng)驗,針對設計、前端、開發(fā)、售后、文案、推廣等六對一服務,響應快,48小時及時工作處理。網(wǎng)絡營銷推廣的優(yōu)勢是能夠根據(jù)用戶設備顯示端的尺寸不同,自動調(diào)整鐵東建站的顯示方式,使網(wǎng)站能夠適用不同顯示終端,在瀏覽器中調(diào)整網(wǎng)站的寬度,無論在任何一種瀏覽器上瀏覽網(wǎng)站,都能展現(xiàn)優(yōu)雅布局與設計,從而大程度地提升瀏覽體驗。創(chuàng)新互聯(lián)建站從事“鐵東網(wǎng)站設計”,“鐵東網(wǎng)站推廣”以來,每個客戶項目都認真落實執(zhí)行。
我們先來了解一下智能合約調(diào)用的基礎原理。智能合約運行在以太坊節(jié)點的 EVM 中。因此要 想調(diào)用合約必須要訪問某個節(jié)點。
以后端程序為例,后端服務若想連接節(jié)點有兩種可能,一種是雙 方在同一主機,此時后端連接節(jié)點可以采用 本地 IPC(Inter-Process Communication,進 程間通信)機制,也可以采用 RPC(Remote Procedure Call,遠程過程調(diào)用)機制;另 一種情況是雙方不在同一臺主機,此時只能采用 RPC 機制進行通信。
提到 RPC, 讀者應該對 Geth 啟動參數(shù)有點印象,Geth 啟動時可以選擇開啟 RPC 服務,對應的 默認服務端口是 8545。。
接著,我們來了解一下智能合約運行的過程。
智能合約的運行過程是后端服務連接某節(jié)點,將 智能合約的調(diào)用(交易)發(fā)送給節(jié)點,節(jié)點在驗證了交易的合法性后進行全網(wǎng)廣播,被礦工打包到 區(qū)塊中代表此交易得到確認,至此交易才算完成。
就像數(shù)據(jù)庫一樣,每個區(qū)塊鏈平臺都會提供主流 開發(fā)語言的 SDK(Software Development Kit,軟件開發(fā)工具包),由于 Geth 本身就是用 Go 語言 編寫的,因此若想使用 Go 語言連接節(jié)點、發(fā)交易,直接在工程內(nèi)導入 go-ethereum(Geth 源碼) 包就可以了,剩下的問題就是流程和 API 的事情了。
總結(jié)一下,智能合約被調(diào)用的兩個關(guān)鍵點是節(jié)點和 SDK。
由于 IPC 要求后端與節(jié)點必須在同一主機,所以很多時候開發(fā)者都會采用 RPC 模式。除了 RPC,以太坊也為開發(fā)者提供了 json- rpc 接口,本文就不展開討論了。
接下來介紹如何使用 Go 語言,借助 go-ethereum 源碼庫來實現(xiàn)智能合約的調(diào)用。這是有固定 步驟的,我們先來說一下總體步驟,以下面的合約為例。
步驟 01:編譯合約,獲取合約 ABI(Application Binary Interface,應用二進制接口)。 單擊【ABI】按鈕拷貝合約 ABI 信息,將其粘貼到文件 calldemo.abi 中(可使用 Go 語言IDE 創(chuàng)建該文件,文件名可自定義,后綴最好使用 abi)。
最好能將 calldemo.abi 單獨保存在一個目錄下,輸入“l(fā)s”命令只能看到 calldemo.abi 文件,參 考效果如下:
步驟 02:獲得合約地址。注意要將合約部署到 Geth 節(jié)點。因此 Environment 選擇為 Web3 Provider。
在【Environment】選項框中選擇“Web3 Provider”,然后單擊【Deploy】按鈕。
部署后,獲得合約地址為:0xa09209c28AEf59a4653b905792a9a910E78E7407。
步驟 03:利用 abigen 工具(Geth 工具包內(nèi)的可執(zhí)行程序)編譯智能合約為 Go 代碼。abigen 工具的作用是將 abi 文件轉(zhuǎn)換為 Go 代碼,命令如下:
其中各參數(shù)的含義如下。 (1)abi:是指定傳入的 abi 文件。 (2)type:是指定輸出文件中的基本結(jié)構(gòu)類型。 (3)pkg:指定輸出文件 package 名稱。 (4)out:指定輸出文件名。 執(zhí)行后,將在代碼目錄下看到 funcdemo.go 文件,讀者可以打開該文件欣賞一下,注意不要修改它。
步驟 04:創(chuàng)建 main.go,填入如下代碼。 注意代碼中 HexToAddress 函數(shù)內(nèi)要傳入該合約部署后的地址,此地址在步驟 01 中獲得。
步驟 04:設置 go mod,以便工程自動識別。
前面有所提及,若要使用 Go 語言調(diào)用智能合約,需要下載 go-ethereum 工程,可以使用下面 的指令:
該指令會自動將 go-ethereum 下載到“$GOPATH/src/github點抗 /ethereum/go-ethereum”,這樣還算 不錯。不過,Go 語言自 1.11 版本后,增加了 module 管理工程的模式。只要設置好了 go mod,下載 依賴工程的事情就不必關(guān)心了。
接下來設置 module 生效和 GOPROXY,命令如下:
在項目工程內(nèi),執(zhí)行初始化,calldemo 可以自定義名稱。
步驟 05:運行代碼。執(zhí)行代碼,將看到下面的效果,以及最終輸出的 2020。
上述輸出信息中,可以看到 Go 語言會自動下載依賴文件,這就是 go mod 的神奇之處。看到 2020,相信讀者也知道運行結(jié)果是正確的了。
在 Go 語言中,如果一個接口在一個包里,其他包要實現(xiàn)該接口,需要遵循下列步驟:
1. 定義接口:
假設接口定義在 `foo` 包中:
go
package foo
type MyInterface interface {
MyMethod() string
}
2. 實現(xiàn)接口:
定義一個新的類型 `Bar`,并為其實現(xiàn) `foo.MyInterface` 接口:
go
package bar
import "your-package/foo"
type Bar struct {
// ...
}
func (b Bar) MyMethod() string {
// implement method
return "bar"
}
在這里,需要導入 `foo` 包,并定義一個 `Bar` 類型,為其實現(xiàn) `foo.MyInterface` 接口,這樣就完成了在不同包中實現(xiàn)接口的目標。
如果在其他包中使用 `Bar`,需要先導入 `bar` 包,然后聲明 `Bar` 實例,并將其轉(zhuǎn)換為 `foo.MyInterface`,然后就可以調(diào)用 `MyMethod` 方法了:
go
import "your-package/bar"
func main() {
var myInterface foo.MyInterface = new(bar.Bar)
myInterface.MyMethod()
}
在這里,我們定義了一個 `myInterface` 實例,將其類型聲明為 `foo.MyInterface`,并將其初始化為 `new(bar.Bar)`。這允許我們調(diào)用 `MyMethod` 方法,這個方法實際上是由 `bar.Bar` 類型實現(xiàn)的。
總結(jié)起來,在其他包中使用其它包的接口,需要實現(xiàn)接口的包定義一個新的類型,并完成接口的實現(xiàn),另一個使用接口的包需要導入實現(xiàn)包的路徑,并將接口轉(zhuǎn)換成實現(xiàn)類型。
近幾年誕生了很多微服務框架,比如JAVA的Spring Cloud、Dubbo;Golang的GoKit和GoMicro以及NodeJs的Seneca。幾乎每種主流語言都有其對應的微服務框架。
Go在微服務框架中有其獨特的優(yōu)勢,至于優(yōu)勢在哪,自行g(shù)oogle。
1、GoKit框架
這是一個工具包的集合,可以幫助攻城獅構(gòu)建強大、可靠和可維護的微服務。提供了用于實現(xiàn)系統(tǒng)監(jiān)控和彈性模式組件的庫,例如日志、跟蹤、限流、熔斷等。
基于這個框架的應用程序架構(gòu)由三個主要的部分組成:
傳輸層:用于網(wǎng)絡通信,服務通常使用HTTP或者gRPC等網(wǎng)絡傳輸協(xié)議,或者使用NATS等發(fā)布訂閱系統(tǒng)相互通信。
接口層:是服務器和客戶端的基本構(gòu)建塊。每個對外提供的接口方法都會定義為一個Endpoint,一遍在服務器和客戶端之間進行網(wǎng)絡通信,每個端點使用傳輸層通過HTTP或gRPC等具體通信模式對外提供服務
服務成:具體的業(yè)務邏輯實現(xiàn)
2、GoMicro框架
這是一個基于Go語言實現(xiàn)的插件化RPC微服務框架。提供了服務發(fā)現(xiàn)、負載均衡、同步傳輸、異步通信以及事件驅(qū)動等機制,嘗試簡化分布式系統(tǒng)之間的通信,讓開發(fā)者更專注于自身業(yè)務邏輯的開發(fā)。
GoMicro的設計哲學是可插拔的架構(gòu)理念,提供了可快速構(gòu)建系統(tǒng)的組件,并且可以根據(jù)自身的需求對GoMicro提供的默認實現(xiàn)進行定制。所有插件都可在倉庫github點抗 /micro/go-plugins 中找到。
基本設計思路:
類型轉(zhuǎn)換、類型斷言、動態(tài)派發(fā)。iface,eface。
反射對象具有的方法:
編譯優(yōu)化:
內(nèi)部實現(xiàn):
實現(xiàn) Context 接口有以下幾個類型(空實現(xiàn)就忽略了):
互斥鎖的控制邏輯:
設計思路:
(以上為寫被讀阻塞,下面是讀被寫阻塞)
總結(jié),讀寫鎖的設計還是非常巧妙的:
設計思路:
WaitGroup 有三個暴露的函數(shù):
部件:
設計思路:
結(jié)構(gòu):
Once 只暴露了一個方法:
實現(xiàn):
三個關(guān)鍵點:
細節(jié):
讓多協(xié)程任務的開始執(zhí)行時間可控(按順序或歸一)。(Context 是控制結(jié)束時間)
設計思路: 通過一個鎖和內(nèi)置的 notifyList 隊列實現(xiàn),Wait() 會生成票據(jù),并將等待協(xié)程信息加入鏈表中,等待控制協(xié)程中發(fā)送信號通知一個(Signal())或所有(Boardcast())等待者(內(nèi)部實現(xiàn)是通過票據(jù)通知的)來控制協(xié)程解除阻塞。
暴露四個函數(shù):
實現(xiàn)細節(jié):
部件:
包: golang.org/x/sync/errgroup
作用:開啟 func() error 函數(shù)簽名的協(xié)程,在同 Group 下協(xié)程并發(fā)執(zhí)行過程并收集首次 err 錯誤。通過 Context 的傳入,還可以控制在首次 err 出現(xiàn)時就終止組內(nèi)各協(xié)程。
設計思路:
結(jié)構(gòu):
暴露的方法:
實現(xiàn)細節(jié):
注意問題:
包: "golang.org/x/sync/semaphore"
作用:排隊借資源(如錢,有借有還)的一種場景。此包相當于對底層信號量的一種暴露。
設計思路:有一定數(shù)量的資源 Weight,每一個 waiter 攜帶一個 channel 和要借的數(shù)量 n。通過隊列排隊執(zhí)行借貸。
結(jié)構(gòu):
暴露方法:
細節(jié):
部件:
細節(jié):
包: "golang.org/x/sync/singleflight"
作用:防擊穿。瞬時的相同請求只調(diào)用一次,response 被所有相同請求共享。
設計思路:按請求的 key 分組(一個 *call 是一個組,用 map 映射存儲組),每個組只進行一次訪問,組內(nèi)每個協(xié)程會獲得對應結(jié)果的一個拷貝。
結(jié)構(gòu):
邏輯:
細節(jié):
部件:
如有錯誤,請批評指正。