前言

本来网上教程很多,其实可以不用写,自己也是跟着这些教程做的。现在的知识更新的太快,踩了不少坑,就想写出来和大家分享下。希望能帮到大家。我的环境是 macOS majave。

环境准备

  1. go 环境,这个自行百度

  2. Ethereum

    1. 首先,先要安装 homebrew https://brew.sh/index_zh-cn.html
    2. 安装 Ethereum:这里用的是 ethereum 的 go 语言客户端
      1. brew tap ethereum/ethereum
      2. brew install ethereum
    3. 安装好了之后运行:geth version
    Geth
    Version: 1.9.5-stable
    Architecture: amd64
    Protocol Versions: [63]
    Network Id: 1
    Go Version: go1.13
    Operating System: darwin
    GOPATH=/Users/lihuazhang/go
    GOROOT=/usr/local/opt/go/libexec
    
    
  3. 安装以太坊编程语言 Solidity —— brew install solidity

  4. nodejs 环境 —— 自行百度,推荐使用 nvm

  5. 安装 truffle —— npm install –g truffle

准备以太坊私链节点

  1. 创建个目录:比如 ethereum,然后创建一个 json 文件 genesis.json

  2. 创世块配置文件:genesis.json

{
    "nonce": "0x0000000000000042",
    "difficulty": "0x400",
    "mixhash": "0x0000000000000000000000000000000000000000000000000000000000000000",
    "coinbase": "0x0000000000000000000000000000000000000000",
    "timestamp": "0x00",
    "parentHash": "0x0000000000000000000000000000000000000000000000000000000000000000",
    "extraData": "0x11bbe8db4e347b4e8c937c1c8370e4b5ed33adb3db69cbdb7a38e1e50b1b82fa",
    "gasLimit": "0x4c4b4000000",
    "config": {
        "chainId": 15,
        "homesteadBlock": 0,
        "eip150Block": 0,
        "eip155Block": 0,
        "eip158Block": 0,
        "byzantiumBlock": 0,
        "constantinopleBlock": 0,
        "petersburgBlock": 0
    },
    "alloc": {}
}

这里要特别注意:byzantiumBlock,constantinopleBlock,petersburgBlock 几个都要放进去。最新的以太坊版本已经在用 byzantiumBlock 了。如果不加的话,合约编译的时候就要指定拜占庭。否则合约执行的时候会返回莫名其妙的错误,这个坑我踩了很久。

  1. 执行 geth --datadir data/chain0 init genesis.json

  2. 再执行 geth --networkid 15 --datadir data/chain0 --identity "mychain00" --port 30000 --rpc --rpcaddr 0.0.0.0 --rpccorsdomain "*" --rpcport 8545 --rpcapi eth,net,web3,personal --allow-insecure-unlock --nodiscover console 参数自行百度

  3. 进入 console 之后,创建账号:personal.newAccount('123456') # 123456是密码

  4. 开始挖矿,输入 miner.start(),出现下面这种图标就算挖到了。

编写和部署合约

1) 在 ethereum 目录下创建一个目录比如 contracts,然后终端进入到这个 contracts 目录,执行 truffle init 会生成contractsmigrationstest三个目录和truffle-config.js文件

2) contracts 就是智能合约存放的目录,默认情况下已经帮你创建好Migrations.sol合约,不用管它在contracts文件夹下创建一个新文件HelloWorld.sol,文件内容如下:

pragma solidity >=0.4.21 <0.6.0;

contract HelloWorld {

  //say hello world
  function say() public pure returns (string memory ) {
    return "Hello World!";
  }

  //print name
  function print(string memory  name) public pure returns (string memory ) {
    return name;
  }

  function multiply(uint a) public pure returns(uint d) {
        return a * 7;
    }
}

3) 修改migrateions文件中2_deploy_contracts.js的内容,如下:

var HelloWorld = artifacts.require("./HelloWorld.sol");
module.exports = function(deployer) {
   deployer.deploy(HelloWorld);
};

4) 修改truffle-config.js的 networks 部分和 compile 部分内容如下:

