以太坊私链部署

Posted by 姚飞亮 on 2020-07-13

以太坊私链部署

项目地址:https://github.com/ethereum/go-ethereum

cd /Users/apple/Documents/app/go_project/src/github.com/ethereum/go-ethereum

安装依赖项后,运行

1
make geth

或者,构建全套实用程序:

1
make all
  1. 安装 Ethereum:这里用的是 ethereum 的 go语言客户端
    1. brew tap ethereum/ethereum
    2. brew install ethereum
  2. 安装好了之后运行:geth version
1
2
3
4
5
6
7
8
9
10
11
geth version
Geth
Version: 1.9.16-unstable
Git Commit: 6d8e51ab8850770925f3aaf79186f0398f24a702
Git Commit Date: 20200707
Architecture: amd64
Protocol Versions: [65 64 63]
Go Version: go1.14
Operating System: darwin
GOPATH=/Users/apple/Documents/app/go_project
GOROOT=/usr/local/go
  1. 安装以太坊编程语言Solidity —— brew install solidity

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

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

准备以太坊私链节点

  1. 创建个目录:比如 ethereum,然后创建一个json文件 genesis.json
  2. 创世块配置文件:genesis.json
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
{
"config": {
"chainId": 1,
"homesteadBlock": 0,
"eip150Block": 0,
"eip155Block": 0,
"eip158Block": 0,
"byzantiumBlock": 0,
"constantinopleBlock": 0,
"petersburgBlock": 0,
"istanbulBlock": 0
},
"alloc": {},
"coinbase": "0x0000000000000000000000000000000000000000",
"difficulty": "0x20000",
"extraData": "",
"gasLimit": "0x2fefd8",
"nonce": "0x0000000000000042",
"mixhash": "0x0000000000000000000000000000000000000000000000000000000000000000",
"parentHash": "0x0000000000000000000000000000000000000000000000000000000000000000",
"timestamp": "0x00"
}

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

1
geth --datadir data init data/genesis.json

启动节点

各选项含义如下:**

  • --identity:指定节点 ID;
  • --rpc:表示开启 HTTP-RPC 服务;
  • --rpcaddr:HTTP-RPC 服务ip地址;
  • --rpcport:指定 HTTP-RPC 服务监听端口号(默认为 8545);
  • --datadir:指定区块链数据的存储位置;
  • --port:指定和其他节点连接所用的端口号(默认为 30303);
  • --nodiscover:关闭节点发现机制,防止加入有同样初始配置的陌生节点
1
2
3
4
5
geth --networkid 1 --dev  --mine  --datadir data  --identity "mychain1" --rpc --rpcaddr 0.0.0.0 --rpcport 8545 --port 30303  --http.corsdomain "*"   --rpcapi eth,net,web3,personal --allow-insecure-unlock    console



INFO [07-12|13:32:22.857] Initialised chain configuration config="{ChainID: 1337 Homestead: 0 DAO: <nil> DAOSupport: false EIP150: 0 EIP155: 0 EIP158: 0 Byzantium: 0 Constantinople: 0 Petersburg: 0 Istanbul: 0, Muir Glacier: <nil>, YOLO v1: <nil>, Engine: clique}"

ChainID: 1337 注意后面MERAMASK使用时会用到否则会报错

命令创建账号

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

1
2
3
4
5
> personal.newAccount('123456')
INFO [07-12|01:17:25.091] Your new key was generated address=0x413668277Fd91E8F58d1B751Ec61198f178404d5
WARN [07-12|01:17:25.093] Please backup your key file! path=/Users/apple/Documents/app/go_project/src/github.com/ethereum/go-ethereum/build/bin/data/keystore/UTC--2020-07-11T17-17-22.670563000Z--413668277fd91e8f58d1b751ec61198f178404d5
WARN [07-12|01:17:25.093] Please remember your password!
"0x413668277fd91e8f58d1b751ec61198f178404d5"

