搭建以太坊测试网络(私有网络)

搭建以太坊测试网络(私有网络)
搭建以太坊测试网络(私有网络)

做 Dapp 开发前必须有一个本地的客户端节点,直接使用主网因为需要耗费以太币肯定不现实。使用测试网络又涉及到同步巨量的区块,非常费时费带宽,还费硬盘。所以对于本地开发Dapp,比较合适的方法是搭建一个以太坊私有网络,本文记录两种方法在本地搭建测试网络的方法。

目录

    • 2.2 运行 geth 执行挖矿
    • 2.3 通过 curl 访问 RPC 接口
    • 2.4 通过 web3 访问接口

使用 Ganache

 Ganache /ɡəˈnæʃ/ – ONE CLICK BLOCKCHAIN。 

使用这种方法最快、最简单、简单到没朋友,直接到 Ganache 官方网站 下载,安装,运行,结束。

它自带dashboard、自带挖矿功能、自动创建10个无密码的账号,每个账号内置 100 ETH可随便使用。运行效果如下图所示:

搭建以太坊测试网络(私有网络)
搭建以太坊测试网络(私有网络)

和普通的以太坊客户端一样,Ganache 通过HTTP提供了一个RPC服务,Dapp 通过 RPC 接口实现“发送交易”,“部署智能合约”等操作。通过 http://127.0.0.1:7454 访问 Gonache 的RPC接口,以太坊完整的 API 列表参考 社区wiki

$ curl http://127.0.0.1:7545/ -XPOST --header 'content-type:application/json' -d '{"jsonrpc":"2.0","method":"net_version","params":[],"id":116}'
{"id":67,"jsonrpc":"2.0","result":"5777"}

使用 Geth

Geth 是 go 语言实现的以太坊 client,目前使用量最大。Geth 官方网站已经提供了各种操作系统预编译好可执行文档,不再需要从源码安装了。 下载地址

搭建以太坊测试网络(私有网络)
搭建以太坊测试网络(私有网络)

下载完成后会得到一个 geth 命令行工具,gtt 将演示在 mac 上如何运行 geth。

搭建一个最基础的区块链网络只有2个步骤:1. 生成创世区块配置。2. 运行 geth 执行挖矿。搭建完成后 gtt 将演示如何在账户之间转账。操作开始

配置创世区块

首先创建一个目录 gethdata , 在目录下新建文档 genesis.json ,写入如下内容

{
    "config": {
        "chainId": 116,
        "homesteadBlock": 0,
        "eip155Block": 0,
        "eip158Block": 0
    },
    "difficulty": "0x400",
    "gasLimit": "0x8000000",
    "alloc": {}
}
  • config :一条链的主要配置,完整的 config 配置说明可以参考 源代码
  • chainid :用来防止重放攻击,在 EIP-155 中提出的。比如 chainid=1 是主网,因为是本地测试网络,所以随便取了一个 116。
  • homesteadBlock :如果是 homestead 版本之后,这个值都设置成 0 即可。Homestead 是以太坊在2016年2月29日正式对外发布的的第二个版本, 官方博客当时发布的文章 ,在这之前的版本叫 Frontier。
  • eip155Blockeip158Block 都是一些 EIP 的加强功能,都设为0表示开启。
  • difficulty : 挖矿的难度,难度约高则出块的时间越长,本地测试网络所以设置的小一些。2018年12月主网的该值为:2,377,570,306,002,620。
  • gasLimit :每个块的gas上限。
  • alloc :预分配给某些账户一些以太币,比如Ganache中默认创建的10个账号每人100以太币可以通过这个配置实现。gtt这里不预分配,接下来通过挖矿来获取以太币。

使用创世区块配置文档生成创世区块:

$ geth init --datadir data genesis.json
INFO [12-11|22:13:20.915] Maximum peer count                       ETH=25 LES=0 total=25
INFO [12-11|22:13:20.925] Allocated cache and file handles         database=/Users/hate/gethdata/data/geth/chaindata cache=16 handles=16
INFO [12-11|22:13:20.929] Writing custom genesis block
INFO [12-11|22:13:20.929] Persisted trie from memory database      nodes=0 size=0.00B time=13.76µs gcnodes=0 gcsize=0.00B gctime=0s livenodes=1 livesize=0.00B
INFO [12-11|22:13:20.929] Successfully wrote genesis state         database=chaindata                                hash=d1a12d…4c8725
INFO [12-11|22:13:20.929] Allocated cache and file handles         database=/Users/hate/gethdata/data/geth/lightchaindata cache=16 handles=16
INFO [12-11|22:13:20.932] Writing custom genesis block
INFO [12-11|22:13:20.932] Persisted trie from memory database      nodes=0 size=0.00B time=1.508µs gcnodes=0 gcsize=0.00B gctime=0s livenodes=1 livesize=0.00B
INFO [12-11|22:13:20.933] Successfully wrote genesis state         database=lightchaindata                                hash=d1a12d…4c8725

