1. 程式人生 > >solidity教程【0.5.7】

solidity教程【0.5.7】

以太坊不僅是一種加密數字貨幣,它更是功能完備的智慧合約平臺,solidity就是用來開發以太坊上的智慧合約的原生開發語言。solidity最早釋出於2015年,它是第一種圖靈完備的智慧合約專用開發語言。目前除了以太坊之外,在其他區塊鏈中也逐漸開始支援solidity,例如hyperledger fabric、tendermint等。在這個solidity快速教程中,我們將使用最新0.5版的solidity,以一個具體的案例來介紹solidity智慧合約的開發、部署與互動,希望對你快速掌握solidity智慧合約的開發有所幫助。

如果要高效系統地掌握以太坊智慧合約與DApp的開發,推薦訪問匯智網的線上互動課程:

以太坊開發入門 | java以太坊 | python以太坊 | php以太坊 | C#以太坊 | 電商DApp實戰 | ERC721通證實戰

0、問題的背景

有一個老爺爺,在生命的最後歲月別無他求,只是希望自己的財產能夠通過遺囑順利地傳給其他家庭成員。

在傳統的遺囑中,遺產分配方案是落實在法律檔案上的,然後當真正開始分配時,法官需要重審檔案並做出相應的決定。常見的問題發生在家庭成員之間對分配比例的爭執上,甚至因此而導致家庭成員關係的破裂。在法庭聽證階段,這些都會影響法官最終的裁決,並因此可能導致不公平的結果,甚至對家庭關係造成進一步的傷害。

那麼,如果我們可以讓遺產分配自動進行,是否可以避免上述情況的發生?

如果遺產是一個智慧合約,那麼就不需要法官了。老爺爺可以自主地利用合約管理資產,然後在他去世後由程式來分配遺產給家庭成員。合約裡的程式碼就決定了最終的分配結果,因此無需法官的介入。例如薩拉分$10000,本得到$5000,朱麗葉得到$2000。程式碼執行後,資產以代幣或加密貨幣的形式自動分配給這些家庭成員,而無需人工介入。雖然不能保證每個成員都對遺產的分配結果滿意,但是沒有人會和程式碼爭執。這聽起來還比較可行,對嗎?

記住這個案例,在這個快速教程中,我們將使用solidity,為老爺爺開發一個簡單的遺囑合約,來滿足他最後的願望。

1、搭建solidity開發環境

開發solidity智慧合約最簡單的方法,就是使用官方提供的線上整合開發環境REMIX,你可以點選

這裡開啟remix,在網頁裡就完成solidity智慧合約的編寫、編譯與部署:

solidity ide remix

在你開啟remix頁面後,注意在右側的run選項頁,environment下拉框中,要選中JavaScript VM。這個選項的意思是使用一個記憶體模擬以太坊節點作為你的solidity智慧合約的執行平臺,這樣就不用考慮與實際的以太坊主網互動所需要的賬號、資金、計算費用等問題,而可以先把精力聚焦在學習如何使用solidity表達你的業務邏輯上。

點選remix頁面左上方的+圖示,就可以建立一個新的程式碼檔案,我們將其命名為will.sol。在remix頁面中間的編輯區域可以同時顯示多個檔案,當前正在編輯的檔案,則以活動選項頁的形式顯示檔名稱。

2、宣告solidity編譯器版本

solidity還是很早期階段的語言,從語法到編譯器都在不斷地演化,所以在solidity程式碼的第一行,一定要用pragma關鍵字宣告這個檔案中的solidity程式碼需要哪個版本的編譯器。例如:

solidity ide remix

注意在solidity中,末尾的分號不可省略。

3、編寫第一個solidity合約

接下來就可以定義我們的第一個合約:

solidity ide remix

使用contract關鍵字來定義一個合約,solidity的合約類似於我們熟悉的OOP中的類,因此通常合約的名稱首字母也會大寫,例如Will。一對大括號用來定義合約的實現 邏輯,單行註釋也使用//,這和很多開發語言都類似。

4、solidity中的全域性變數和建構函式

在我們開始寫程式碼之前,應當首先明確遺囑的條款。假設老爺爺的遺產是50個以太幣,其中20個留給他的兒子康萊德,剩下的30個留給他的妻子麗莎。在真實的環境中,當老爺爺去世後,應當有一個外部的程式將呼叫合約中定義的方法來分配遺產,但是我們為了便於學習將自己完成這個呼叫。

現在,讓我們先完成如下程式碼:

  • 表徵合約所有者的變數
  • 表徵遺產數量的變數
  • 表徵老爺爺是否還健在的變數
  • 設定上述變數初始值的建構函式

solidity ide remix