查看当前节点下面是否有账号存在

1
2
3
4
5
> personal.listAccounts
["0xed73e8786b1bb7becec87b61bec8edc5944bf4a2", "0x413668277fd91e8f58d1b751ec61198f178404d5"]
> eth.coinbase
"0xed73e8786b1bb7becec87b61bec8edc5944bf4a2"
0x585603d82bcF96B521772B3D7D5Dd70B6705AE76

挖矿

执行设置挖矿miner地址:

1
2
> miner.setEtherbase(eth.coinbase)
true

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

1
miner.start()

转账

转账前需要解锁

1
personal.unlockAccount(eth.coinbase, '')

转账

1
2
3
eth.sendTransaction({from:eth.coinbase, to:eth.accounts[1], value: web3.toWei(99999, "ether")})
eth.sendTransaction({from:eth.accounts[1], to:eth.accounts[2], value: web3.toWei(100, "ether")})
eth.sendTransaction({from:"0xed73e8786b1bb7becec87b61bec8edc5944bf4a2", to:"0x413668277fd91e8f58d1b751ec61198f178404d5", value: web3.toWei(10, "ether")})

MERAMASK 插件使用

网络名称 :mychain1

新增 RPC URL: http://127.0.0.1:8545/

ChainID: 1337 //上面已经提到,如果不对会得倒以下错误

1
2
3
EthQuery - RPC Error - Error: [ethjs-rpc] rpc error with payload {"id":7020279539214,"jsonrpc":"2.0","params":["0xf8690180825208944005c7b1e11d1864c583a43f27cb80043484ec4a8829a2241af62c000080820a96a0337725da801de5ddf4ed45afa084d1d03917398ee0110aa3652368c399f93739a04f94d25a566a08117acf6dce48c6d7d9d38dd804900b93b7b37860bbe6819425"],"method":"eth_sendRawTransaction"} [object Object]

err="invalid sender"

如果从eth.coinbase账户转币需要解锁

personal.unlockAccount(eth.coinbase, ‘’)

否则会出现以下错误

1
err="authentication needed: password or unlock"

remix 使用

环境 ENVIRONMENT : Injected Web3

  • JavaScript VM:所有交易将在浏览器的沙盒区块链中执行。这意味着您在重新加载页面时不会保留任何内容。JsVM是其自己的区块链,每次重新加载时,它将启动一个新的区块链,旧的区块链将不会保存。
  • Injected Web3:Remix将连接到注入的Web3提供程序。Metamask是注入web3的提供程序的示例。
  • Web3 Provider:Remix将连接到远程节点。您需要将URL提供给选定的提供商:geth,奇偶校验或任何以太坊客户端。

MERAMASK 插件选择连接

1
2
3
4
5
6
Published DemeterContract's Metadata
Metadata of "demetercontract" was published successfully.
browser/tests/DemeterContract.sol :
dweb:/ipfs/QmNQNYDRwQzRnhA5LKraQmcExEjuuFepAs1wxF4vv9Fd1Z
metadata.json :
dweb:/ipfs/QmUSXV97L4Z7P5EguEZ3urkX8x3yHzL39knaQcSKFL31in

启动第二个节点

启动节点

1
geth --networkid 1 --dev  --mine  --datadir tmpdata1  --identity "mychain1" --rpc --rpcaddr 0.0.0.0 --rpcport 8101 --port 30301  --http.corsdomain "*"   --rpcapi eth,net,web3,personal --allow-insecure-unlock    console  1>> tmpdata1/01.log

从另一个终端窗口连接到节点上的IPC控制台

1
geth attach ipc:tmpdata1/geth.ipc