生成的目录结构如下,geth 使用LevelDB 保存区块,位于 data/geth/chaindata 目录中 :

$ tree data/
data/
├── geth
│   ├── chaindata
│   │   ├── 000001.log
│   │   ├── CURRENT
│   │   ├── LOCK
│   │   ├── LOG
│   │   └── MANIFEST-000000
│   └── lightchaindata
│       ├── 000001.log
│       ├── CURRENT
│       ├── LOCK
│       ├── LOG
│       └── MANIFEST-000000
└── keystore

运行 geth 执行挖矿

以太坊会奖励挖到矿的矿工以太币,所以生成一个账号用于接收奖励的以太币,记住一定要指定 –datadir,否则账号会被生成到其他奇怪的地方:

$ geth --datadir data account new
INFO [12-11|22:20:33.398] Maximum peer count                       ETH=25 LES=0 total=25
Your new account is locked with a password. Please give a password. Do not forget this password.
Passphrase:
Repeat passphrase:
Address: {9b22aa106d97dd76369f6a6985219a914ffa9212}

输入两次密码即可, 9b22aa106d97dd76369f6a6985219a914ffa9212 是账号的公钥。这里所有的技术资料都会强调 必须记住这个密码 ,因为没有任何找回密码的方法,一旦密码丢失或者被忘记,这个账号里的以太币将会永远尘封。因为我们是测试网络,真的忘记了也没关系。

接下来正式运行 geth 节点,开始挖矿:

$ geth --datadir data --port 8545 --rpc --rpcapi "eth,net,rpc,web,personal,admin,web3" --mine --miner.threads 1
INFO [12-11|22:25:55.335] Maximum peer count                       ETH=25 LES=0 total=25
INFO [12-11|22:25:55.346] Starting peer-to-peer node               instance=Geth/v1.8.19-stable-dae82f09/darwin-amd64/go1.11.2
INFO [12-11|22:25:55.346] Allocated cache and file handles         database=/Users/hate/gethdata/data/geth/chaindata cache=512 handles=1024
INFO [12-11|22:25:55.358] Initialised chain configuration          config="{ChainID: 987 Homestead: 0 DAO: <nil> DAOSupport: false EIP150: <nil> EIP155: 0 EIP158: 0 Byzantium: <nil> Constantinople: <nil> Engine: unknown}"
INFO [12-11|22:25:55.358] Disk storage enabled for ethash caches   dir=/Users/hate/gethdata/data/geth/ethash count=3
INFO [12-11|22:25:55.358] Disk storage enabled for ethash DAGs     dir=/Users/hate/.ethash                   count=2
INFO [12-11|22:25:55.358] Initialising Ethereum protocol           versions="[63 62]" network=1
INFO [12-11|22:25:55.421] Loaded most recent local header          number=0 hash=d1a12d…4c8725 td=1024 age=49y7mo3w
INFO [12-11|22:25:55.421] Loaded most recent local full block      number=0 hash=d1a12d…4c8725 td=1024 age=49y7mo3w
INFO [12-11|22:25:55.421] Loaded most recent local fast block      number=0 hash=d1a12d…4c8725 td=1024 age=49y7mo3w
INFO [12-11|22:25:55.422] Loaded local transaction journal         transactions=0 dropped=0
INFO [12-11|22:25:55.422] Regenerated local transaction journal    transactions=0 accounts=0
INFO [12-11|22:25:55.448] New local node record                    seq=3 id=9df1402f69b38851 ip=127.0.0.1 udp=8545 tcp=8545
INFO [12-11|22:25:55.448] Started P2P networking                   self=enode://ebaa16484901434cb3326ea3bc2c84b5d1483d1b1795e2bac6f2c81369a31577eec4a1b4965462a0c396bba48a72ec0546a347f3b69a58d292c01065b71726da@127.0.0.1:8545
INFO [12-11|22:25:55.450] IPC endpoint opened                      url=/Users/hate/gethdata/data/geth.ipc
INFO [12-11|22:25:55.451] HTTP endpoint opened                     url=http://127.0.0.1:8545              cors= vhosts=localhost
INFO [12-11|22:25:55.451] Transaction pool price threshold updated price=1000000000
INFO [12-11|22:25:55.451] Updated mining threads                   threads=1
INFO [12-11|22:25:55.451] Transaction pool price threshold updated price=1000000000
INFO [12-11|22:25:55.451] Etherbase automatically configured       address=0x9b22aa106d97dd76369f6a6985219a914ffa9212
INFO [12-11|22:25:55.451] Commit new mining work                   number=1 sealhash=1ed00a…dca68d uncles=0 txs=0 gas=0 fees=0 elapsed=174.855µs
INFO [12-11|22:25:57.672] Mapped network port                      proto=tcp extport=8545 intport=8545 interface="UPNP IGDv1-IP1"
INFO [12-11|22:25:57.700] Mapped network port                      proto=udp extport=8545 intport=8545 interface="UPNP IGDv1-IP1"
INFO [12-11|22:25:58.096] New local node record                    seq=4 id=9df1402f69b38851 ip=192.168.1.11 udp=8545 tcp=8545

