iT邦幫忙

第 11 屆 iThome 鐵人賽

DAY 5
1
Blockchain

區塊練起來-智能合約與DApp開發系列 第 5

[區塊練起來-智能合約與DApp開發] DAY 05 - HelloWorld合約

貼心小語

上一篇已經將開發智能合約時會使用到的工具安裝好並學會基本知識,此篇開始會講解 Solidity 這個語言並實作智能合約。


Solidity簡介

https://ithelp.ithome.com.tw/upload/images/20190809/20119338GhV5QRV9lp.png
圖片來源:維基百科

Solidiy 是一個合約導向的語言,是靜態語言,它的語法跟 JavaScript 有些相近,對於 JavaScript 的使用者而言,會比較容易上手,我認為這樣的設計,能夠促進 DApp 的開發,畢竟在語言的學習上成本相對較低!

網路上有 Solidity 的相關資料,但在閱讀時要看好版本,因為 Solidity 現階段還不夠穩定,會經常有變動,在不同版本可能會有語法上的差異,這邊我們會使用 0.5.0 版進行開發,是較新的版本。

那是不是應該要安裝 Solidity 的相關程式呢?在前一篇安裝 Truffle 的同時,就連同 Solidity 一起安裝了,所以不需要額外安裝囉/images/emoticon/emoticon01.gif

那廢話不多說,馬上進入 Solidity 基本結構!

基本結構

版本定義

在開頭第一行一定要先定義使用的 Solidity 版本,讓編譯器知道怎麼編譯智能合約,那要定義的話就使用 pragma 關鍵字,比較常見的定義方式如下,使用 ^ 來定義 最低可接受版本數

pragma solidity ^0.5.0;

那也可以設定版本區間,方法很簡單且直觀,如下:

pragma solidity >=0.4.21 <0.6.0;

合約定義

定義合約就像物件導向語言定義類別一樣,在物件導向語言裡定義類別用 class ,在 Solidity 裡定義合約用 contract ,並且可以設置 constructor ,如下:

pragma solidity ^0.5.0;

contract HelloWorld {
  string public message;
  constructor() public {
    message = "HelloWorld";
  }
}

從上方的範例程式碼可以發現, public 放在後方而不是前方,這個很重要,在 Solidity 中,定義 publicprivate 是寫在後方的!

constructor 可以有參數,只要在部署合約時,連同參數一同部署即可,如下:

pragma solidity ^0.5.0;

contract HelloWorld {
  string public message;
  constructor(string memory text) public {
    message = text;
  }
}

咦?為什麼參數裡面除了型別以外還多了個 memory 呢?嘿嘿,先小賣關子,請繼續往下看/images/emoticon/emoticon07.gif

狀態變數

在 Solidity 中,狀態變數就是在合約中的全域變數,會永久儲存在區塊鏈中的,所謂的「改變合約狀態」就是指「變更狀態變數」,狀態變數宣告如下:

pragma solidity ^0.5.0;

contract HelloWorld {
  string public message;
}

Memory/Storage

了解狀態變數後就可以來說說 memory 以及 storage

  • memory:為暫時使用的變數,當執行完函式時這個變數就會被移除,有點類似區域變數的概念。
  • storage:為儲存在區塊鏈中的變數,狀態變數默認就是 storage ,有點類似全域變數的概念。

函式

以物件導向的角度來看,可以將函式看成是合約中的方法。
若有回傳值,將回傳值的型別寫在後方,使用 returns 保留字。
會用 修飾詞 來定義該函式是否有修改或讀取狀態變數,主要的目的是減少 Gas 的消耗,共分為兩種:

  • view :有讀取狀態變數,但沒有改變狀態變數時可以使用。
  • pure :沒有讀取也沒有改變狀態變數時可以使用。
    範例如下:
pragma solidity ^0.5.0;

contract HelloWorld {
  string public message;
  
  constructor(string memory text) public {
    message = text;
  }
  
  function print(string memory name) public pure returns (string memory) {
    return name;
  }
    
  function alert() public view returns(string memory) {
    return message;
  }
}

上方的範例就是一個簡單的 HelloWorld 合約了!那來進行合約的測試吧!

測試合約

先將Ganache打開並且把HelloWorld合約編譯好,再來要設定部署檔,這邊我們直接修改 1_initial_migration.js ,並設定constructor的參數,這邊範例參數為 HelloWorld!

const HelloWorld = artifacts.require("HelloWorld");

module.exports = function(deployer) {
  deployer.deploy(HelloWorld, 'HelloWorld!');
};

調整完畢後進行部署:

truffle migrate

接著就是重頭戲了,要使用 Truffle 的 console 模式來進行測試,輸入指令:

truffle console

此時會進入 console 模式,使用的語法為 JavaScript ,這邊我們先宣告一個變數待會用來存放合約實體:

let contract

接著要找出已部署的 HelloWorld 合約,並把合約實體存入 contract 變數中:

HelloWorld.deployed().then(instance => contract = instance)

把合約實體存入後,就可以呼叫合約中的函式,先呼叫 alert 函式:

contract.alert()

就會看到 HelloWorld! 字串,接著來測試 print 函式:

contract.print("HAO")

會看到 HAO 字串。


今日小結

今天學習到智能合約撰寫的基本架構,如:版本定義、合約定義、 memory 與 storage 等,並且完成 HelloWorld 智能合約,還透過 Truffle 進行測試。


參考資料

Solidity 中 storage 和 memory 的区别问题


上一篇
[區塊練起來-智能合約與DApp開發] DAY 04 - 智能合約開發工具
下一篇
[區塊練起來-智能合約與DApp開發] DAY 06 - Solidity 型別
系列文
區塊練起來-智能合約與DApp開發31
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

1 則留言

0
tytom2003
iT邦新手 5 級 ‧ 2021-01-21 14:35:02

當我在remix compile helloworld.sol時,他出現"browser/HelloWorld.sol:14:2: DeclarationError: Identifier already declared. function message() public view returns(string memory) { ^ (Relevant source part starts here and spans across multiple lines). browser/HelloWorld.sol:5:3: The previous declaration is here: string public message; ^-------------------^" 這個error.

HAO iT邦研究生 3 級 ‧ 2021-01-24 14:53:13 檢舉

抱歉,範例裡面重複命名 message 了,function 應該為 alert,我馬上修正,謝謝提醒!

我要留言

立即登入留言