要检查geth使用的端口并找到您的enode URI,请运行:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
> admin.nodeInfo
{
enode: "enode://82fc36da840a160bf80de90aa23132ac22eb53fc60ab62ac051e80a811b2e92b356886d3e6dbdd8f11f034d067eb2ecd149122c3e8493341184edd2f555bc311@127.0.0.1:30303?discport=0",
enr: "enr:-JC4QB_kvZUsRnwuMU8GLs2Z0HIapvg3ShgkduDSRtaQyGYWGaHF372_nfP6PB63QYTFkZBK9FtSRv9utCeTTcSr1MAJg2V0aMfGhOZyIzeAgmlkgnY0gmlwhH8AAAGJc2VjcDI1NmsxoQOC_DbahAoWC_gN6QqiMTKsIutT_GCrYqwFHoCoEbLpK4N0Y3CCdl8",
id: "10adfd90e75461577e292b7df8c5c1153fffaad628fa62a3df0ae29175f30731",
ip: "127.0.0.1",
listenAddr: "[::]:30303",
name: "Geth/111/v1.9.16-unstable-6d8e51ab-20200707/darwin-amd64/go1.14",
ports: {
discovery: 0,
listener: 30303
},
protocols: {
eth: {
config: {
byzantiumBlock: 0,
chainId: 1337,
clique: {...},
constantinopleBlock: 0,
eip150Block: 0,
eip150Hash: "0x0000000000000000000000000000000000000000000000000000000000000000",
eip155Block: 0,
eip158Block: 0,
homesteadBlock: 0,
istanbulBlock: 0,
petersburgBlock: 0
},
difficulty: 21,
genesis: "0xf5e67f9f05de71cb3d0740331ef211ad9f9e32b7f709fa0d28dcf8675dfd65ad",
head: "0x3562d50b915960920180c1439c5ee732136c2e39f20569c97fa578140cbca39e",
network: 111
}
}
}

> admin.nodeInfo.enode
"enode://82fc36da840a160bf80de90aa23132ac22eb53fc60ab62ac051e80a811b2e92b356886d3e6dbdd8f11f034d067eb2ecd149122c3e8493341184edd2f555bc311@127.0.0.1:30303?discport=0"

第一种连接方式 如果要将此实例连接到先前启动的节点,则可以使用从控制台将其添加为对等实例admin.addPeer(enodeUrlOfFirstInstance)节点2通过节点1的enode连接网络

1
2
> admin.addPeer("enode://82fc36da840a160bf80de90aa23132ac22eb53fc60ab62ac051e80a811b2e92b356886d3e6dbdd8f11f034d067eb2ecd149122c3e8493341184edd2f555bc311@192.168.43.52:30303")
true

第二种连接方式设置引导节点

1
2
3
4
5
6
7
> bootnode -genkey bootnode.key

> cat bootnode.key
11042159d89a7a42ac23463ae4b02881c8ac73e2f99cffd0f88cf32b7e186306

bootnode -nodekey bootnode.key
enode://840dd3574337a628c9b38c6faca48f6fbb24e5f53662e7229eac553624b7ad8bafc910092ec9bb7b6072386d2d14cd88b0de8dfbae811d2b999f2d1750845933@127.0.0.1:0?discport=30301

在测试2节点个节点联通时,发现联不通可能是在命令里加了 –dev 参数的原因

第三种连接方式使用相同的创世纪区块初始化genesis.json文件

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
{
"config": {
"chainId": 111,
"homesteadBlock": 0,
"eip150Block": 0,
"eip155Block": 0,
"eip158Block": 0,
"byzantiumBlock": 0,
"constantinopleBlock": 0,
"petersburgBlock": 0,
"istanbulBlock": 0
},
"alloc": {},
"coinbase": "0x0000000000000000000000000000000000000000",
"difficulty": "0x01",
"extraData": "0x0",
"gasLimit": "0x2fefd8",
"nonce": "0x0000000000000042",
"mixhash": "0x0000000000000000000000000000000000000000000000000000000000000000",
"parentHash": "0x0000000000000000000000000000000000000000000000000000000000000000",
"timestamp": "0x00"
}

区块参数释义:

