这篇博客演示的基本操作系统环境是CentOS 7,参考书籍:以太坊开发实战——以太坊关键技术与案例分析 第五章(吴寿鹤、冯翔、刘涛、周广益 著)。
文章结构:
一.geth客户端安装
二.搭建一个私有链
1.新建一个geth工作目录
2.创世区块配置文件
3.初始化
4.启动私有链
三.以太坊私有链上的基本操作
1.创建用户
2.查看余额
3.挖矿
4.解锁账户
5.交易
6.区块
7.账户管理
8.区块数据管理
9.远程节点连接
10.通过attach命令连接已启动节点
四.常见问题
1.执行miner.start()返回null
这篇博客演示的基本操作系统环境是CentOS 7,参考书籍:以太坊开发实战——以太坊关键技术与案例分析(吴寿鹤、冯翔、刘涛、周广益 著)。首先从github上获取go-ethereum源码,然后编译geth。获取源码命令:
[root@localhost opt]# git clone https://github.com/ethereum/go-ethereum.git
如果git未安装请自行百度安装。
如上图所示,由于之前在本目录中下载过go-ethereum,故显示其已存在。然后进入到go-ethereum目录,进行编译:
[root@localhost opt]# cd go-ethereum/
[root@localhost go-ethereum]# make geth
由于我的客户端编译过了,所以没有显示编译细节,但只要编译成功便会在末尾显示:Run "/opt/go-ethereum/build/bin/geth" to launch geth来提示启动geth,注意双引号之间的内容为你安装时的路径,会有所不同。
1.新建一个geth工作目录
$ mkdir geth
$ cd geth
$ mkdir db
$ touch gensis.json
//执行完成后目录结构
geth
├── db
└── gensis.json
2.创世区块配置文件
gensis. json文件内容如下:
{
"config": {
"chainId": 15,
"homesteadBlock": 0,
"eip155Block": 0,
"eip158Block": 0
},
"coinbase" : "0x0000000000000000000000000000000000000000",
"difficulty" : "0x40000",
"extraData" : "",
"gasLimit" : "0xffffffff",
"nonce" : "0x0000000000000042",
"mixhash" : "0x0000000000000000000000000000000000000000000000000000000000000000",
"parentHash" : "0x0000000000000000000000000000000000000000000000000000000000000000",
"timestamp" : "0x00",
"alloc": { }
}
相关参数作用表如下:
chainID | 指定了独立的区块链网络 ID。网络 ID 在连接到其他节点的时候会用到,以太坊公网的网络 ID 是 1,为了不与公有链网络冲突,运行私有链节点的时候要指定自己的网络 ID。不同 ID 网络的节点无法相互连接 |
homesteadBlock | 取值为0表示正在使用homesteadBlock版本。 以太坊的发展分成了四个阶段:(每个阶段进步到下一个阶段都是通过硬分叉的方式实现的) 1.Frontier(前沿):2015年7月30日,以太坊发布了Frontier阶段,此时的软件还不太成熟,但可以进行基本的挖矿测试去中心化应用(Dapps),该阶段参与者主要为开发者。 2.HomesteadBlock(家园):在2016年3月14日(圆周率节),以太坊发布了HomesteadBlock阶段。以太坊开始平稳运行,提供了图形界面的钱包,普通用户也可以体验和使用以太坊。 3.Metropolis(大都会):Metropolis被分成了两个阶段:Byzantium(拜占庭)和Constantinople (居士坦丁堡)。 2017.10.16,以太坊拜占庭硬分叉成功,引入了包括:zk-SNARKs(简明非交互零知识证明)、revert功能、return和抽象账户。 2019年2月底,以太坊区块链的第7,080,000区块作为激活点正式开启君士坦丁堡硬分叉,点在于将以太坊的共识机制由PoW向PoW+PoS混合机制过渡,从而使整个以太坊网络更加的轻盈、快捷与安全。按官方说法,具体在现有以太坊PoW主网上进行升级的有以下5个方面: (1).EIP 145:给EVM增加移位相关指令,包括左移SHL,逻辑右移SHR,算术右移SAR (2).EIP 1014:产生合约地址的一种新规则,与状态通道有关。规则为keccak256( 0xff ++ address ++ salt ++ keccak256(init_code)))[12:] (3).EIP 1052:为EVM增加EXTCODEHASH指令,这个指令可以获得一个合约bytecode的keccak256的hash值; (4).EIP 1283:修改EVM的SSTORE指令gas计算方式,预计会减少许多合约的gas消耗,需要硬分叉支持; (5).EIP 1234:将是潜在最有争议的提案,也需要硬分叉支持,它包括难度炸弹(Difficulty Bomb)协议推迟12个月和挖矿奖励调整,难度炸弹使挖矿难度随时间推移越来越高,挖矿奖励调整将挖矿奖励从3个降低到2个; 4.Serenity(宁静) |
eip155Block | eip是ethereum improvement proposal的缩写,你的链不会因为因为这些提议分叉,故设置为“0”即可 |
eip158Block | eip是ethereum improvement proposal的缩写,你的链不会因为因为这些提议分叉,故设置为“0”即可 |
mixhsah | 与nonce配合用于挖矿,由上一个区块的一部分生成的哈希。注意它和nonce的设置需要满足以太坊的Yellow paper, 4.3.4. Block Header Validity, (44)章节所描述的条件。 |
nonce | nonce就是一个64位随机数,用于挖矿,注意它和mixhash的设置需要满足以太坊的Yellow paper, 4.3.4. Block Header Validity, (44)章节所描述的条件。 |
difficulty | 设置设置当前区块难度,如果难度过大,CPU挖矿就很难 |
alloc | 给某个账户预分配以太币 |
coinbase | 矿工帐号 |
timestamp | 创世块的时间戳 |
parentHash | 上一个区块的哈希值,由于是创世区块,所以值为0 |
extraData | 可以写入32Byte大小的任意数据,每个block都会有,由挖出block的miner来决定要不要在里面写什么 |
gasLimit | 该值设置对GAS的消耗总量限制,用来限制区块能包含的交易信息总 |
3.初始化
//进入geth目录中,执行初始化命令:
$ geth --datadir "./db" init gensis.json
geth init命令用来初始化区块连,命令可以带有选项和参数,其中--datadir后面跟了一个目录名db,表示指定数据存放目录为db,gensis.json为init命令的参数。初始化成功后,会在db目录中生成geth和keystore两个文件夹,其中,geth/db/geth/chaindata中存放的是区块数据,geth/db/keystore中存放的是账户数据。geth目录结构如下:
[root@localhost geth]# tree ../geth/
../geth/
├── db
│ ├── geth
│ │ ├── chaindata
│ │ │ ├── 000001.log
│ │ │ ├── CURRENT
│ │ │ ├── LOCK
│ │ │ ├── LOG
│ │ │ └── MANIFEST-000000
│ │ └── lightchaindata
│ │ ├── 000001.log
│ │ ├── CURRENT
│ │ ├── LOCK
│ │ ├── LOG
│ │ └── MANIFEST-000000
│ └── keystore
└── gensis.json
4.启动私有链
//console 2>>geth.log 表示将日志输出到geth.log,打开另外一个控制台执行tail -f 查看日志
$ geth --datadir "./db" --nodiscover console 2>>geth.log
geth启动参数详解:
identity | 区块链的标识,用于标识目前网络的名字 |
datadir | 指明当前区块链私钥和网络数据存放的位置 |
port | 指定以太坊网络监听端口,默认为30303 |
rpc | 开启HTTP-RPC服务,可以进行智能合约的部署和调试 |
rpcaddr | 指定HTTP-RPC服务监听地址,默认为“localhost” |
rpcapi | 设置允许连接的rpc的客户端,一般为db、eth、net、web3 |
rpcport | 指定HTTP-RPC服务监听端口,默认为8545 |
networkid |
指定以太坊id,其实就是区块链网络的身份标识,共有链为1,测试链为3,默认启动id为1 |
etherbase | 指定矿工帐号,默认为keystory中首个帐号 |
mine | 开启挖矿,默认为CPU挖矿 |
minerthreads | 挖矿占用CPU线程数,默认为4 |
nodiscover | 关闭自动连接节点,但可以手动添加节点,在搭建私有链时,为避免其他节点连入私有链,可使用该命令 |
maxpeers | 设置允许最大节点数,默认为25 |
console | 启动命令行模式,可以在geth中执行命令 |
启动后进入javascript命令行控制台,显示结果如下:
[root@localhost geth]# geth --datadir "./db" --nodiscover console 2>>geth.log
Welcome to the Geth JavaScript console!
instance: Geth/v1.8.20-unstable/linux-amd64/go1.11
coinbase: 0x1baed334cbf41a94daef7b247beebd6fdc45100c
at block: 112 (Mon, 25 Mar 2019 21:37:17 HKT)
datadir: /opt/geth/db
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
>
打开另一个终端,执行 tail -f geth.log可以时刻查看相关日志内容:
[root@localhost geth]# tail -f geth.log
INFO [03-26|10:20:55.418] Loaded most recent local header number=112 hash=842b42…2c27da td=28062821 age=12h43m38s
INFO [03-26|10:20:55.418] Loaded most recent local full block number=112 hash=842b42…2c27da td=28062821 age=12h43m38s
INFO [03-26|10:20:55.418] Loaded most recent local fast block number=112 hash=842b42…2c27da td=28062821 age=12h43m38s
INFO [03-26|10:20:55.419] Loaded local transaction journal transactions=0 dropped=0
INFO [03-26|10:20:55.419] Regenerated local transaction journal transactions=0 accounts=0
WARN [03-26|10:20:55.419] Blockchain not empty, fast sync disabled
INFO [03-26|10:20:55.584] New local node record seq=2 id=c9432d51b9f92fe1 ip=127.0.0.1 udp=0 tcp=30303
INFO [03-26|10:20:55.584] Started P2P networking self="enode://688e30b0fd748189b882fb54af5ddf5c2d11555fbf9fd869a96b0f59729cab43b7e6f4c02e59df5ee94a4c2890e54804fa7a2e9476d82e708a903b6b9cc5383a@127.0.0.1:30303?discport=0"
INFO [03-26|10:20:55.587] IPC endpoint opened url=/opt/geth/db/geth.ipc
INFO [03-26|10:20:55.786] Etherbase automatically configured address=0x1Baed334CbF41A94daEF7B247bEebD6fdC45100C
以太坊的javascript控制台中内置了一些以太坊对象,通过这些对象我们可以很方便的与以太坊交互:
1.创建用户
//查看帐户,可以看到有我之前创建的三个账户,若没有创建过账户则显示: []
> eth.accounts
["0x1baed334cbf41a94daef7b247beebd6fdc45100c", "0xdb3d4ae8e3624d1ec75bba5c4da024c5984e3b17", "0x115b0ba0ffddb13cd513ec38679e1089c252c839"]
>
//建帐户的方式有两种,第一种创建帐户时直接初始化密码
//如下创建的账户为“0xeed50d745a67eaa2a2eaf9e08a2485d1c1145103”,密码为“444444”
> personal.newAccount("444444")
"0xeed50d745a67eaa2a2eaf9e08a2485d1c1145103"
>
//第二种方法是先创建账户,然后输入密码"555555"
> personal.newAccount()
Passphrase:
Repeat passphrase:
"0x6ccfd99b17da037d7f974aa9bd9bd65a04f514d1"
>
//此时查看已创建的用户,有5个
> eth.accounts
["0x1baed334cbf41a94daef7b247beebd6fdc45100c", "0xdb3d4ae8e3624d1ec75bba5c4da024c5984e3b17", "0x115b0ba0ffddb13cd513ec38679e1089c252c839", "0xeed50d745a67eaa2a2eaf9e08a2485d1c1145103", "0x6ccfd99b17da037d7f974aa9bd9bd65a04f514d1"]
>
//账户创建成功后会返回账户地公钥,生成的账户文件在keystore文件夹下:
db/keystore/
├── UTC--2019-03-25T13-11-16.002140069Z--1baed334cbf41a94daef7b247beebd6fdc45100c
├── UTC--2019-03-25T13-15-38.206845483Z--db3d4ae8e3624d1ec75bba5c4da024c5984e3b17
├── UTC--2019-03-25T13-28-30.957174224Z--115b0ba0ffddb13cd513ec38679e1089c252c839
├── UTC--2019-03-26T02-47-59.331021277Z--eed50d745a67eaa2a2eaf9e08a2485d1c1145103
└── UTC--2019-03-26T02-52-31.434967091Z--6ccfd99b17da037d7f974aa9bd9bd65a04f514d1
2.查看余额
以太币的最小单位为wei,1 ether = wei
//由于我的账户挖过矿,且发生过交易,故前三个账户有余额,单位为wei
//而新创建的两个账户未发生过交易,故余额为0
> eth.getBalance(eth.accounts[0])
557000021000000000000
> eth.getBalance(eth.accounts[1])
999979000000000000
> eth.getBalance(eth.accounts[2])
2000000000000000000
> eth.getBalance(eth.accounts[3])
0
> eth.getBalance(eth.accounts[4])
0
>
3.挖矿
//在挖矿之前要先设置挖矿奖励地址,默认为创建的第一个账户地址,即eth.accounts[0]
> miner.setEtherbase(eth.accounts[0])
true
>
//设置完成后,查看是否设置成功,返回结果为设置后的挖矿奖励地址
> eth.coinbase
"0x1baed334cbf41a94daef7b247beebd6fdc45100c"
>
//开始挖矿
> miner.start()
null
//在之前打开的另一个终端中可以看到挖矿日志记录
INFO [03-26|13:05:36.057] Updated mining threads threads=4
INFO [03-26|13:05:36.057] Transaction pool price threshold updated price=1000000000
INFO [03-26|13:05:36.059] Commit new mining work number=113 sealhash=527c2b…95e338 uncles=0 txs=0 gas=0 fees=0 elapsed=746.685µs
INFO [03-26|13:06:55.500] Successfully sealed new block number=113 sealhash=527c2b…95e338 hash=0b5a7f…5202bb elapsed=1m19.441s
INFO [03-26|13:06:55.500] mined potential block number=113 hash=0b5a7f…5202bb
INFO [03-26|13:06:55.501] Commit new mining work number=114 sealhash=20a5a4…07fb8c uncles=0 txs=0 gas=0 fees=0 elapsed=137.993µs
INFO [03-26|13:06:56.895] Successfully sealed new block number=114 sealhash=20a5a4…07fb8c hash=5bae51…cca193 elapsed=1.394s
INFO [03-26|13:06:56.895] mined potential block number=114 hash=5bae51…cca193
INFO [03-26|13:06:56.895] Commit new mining work number=115 sealhash=75cdcb…42129c uncles=0 txs=0 gas=0 fees=0 elapsed=187.946µs
INFO [03-26|13:07:00.470] Successfully sealed new block number=115 sealhash=75cdcb…42129c hash=52352a…4e6153 elapsed=3.574s
INFO [03-26|13:07:00.470] mined potential block number=115 hash=52352a…4e6153
INFO [03-26|13:07:00.470] Commit new mining work number=116 sealhash=8590f9…10690f uncles=0 txs=0 gas=0 fees=0 elapsed=138.993µs
INFO [03-26|13:07:01.796] Successfully sealed new block number=116 sealhash=8590f9…10690f hash=2bc9b7…1d7a1c elapsed=1.326s
INFO [03-26|13:07:01.796] mined potential block number=116 hash=2bc9b7…1d7a1c
INFO [03-26|13:07:01.797] Commit new mining work number=117 sealhash=4f171e…976b8e uncles=0 txs=0 gas=0 fees=0 elapsed=208.115µs
INFO [03-26|13:07:02.863] Successfully sealed new block number=117 sealhash=4f171e…976b8e hash=89b748…8abebc elapsed=1.066s
INFO [03-26|13:07:02.864] mined potential block number=117 hash=89b748…8abebc
INFO [03-26|13:07:02.864] Commit new mining work number=118 sealhash=d23ff5…1ee086 uncles=0 txs=0 gas=0 fees=0 elapsed=173.425µs
INFO [03-26|13:07:06.387] Successfully sealed new block number=118 sealhash=d23ff5…1ee086 hash=573e64…31050e elapsed=3.522s
INFO [03-26|13:07:06.387] mined potential block number=118 hash=573e64…31050e
INFO [03-26|13:07:06.387] Commit new mining work number=119 sealhash=c8840a…c9c0af uncles=0 txs=0 gas=0 fees=0 elapsed=228.028µs
INFO [03-26|13:07:12.455] Successfully sealed new block number=119 sealhash=c8840a…c9c0af hash=dae780…86c027 elapsed=6.068s
INFO [03-26|13:07:12.455] mined potential block number=119 hash=dae780…86c027
INFO [03-26|13:07:12.455] Commit new mining work number=120 sealhash=f89e85…f46780 uncles=0 txs=0 gas=0 fees=0 elapsed=134.293µs
INFO [03-26|13:07:12.851] Successfully sealed new block number=120 sealhash=f89e85…f46780 hash=b034c6…e2c5fc elapsed=395.460ms
INFO [03-26|13:07:12.851] block reached canonical chain number=113 hash=0b5a7f…5202bb
INFO [03-26|13:07:12.851] mined potential block number=120 hash=b034c6…e2c5fc
4.解锁账户
//方式一,参数中只传入要解锁的账户地址,控制台提示输入密码时请输入密码,成功后返回true
> personal.unlockAccount(eth.accounts[2])
Unlock account 0x115b0ba0ffddb13cd513ec38679e1089c252c839
Passphrase:
true
>
//方式二,参数中传入账户地址和密码
> personal.unlockAccount(eth.accounts[2],"333333")
true
>
//方式三,参数中传入账户地址、密码、账户解锁状态持续时间
> personal.unlockAccount(eth.accounts[2],"333333",300)
true
>
5.交易
//发起交易,内容为accounts[2]账户向accounts[3]账户发送1 ether以太币,返回值为交易hash
//此时的交易正在矿工的交易池中等待被打包
> eth.sendTransaction({from: eth.accounts[2], to: eth.accounts[3],value: web3.toWei(1,"ether")})
"0x28f7e6989893d6e8b1cd26d5d7a285654f5a3c8eff7d6b2029817496deb8bda0"
//查看accounts[2]用户和accounts[3]用户的余额如下:
> eth.getBalance(eth.accounts[2])
2000000000000000000
> eth.getBalance(eth.accounts[3])
0
//查看交易池等待被打包的交易,其中有一条pending的交易,表示已提交但还未被处理的交易
> txpool.status
{
pending: 1,
queued: 0
}
//查看pending交易详情
> txpool.inspect.pending
{
0x115B0ba0ffDdB13Cd513ec38679E1089C252C839: {
0: "0xeed50D745A67EaA2A2EAf9e08A2485D1c1145103: 1000000000000000000 wei + 90000 gas × 1000000000 wei"
}
}
//要使交易被处理,必须要挖矿,启动挖矿后,等待挖到一个区块之后就可以停止挖矿了
> miner.start(1);admin.sleepBlocks(1);miner.stop();
null
>
//在日志显示终端可以看到正常执行后的挖矿日志
INFO [03-26|14:37:06.377] Updated mining threads threads=1
INFO [03-26|14:37:06.377] Transaction pool price threshold updated price=1000000000
INFO [03-26|14:37:06.378] Commit new mining work number=418 sealhash=14f834…2c37a4 uncles=0 txs=0 gas=0 fees=0 elapsed=376.473µs
INFO [03-26|14:37:06.381] Commit new mining work number=418 sealhash=f1a1e0…13c185 uncles=0 txs=1 gas=21000 fees=2.1e-05 elapsed=3.129ms
INFO [03-26|14:37:06.537] Successfully sealed new block number=418 sealhash=f1a1e0…13c185 hash=a79ae1…4cce3e elapsed=158.086ms
INFO [03-26|14:37:06.537] block reached canonical chain number=411 hash=8de5b1…25b9e2
INFO [03-26|14:37:06.537] mined potential block number=418 hash=a79ae1…4cce3e
INFO [03-26|14:37:06.537] Commit new mining work number=419 sealhash=58dcdb…adddbf uncles=0 txs=0 gas=0 fees=0 elapsed=217.251µs
//此时交易已经成功打包,并且加入区块链中了,此时查看余额:
> eth.getBalance(eth.accounts[2])
999979000000000000
> eth.getBalance(eth.accounts[3])
1000000000000000000
>
accounts[3]余额正确为1 ether,而accounts[2]似乎应该由2 ether变为1 ether,但结果并不是,这其中的原由便需要好好解释一下。
在以太坊中一个比较重要的概念就是gas,当你调用一个智能合约的时候,整个网络中的每个矿工会分别执行你调用的合约程序,这会消耗矿工的CPU、内存、与硬盘空间,在合约中执行每个命令的消耗会用单位gas计数。
gasPrice是你愿意为单位gas支付的费用,以gwei为单位表示。1 gwei = 1 000 000 000 wei,在交易中gasPrice是由发起交易的人规定的,每个矿工接收到交易请求时,会根据gasPrice的高低来决定是否要打包进区块中。
如果你希望矿工运行你的合约,你最好提供高一点的gasPrice。在某种程度上,这是一场基于合约运行,有多意愿付费驱动下的竞价。
在每个交易中必须包含gasLimit和gasPrice的值。gasLimit代表这个交易在执行过程中最多被允许消耗的gas数量。gasLimit和gasPrice就代表了交易发送者愿意为执行交易支付的wei的最大值。其最多可能付款金额 = gasLimit X gasPrice (wei)。
在交易完成后,如果实际消耗的gas小于gasLimit,那么剩余的gas会返回给交易发起者,交易实际法非金额计算方式:
实际交易费 = gasUsed X gasPrice
回到本例子中,通过查看下文中本交易被发起时的交易详情可以知道,本例子的转账交易发起时的gas = 90000,gasPrice = 1 000 000 000。而交易完成后被打包进区块后,该交易的详细信息中gasUsed: = 21 000 。
故这次交易的花费了:21 000 X 1 000 000 000 = 21 000 000 000 000 wei
accounts[2]向accounts[3]转账了1 ether后剩余1 ether = 1 000 000 000 000 000 000 wei,但还要承担交易费,故:
1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
— 2 1 0 0 0 0 0 0 0 0 0 0 0 0
——————————————————————
9 9 9 9 7 9 0 0 0 0 0 0 0 0 0 0 0 0
所以accounts[2]账户的余额为999 979 000 000 000 000
6.区块
//查看指定交易哈希值 所对应交易 被发起时的交易详情:
> eth.getTransaction("0x28f7e6989893d6e8b1cd26d5d7a285654f5a3c8eff7d6b2029817496deb8bda0")
{
blockHash: "0xa79ae173965c379d7fd75e865faf955e65d55feb1b3afe840a18fbe8f04cce3e",
blockNumber: 418,
from: "0x115b0ba0ffddb13cd513ec38679e1089c252c839",
gas: 90000,
gasPrice: 1000000000,
hash: "0x28f7e6989893d6e8b1cd26d5d7a285654f5a3c8eff7d6b2029817496deb8bda0",
input: "0x",
nonce: 0,
r: "0xb7579b66aa0e051b7ec7e8dad8f4d07454d415df6d7a2497a76f76b7e4bb0b62",
s: "0x53357a3b80e1e478012b89df718be16613f4f3a20141393acb16538dd3b02d23",
to: "0xeed50d745a67eaa2a2eaf9e08a2485d1c1145103",
transactionIndex: 0,
v: "0x42",
value: 1000000000000000000
}
>
其中参数详情 :
blockHash | 交易所在区块的哈希值。当这个区块处于pending时将会返回null |
blockNumber | 交易所在区块的区号。当这个区块处于pending时将会返回null |
from | 交易发起的地址 |
gas | 交易发起者提供的gas数量 |
gasPrice | 交易发起者提供的gasPrice,单位为wei |
hash | 交易的哈希值 |
input | 交易附带的数据 |
nonce | 交易的发起者在之前发起过的交易数量 |
transactionIndex | 交易在区块中的序号。当这个区块处于pending时将会返回null |
value | 交易附带的货币量,单位为wei |
to | 交易接受者的地址 |
//查看指定交易哈希值 所对应交易 被打包进区块时的详细信息:
> eth.getTransactionReceipt("0x28f7e6989893d6e8b1cd26d5d7a285654f5a3c8eff7d6b2029817496deb8bda0")
{
blockHash: "0xa79ae173965c379d7fd75e865faf955e65d55feb1b3afe840a18fbe8f04cce3e",
blockNumber: 418,
contractAddress: null,
cumulativeGasUsed: 21000,
from: "0x115b0ba0ffddb13cd513ec38679e1089c252c839",
gasUsed: 21000,
logs: [],
logsBloom: "0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000",
root: "0x45ddc0ef9a33a1e97acdd4b966ad631278f15a5744699ff7672f13f07d60e2e3",
to: "0xeed50d745a67eaa2a2eaf9e08a2485d1c1145103",
transactionHash: "0x28f7e6989893d6e8b1cd26d5d7a285654f5a3c8eff7d6b2029817496deb8bda0",
transactionIndex: 0
}
>
其中参数详情 :
blockHash | 交易所在区块的哈希值。 |
blockNumber | 交易所在区块的区号。 |
contractAddress | 创建的合约地址。如果是一个合约创建交易,则返回合约地址,其他情况返回null |
cumulativeGasUsed | 当前交易执行后累计花费的gas总值 |
from | 交易发送者的地址 |
gasUsed | 执行当前这个交易单独花费的gas |
logs | 这个交易产生的日志对象数组 |
logsBloom | logsBloom由logs中的address与topics共同决定,详细请看以太坊黄皮书,作用是便于快速查找监听的事件是否在该交易中产生 |
root | 交易执行后的stateroot |
to | 交易接收者的地址。如果是一个合约创建的交易,返回null |
transactionHash | 交易的哈希值 |
transationIndex | 交易在区块里面的序号 |
常用查询区块命令:
//查看当前区块链节点中第Number为1的区块详情
> eth.getBlock(1)
{
difficulty: 249472,
extraData: "0xd683010814846765746886676f312e3131856c696e7578",
gasLimit: 4290772993,
gasUsed: 0,
hash: "0xc18e6263be514c9c79b822d1d1fa9c17f25c148f4e71fb876da2c676eb19df2a",
logsBloom: "0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000",
miner: "0x1baed334cbf41a94daef7b247beebd6fdc45100c",
mixHash: "0xf67374106da53196fe47cd9002ea0e18415d209efae336619c8fa4fab1359455",
nonce: "0x1f7390e1d36e28fd",
number: 1,
parentHash: "0xa0e580c6769ac3dd80894b2a256164a76b796839d2eb7f799ef6b9850ea5e82e",
receiptsRoot: "0x56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421",
sha3Uncles: "0x1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347",
size: 535,
stateRoot: "0xbb491beccc4865b5728c8cec43bc46846591d54ba2a87dbd86aa03af18bcdbfd",
timestamp: 1553519563,
totalDifficulty: 511616,
transactions: [],
transactionsRoot: "0x56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421",
uncles: []
}
>
参数含义如下:
difficulty | 挖矿难度,后面区块难度会随着区块高度升高而提高 |
extraData | 当前区块链附加信息,若创世区块该值为空,则在第二个区块中会保存创建该私有链时的geth、go,以及操作系统版本,保存的信息为第一个挖到该区块的矿工信息 |
gasLimit | 该区块允许的最大gas数 |
GasUsed | gas花费,在以太坊中交易和部署智能合约会消耗gas |
hash | 当前区块哈希值 |
logsBloom | logsBloom由logs中的address与topics共同决定,详细请看以太坊黄皮书,作用是便于快速查找监听的事件是否在该交易中产生 |
miner |
挖到该区块的矿工地址 |
mixHash | 与nonce配合用于挖矿,由上一个区块的一部分生成的hash |
nonce | 工作量证明 |
number | 当前区块链高度 |
parentHash | 上一个区块链哈希值 |
receiptsRoot | 区块receipt trie的根 |
sha3Uncles | 对叔区块进行hash运算的结果 |
size | 区块大小,以字节为单位 |
stateRoot | 块的状态树根结果 |
timestamp | 时间戳 |
totalDifficulty | 达到该区块的难度综总数 |
transactions | 以数组的形式保存交易的tx值 |
transactionsRoot | 交易的默尔克树根 |
uncles | 当前区块引用的束缚区块的哈希值 |
7.账户管理
(1).创建新帐号
[root@localhost geth]# geth --datadir "./db1" account new
INFO [03-29|20:39:53.169] 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: {b1d70e94ffcba142fd024ece374e0be3cd9c08ad}
(2).列举已存在帐号
[root@localhost geth]# geth --datadir "./db1" account list
INFO [03-29|20:46:02.607] Maximum peer count ETH=25 LES=0 total=25
Account #0: {c4e87bb87064c40ecc07ed8955f35533c92a82f0} keystore:///opt/geth/db1/keystore/UTC--2019-03-28T13-07-34.305959164Z--c4e87bb87064c40ecc07ed8955f35533c92a82f0
Account #1: {70083e2f06da81015c1ee24b60a53fde4f30bddb} keystore:///opt/geth/db1/keystore/UTC--2019-03-28T14-08-09.815911074Z--70083e2f06da81015c1ee24b60a53fde4f30bddb
Account #2: {da66a23edbec03deef9eea953c1a2d865bf3acb3} keystore:///opt/geth/db1/keystore/UTC--2019-03-28T14-21-37.216641721Z--da66a23edbec03deef9eea953c1a2d865bf3acb3
Account #3: {b1d70e94ffcba142fd024ece374e0be3cd9c08ad} keystore:///opt/geth/db1/keystore/UTC--2019-03-29T12-40-09.120020587Z--b1d70e94ffcba142fd024ece374e0be3cd9c08ad
(3).修改账户密码
[root@localhost geth]# geth --datadir "./db1" account update b1d70e94ffcba142fd024ece374e0be3cd9c08ad
INFO [03-29|20:48:53.009] Maximum peer count ETH=25 LES=0 total=25
Unlocking account b1d70e94ffcba142fd024ece374e0be3cd9c08ad | Attempt 1/3
Passphrase:
INFO [03-29|20:48:58.466] Unlocked account address=0xB1d70e94FfCBa142FD024ecE374e0bE3Cd9C08ad
Please give a new password. Do not forget this password.
Passphrase:
Repeat passphrase:
(4).导入密钥文件
[root@localhost geth]# geth --datadir "./db1" account import ecc.key
INFO [03-29|21:06:10.906] 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: {fc563cb4086c1c9621c72b1a9f8d3b487fe438e9}
//其中ecc.key是ECDSA[椭圆曲线数字签名算法(ECDSA)是使用椭圆曲线密码(ECC)对数字签名算法(DSA)的模拟]的私钥
[root@localhost geth]# cat ecc.key
25066ae7675c08bdafded1c1403cc5d1431597149eac21261c5a3002339a007b
8.区块数据管理
(1).导出区块数据
//将db1目录中的区块数据导入到bak文件中:
[root@localhost geth]# geth --datadir "./db1" export ./bak
INFO [03-29|21:14:53.492] Maximum peer count ETH=25 LES=0 total=25
INFO [03-29|21:14:53.496] Allocated cache and file handles database=/opt/geth/db1/geth/chaindata cache=512 handles=1024
INFO [03-29|21:14:53.810] Disk storage enabled for ethash caches dir=/opt/geth/db1/geth/ethash count=3
INFO [03-29|21:14:53.810] Disk storage enabled for ethash DAGs dir=/root/.ethash count=2
INFO [03-29|21:14:53.870] Loaded most recent local header number=35 hash=7f2f97…73ba58 td=4603649 age=23h9m8s
INFO [03-29|21:14:53.870] Loaded most recent local full block number=35 hash=7f2f97…73ba58 td=4603649 age=23h9m8s
INFO [03-29|21:14:53.870] Loaded most recent local fast block number=35 hash=7f2f97…73ba58 td=4603649 age=23h9m8s
INFO [03-29|21:14:53.870] Exporting blockchain file=./bak
INFO [03-29|21:14:53.870] Exporting batch of blocks count=36
INFO [03-29|21:14:53.873] Exported blockchain file=./bak
Export done in 3.070252ms
//导入成功好会在当前目录下生成一个bak文件
[root@localhost geth]# ll
total 48
-rwxr-xr-x. 1 root root 19230 Mar 29 21:14 bak
drwx------. 4 root root 49 Mar 28 22:06 db1
-rw-r--r--. 1 root root 65 Mar 29 21:06 ecc.key
-rw-r--r--. 1 root root 605 Mar 28 20:11 gensis.json
-rw-r--r--. 1 root root 20377 Mar 28 22:06 geth.log
(2).移除区块数据
[root@localhost geth]# geth --datadir "./db1" removedb
INFO [03-29|21:18:16.562] Maximum peer count ETH=25 LES=0 total=25
/opt/geth/db1/geth/chaindata
Remove this database? [y/N] y
Remove this database? [y/N] y
INFO [03-29|21:18:23.975] Database successfully deleted database=chaindata elapsed=1.166ms
/opt/geth/db1/geth/lightchaindata
Remove this database? [y/N] y
Remove this database? [y/N] y
INFO [03-29|21:18:26.355] Database successfully deleted database=lightchaindata elapsed=1.276ms
(3).导入区块数据
//导入区块数据之前要用gensis.json文件执行初始化
[root@localhost geth]# geth --datadir "./db1" init gensis.json
INFO [03-29|21:19:30.372] Maximum peer count ETH=25 LES=0 total=25
INFO [03-29|21:19:30.374] Allocated cache and file handles database=/opt/geth/db/geth/chaindata cache=16 handles=16
INFO [03-29|21:19:30.464] Writing custom genesis block
INFO [03-29|21:19:30.464] Persisted trie from memory database nodes=0 size=0.00B time=21.737µs gcnodes=0 gcsize=0.00B gctime=0s livenodes=1 livesize=0.00B
INFO [03-29|21:19:30.464] Successfully wrote genesis state database=chaindata hash=1ef75f…d1799a
INFO [03-29|21:19:30.464] Allocated cache and file handles database=/opt/geth/db/geth/lightchaindata cache=16 handles=16
INFO [03-29|21:19:30.548] Writing custom genesis block
INFO [03-29|21:19:30.548] Persisted trie from memory database nodes=0 size=0.00B time=6.821µs gcnodes=0 gcsize=0.00B gctime=0s livenodes=1 livesize=0.00B
INFO [03-29|21:19:30.549] Successfully wrote genesis state database=lightchaindata hash=1ef75f…d1799a
//初始化完成后就可以导入区块数据le
[root@localhost geth]# geth --datadir "./db1" import ./bak
INFO [03-29|21:21:32.802] Maximum peer count ETH=25 LES=0 total=25
INFO [03-29|21:21:32.805] Allocated cache and file handles database=/opt/geth/db1/geth/chaindata cache=512 handles=1024
INFO [03-29|21:21:32.990] Writing default main-net genesis block
INFO [03-29|21:21:33.440] Persisted trie from memory database nodes=12356 size=1.88mB time=72.102914ms gcnodes=0 gcsize=0.00B gctime=0s livenodes=1 livesize=0.00B
INFO [03-29|21:21:33.440] Disk storage enabled for ethash caches dir=/opt/geth/db1/geth/ethash count=3
INFO [03-29|21:21:33.440] Disk storage enabled for ethash DAGs dir=/root/.ethash count=2
INFO [03-29|21:21:33.468] Loaded most recent local header number=0 hash=d4e567…cb8fa3 td=17179869184 age=49y11mo2w
INFO [03-29|21:21:33.468] Loaded most recent local full block number=0 hash=d4e567…cb8fa3 td=17179869184 age=49y11mo2w
INFO [03-29|21:21:33.468] Loaded most recent local fast block number=0 hash=d4e567…cb8fa3 td=17179869184 age=49y11mo2w
INFO [03-29|21:21:33.469] Importing blockchain file=./bak
ERROR[03-29|21:21:33.471]
########## BAD BLOCK #########
Chain config: {ChainID: 1 Homestead: 1150000 DAO: 1920000 DAOSupport: true EIP150: 2463000 EIP155: 2675000 EIP158: 2675000 Byzantium: 4370000 Constantinople: Engine: ethash}
Number: 1
Hash: 0xa5144c4a46a7047492371bdee8459785d09ae44e32d06a8a96c7409dfd35013a
Error: unknown ancestor
##############################
ERROR[03-29|21:21:33.471] Import error err="invalid block 35: unknown ancestor"
INFO [03-29|21:21:33.471] Blockchain manager stopped
Import done in 2.573417ms.
Compactions
Level | Tables | Size(MB) | Time(sec) | Read(MB) | Write(MB)
-------+------------+---------------+---------------+---------------+---------------
Read(MB):0.00000 Write(MB):2.38956
Trie cache misses: 0
Trie cache unloads: 0
Object memory: 268.085 MB current, 267.908 MB peak
System memory: 334.967 MB current, 334.967 MB peak
Allocations: 1.118 million
GC pause: 396.612µs
Compacting entire database...
Compaction done in 786.903722ms.
Compactions
Level | Tables | Size(MB) | Time(sec) | Read(MB) | Write(MB)
-------+------------+---------------+---------------+---------------+---------------
0 | 0 | 0.00000 | 0.59842 | 0.00000 | 1.91527
1 | 1 | 1.91526 | 0.13436 | 1.91527 | 1.91526
Read(MB):1.88542 Write(MB):6.22033
INFO [03-29|21:21:34.304] Database closed database=/opt/geth/db1/geth/chaindata
(4).dump
//从区块链中dump制定区块数据,geth命令后可以传入区块编号或区块hash值
$ geth --datadir "./db1" dump 0
9.远程节点连接
(1).查看节点信息
> admin.nodeInfo
{
enode: "enode://4b13086b294f1b7b0801ff78eb62cd9b1bf2991819ccc2b69df9a0371a031c0d8f25e84aa92781cb590a20b4ed25d4c67184c44470e008a77dfbe9ec4fedfe20@127.0.0.1:38690?discport=0",
enr: "0xf895b8407a227a916f7016b5dec567b0ecb41d6452fb41130b69bf861fae9ed271ff9c46607ae835137bf7b5508dfdd86a8df8ce859c61d044513ed707d72f5a58e272a50183636170ccc5836574683fc58373686806826964827634826970847f00000189736563703235366b31a1024b13086b294f1b7b0801ff78eb62cd9b1bf2991819ccc2b69df9a0371a031c0d83746370829722",
id: "d0bd4223d5c476927e34787e99179c27da96f4e1dee7913a345d445c89a164dd",
ip: "127.0.0.1",
listenAddr: "[::]:38690",
name: "Geth/v1.8.20-unstable/linux-amd64/go1.11",
ports: {
discovery: 0,
listener: 38690
},
protocols: {
eth: {
config: {
byzantiumBlock: 0,
chainId: 1337,
clique: {...},
constantinopleBlock: 0,
eip150Block: 0,
eip150Hash: "0x0000000000000000000000000000000000000000000000000000000000000000",
eip155Block: 0,
eip158Block: 0,
homesteadBlock: 0
},
difficulty: 37,
genesis: "0x004680c14f64dd409489eb632569fb1440bffbfbbc4996263e3f3cadb10e37a1",
head: "0x782e496b3110c566136549d7dfbc2cf7700b6414fcc3aa9d74eb5984ab076f39",
network: 1337
},
shh: {
maxMessageSize: 1048576,
minimumPoW: 0.2,
version: "6.0"
}
}
}
(2).添加其他节点
可以通过admin.addPeer()方法连接到其他节点,两个接节点想要联通,必须保证网络时相通的,并且要指定相同的networkid。我的第一个节点时我的本机节点,另一个节点时远程服务器节点,两个节点的gensis.json文件相同。
首先通过在远程服务器节点获取其encode信息,注意要把encode中的[::]替换成该机器的IP地址。
> admin.nodeInfo.enode
"enode://e5b417b09f971fc06a4a413ed4ed2d431cd303e286e44b01cf6c126c51708bde44cf6f692f611e441ba22f0ebce1b384d3f418af338589358daacd322f9df966@207.246.103.126:30303"
//在本机连接远程服务器节点
> admin.addPeer("enode://e5b417b09f971fc06a4a413ed4ed2d431cd303e286e44b01cf6c126c51708bde44cf6f692f611e441ba22f0ebce1b384d3f418af338589358daacd322f9df966@207.246.103.126:30303")
true
(3).查看已连接的远程节点
> admin.peers
[{
caps: ["eth/63"],
enode: "enode://e5b417b09f971fc06a4a413ed4ed2d431cd303e286e44b01cf6c126c51708bde44cf6f692f611e441ba22f0ebce1b384d3f418af338589358daacd322f9df966@207.246.103.126:30303",
id: "f40c748606f81f3d600584b70e4425165ed68ed47484d20afe5051655e509719",
name: "Geth/v1.8.23-stable/linux-amd64/go1.10.3",
network: {
inbound: false,
localAddress: "192.168.124.48:48550",
remoteAddress: "207.246.103.126:30303",
static: true,
trusted: false
},
protocols: {
eth: {
difficulty: 1,
head: "0x1ef75f7ced81aa0ff14865c59117439c6ae6760468d64e46e06311190dd1799a",
version: 63
}
}
}]
10.通过attach命令连接已启动节点
当通过geth命令启动了一个以太坊私有链时,会在数据目录下生成一个geth.ipc文件,在本例子中即为“./db/geth.ipc”。通过attach命令可以连接这个已经启动的节点,来启动一个Js命令环境:
[root@localhost geth]# geth --datadir "./db" attach ipc:./db/geth.ipc
Welcome to the Geth JavaScript console!
instance: Geth/v1.9.0-unstable-acbb8a14/linux-amd64/go1.11
coinbase: 0x8c7ae59ab7e5d510ae3f09a9544978f50315b5f5
at block: 107 (Sat, 06 Apr 2019 15:27:50 HKT)
datadir: /opt/geth/db
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
>
1.执行miner.start()返回null
解决方案借鉴自:https://blog.csdn.net/billwzf/article/details/83145111
geth版本更新之后,–dev模式(回归测试模式)下新增了一个参数项:
--dev Ephemeral proof-of-authority network with a pre-funded developer account, mining enabled
--dev.period value Block period to use in developer mode (0 = mine only if transaction pending) (default: 0)
–dev是我们常用的参数,之前版本中我们只用使用–dev然后执行miner.start()就可以挖矿,但是在后面的版本中,当我们会发现只有发送交易了才会挖一个块。引起此问题的原因就是新增了–dev.period value配置项。此配置默认值为0,也就是说只有pending中存在交易才会挖矿。所以–dev参数依旧使用,然后再在后面添加–dev.period 1,即设置dev.period的参数为1。
由于此参数的存在,使得存在两种启动模式:
1.dev模式
//该模式下需要在pending中先存在交易才可以挖矿
geth --networkid 15 --dev console 2>>geth.log
2.dev自动挖矿模式
geth --networkid 15 --dev --dev.period 1 console 2>>geth.log