等待几秒中之后,如果成功挖到矿可以看到如下日志:

INFO [12-11|22:26:14.529] Successfully sealed new block            number=1 sealhash=1ed00a…dca68d hash=8659aa…82ea53 elapsed=19.078s
INFO [12-11|22:26:14.529] :hammer: mined potential block                  number=1 hash=8659aa…82ea53
INFO [12-11|22:26:14.530] Commit new mining work                   number=2 sealhash=faee35…02af6c uncles=0 txs=0 gas=0 fees=0 elapsed=784.401µs
INFO [12-11|22:26:18.832] Successfully sealed new block            number=2 sealhash=faee35…02af6c hash=1945a2…554ad8 elapsed=4.302s
INFO [12-11|22:26:18.832] :hammer: mined potential block                  number=2 hash=1945a2…554ad8
INFO [12-11|22:26:18.832] Commit new mining work                   number=3 sealhash=e061eb…14c099 uncles=0 txs=0 gas=0 fees=0 elapsed=116.125µs
INFO [12-11|22:26:19.392] Successfully sealed new block            number=3 sealhash=e061eb…14c099 hash=f2a530…27c357 elapsed=559.819ms
INFO [12-11|22:26:19.392] :hammer: mined potential block                  number=3 hash=f2a530…27c357

至此,一个本地测试网络已经搭建完成,我们可以使用任意客户端连接到这个网络。

通过 curl 访问 RPC 接口

在使用高级客户端前,先使用curl访问体验下以太坊的 RPC 接口,因为一些高级客户端是在 RPC 之上的封装,最终还是通过这些API和 Geth 进行交互的。

先设置一个 alias,减少敲击键盘的次数:

alias rpc="curl http://127.0.0.1:8545/ -XPOST --header 'content-type:application/json'"

查看当前Geth节点是否在挖矿:

$ rpc -d '{"jsonrpc":"2.0","method":"eth_mining","params":[],"id":116}'
{"id":116,"jsonrpc":"2.0","result":true}

使用 nc 可以通过本地 ipc 来获取同样结果:

echo -e '{"jsonrpc":"2.0","method":"eth_mining","params":[],"id":74}' | nc -U /Users/hate/gethdata/data/geth.ipc
{"jsonrpc":"2.0","id":74,"result":true}

查看当前块个数:

$ rpc -d '{"jsonrpc":"2.0","method":"eth_blockNumber","params":[],"id":116}'
{"id":116,"jsonrpc":"2.0","result":"0x1b"}

查看Geth中的所有账户:

$ rpc -d '{"jsonrpc":"2.0","method":"eth_accounts","params":[],"id":116}'
{"jsonrpc":"2.0","id":116,"result":["0x9b22aa106d97dd76369f6a6985219a914ffa9212"]}

查看账户余额,因为不断在挖矿,余额会不断增加:

$ rpc -d '{"jsonrpc":"2.0","method":"eth_getBalance","params":["0x9b22aa106d97dd76369f6a6985219a914ffa9212", "latest"],"id":116}'
{"jsonrpc":"2.0","id":116,"result":"0x3705f4624cad7c0000"}

再创建一个账户,创建账户的API属于 以太坊的管理API ,和普通API有些许不同:

$ rpc -d '{"jsonrpc":"2.0","method":"personal_newAccount","params":[""],"id":116}'
{"jsonrpc":"2.0","id":116,"result":"0x21f3173afda406431d379b9479ddac3c4584df5e"}

新用户的余额为0:

$ rpc -d '{"jsonrpc":"2.0","method":"eth_getBalance","params":["0x21f3173afda406431d379b9479ddac3c4584df5e", "latest"],"id":116}'

我们给他转一些以太币:

# 转账前需要先解锁账户
$ rpc -d '{"jsonrpc":"2.0","method":"personal_unlockAccount","params":["0x9b22aa106d97dd76369f6a6985219a914ffa9212", "", 60],"id":116}'
{"jsonrpc":"2.0","id":116,"result":true}

