Solidity 的運作方式可以分解為三個主要步驟:編寫、編譯 和 執行。開發者能用人類能懂的語言寫程式,然後編譯器將其翻譯成機器語言,最終由各節點在去中心化的環境中執行。
1. 編寫 (Writing)
首先,開發者使用 Solidity 語言來編寫智能合約。這段程式碼包含了合約的邏輯、規則和變數,例如一個代幣合約如何處理轉帳、或一個拍賣合約如何管理出價。
2. 編譯 (Compiling)
寫好的 Solidity 程式碼是人類可讀的,但區塊鏈的底層虛擬機(例如 EVM,以太坊虛擬機)無法直接理解。因此,我們需要使用一個稱為 Solidity 編譯器 (solc) 的工具,將程式碼轉換成 EVM 能夠執行的 位元碼 (bytecode)。
這個位元碼是合約的機器語言,由一系列低階的指令(稱為 opcode)組成。編譯過程還會產生 ABI (Application Binary Interface),它就像是合約的公開介面說明書,告訴外界如何與合約互動。
3. 執行 (Executing)
一旦合約被編譯成位元碼,它就可以被部署到區塊鏈上。當用戶與合約互動(例如呼叫一個函式)時,這個過程會在所有運行區塊鏈網路的節點上發生。
- 交易 (Transaction):如果互動會改變區塊鏈的狀態(例如發送代幣),那麼這會是一個交易。這筆交易會被發送到網路上,由礦工或驗證者打包到區塊中。
- 節點運算:每個節點的底層虛擬機都會載入合約的位元碼,並執行其中的指令。節點EVM 會追蹤所有的狀態變動,並確保每個節點都得到相同的結果。這就是區塊鏈達成共識的關鍵。
Solidity範例
以下是Solidity可顯示Hello World的範例程式碼
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.20;
contract HelloWorld {
string public message;
constructor() {
message = "Hello World";
}
function updateMessage(string memory _newMessage) public {
message = _newMessage;
}
}
程式碼解說
pragma solidity ^0.8.20;
: 指定編譯器版本。這行告訴編譯器,這個合約需要使用0.8.20
或更新,但不高於0.9.0
的 Solidity 版本來編譯。contract HelloWorld { ... }
: 這是定義一個智能合約的關鍵字。HelloWorld
是這個合約的名稱。string public message;
:string
是一種用於儲存文字的變數類型。public
關鍵字很特別。當你將一個狀態變數設為public
時,Solidity 會自動為你創建一個同名的getter
函式。這意味著,任何人都可以透過呼叫message()
這個函式來讀取message
變數的值,而不需要我們自己手動寫一個getMessage
的函式。
constructor() { ... }
: 建構函式,只在合約部署到區塊鏈時執行一次。在這裡,我們將message
的初始值設定為"Hello World"
。function updateMessage(string memory _newMessage) public { ... }
:updateMessage
是一個公共函式,任何人都可以呼叫它。- 它接受一個名為
_newMessage
的參數,類型是string memory
。memory
表示這個字串是儲存在記憶體中,只在函式執行期間存在。 - 函式內部,我們將
message
的值更新為傳入的_newMessage
。由於這會改變區塊鏈的狀態,因此執行這個函式需要花費 Gas。
Remix IDE
Remix IDE (Integrated Development Environment,整合式開發環境) 是一個專為開發、測試和部署智能合約 (Smart Contracts) 而設計的強大開源工具。它最主要的優點是基於網頁,你不需要安裝任何東西,只需要一個瀏覽器就能開始使用。
將上述範例程式碼貼到 Remix IDE(一個線上開發環境)中,然後:
- 點擊左側的「
Compile
」標籤,編譯合約。 - 切換到「
Deploy & Run Transactions
」標籤,部署合約。 - 部署完成後,在
Deployed Contracts
下方看到合約的介面。- 每次佈署都會產生新的contract address,如果佈署多次會出現多個,選擇其中一個佈署的合約地址即可
- 展開合約,下方會出現一個新的區塊,顯示你合約中的所有
public
和external
函式。- 紅色按鈕: 代表這個函式會 修改 區塊鏈的狀態 (需要花費 Gas)。
- 藍色按鈕: 代表這個函式只會 讀取 區塊鏈的狀態 (不需要花費 Gas)。
- 藍色按鈕測試,可點擊
message
按鈕就會出現0:string: Hello World
。 - 紅色按鈕測試,可在
updateMessage
函式旁的輸入框中,輸入想更改的新訊息(例如"Hello Blockchain"
),然後點擊updateMessage
按鈕。可以注意到訊息提到花費了32263 gas - 再次點擊
message
按鈕就會出現0:string: Hello Blockchain
,會發現訊息已經被成功更新。
Environment (環境)
在 Remix IDE的Deploy & Run Transactions
中,Environment可指定在哪個區塊鏈環境中執行你的合約,決定了你的合約會部署到哪裡。
Remix VM
(Remix 虛擬機):這是 Remix 內建的模擬區塊鏈環境。- 優點: 區塊鏈的運作速度非常快,不需要連接到任何外部網路,所有交易都是即時的。你可以免費測試合約,不需要花費任何 Gas。
- 缺點: 交易記錄只存在於瀏覽器中,刷新頁面後會消失。這是一個隔離的沙盒環境,不具備真實的區塊鏈功能。
Injected Provider
:這個選項會連接你瀏覽器中的錢包擴充程式,例如 MetaMask。- 優點: 讓你可以在真實的區塊鏈網路(如主網、測試網或本地網路)上部署和互動合約。你可以使用你的真實帳戶並花費真實的 Gas。
- 缺點: 需要連接到網路,交易需要等待區塊確認時間,並且會消耗真實的 Gas。
Hardhat Provider
:這選項讓你連接到本地端運行的開發環境。- 優點: 提供了更強大的開發和測試功能,適合進階開發者。
- 缺點: 需要額外設定本地開發環境。
Account (帳戶)
在 Remix IDE的Deploy & Run Transactions
中,Account用來選擇一個帳戶來部署或執行交易。
Remix VM
: 這裡會預設提供幾個帶有虛擬資金的測試帳戶,你可以任意選擇一個來使用,不用擔心花費。Injected Provider
: 這個列表會顯示你連接的 MetaMask 錢包中所有可用的帳戶。
ABI
ABI (Application Binary Interface)就像是合約的「說明書」,用來定義合約中所有函式的公開介面。有了這個 ABI,外部應用程式(如 Remix IDE、MetaMask 錢包或任何 dApp)才能知道如何與你的智能合約互動。
Remix的Compile頁面下方可以產生ABI,分區說明如下
1. 建構函式 (Constructor)
{
"inputs": [],
"stateMutability": "nonpayable",
"type": "constructor"
}
type: "constructor"
:這部分說明了這是一個建構函式,只在合約部署時執行一次。inputs: []
:空的陣列表示這個建構函式不接受任何參數。stateMutability: "nonpayable"
:表示這個函式會修改區塊鏈的狀態(例如設定初始訊息),因此需要支付 Gas 費用。
2. updateMessage
函式
{
"inputs": [
{
"internalType": "string",
"name": "_newMessage",
"type": "string"
}
],
"name": "updateMessage",
"outputs": [],
"stateMutability": "nonpayable",
"type": "function"
}
type: "function"
:這是一個普通的函式。name: "updateMessage"
:函式的名稱。inputs
:這個函式接受一個參數:name: "_newMessage"
:參數的名稱。type: "string"
:參數的類型是字串。
outputs: []
:空的陣列表示這個函式不回傳任何值。stateMutability: "nonpayable"
:表示這個函式會修改區塊鏈的狀態(更新訊息),因此需要支付 Gas 費用。
3. message
函式
{
"inputs": [],
"name": "message",
"outputs": [
{
"internalType": "string",
"name": "",
"type": "string"
}
],
"stateMutability": "view",
"type": "function"
}
type: "function"
:這是一個普通的函式。name: "message"
:函式的名稱。inputs: []
:空的陣列表示這個函式不接受任何參數。outputs
:這個函式有一個回傳值:type: "string"
:回傳值的類型是字串。
stateMutability: "view"
:這是最重要的部分。它表明這個函式是一個 只讀函式,它不會修改區塊鏈的狀態。因此,呼叫這個函式是 免費的,不需要支付 Gas 費用。