第5行程式碼定義了合約的所有者。當我們在solidity中定義變數時,必須先宣告其型別。address是solidity中一種特殊的型別,它表示一個以太坊地址。address型別的變數有一些特殊的方法,我們在後面會進一步瞭解。

第6行程式碼定義的fortune變數用來儲存老爺爺的遺產數量,它的型別是uintunsigned int,意思是這個變數是0或正整數。solidity中有很多資料型別,但我們不會在這裡一一介紹,你可以在官方文件中深入瞭解solidity的資料型別。

第7行程式碼定義的isDeceased變數用來標識老爺爺是否已經去世,這是一個開關量,因此其型別為boolean,可能的值只有兩個:true或false,預設值為false。

第9~13行程式碼是合約的建構函式,這個特殊的函式將在合約部署的時候自動執行。

public關鍵字被稱為可見性修飾符,它的作用是宣告被修飾的方法是否允許外部呼叫。public意味著在合約內部或外部(由其他合約或其他人)都可以呼叫該方法。

payable關鍵字是solidity的特色之一,它使得被修飾的方法可以傳送或接收以太幣。為建構函式宣告payable關鍵字意味著當我們部署合約的時候,可以直接向合約存入以太幣,例如,作為遺產的50個以太幣。當合約接收到以太幣後,這些幣就儲存在合約 地址上了。

在建構函式內部,我們將owner變數的值設定為msg.sender,這是一個以太坊平臺預置的全域性變數,表示呼叫合約方法的賬號地址,在我們的案例中,這個地址是老爺爺的。

同時我們將fortune變數的值設定為msg.value,這是另一個全域性變數,它表示被呼叫的方法接收到的以太幣的數量。

雖然變數isDeceased被自動初始化為預設值false,但為了清晰起見,我們將其顯式地設定為false。

5、使用solidity修飾符

在solidity中,修飾符(Modifier)可以為函式附加額外的條件邏輯。例如,假設我有一個用來關燈的方法,同時有一個修飾符要求燈開關必須處於on狀態,那麼我們就可以在方法上附加宣告這個修飾符,以便確保只有在燈開關處於on狀態時,才可以呼叫這個方法,否則就丟擲異常。

solidity ide remix

第15行程式碼定義了onlyOwner修飾符。如果一個方法附加聲明瞭這個修飾符,那麼就要求呼叫方法的賬號(msg.sender)必須與owner變數的值一致(別忘了我們在建構函式中設定了owner的值)。這個呼叫條件有助於遺產的分配,我們將在後面看到這一點。

require關鍵字的意思是,括號裡的表示式的值必須為真(true),否則就會丟擲異常,不再繼續執行程式碼。

_;起到佔位符的作用,在執行過程中,以太坊虛擬機器會用被修飾的方法程式碼來替換它。

第20行程式碼定義了mustBeDeceased修飾符。如果一個方法附加聲明瞭這個修飾符,那麼就只有在isDeceased變數值為true時,才可以呼叫該方法,否則就丟擲異常。

在上面的程式碼中,我們使用修飾符來限定方法的執行條件,當然也可以不使用修飾符,而直接在方法實現程式碼中使用require,不過修飾符看起來更高階一些,也更容易實現程式碼的複用。

6、設定遺產分配方案

現在我們要繼續完成遺產在家庭成員之間的分配任務,這需要他們的錢包地址和分配數量。

正如我們之前所述,康萊德將收到20個以太幣而麗莎將繼承30個。讓我們建立一個數組來儲存他們的錢包地址,然後寫一個方法來分配遺產。

solidity ide remix

第25行程式碼定義了一個空陣列familyWallets,用來儲存所有家庭成員的錢包地址。和其他語言一樣,在solidity中陣列是順序存放並且可以使用序號來存取。注意方括號之前的關鍵字paybale,只有address payable型別的變數,才可以接收以太幣,這是0.5版本的solidity與之前版本的區別之一。

第27行程式碼建立了一個從address型別到uint型別的對映表變數inheritance,用來儲存每個錢包地址的遺產數量。這是一個鍵/值對資料結構,類似於其他語言中的字典或雜湊表,可以用鍵來存取值。

第29行程式碼定義了一個方法,它的功能是將一個錢包地址新增到familyWallets陣列,然後設定該地址在inheritance對映表中的遺產數量。注意附加的onlyOwner修飾符,猜一下為什麼我們要在這裡宣告這個修飾符?

第30行程式碼將傳入方法的錢包地址追加到familyWallets陣列的末尾。

第31行程式碼將傳入方法的遺產繼承數量設定為對映表inheritance的指定地址(傳入方法的另一個引數)的值。

7、實現遺產自動分配