development: {
 host: "localhost",     // Localhost (default: none)
 port: 8545,            // 前面部署链的端口
 network_id: "*",       // Any network (default: none)
 gas: 53170200,
 from: "0x4860a6d6f378df07d86a227a5d2a7f553ca68e50" //前面部署链的创建的账号的地址
},
compilers: {
    solc: {
      version: "0.4.25",    // Fetch exact version from solc-bin (default: truffle's version)
      docker: false,        // Use "0.5.1" you've installed locally with docker (default: false)
      settings: {          // See the solidity docs for advice about optimization and evmVersion
       optimizer: {
         enabled: false,
         runs: 200
       },
       evmVersion: "byzantium"
      }
    }
}

5) 编译合约:truffle compile

6) 部署合约:truffle migrate --reset --network development

7) 如果部署的时候,遇到 authentication needed: password or unlock 错误。请解锁账号:去 geth 那个终端执行 personal.unlockAccount(eth.accounts[0], "123456", 10000)

8) 运行部署命令之后,需要交易确认,这个时候需要继续挖矿,把交易打包到下一个区块,在 geth console 里运行 miner.start()

9) 部署成功的日志:

➜  contract truffle migrate --reset --network development

Compiling your contracts...
===========================
> Everything is up to date, there is nothing to compile.



Starting migrations...
======================
> Network name:    'development'
> Network id:      15
> Block gas limit: 0x359abe9aa9


1_initial_migration.js
======================

   Replacing 'Migrations'
   ----------------------
   > transaction hash:    0x6df6bc66f92db8100b6ee015b6277227585752e097d08639295a5303938d4501
   > Blocks: 0            Seconds: 4
   > contract address:    0xAE36440bDbEF7FbFc71dC6508D42E381F80851D8
   > block number:        3200
   > block timestamp:     1570087488
   > account:             0xb36CFa79Ccd84694C6372E94aDF76ae83c09685D
   > balance:             6400
   > gas used:            261393
   > gas price:           20 gwei
   > value sent:          0 ETH
   > total cost:          0.00522786 ETH


   > Saving migration to chain.
   > Saving artifacts
   -------------------------------------
   > Total cost:          0.00522786 ETH


2_deploy_contracts.js
=====================

   Replacing 'HelloWorld'
   ----------------------
   > transaction hash:    0x95687f6120bf9034ce2548c60645750bd38db05f7839c0fd5560ad5d624546ab
   > Blocks: 0            Seconds: 0
   > contract address:    0xE6b2d56B65E2d39B1Bb976bf11813c8366E2DE26
   > block number:        3204
   > block timestamp:     1570087493
   > account:             0xb36CFa79Ccd84694C6372E94aDF76ae83c09685D
   > balance:             6410
   > gas used:            240179
   > gas price:           20 gwei
   > value sent:          0 ETH
   > total cost:          0.00480358 ETH


   > Saving migration to chain.
   > Saving artifacts
   -------------------------------------
   > Total cost:          0.00480358 ETH


Summary
=======
> Total deployments:   2
> Final cost:          0.01003144 ETH

调用合约

  1. 我们已经拿到了合约的地址:0xE6b2d56B65E2d39B1Bb976bf11813c8366E2DE26
  2. 我们要拿到 abi,在 build 目录下面找到对应的 HelloWorld.json,把 abi 那个数组拿出来,需要进行压缩。https://www.sojson.com/yasuo.html
  3. 然后到 geth console 下面把刚刚的挖矿给停了,敲 miner.stop(),别管刷的日志。
  4. 然后敲打:abi=[{"constant":true,"inputs":[],"name":"say","outputs":[{"name":"","type":"string"}],"payable":false,"stateMutability":"pure","type":"function"},{"constant":true,"inputs":[{"name":"name","type":"string"}],"name":"print","outputs":[{"name":"","type":"string"}],"payable":false,"stateMutability":"pure","type":"function"},{"constant":true,"inputs":[{"name":"a","type":"uint256"}],"name":"multiply","outputs":[{"name":"d","type":"uint256"}],"payable":false,"stateMutability":"pure","type":"function"}] 类似这样,你的 abi 和我不一样。
  5. 然后在输入:testContract=eth.contract(abi).at("0xE6b2d56B65E2d39B1Bb976bf11813c8366E2DE26")
  6. 就可以开始使用 testContract 了,试试看 testContract.say()


↙↙↙阅读原文可查看相关链接,并与作者交流