智能合約編寫之Solidity的基礎特性|FISCO BCOS系列開發教程

3月25日,BSN第二次開發者大賽正式啓動,本次大賽以“編寫基於多種底層框架的智能合約”爲主題,開發者可基於FISCO BCOS等主流底層框架,結合業務場景設計、開發並部署智能合約。

爲了讓大家更好上手智能合約開發,區塊鏈服務網絡發展聯盟與FISCO BCOS開源社區共同推出“7個課時速成智能合約全能型開發”系列教程,助力開發者學習並熟悉合約開發,輕鬆應對此次大賽並拔得頭籌。

solidity

solidity

系列專題 | 超話區塊鏈之智能合約專場

編寫篇:智能合約編寫之  Solidity的基礎特性

作者:儲雨知

solidity

如前篇介紹,目前大部分的聯盟鏈平臺,包括FISCO BCOS,都採用Solidity作爲智能合約開發語言,因此熟悉並上手Solidity十分必要。 

作爲一門面向區塊鏈平臺設計的圖靈完備的編程語言,Solidity支持函數調用、修飾符、重載、事件、繼承等多種特性,在區塊鏈社區中,擁有廣泛的影響力和踊躍的社區支持。但對於剛接觸區塊鏈的人而言,Solidity是一門陌生的語言。 

智能合約編寫階段將從Solidity基礎特性、高級特性、設計模式以及編程攻略分別展開,帶讀者認識Solidity並掌握其運用,更好地進行智能合約開發。 

本篇將圍繞Solidity的基礎特性,帶大家上手開發一個最基本的智能合約。

智能合約代碼結構

任何編程語言都有其規範的代碼結構,用於表達在一個代碼文件中如何組織和編寫代碼,Solidity也一樣。 

本節,我們將通過一個簡單的合約示例,來了解智能合約的代碼結構。

solidity

上面這段程序包括了以下功能:

  • 通過構造函數來部署合約

  • 通過setValue函數設置合約狀態

  • 通過getValue函數查詢合約狀態

整個合約主要分爲以下幾個構成部分:

  • 狀態變量 - _admin, _state,這些變量會被永久保存,也可以被函數修改

  • 構造函數 - 用於部署並初始化合約

  • 事件 - SetState, 功能類似日誌,記錄了一個事件的發生

  • 修飾符 - onlyAdmin, 用於給函數加一層"外衣"

  • 函數 - setState, getState,用於讀寫狀態變量 

下面將逐一介紹上述構成部分。 

  狀態變量

狀態變量是合約的骨髓,它記錄了合約的業務信息。用戶可以通過函數來修改這些狀態變量,這些修改也會被包含到交易中;交易經過區塊鏈網絡確認後,修改即爲生效。

solidity

狀態變量的聲明方式爲:[類型]  [訪問修飾符-可選] [字段名]

  構造函數

構造函數用於初始化合約,它允許用戶傳入一些基本的數據,寫入到狀態變量中。

在上述例子中,設置了_admin字段,作爲後面演示其他功能的前提。

solidity

和java不同的是,構造函數不支持重載,只能指定一個構造函數。

  函數

函數被用來讀寫狀態變量。對變量的修改將會被包含在交易中,經區塊鏈網絡確認後才生效。生效後,修改會被永久的保存在區塊鏈賬本中。

函數簽名定義了函數名、輸入輸出參數、訪問修飾符、自定義修飾符。

solidity

函數還可以返回多個返回值:

solidity

在本合約中,還有一個配備了view修飾符的函數。這個view表示了該函數不會修改任何狀態變量。 

與view類似的還有修飾符pure,其表明該函數是純函數,連狀態變量都不用讀,函數的運行僅僅依賴於參數。

solidity

如果在view函數中嘗試修改狀態變量,或者在pure函數中訪問狀態變量,編譯器均會報錯。

  事件

事件類似於日誌,會被記錄到區塊鏈中,客戶端可以通過web3訂閱這些事件。

定義事件

solidity

構造事件

solidity

這裏有幾點需要注意: 

  • 事件的名稱可以任意指定,不一定要和函數名掛鉤,但推薦兩者掛鉤,以便清晰地表達發生的事情.

  • 構造事件時,也可不寫emit,但因爲事件和函數無論是名稱還是參數都高度相關,這樣操作很容易筆誤將事件寫成函數調用,因此不推薦。

solidity

  修飾符

修飾符是合約中非常重要的一環。它掛在函數聲明上,爲函數提供一些額外的功能,例如檢查、清理等工作。

在本例中,修飾符onlyAdmin要求函數調用前,需要先檢測函數的調用者是否爲函數部署時設定的那個管理員(即合約的部署人)。

solidity

值得注意的是,定義在修飾符中的下劃線“_”,表示函數的調用,指代的是開發者用修飾符修飾的函數。在本例中,表達的是setState函數調用的意思。

智能合約的運行

瞭解了上述的智能合約示例的結構,就可以直接上手運行,運行合約的方式有多種,大家可以任意採取其中一種:

  • 方法二:使用FISCO BCOS開源項目WeBASE提供的在線ide WEBASE-front運行

本例中使用remix作爲運行示例。

  編譯

