使用Geth和Web3.js部署您的第一個私有以太坊智慧合約

買賣虛擬貨幣
以太坊智慧合約基本上是使用區塊鏈中的以太坊虛擬機器(EVM)執行的程式。建立以太坊地址時,會分配一個以太坊地址,並且每個互動使用一個事務。合約/應用程式將在區塊鏈中具有狀態,並且與之互動時狀態將發生變化。重要的是,一旦合約被髮送到區塊鏈,它就永遠不會改變(它是不可變的)。您可以透過更改再次上載同一個合約,但前一個合約將保持不變,並且它們將在彼此不知情的情況下並行執行。在智慧合約進入主網之前,質量保證和測試至關重要。 如何建立以太坊智慧合約?Solidity是以太坊智慧合約的主要編譯器之一。你可以像這樣在Ubuntu中安裝它。apt-get install solc在本教程中,我將使用Remix的示例合約之一(Owner.sol)。在較高階別上,此合約會將合約的所有者設定為部署它的人。有一個“ getter”可以檢索當前所有者是誰,還有一個“ setter”可以允許當前所有者設定另一個所有者。非常簡單,但可以達到目的。pragma solidity >=0.4.22 <0.7.0;
contract Owner {address private owner;    event OwnerSet(address indexed oldOwner, address indexed newOwner);    modifier isOwner() {        require(msg.sender == owner, "Caller is not owner");        _;
    }    constructor() public {        owner = msg.sender;        emit OwnerSet(address(0), owner);    }function changeOwner(address newOwner) public isOwner {
        emit OwnerSet(owner, newOwner);        owner = newOwner;    }function getOwner() external view returns (address) {        return owner;    }
}快速Remix介紹使用一些示例合約重新Remix載入。我們正在使用的一個在上面稱為Owner.sol。我刪除了本教程中包含的註釋。我將解釋如何與之互動。

我們將從檔案瀏覽器開始在左側選單中進行操作。您只需在這裡選擇Owner.sol。

然後,您想將一個選單選項下移到Solidity Compiler。只需單擊藍色的Compile Owner.sol按鈕。

現在將滑鼠移到Deploy&runtransactions選單。只需單擊橙色Deploy按鈕。

請注意,Remix提供了幾個可使用的資金帳戶。每個賬戶有100以太幣資金。)我將使用從0x5B3開始的第一個帳戶來部署合約。

單擊橙色Deploy後,您將看到部署在deployed Contracts下的合約。你也會注意到它有自己的以太坊地址。

我展開了合約,您可以從那裡看到合約中的兩種方法。帶輸入欄位的“ getter” getOwner和“ setter” changeOwner。我單擊getOwner按鈕並看到部署的地址:0x5B38Da6a701c568545dCfcB03FcB875f56beddC4

我想改變合約的所有者。在頂部,我移動到第二個帳戶,以便能夠複製它,然後移回第一個帳戶,即所有者。

現在從0x5B3帳戶執行changeOwner方法,將新帳戶設定為0xAb8帳戶。

現在我再次執行getOwner方法,並正確地將所有者更改為0xAb8483F64d9C6d1EcF9b849Ae677dD3315835cb2

因此這只是Remix的1分鐘介紹。我建議您自己嘗試一下。嘗試將changeOwner設定為無效地址,或者嘗試使changeOwner不作為所有者,然後看看會發生什麼。

在Ubuntu中使用solc編譯Owner.sol

現在您可能會遇到的一個問題是,Remix中的預設Owner.sol合約使用的編譯器≥0.4.22並且<0.7.0。我的Ubuntu系統上安裝的solc編譯器是0.7.1

# solc --version
solc, the solidity compiler commandline interface
Version: 0.7.1+commit.f4a555be.Linux.g++

對於0.7.1中的合約,語法略有不同。請在下面使用我更改後的Owner.sol。您還可以將Remix中的編譯器版本更改為0.7.1,並也使用此合約。

pragma solidity >=0.4.22 <0.8.0;
contract Owner {
  address public owner;
  event OwnerSet(address indexed oldOwner, address indexed newOwner);
  modifier isOwner() {
    require(msg.sender == owner, "Caller is not owner");
    _;
  }
  constructor() {
    emit OwnerSet(address(0), owner);
    owner = msg.sender;
  }
  function changeOwner(address newOwner) public isOwner {
    emit OwnerSet(owner, newOwner);
    owner = newOwner;
  }
  function getOwner() external view returns (address) {
    return owner;
  }
}

我希望您按照以下方式編譯Owner.sol合約。