讓我們總結一下。到目前為止,我們已經學習了全域性變數、資料型別、建構函式、特殊的關鍵字例如payablepublic、內建的全域性變數例如msg.sendermsg.value、修飾符和require、陣列、對映表和方法。我們已經搭好了合約的框架,現在讓我們把各部分整合起來最終完成合約。

作為這個教程最後一部分的程式碼,我們將實現家庭成員遺產的自動分配。

solidity ide remix

第34行定義了payout()方法,注意private關鍵字,這個可視性修飾符public的反義詞,它只允許被修飾的方法在合約內部呼叫,就像在第42行的程式碼那樣。之所以在這裡使用private,主要是考慮到安全性,因為我們 不希望任何來自合約外部的呼叫。注意最後的mustBeDeceased修飾符,目前我們依然不能滿足這個修飾符要求的條件來執行payout()方法。

第35行程式碼是一個for迴圈,用來遍歷familyWallets陣列。語法如下:

  • 定義一個計數器變數i,
  • 宣告迴圈的執行條件
  • 每個週期計數器變數i加1

第36行程式碼是整個合約的核心,我們呼叫address型別的地址物件的transfer()方法,向該地址轉賬預定的遺產繼承數量,inheritance[familyWallets[i]]表示在inheritance對映表中,鍵familyWallets[i]的值,也就是第i個家庭成員的遺產繼承數量。

第40~42行程式碼定義了一個方法,當老爺爺去世後將呼叫這個方法來觸發遺產的分配。在這裡我們將變數isDeceased的值設定為true。

現在我們完成了嗎?

實際上,還不完全是...

這個智慧合約的程式碼是寫完了,但是我們怎麼用它?現在是收穫果實的時候了。

8、solidity合約部署與互動

你的remix頁面看起來應該像這樣:

solidity ide remix

在remix頁面右邊切換到compile選項頁,確認按下圖選中編譯器的版本,然後點選[start to compile]:

solidity ide remix

你可能會看到靜態分析生成的一個藍色文字框,我們暫時忽略它的提醒,切換到 run選項頁:

solidity ide remix

確保Environment下拉框中選中了Javascript VM,點選account的下拉選單將顯示5個測試賬戶,每個賬戶都有100個以太幣,讓我們選擇第一個。

向以太坊區塊鏈部署合約並不是免費的,部署者需要支付手續費,通常被稱為gas。引入這一機制的目的是避免區塊鏈計算資源被惡意濫用,要進一步瞭解gas,可以檢視這篇文章:1分鐘搞清Gas/ Gas Price/ Gas Limit

gas limit欄位使用預設值就可以了,我們先不修改它。

value欄位表示我們在部署合約時要傳送給合約的以太幣數量。輸入50,還記得 我們在定義建構函式時附加的payable關鍵字嗎?

現在繼續,點選[deploy]。

你可能立刻會注意到3件事。首先,選中的賬戶餘額現在變成了49.9999… ,這是因為 我們轉給合約50個以太幣,還要扣除一點部署手續費。頁面底部的控制檯也會提供 關於部署過程的詳細資訊,你可以檢視一下。現在看起來是這樣:

solidity ide remix

我們的合約已經成功部署了!它生成了自己的地址,並且顯示出我們定義的兩個合約方法。作為合約的持有者,我們要做的第一件事,是設定家庭成員的繼承數量:康萊德(20)、麗莎(30)。假設我們用account下拉選單中的第二個作為康萊德的賬號,麗莎的用第三個。

選擇第二個賬號,點選[拷貝到剪下板]圖示,然後輸入上圖中的setInheritance後面的文字輸入框。

在我們執行setInheritance方法之前,有幾件事情要記住。

傳入合約的以太幣數量的單位是wei而不是以太幣,1 ETH = 1,000,000,000,000,000,000 WEI,這是非常小的單位,因此我們需要將以太幣表示的遺產數量先轉換為以WEI為單位的值。

在將遺產數量換算後,在將其寫入上圖中的setInheritance後面的文字輸入框中,之前輸入的地址後面,這兩個值之間注意要用逗號隔開。

還有,別忘了在account下拉框選中第一個賬號,還記得onlyOwner修飾符嗎?只有合約的持有人才可以呼叫setInheritance方法!

現在讓我們依次為康萊德和麗莎執行setInheritance方法。你應當可以看到控制檯輸出的成功資訊。看一下其中的decoded input

solidity ide remix

你看,它顯示的就是我們輸入的資料。

遺產分配好了,但是壞訊息來了。老爺爺在73歲時,在一次北極探險中不幸因心臟病 突發去世。他總是這麼充滿激情與活力。

當我們紀念這位老爺爺的同時,我們同時呼叫遺囑合約的deceased()方法,完成 老爺爺的最後的願望。。。


原文:solidity 0.5.7簡明