参数 说明
chainId 指定了独立的区块链网络ID。网络ID在连接到其他节点的时候会用到,以太坊公网的网络ID是 1,为了不与公有链网络冲突,运行私有链节点的时候要指定自己的网络ID。不同ID网络的节点无法相互连接。
homesteadBlock homestead 算法块
eip150Block eip150 算法块
eip155Block eip155 算法块
eip158Block eip158 算法块
alloc 用来预置账号以及账号的以太币数量
coinbase 矿工账号
extraData 附加信息
difficulty 设置设置当前区块的难度,值越大挖矿就越难。
gasLimit 该值设置对GAS的消耗总量限制,用来限制区块能包含的交易信息总和
nonce 挖矿用的64位随机数
mixhash 与 nonce 配合挖矿,与上一个区块的 hash 有关
parentHash 上一个区块的hash,创世块就为0
timestamp 设置创世块的时间戳

1
2
3
geth account new
Public address of the key: 0x2E82C574603da92489B6514D0f4DAE6bc5BC61E5
Path of the secret key file: /Users/apple/Library/Ethereum/keystore/UTC--2020-07-12T15-56-33.495853000Z--2e82c574603da92489b6514d0f4dae6bc5bc61e5

启动节点1

1
2
geth --datadir data1 init data1/genesis.json
geth --datadir data1 --networkid 15 --ipcdisable --port 61911 --rpcport 8101 --nodiscover console

发现账户是空的

1
2
eth.accounts
[]

创建账户

1
> personal.newAccount()

将创建后的账户添加到genesis.json文件的 “alloc”: {},

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
{
"config": {
"chainId": 111,
"homesteadBlock": 0,
"eip150Block": 0,
"eip155Block": 0,
"eip158Block": 0,
"byzantiumBlock": 0,
"constantinopleBlock": 0,
"petersburgBlock": 0,
"istanbulBlock": 0
},
"alloc": {
"0x510f1cdce4f3dd7ecc0c84099bf7f40bbe38fdc6":{
"balance":"1000000000000000000000000"
}
},
"coinbase": "0x0000000000000000000000000000000000000000",
"difficulty": "0x01",
"extraData": "",
"gasLimit": "0x2fefd8",
"nonce": "0x0000000000000042",
"mixhash": "0x0000000000000000000000000000000000000000000000000000000000000000",
"parentHash": "0x0000000000000000000000000000000000000000000000000000000000000000",
"timestamp": "0x00"
}

再次启动节点1 可以看到账户及余额

1
2
3
4
5
6
7
8
9
geth --syncmode "full" --datadir data1 --networkid 15 --rpc --rpcaddr 0.0.0.0   --port 61911 --rpcport 8101  --http.corsdomain "*"   --rpcapi eth,net,web3,personal --allow-insecure-unlock   console

//开始挖矿
miner.start();

> web3.eth.coinbase
"0x510f1cdce4f3dd7ecc0c84099bf7f40bbe38fdc6"
> eth.getBalance(web3.eth.coinbase)
9.9999195e+23

查看节点1的enode

1
2
> admin.nodeInfo.enode
"enode://f5454bb17ebaad5125c4db97036329972822ff13d1d481cfdb1c9e1b3569050880d382363d85f7548837203ed524296e272440fc6ff2cd70f81636985d96c36d@127.0.0.1:61911"

启动节点2 带上–bootnodes 节点1的enode

1
2
3
4
5
6
7
8
9
geth --datadir data2 init data2/genesis.json

geth --syncmode "full" --datadir data2 --networkid 15 --rpc --rpcaddr 0.0.0.0 --port 61910 --rpcport 8100 console

> personal.newAccount()
//创建账户,不创建账户无法启动挖矿功能