~/dapp# solc --combined-json abi,bin Owner.sol > Owner.json
Warning: SPDX license identifier not provided in source file. Before publishing, consider adding a comment containing "SPDX-License-Identifier: <SPDX-License>" to each source file. Use "SPDX-License-Identifier: UNLICENSED" for non-open-source code. Please see https://spdx.org for more information.
--> Owner.sol
~/dapp# cat Owner.json
{"contracts":{"Owner.sol:Owner":{"abi":"[{\"inputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"constructor\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"oldOwner\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"newOwner\",\"type\":\"address\"}],\"name\":\"OwnerSet\",\"type\":\"event\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"newOwner\",\"type\":\"address\"}],\"name\":\"changeOwner\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"getOwner\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"owner\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"}]","bin":"608060405234801561001057600080fd5b5060008054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16600073ffffffffffffffffffffffffffffffffffffffff167f342827c97908e5e2f71151c08502a66d44b6f758e3ac2f1de95f02eb95f0a73560405160405180910390a3336000806101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff1602179055506102f3806100db6000396000f3fe608060405234801561001057600080fd5b50600436106100415760003560e01c8063893d20e8146100465780638da5cb5b1461007a578063a6f9dae1146100ae575b600080fd5b61004e6100f2565b604051808273ffffffffffffffffffffffffffffffffffffffff16815260200191505060405180910390f35b61008261011b565b604051808273ffffffffffffffffffffffffffffffffffffffff16815260200191505060405180910390f35b6100f0600480360360208110156100c457600080fd5b81019080803573ffffffffffffffffffffffffffffffffffffffff16906020019092919050505061013f565b005b60008060009054906101000a900473ffffffffffffffffffffffffffffffffffffffff16905090565b60008054906101000a900473ffffffffffffffffffffffffffffffffffffffff1681565b60008054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff1614610200576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004018080602001828103825260138152602001807f43616c6c6572206973206e6f74206f776e65720000000000000000000000000081525060200191505060405180910390fd5b8073ffffffffffffffffffffffffffffffffffffffff1660008054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff167f342827c97908e5e2f71151c08502a66d44b6f758e3ac2f1de95f02eb95f0a73560405160405180910390a3806000806101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff1602179055505056fea2646970667358221220ba9a494e8dd99908b8c962ed752cac0bf679199c5c8dad87d13f5f9d9088c39c64736f6c63430007010033"}},"version":"0.7.1+commit.f4a555be.Linux.g++"}

為了方便地讀取這個JSON輸出,我建議安裝“jq”。

apt-get install jq -y
~/dapp# cat Owner.json | jq .
{
  "contracts": {
    "Owner.sol:Owner": {
      "abi": "[{\"inputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"constructor\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"oldOwner\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"newOwner\",\"type\":\"address\"}],\"name\":\"OwnerSet\",\"type\":\"event\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"newOwner\",\"type\":\"address\"}],\"name\":\"changeOwner\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"getOwner\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"owner\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"}]",
      "bin": "608060405234801561001057600080fd5b5060008054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16600073ffffffffffffffffffffffffffffffffffffffff167f342827c97908e5e2f71151c08502a66d44b6f758e3ac2f1de95f02eb95f0a73560405160405180910390a3336000806101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff1602179055506102f3806100db6000396000f3fe608060405234801561001057600080fd5b50600436106100415760003560e01c8063893d20e8146100465780638da5cb5b1461007a578063a6f9dae1146100ae575b600080fd5b61004e6100f2565b604051808273ffffffffffffffffffffffffffffffffffffffff16815260200191505060405180910390f35b61008261011b565b604051808273ffffffffffffffffffffffffffffffffffffffff16815260200191505060405180910390f35b6100f0600480360360208110156100c457600080fd5b81019080803573ffffffffffffffffffffffffffffffffffffffff16906020019092919050505061013f565b005b60008060009054906101000a900473ffffffffffffffffffffffffffffffffffffffff16905090565b60008054906101000a900473ffffffffffffffffffffffffffffffffffffffff1681565b60008054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff1614610200576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004018080602001828103825260138152602001807f43616c6c6572206973206e6f74206f776e65720000000000000000000000000081525060200191505060405180910390fd5b8073ffffffffffffffffffffffffffffffffffffffff1660008054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff167f342827c97908e5e2f71151c08502a66d44b6f758e3ac2f1de95f02eb95f0a73560405160405180910390a3806000806101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff1602179055505056fea2646970667358221220ba9a494e8dd99908b8c962ed752cac0bf679199c5c8dad87d13f5f9d9088c39c64736f6c63430007010033"
    }
  },
  "version": "0.7.1+commit.f4a555be.Linux.g++"
}