$ rpc -d '{"jsonrpc":"2.0","method":"eth_sendTransaction","params":[{"from": "0x9b22aa106d97dd76369f6a6985219a914ffa9212", "to": "0x21f3173afda406431d379b9479ddac3c4584df5e", "value":"
0x64"}],"id":116}'
{"jsonrpc":"2.0","id":116,"result":"0xfafeaf2dd2640a08e4df0654436832396efd1f7418c1196c99d3c02ecdea5ab0"}

# eth_sendTransaction 返回是交易的哈希值,通过交易哈希值可以获取交易收据(Receipt),只要收到收据说明交易已经被旷工打包进块里,即已经生效了。
$ rpc -d '{"jsonrpc":"2.0","method":"eth_getTransactionReceipt","params":["0xfafeaf2dd2640a08e4df0654436832396efd1f7418c1196c99d3c02ecdea5ab0"],"id":116}' | python -mjson.tool
{
    "id": 116,
    "jsonrpc": "2.0",
    "result": {
        "blockHash": "0xa3febc641fa918cf220eb1a3290cbc70ea3376e03f6c07c4266b2881e07ca4f1",
        "blockNumber": "0x1cc",
        "contractAddress": null,
        "cumulativeGasUsed": "0x5208",
        "from": "0x9b22aa106d97dd76369f6a6985219a914ffa9212",
        "gasUsed": "0x5208",
        "logs": [],
        "logsBloom": "0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000",
        "root": "0x62f6b7037a78939133ec7f30c8f13597a2a4d7580e70ef9c47648d359ea4eb2c",
        "to": "0x21f3173afda406431d379b9479ddac3c4584df5e",
        "transactionHash": "0xfafeaf2dd2640a08e4df0654436832396efd1f7418c1196c99d3c02ecdea5ab0",
        "transactionIndex": "0x0"
    }
}

# 查看交易的内容
$ rpc -d '{"jsonrpc":"2.0","method":"eth_getTransactionByHash","params":["0xfafeaf2dd2640a08e4df0654436832396efd1f7418c1196c99d3c02ecdea5ab0"],"id":116}' | python -mjson.tool
{
    "id": 116,
    "jsonrpc": "2.0",
    "result": {
        "blockHash": "0xa3febc641fa918cf220eb1a3290cbc70ea3376e03f6c07c4266b2881e07ca4f1",
        "blockNumber": "0x1cc",
        "from": "0x9b22aa106d97dd76369f6a6985219a914ffa9212",
        "gas": "0x15f90",
        "gasPrice": "0x3b9aca00",
        "hash": "0xfafeaf2dd2640a08e4df0654436832396efd1f7418c1196c99d3c02ecdea5ab0",
        "input": "0x",
        "nonce": "0x0",
        "r": "0x80a7b45ef3809f04172ab5d7c182e8ebe5ce0fda43737a08470b9cb4fd64bc9a",
        "s": "0x7030e6c585bdc489a83bb4b040b75a8db0541f594019436ce1c162fb040f2947",
        "to": "0x21f3173afda406431d379b9479ddac3c4584df5e",
        "transactionIndex": "0x0",
        "v": "0x7d9",
        "value": "0x64"
    }
}

再次查看余额,已经有了100wei(0x64=100):

$ rpc -d '{"jsonrpc":"2.0","method":"eth_getBalance","params":["0x21f3173afda406431d379b9479ddac3c4584df5e", "latest"],"id":116}'
{"jsonrpc":"2.0","id":116,"result":"0x64"}

通过 web3 访问接口

geth 中自带了一个 web3.js 的客户端,从实现原理上web3.js 是对 RPC 的封装,对开发人员更加友好,使用方法很简单:

$ geth attach http://127.0.0.1:8545
Welcome to the Geth JavaScript console!

instance: Geth/v1.8.19-stable-dae82f09/darwin-amd64/go1.11.2
coinbase: 0x9b22aa106d97dd76369f6a6985219a914ffa9212
at block: 619 (Tue, 11 Dec 2018 22:58:07 CST)
 datadir: /Users/hate/gethdata/data
 modules: admin:1.0 eth:1.0 net:1.0 personal:1.0 rpc:1.0 web3:1.0

之后会进入 node 的交互界面,Tips:这里支持tab键自动补齐!

查看余额:

> eth.getBalance('0x21f3173afda406431d379b9479ddac3c4584df5e')
100

查看是否在挖矿:

> eth.mining
true

之前使用 curl 执行的操作全部都可以使用 web3.js 来实现,只不过使用起来方便很多,对用户也友好许多。

至此一个本地测试网络已经搭建完成,Happy mining !