//创建账户后再次启动节点2 节点2还没有账户,先不开启挖矿,去掉 --mine; 两个节点初始化的创世区块必须要一模一样 节点2"alloc"为空
geth --syncmode "full" --datadir data2 --networkid 15 --rpc --rpcaddr 0.0.0.0 --port 61910 --rpcport 8100 --http.corsdomain "*" --rpcapi eth,net,web3,personal --allow-insecure-unlock --bootnodes "enode://f5454bb17ebaad5125c4db97036329972822ff13d1d481cfdb1c9e1b3569050880d382363d85f7548837203ed524296e272440fc6ff2cd70f81636985d96c36d@127.0.0.1:61911" console

查看网络

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
> net.peerCount

> admin.peers
[{
caps: ["eth/62", "eth/63", "par/1", "par/2", "par/3", "pip/1"],
enode: "enode://4b9b92e32084ce52253a4b2f5f34a2c8e7f7379aed45924ba2a4aa1be8d0cf469cd4cd7ac9955f3f2e9d0b8937503c8359fa14afdf3168d81e8cbc70ba6c1c6b@209.126.69.171:30303",
id: "e7b99d68ac3e1f85b21e1b2f024811815f4297f72b0b5014dcfe8d5cb6dda64d",
name: "Parity-Ethereum/v2.4.6-stable-94164e1-20190514/x86_64-linux-gnu/rustc1.34.1",
network: {
inbound: false,
localAddress: "192.168.43.52:60970",
remoteAddress: "209.126.69.171:30303",
static: false,
trusted: false
},
protocols: {
eth: "handshake"
}
}]

终端1账户0向账户1转账

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
//解锁账户0(密码为空)
personal.unlockAccount(personal.listAccounts[0]);
//以太币转wei
amount = web3.toWei(5,'ether');
//转账
eth.sendTransaction({from:personal.listAccounts[0],to:personal.listAccounts[1],value:amount});
//查看交易状态
txpool.status
//查看区块信息
eth.getBlock("pending",true);

{
difficulty: 2,
extraData: "0xd783010910846765746886676f312e31348664617277696e00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000",
gasLimit: 6301605,
gasUsed: 0,
hash: null,
logsBloom: "0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000",
miner: null,
mixHash: "0x0000000000000000000000000000000000000000000000000000000000000000",
nonce: null,
number: 3,
parentHash: "0x1100bb5dbf6803d444b79ddc128ebb21485879cc5d6ad563e6ff97cb2a49b841",
receiptsRoot: "0x56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421",
sha3Uncles: "0x1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347",
size: 606,
stateRoot: "0x0f2bff95db3fcaefdce401685cdddd5780b47e054e427611e3bebd37612e04cb",
timestamp: 1594311926,
totalDifficulty: 0,
transactions: [],
transactionsRoot: "0x56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421",
uncles: []
}

//开始挖矿
miner.start();
//停止挖矿
miner.stop();
//查看交易状态
txpool.status
//查看账户1的余额
eth.getBalance(personal.listAccounts[0])
eth.getBalance(personal.listAccounts[1])
//转账成功!!!
//查看区块数
eth.blockNumber
//查看交易信息
eth.getTransaction("0x7811782799fb175f9576848f1928031dcc25248c4ebf218764ee6296159f53c4")

{
blockHash: "0x1100bb5dbf6803d444b79ddc128ebb21485879cc5d6ad563e6ff97cb2a49b841",
blockNumber: 2,
from: "0x0caad1f289fdfdf0a0988d2f4239caa2453d73cc",
gas: 21000,
gasPrice: 1,
hash: "0x7811782799fb175f9576848f1928031dcc25248c4ebf218764ee6296159f53c4",
input: "0x",
nonce: 1,
r: "0x8e08d5260f970e0879525ae515b47508f358a84cdda053110bcc3062f380fea7",
s: "0x4a8d2c63aa5bba7af84d84fdbe59a79620dd67e72f9a1ca40cd9a2ab8471d87",
to: "0xd981f82235febaa46d23a6c4be45abccb9310a95",
transactionIndex: 0,
v: "0xa96",
value: 5000000000000000000
}

//查看区块信息(区块号)
eth.getBlock(1)


Ω