以太坊作為全球領先的智能合約平臺,允許開發(fā)者構(gòu)建去中心化應用(DApps),而Geth(Go-Ethereum)是以太坊官方的Go語言實現(xiàn)客戶端,功能強大且廣泛使用,本文將詳細介紹如何使用Geth客戶端從零開始部署一個智能合約到本地或私有以太坊網(wǎng)絡,整個過程清晰明了,適合有一定區(qū)塊鏈基礎的開發(fā)者參考。

準備工作:環(huán)境與工具

在開始之前,確保你的開發(fā)環(huán)境已準備好以下工具:

  1. Geth客戶端:從Geth官方GitHub倉庫下載適合你操作系統(tǒng)的版本,并安裝,或者使用go get -u github.com/ethereum/go-ethereum命令進行安裝(需要Go環(huán)境)。
  2. Solidity編譯器(solc):用于將Solidity編寫的智能合約編譯成以太坊虛擬機(EVM)可執(zhí)行的字節(jié)碼,可以通過npm安裝:npm install -g solc。
  3. Node.js和npm:用于管理項目依賴和運行一些輔助腳本(如truffle,但本文主要用原生工具)。
  4. 文本編輯器或IDE:如VS Code,用于編寫智能合約和腳本。
  5. 基礎編程知識:Solidity語言基礎和基本的命令行操作。

啟動私有以太坊節(jié)點(可選,推薦用于測試)

為了不影響主網(wǎng),也為了更自由地進行測試,我們通常選擇在本地或私有網(wǎng)絡上部署和測試合約,這里以啟動一個私有Geth節(jié)點為例。

  1. 初始化節(jié)點: 打開終端,創(chuàng)建一個用于存放節(jié)點數(shù)據(jù)的目錄,然后運行初始化命令:

    mkdir myethereum
    cd myethereum
    geth --datadir "./data" init genesis.json

    genesis.json是創(chuàng)世塊文件,你可以自定義一個簡單的創(chuàng)世配置,

    {
      "config": {
        "chainId": 15, // 私有鏈ID,自定義
        "homesteadBlock": 0,
        "eip155Block": 0,
        "eip158Block": 0
      },
      "difficulty": "0x4000",
      "gasLimit": "0xffffffff",
      "alloc": {
        // 可以預分配一些以太坊給某些地址,方便測試
        "0x70997970C51812dc3A010C7d01b50e0d17dc79C8": { "balance": "1000000000000000000000" }
      }
    }
  2. 啟動私有節(jié)點

    geth --datadir "./data" --networkid 15 --http --http.addr "0.0.0.0" --http.port "8545" --http.api "eth,web3,personal,miner,net"
    • --datadir "./data":指定數(shù)據(jù)目錄。
    • --networkid 15:指定網(wǎng)絡ID,與genesis.json中的chainId一致。
    • --http:啟用HTTP-RPC服務。
    • --http.addr "0.0.0.0":允許任何IP訪問。
    • --http.port "8545":指定HTTP端口。
    • --http.api:開放的API接口。

    啟動后,Geth會開始同步區(qū)塊,你可以通過另一個終端窗口使用geth attach http://localhost:8545連接到這個節(jié)點控制臺。

編寫智能合約

我們以一個簡單的Storage合約為例,它允許存儲和讀取一個uint256類型的數(shù)字。

創(chuàng)建一個名為Storage.sol的文件:

// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;
隨機配圖
contract Storage { uint256 private storedData; event DataSet(uint256 newValue); function set(uint256 x) public { storedData = x; emit DataSet(x); } function get() public view returns (uint256) { return storedData; } }

編譯智能合約

  1. 確保solc可用:在終端運行 solc --version 檢查。

  2. 編譯合約: 在Storage.sol文件所在的目錄下,運行以下命令:

    solc --bin --abi Storage.sol -o compiled
    • --bin:生成合約的字節(jié)碼(Bytecode)。
    • --abi:生成合約的應用二進制接口(ABI)。
    • -o compiled:指定輸出目錄為compiled

    執(zhí)行后,你會得到compiled/Storage.bincompiled/Storage.abi兩個文件。

部署合約到Geth節(jié)點

部署合約需要發(fā)送一筆交易到Geth節(jié)點,我們可以通過Geth的JavaScript控制臺來完成。

  1. 連接到Geth節(jié)點: 如果你之前沒有連接,現(xiàn)在運行:

    geth attach http://localhost:8545

    這將打開一個Geth JavaScript交互式環(huán)境。

  2. 解鎖賬戶: 假設你想使用預分配地址0x70997970C51812dc3A010C7d01b50e0d17dc79C8來部署合約,首先需要解鎖該賬戶:

    personal.unlockAccount("0x70997970C51812dc3A010C7d01b50e0d17dc79C8", "your_password")

    (注意:在實際操作中,請確保密碼安全,并且測試網(wǎng)絡可以使用簡單密碼。)

  3. 讀取合約字節(jié)碼和ABI: 在控制臺中,我們需要讀取之前編譯生成的字節(jié)碼和ABI,你可以直接復制粘貼,或者如果你在控制臺所在的目錄有這些文件,可以讀取文件內(nèi)容(Geth控制臺支持Node.js的fs模塊,但更簡單的是直接復制)。 將Storage.bin復制到一個變量中:

    var bytecode = "0x608060405234801561001057600080fd5b5061014f806100206000396000f3fe608060405234801561001057600080fd5b50600436106100415760003560e01c806360fe47b1146100465780636d4ce63c14610064575b600080fd5b61004e610088565b60405161005b91906100d6565b60405180910390f35b61007e6004803603810190610079919061011d565b610091565b60405161008b91906100d6565b60405180910390f35b60008054905090565b60008060009054906101000a900473ffffffffffffffffffffffffffffffffffffffff16816000815181106100cc57fe5b602002602001019073ffffffffffffffffffffffffffffffffffffffff16908173ffffffffffffffffffffffffffffffffffffffff1681525050905050919050565b60008160008151811061011857fe5b6020026020010151905091905056fe"; // 這里替換為你的實際字節(jié)碼,注意0x前綴

    Storage.abi復制到一個變量中:

    var abi = [{"inputs":[],"name":"get","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"x","type":"uint256"}],"name":"set","outputs":[],"stateMutability":"nonpayable","type":"function"}]; // 這里替換為你的實際ABI
  4. 創(chuàng)建合約對象并部署

    var contract = web3.eth.contract(abi);
    var deployTx = {
        from: "0x70997970C51812dc3A010C7d01b50e0d17dc79C8", // 部署者地址
        data: bytecode,
        gas: 2000000 // 指定gas限制,根據(jù)合約復雜度調(diào)整
    };
    var contractInstance = new contract(deployTx);
    contractInstance.new(100, { // new(100) 是構(gòu)造函數(shù)參數(shù),如果Storage合約有構(gòu)造函數(shù)需要參數(shù)的話,這里Storage沒有,所以可以省略,但為了示例