首先,在remix的文件ide中鍵入代碼後,通過編譯按鈕來編譯。成功後會在按鈕上出現一個綠色對勾:

solidity

  部署

編譯成功後就可進行部署環節,部署成功後會出現合約實例。

solidity

  setState

合約部署後,我們來調用setState(4)。在執行成功後,會產生一條交易收據,裏面包含了交易的執行信息。

solidity

在這裏,用戶可以看到交易執行狀態(status)、交易執行人(from)、交易輸入輸出(decoded input, decoded output)、交易開銷(execution cost)以及交易日誌(logs)。

在logs中,我們看到SetState事件被拋出,裏面的參數也記錄了事件傳入的值4。

如果我們換一個賬戶來執行,那麼調用會失敗,因爲onlyAdmin修飾符會阻止用戶調用。

solidity

  getState

調用getState後,可以直接看到所得到的值爲4,正好是我們先前setState所傳入的值:

solidity

Solidity數據類型

在前文的示例中,我們用到了uint等數據類型。由於Solidity類型設計比較特殊,這裏也會簡單介紹一下Solidity的數據類型。

  整型系列

Solidity提供了一組數據類型來表示整數, 包含無符號整數與有符號整數。每類整數還可根據長度細分,具體細分類型如下。


solidity

  定長bytes系列

Solidity提供了bytes1到bytes32的類型,它們是固定長度的字節數組。

用戶可以讀取定長bytes的內容。

solidity

並且,可以將整數類型轉換爲bytes。

solidity

這裏有一個關鍵細節,Solidity採取大端序編碼,高地址存的是整數的小端。例如,b[0]是低地址端,它存整數的高端,所以值爲0;取b[31]纔是1。

solidity

  變長bytes

從上文中,讀者可瞭解定長byte數組。此外,Solidity還提供了一個變長byte數組:bytes。使用方式類似數組,後文會有介紹。

  string

Solidity提供的string,本質是一串經UTF-8編碼的字節數組,它兼容於變長bytes類型。

目前Solidity對string的支持不佳,也沒有字符的概念。用戶可以將string轉成bytes。


solidity

要注意的是,當將string轉換成bytes時,數據內容本身不會被拷貝,如上文中,str和b變量指向的都是同一個字符串abc。

  address 

address表示賬戶地址,它由私鑰間接生成,是一個20字節的數據。同樣,它也可以被轉換爲bytes20。

solidity

  mapping 

mapping表示映射, 是極其重要的數據結構。它與java中的映射存在如下幾點差別: 

  • 它無法迭代keys,因爲它只保存鍵的哈希,而不保存鍵值,如果想迭代,可以用開源的可迭代哈希類庫

  • 如果一個key未被保存在mapping中,一樣可以正常讀取到對應value,只是value是空值(字節全爲0)。所以它也不需要put、get等操作,用戶直接去操作它即可。


solidity

  數組

如果數組是狀態變量,那麼支持push等操作:

solidity

 數組也可以以局部變量的方式使用,但稍有不同:

solidity

  struct

Solidity允許開發者自定義結構對象。結構體既可以作爲狀態變量存儲,也可以在函數中作爲局部變量存在。  

solidity

本節中只介紹了比較常見的數據類型,更完整的列表可參考Solidity官方網站:

https://solidity.readthedocs.io/en/v0.6.3/types.html 

全局變量

示例合約代碼的構造函數中,包含msg.sender。它屬於全局變量。在智能合約中,全局變量或全局方法可用於獲取和當前區塊、交易相關的一些基本信息,如塊高、塊時間、合約調用者等。

比較常用的全局變量是msg變量,表示調用上下文,常見的全局變量有以下幾種:

  • msg.sender:合約的直接調用者。

    由於是直接調用者,所以當處於 用戶A->合約1->合約2 調用鏈下,若在合約2內使用msg.sender,得到的會是合約1的地址。如果想獲取用戶A,可以用tx.origin.

  • tx.origin:交易的"始作俑者",整個調用鏈的起點。

  • msg.calldata:包含完整的調用信息,包括函數標識、參數等。calldata的前4字節就是函數標識,與msg.sig相同。

  • msg.sig:msg.calldata的前4字節,用於標識函數。

  • block.number:表示當前所在的區塊高度。

  • now:表示當前的時間戳。也可以用block.timestamp表示。

這裏只列出了部分常見全局變量,完整版本請參考:

https://solidity.readthedocs.io/en/v0.4.24/units-and-global-variables.html

結語

本文以一個簡單的示例合約作爲引入,介紹了運用Solidity開發智能合約的基本知識。讀者可以嘗試運行該合約,感受智能合約的開發。

若想更深入學習智能合約示例,推薦官方網站示例供讀者學習,也可關注本專題後續系列文章:

https://solidity.readthedocs.io/en/v0.6.2/solidity-by-example.html

在官網的示例中,提供了投票、競拍、微支付通道等多個案例,這些案例貼近實際生活,是很好的學習資料。

solidity

FISCO BCOS的代碼完全開源且免費

下載地址↓↓↓

https://github.com/FISCO-BCOS/FISCO-BCOS

solidity

文章來源於FISCO BCOS開源社區 ,作者儲雨知

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章