智能合約調(diào)用是實現(xiàn)一個 DApp 的關(guān)鍵,一個完整的 DApp 包括前端、后端、智能合約及區(qū)塊 鏈系統(tǒng),智能合約的調(diào)用是連接區(qū)塊鏈與前后端的關(guān)鍵。
專注于為中小企業(yè)提供網(wǎng)站建設(shè)、網(wǎng)站設(shè)計服務(wù),電腦端+手機(jī)端+微信端的三站合一,更高效的管理,為中小企業(yè)臨潼免費(fèi)做網(wǎng)站提供優(yōu)質(zhì)的服務(wù)。我們立足成都,凝聚了一批互聯(lián)網(wǎng)行業(yè)人才,有力地推動了上1000家企業(yè)的穩(wěn)健成長,幫助中小企業(yè)通過網(wǎng)站建設(shè)實現(xiàn)規(guī)模擴(kuò)充和轉(zhuǎn)變。
我們先來了解一下智能合約調(diào)用的基礎(chǔ)原理。智能合約運(yùn)行在以太坊節(jié)點的 EVM 中。因此要 想調(diào)用合約必須要訪問某個節(jié)點。
以后端程序為例,后端服務(wù)若想連接節(jié)點有兩種可能,一種是雙 方在同一主機(jī),此時后端連接節(jié)點可以采用 本地 IPC(Inter-Process Communication,進(jìn) 程間通信)機(jī)制,也可以采用 RPC(Remote Procedure Call,遠(yuǎn)程過程調(diào)用)機(jī)制;另 一種情況是雙方不在同一臺主機(jī),此時只能采用 RPC 機(jī)制進(jìn)行通信。
提到 RPC, 讀者應(yīng)該對 Geth 啟動參數(shù)有點印象,Geth 啟動時可以選擇開啟 RPC 服務(wù),對應(yīng)的 默認(rèn)服務(wù)端口是 8545。。
接著,我們來了解一下智能合約運(yùn)行的過程。
智能合約的運(yùn)行過程是后端服務(wù)連接某節(jié)點,將 智能合約的調(diào)用(交易)發(fā)送給節(jié)點,節(jié)點在驗證了交易的合法性后進(jìn)行全網(wǎng)廣播,被礦工打包到 區(qū)塊中代表此交易得到確認(rèn),至此交易才算完成。
就像數(shù)據(jù)庫一樣,每個區(qū)塊鏈平臺都會提供主流 開發(fā)語言的 SDK(Software Development Kit,軟件開發(fā)工具包),由于 Geth 本身就是用 Go 語言 編寫的,因此若想使用 Go 語言連接節(jié)點、發(fā)交易,直接在工程內(nèi)導(dǎo)入 go-ethereum(Geth 源碼) 包就可以了,剩下的問題就是流程和 API 的事情了。
總結(jié)一下,智能合約被調(diào)用的兩個關(guān)鍵點是節(jié)點和 SDK。
由于 IPC 要求后端與節(jié)點必須在同一主機(jī),所以很多時候開發(fā)者都會采用 RPC 模式。除了 RPC,以太坊也為開發(fā)者提供了 json- rpc 接口,本文就不展開討論了。
接下來介紹如何使用 Go 語言,借助 go-ethereum 源碼庫來實現(xiàn)智能合約的調(diào)用。這是有固定 步驟的,我們先來說一下總體步驟,以下面的合約為例。
步驟 01:編譯合約,獲取合約 ABI(Application Binary Interface,應(yīng)用二進(jìn)制接口)。 單擊【ABI】按鈕拷貝合約 ABI 信息,將其粘貼到文件 calldemo.abi 中(可使用 Go 語言IDE 創(chuàng)建該文件,文件名可自定義,后綴最好使用 abi)。
最好能將 calldemo.abi 單獨(dú)保存在一個目錄下,輸入“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:設(shè)置 go mod,以便工程自動識別。
前面有所提及,若要使用 Go 語言調(diào)用智能合約,需要下載 go-ethereum 工程,可以使用下面 的指令:
該指令會自動將 go-ethereum 下載到“$GOPATH/src/github.com/ethereum/go-ethereum”,這樣還算 不錯。不過,Go 語言自 1.11 版本后,增加了 module 管理工程的模式。只要設(shè)置好了 go mod,下載 依賴工程的事情就不必關(guān)心了。
接下來設(shè)置 module 生效和 GOPROXY,命令如下:
在項目工程內(nèi),執(zhí)行初始化,calldemo 可以自定義名稱。
步驟 05:運(yùn)行代碼。執(zhí)行代碼,將看到下面的效果,以及最終輸出的 2020。
上述輸出信息中,可以看到 Go 語言會自動下載依賴文件,這就是 go mod 的神奇之處??吹?2020,相信讀者也知道運(yùn)行結(jié)果是正確的了。
Fabric區(qū)塊鏈開發(fā)詳解,本課程面向初學(xué)者,內(nèi)容即包含Hyperledger Fabric的身份證書與MSP服務(wù)、權(quán)限策略、通道配置與啟動、鏈碼通信接口等核心概念,也包含F(xiàn)abric網(wǎng)絡(luò)設(shè)計、鏈碼與應(yīng)用開發(fā)的操作實踐,是學(xué)習(xí)Fabric區(qū)塊鏈開發(fā)的最佳選擇。
給你個免費(fèi)區(qū)塊鏈博客看看。
Go 由于不支持泛型而臭名昭著,但最近,泛型已接近成為現(xiàn)實。Go 團(tuán)隊實施了一個看起來比較穩(wěn)定的設(shè)計草案,并且正以源到源翻譯器原型的形式獲得關(guān)注。本文講述的是泛型的最新設(shè)計,以及如何自己嘗試泛型。
例子
FIFO Stack
假設(shè)你要創(chuàng)建一個先進(jìn)先出堆棧。沒有泛型,你可能會這樣實現(xiàn):
type?Stack?[]interface{}func?(s?Stack)?Peek()?interface{}?{
return?s[len(s)-1]
}
func?(s?*Stack)?Pop()?{
*s?=?(*s)[:
len(*s)-1]
}
func?(s?*Stack)?Push(value?interface{})?{
*s?=?
append(*s,?value)
}
但是,這里存在一個問題:每當(dāng)你 Peek 項時,都必須使用類型斷言將其從 interface{} 轉(zhuǎn)換為你需要的類型。如果你的堆棧是 *MyObject 的堆棧,則意味著很多 s.Peek().(*MyObject)這樣的代碼。這不僅讓人眼花繚亂,而且還可能引發(fā)錯誤。比如忘記 * 怎么辦?或者如果您輸入錯誤的類型怎么辦?s.Push(MyObject{})` 可以順利編譯,而且你可能不會發(fā)現(xiàn)到自己的錯誤,直到它影響到你的整個服務(wù)為止。
通常,使用 interface{} 是相對危險的。使用更多受限制的類型總是更安全,因為可以在編譯時而不是運(yùn)行時發(fā)現(xiàn)問題。
泛型通過允許類型具有類型參數(shù)來解決此問題:
type?Stack(type?T)?[]Tfunc?(s?Stack(T))?Peek()?T?{
return?s[len(s)-1]
}
func?(s?*Stack(T))?Pop()?{
*s?=?(*s)[:
len(*s)-1]
}
func?(s?*Stack(T))?Push(value?T)?{
*s?=?
append(*s,?value)
}
這會向 Stack 添加一個類型參數(shù),從而完全不需要 interface{}?,F(xiàn)在,當(dāng)你使用 Peek() 時,返回的值已經(jīng)是原始類型,并且沒有機(jī)會返回錯誤的值類型。這種方式更安全,更容易使用。(譯注:就是看起來更丑陋,^-^)
此外,泛型代碼通常更易于編譯器優(yōu)化,從而獲得更好的性能(以二進(jìn)制大小為代價)。如果我們對上面的非泛型代碼和泛型代碼進(jìn)行基準(zhǔn)測試,我們可以看到區(qū)別:
type?MyObject?struct?{
X?
int
}
var?sink?MyObjectfunc?BenchmarkGo1(b?*testing.B)?{
for?i?:=?0;?i??b.N;?i++?{
var?s?Stack
s.Push(MyObject{})
s.Push(MyObject{})
s.Pop()
sink?=?s.Peek().(MyObject)
}
}
func?BenchmarkGo2(b?*testing.B)?{
for?i?:=?0;?i??b.N;?i++?{
var?s?Stack(MyObject)
s.Push(MyObject{})
s.Push(MyObject{})
s.Pop()
sink?=?s.Peek()
}
}
結(jié)果:
BenchmarkGo1BenchmarkGo1-16?????12837528?????????87.0?ns/op???????48?B/op????????2?allocs/opBenchmarkGo2BenchmarkGo2-16?????28406479?????????41.9?ns/op???????24?B/op????????2?allocs/op
在這種情況下,我們分配更少的內(nèi)存,同時泛型的速度是非泛型的兩倍。
合約(Contracts)
上面的堆棧示例適用于任何類型。但是,在許多情況下,你需要編寫僅適用于具有某些特征的類型的代碼。例如,你可能希望堆棧要求類型實現(xiàn) String() 函數(shù)
1.
1.1符號命名規(guī)則
1.1.1符號名包括模塊名、常量名、標(biāo)號名、子程序名等。這些名字應(yīng)該能反映它所代表的實際東西,具有一定的意義,使其能夠見名知義,有助于對程序功能的理解。命名采用匈牙利命名法。規(guī)則如下:
(1)所有宏定義、枚舉常數(shù)和const變量,用大寫字母命名。在復(fù)合詞里用下劃線隔開每個詞。
(2)復(fù)合詞中每個單詞的第一個字母大寫。除了規(guī)則5.1.1.1以外,避免使用下劃線。
(3)類、類型定義和枚舉型名的第一個字母大寫。
(4)函數(shù)名是復(fù)合詞的,第一個詞采用全部小寫,隨后每個單詞采用第一個字母大寫,其它字母小寫方式;如果是單個詞的,采用全部小寫方式。
(5)循環(huán)變量可采用i, j, k等,不受上述規(guī)則限制。
(6) 類的成員變量應(yīng)采用m_開頭。
(7) 全局變量詞頭為g_ 。
(8) 臨時變量詞頭為tmp_ 。
(9) 對結(jié)構(gòu)體內(nèi)的變量命名, 遵循變量的具體含義命名原則
(10)用小寫字母的前綴表示變量的類型,前綴的下一個字母用大寫。
表 1
詞頭 類型 詞頭 類型
ch char l long
i integer u unsigned
b boolean p pointer
f float lp long pointer
d double s string
st structure sz ASCII string
by byte n short int
H handle x,y 分別為x,y坐標(biāo)
dw DWORD fn function
表 2
詞頭 變量名 詞頭 變量名
task task sig signal
sb binary semaphores wd watchdog
sm mutual exclusion tm timer
sc counting semaphores msg message
pipe pipe
例:
#define ARRAY_SIZE 24 /*規(guī)則5.1.1.1*/
int g_iFlag;
class MyClass /*規(guī)則5.1.1.3*/
{
};
void someFunc( ) /*規(guī)則5.1.1.2和5.1.1.4*/
{
int nArray[ARRAY_SIZE];
unsigned char uchByte;
char szName[ ];
char *pszName = szName;
}
(11)有些詞頭(如p和u)可以和其它詞頭組合。
例:WDOG_ID wdId;
WDOG_ID g_wdId; /*全局watchdog Id,故以g_開頭*/
1.1.2名字的長度一般不要過長或過短。過長的名字會增加工作量,使程序邏輯流程變得模糊;過短的名字無法表達(dá)符號的實際意義。約定長度范圍:3-31;
1.2數(shù)據(jù)和函數(shù)說明
1.2.1數(shù)據(jù)說明次序應(yīng)當(dāng)規(guī)范化,使數(shù)據(jù)屬性容易查找,也有利于測試、排錯和維護(hù)。說明的先后次序應(yīng)固定,應(yīng)按邏輯功能排序,邏輯功能塊內(nèi)建議采用下列順序:整型說明、實型說明、字符說明、邏輯量說明。
1.2.2如果設(shè)計了一個復(fù)雜的數(shù)據(jù)結(jié)構(gòu),應(yīng)當(dāng)通過注釋對其變量的含義、用途進(jìn)行說明。
1.2.3在函數(shù)的聲明中使用異常聲明。
如:void f() throw(toobig, toosmall, divzero);
在聲明一個函數(shù)時,將它所拋出的異常列出,便于函數(shù)的使用者了解可能會發(fā)生哪些異常。
1.3 程序注釋
1.3.1程序注釋是程序員與日后的程序讀者之間通信的重要手段之一,注釋分為文件注釋、函數(shù)注釋和功能注釋。
1.3.2正規(guī)程序的注釋應(yīng)注意:
——注釋行的數(shù)量占到整個源程序的1/3到1/2。
1.3.3文件注釋位于整個源程序的最開始部分,注釋后空兩行開始程序正文。它包括:
——程序標(biāo)題。
——目的、功能說明。
——文件作者、最后修改日期等說明。
例:
./********************************************************************
(空一行)
標(biāo)題: Demo.c
功能: 測試VxWorks的各種系統(tǒng)調(diào)用.
說明:
該程序測試各種VxWorks的系統(tǒng)調(diào)用函數(shù)。包括任務(wù)(taks)的創(chuàng)建、掛起及任務(wù)間通過信號燈實現(xiàn)同步,通過消息隊列 進(jìn)行通訊。
程序創(chuàng)建了兩個任務(wù):一個高優(yōu)先級的任務(wù)和一個低優(yōu)先級的任務(wù)。兩個任務(wù)間通過一個二進(jìn)制的信號燈進(jìn)行同步,通過消息隊列進(jìn)行通訊。
當(dāng)前版本: x.x
修改信息: 2000.06.05 John, Initial Version
2000.07.05 Tom, Bug xxxx fixed
**************************************************************/
(空2行,開始程序正文)
1.3.4 函數(shù)注釋通常置于每函數(shù)或過程的開頭部分,它應(yīng)當(dāng)給出函數(shù)或過程的整體說明對于理解程序本身具有引導(dǎo)作用。一般包括如下條目:
——模塊標(biāo)題。
——有關(guān)本模塊功能和目的的說明。
——調(diào)用格式
——接口說明:包括輸入、輸出、返回值、異常。
——算法。如果模塊中采用了一些復(fù)雜的算法。
例:
file://(/注釋開頭應(yīng)和上一函數(shù)空兩行)
(注釋開頭與上一函數(shù)最后一行間隔兩行)
/********************************************************************
標(biāo)題:assignmentComplete
功能:BSC=MSC消息生成函數(shù),生成assignment_complete指配完成消息(BSMAP消息) .
格式:
int assignmentComplete(int iCellId, int iServiceChannnelNum, char *pszMSGData) throw(exception1, exception2)
輸入:
int iCellId: MS所在的小區(qū)識別
iCellId取值:0x00-——0xff
int iServiceChannnelNum:MS所占的業(yè)務(wù)信道號碼
輸出:
char * pszMSGData:指配完成消息數(shù)據(jù)
返回值: 0x00正常
異常:exception1異常情況1, exception2異常情況2
********************************************************************/
( 注釋后直接開始程序正文,不空行。)
1.3.5功能性注釋嵌在源程序體中,用于描述其后的語句或程序段做什么工作,也就是解釋下面要做什么,或是執(zhí)行了下面的語句會怎么樣。而不要解釋下面怎么做,因為解釋怎么做常常與程序本身是重復(fù)的。
例:
/*把 amount 加到 total中*/
total = amount + total;
這樣的注釋僅僅是重復(fù)了下面的程序,對于理解它的工作并沒有什么作用。而下面的注釋,有助于讀者理解。
/*將每月的銷售額amount加到年銷售額total中*/
total = amount + total;
1.4 函數(shù)編寫應(yīng)盡可能短小精悍,一般不超過兩屏,以便于調(diào)試和理解。
1.5語句結(jié)構(gòu)
為保證語句結(jié)構(gòu)的清晰和程序的可讀性,在編寫軟件程序時應(yīng)注意以下幾個方面的問題:
——在一行內(nèi)只寫一條語句,并采用空格、空行和移行保證清楚的視覺效果。
——每一個嵌套的函數(shù)塊,使用一個TAB縮進(jìn)(可以設(shè)定為4個空格),大括號必須放在條件語句的下一行,單獨(dú)成一行,便于匹對:
如,有一段程序如下:
for(i=1;in-1;i++){ t=1; for(j=i+1;jn;j++){
if(a[j]a[t] ) t=j; if(t!=i ){work=a[t];a[t]=a[I];a[I]=work;}}}
應(yīng)寫為
for( i=1; in-1; i++)
{
t=1;
for(j = i+1; jn; j++)
{
if(a[i]a[j])
t=j;
if(t!=1)
{ .5.
Q/ECC/BJ 010—2001
work=a[t];
a[t]=a[i];
a[i]=work;
}
}
}
——文件之中不得存在無規(guī)則的空行,比如說連續(xù)十個空行。
一般來講函數(shù)與函數(shù)之間的空行為2-3行;
在函數(shù)體內(nèi)部,在邏輯上獨(dú)立的兩個函數(shù)塊可適當(dāng)空行,一般為1-2行。
——程序編寫首先應(yīng)考慮清晰性,不要刻意追求技巧性而使得程序難以理解。
——每行長度盡量避免超過屏幕寬度,應(yīng)不超過80個字符。
——除非對效率有特殊要求,編寫程序要作到清晰第一,效率第二。
——盡可能使用函數(shù)庫。
——盡量用公共過程或子程序去代替重復(fù)的功能代碼段。要注意,這個代碼應(yīng)具有一個獨(dú)立的功能,不要只因代碼形式一樣便將其抽出組成一個公共過程或子程序。
——使用括號清晰地表達(dá)算術(shù)表達(dá)式和邏輯表達(dá)式的運(yùn)算順序。如將 x=a*b/c*d 寫成 x=(a*b/c)*d可避免閱讀者誤解為x=(a*b)/(c*d)。
——避免不必要的轉(zhuǎn)移。
——避免采用過于復(fù)雜的條件測試。
——避免過多的循環(huán)嵌套和條件嵌套。
——建議不要使用 *=,^=, /=等運(yùn)算符。
——一個函數(shù)不要超過200行。一個文件應(yīng)避免超過2000行。
——盡量避免使用go to語句。
——避免采用多賦值語句,如x = y = z ;
——不鼓勵采用?:操作符,如z = (ab)?a:b;
——不要使用空的if else 語句。如
if(cMychar = ‘A’)
if(cMychar = ‘Z’)
printf(“This is a letter \n”);
else
printf(“This is not a letter \n”);
else到底是否定哪個if容易引起誤解??赏ㄟ^加{}避免誤解。
——盡量減少使用“否定”條件的條件語句。如:
把 if( !( (cMychar’0’) || (cMychar’9’) ) )
改為if( (cMychar=’0’) (cMychar=’9’)
分享題目:go語言操作bsc合約 go語言智能合約
網(wǎng)站路徑:http://jinyejixie.com/article2/ddcoioc.html
成都網(wǎng)站建設(shè)公司_創(chuàng)新互聯(lián),為您提供軟件開發(fā)、動態(tài)網(wǎng)站、企業(yè)網(wǎng)站制作、云服務(wù)器、定制開發(fā)、定制網(wǎng)站
聲明:本網(wǎng)站發(fā)布的內(nèi)容(圖片、視頻和文字)以用戶投稿、用戶轉(zhuǎn)載內(nèi)容為主,如果涉及侵權(quán)請盡快告知,我們將會在第一時間刪除。文章觀點不代表本網(wǎng)站立場,如需處理請聯(lián)系客服。電話:028-86922220;郵箱:631063699@qq.com。內(nèi)容未經(jīng)允許不得轉(zhuǎn)載,或轉(zhuǎn)載時需注明來源: 創(chuàng)新互聯(lián)