現在,對於下一部分,您將需要一個以太坊Geth節點來安裝智慧合約。

我現在要連線到我的工作節點…

~/geth# ./2020-attach.sh
Welcome to the Geth JavaScript console!
instance: Geth/v1.9.21-stable-0287d548/linux-amd64/go1.15
coinbase: 0x6be8a6cad397746efc5033e27e82477e27c9afec
at block: 3981 (Tue Sep 22 2020 22:44:03 GMT+0100 (BST))
datadir: /root/.ethereum/net2020
modules: admin:1.0 debug:1.0 eth:1.0 ethash:1.0 miner:1.0 net:1.0 personal:1.0 rpc:1.0 txpool:1.0 web3:1.0
> eth.blockNumber
3983

要部署合約,請執行以下操作。

> var ownerContractCompiled = {"contracts":{"Owner.sol:Owner":{"abi":"[{\"inputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"constructor\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"oldOwner\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"newOwner\",\"type\":\"address\"}],\"name\":\"OwnerSet\",\"type\":\"event\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"newOwner\",\"type\":\"address\"}],\"name\":\"changeOwner\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"getOwner\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"owner\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"}]","bin":"608060405234801561001057600080fd5b5060008054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16600073ffffffffffffffffffffffffffffffffffffffff167f342827c97908e5e2f71151c08502a66d44b6f758e3ac2f1de95f02eb95f0a73560405160405180910390a3336000806101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff1602179055506102f3806100db6000396000f3fe608060405234801561001057600080fd5b50600436106100415760003560e01c8063893d20e8146100465780638da5cb5b1461007a578063a6f9dae1146100ae575b600080fd5b61004e6100f2565b604051808273ffffffffffffffffffffffffffffffffffffffff16815260200191505060405180910390f35b61008261011b565b604051808273ffffffffffffffffffffffffffffffffffffffff16815260200191505060405180910390f35b6100f0600480360360208110156100c457600080fd5b81019080803573ffffffffffffffffffffffffffffffffffffffff16906020019092919050505061013f565b005b60008060009054906101000a900473ffffffffffffffffffffffffffffffffffffffff16905090565b60008054906101000a900473ffffffffffffffffffffffffffffffffffffffff1681565b60008054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff1614610200576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004018080602001828103825260138152602001807f43616c6c6572206973206e6f74206f776e65720000000000000000000000000081525060200191505060405180910390fd5b8073ffffffffffffffffffffffffffffffffffffffff1660008054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff167f342827c97908e5e2f71151c08502a66d44b6f758e3ac2f1de95f02eb95f0a73560405160405180910390a3806000806101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff1602179055505056fea2646970667358221220ba9a494e8dd99908b8c962ed752cac0bf679199c5c8dad87d13f5f9d9088c39c64736f6c63430007010033"}},"version":"0.7.1+commit.f4a555be.Linux.g++"}

> typeof ownerContractCompiled.contracts["Owner.sol:Owner"].abi
"string"

> var ownerContract = eth.contract(JSON.parse(ownerContractCompiled.contracts["Owner.sol:Owner"].abi))

> eth.mining
true    <--   make sure you are mining or miner.start(1)

> eth.coinbase
"0x6be8a6cad397746efc5033e27e82477e27c9afec"   <--   you will have your own address
> var deployTransactionObject = { from: eth.coinbase, data: "0x" + ownerContractCompiled.contracts["Owner.sol:Owner"].bin, gas: 1000000 }

> personal.unlockAccount(eth.coinbase)
Unlock account 0x6be8a6cad397746efc5033e27e82477e27c9afec
Passphrase:
true

> var ownerContractInstance = ownerContract.new(deployTransactionObject)

請注意,合約已部署,我們的兩種方法都在這裡。

> ownerContractInstance
{
  abi: [{
    inputs: [],
    stateMutability: "nonpayable",
    type: "constructor"
  }, {
  anonymous: false,
    inputs: [{...}, {...}],
    name: "OwnerSet",
    type: "event"
  }, {
  inputs: [{...}],
    name: "changeOwner",
    outputs: [],
    stateMutability: "nonpayable",
    type: "function"
  }, {
  inputs: [],
    name: "getOwner",
    outputs: [{...}],
    stateMutability: "view",
    type: "function"
  }, {
  inputs: [],
    name: "owner",
    outputs: [{...}],
    stateMutability: "view",
    type: "function"
  }],
  address: "0xb2c455aa1ac281180b4faca7b8896092169ccd55",
  transactionHash: "0x38391d46e37e79b7764df2ba31cc32ff45457e2a33a5826b8af15fce9a0e5cf2",
  OwnerSet: function(),
  allEvents: function(),
  changeOwner: function(),
  getOwner: function(),
  owner: function()
}

區塊鏈中有交易收據。

> eth.getTransactionReceipt(ownerContractInstance.transactionHash);
{
  blockHash: "0x94a0e3c9c9d562c34061147e1ef21f9260178693df124ff81cba37f1818fa8a7",
  blockNumber: 4061,
  contractAddress: "0xb2c455aa1ac281180b4faca7b8896092169ccd55",
  cumulativeGasUsed: 287352,
  from: "0x6be8a6cad397746efc5033e27e82477e27c9afec",
  gasUsed: 287352,
  logs: [{
    address: "0xb2c455aa1ac281180b4faca7b8896092169ccd55",
    blockHash: "0x94a0e3c9c9d562c34061147e1ef21f9260178693df124ff81cba37f1818fa8a7",
  blockNumber: 4061,
  data: "0x",
  logIndex: 0,
  removed: false,
  topics: ["0x342827c97908e5e2f71151c08502a66d44b6f758e3ac2f1de95f02eb95f0a735", "0x0000000000000000000000000000000000000000000000000000000000000000", "0x0000000000000000000000000000000000000000000000000000000000000000"],
  transactionHash: "0x38391d46e37e79b7764df2ba31cc32ff45457e2a33a5826b8af15fce9a0e5cf2",
  transactionIndex: 0
  }],
  logsBloom: "0x00000000000000000000000000000000000000000400000000000000000000000000000000000000000000040000000000000000000000000000000000000000000000002000000000000000800000000000000000000000000000000000000000000000020000000000000000000800000000000000000000000000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000004000000000000000000000000000000000",
  root: "0xb37e7b1b1e55b358585677fe3cad149e859540f8981c0d9c57d8adc5af536c20",
  to: null,
  transactionHash: "0x38391d46e37e79b7764df2ba31cc32ff45457e2a33a5826b8af15fce9a0e5cf2",
  transactionIndex: 0
}

合約已部署並正常工作。您將不希望一遍又一遍地部署合約以與之整合。這就是您與現有合約進行互動的方式。

> var ownerContractAddress = eth.getTransactionReceipt(ownerContractInstance.transactionHash).contractAddress
> ownerContractAddress
"0xb2c455aa1ac281180b4faca7b8896092169ccd55"

現在你可以在這裡提供合約地址。我們正在使用一個變數,但您也可以提供實際地址。請注意以前使用的“.at”而不是“.new”。這意味著您希望檢索現有合約,而不是建立新合約。

> var ownerContractInstance = ownerContract.at(ownerContractAddress)

任何人都可以檢索合約二進位制檔案。

> var deployedBinary = eth.getCode(ownerContractAddress)
> ("0x" + ownerContractCompiled.contracts["Owner.sol:Owner"].bin.substring(2 + ownerContractCompiled.contracts["Owner.sol:Owner"].bin.length - deployedBinary.length)).localeCompare(deployedBinary);
0   <--   this means the contract is the same as the contract deployed

這就是我們訪問合約方法的方式。

> ownerContractInstance.getOwner()
> ownerContractInstance.setOwner(eth.accounts[1], { from: eth.accounts[0] })

使用React.js或Node.js庫(Web3.js)與您的智慧合約進行互動。

因此,讓我們開始建立一個非常基本的React.js應用程式。我將使用“ create-react-app”工具建立預設應用程式。

% create-react-app mediumtutorialCreating a new React app in /Repos/React/mediumtutorial.*** INSTALL PROCESS ***Success! Created mediumtutorial at /Repos/React/mediumtutorialInside that directory, you can run several commands:yarn start
Starts the development server.yarn build
Bundles the app into static files for production.yarn test
Starts the test runner.yarn eject
Removes this tool and copies build dependencies, configuration files and scripts into the app directory. If you do this, you can’t go back!We suggest that you begin by typing:cd mediumtutorial
yarn startHappy hacking!

按照說明,如果您將目錄更改為“ mediumtutorial”和“ yarn start”,它將開啟您的預設瀏覽器,您應該會看到。

% cd mediumtutorial
mediumtutorial % yarn add web3

該庫可用於Node.js和React.js。您可以像這樣與Geth節點RPC進行互動。

let web3 = new Web3('ws://localhost:8546');

免責聲明:

  1. 本文版權歸原作者所有,僅代表作者本人觀點,不代表鏈報觀點或立場。
  2. 如發現文章、圖片等侵權行爲,侵權責任將由作者本人承擔。
  3. 鏈報僅提供相關項目信息,不構成任何投資建議

推荐阅读

;