客户端安装
以太坊客户端安装,即geth的安装。geth是go-ethereum的简写,是一个用go语言编写的以太坊客户端,是在以太坊智能合约开发中最常用的命令行工具。在mac上可以通过brew工具直接安装:
> brew tap ethereum/ethereum
> brew install ethereum
安装完成,用以下命令测试,若出现帮助相关的信息,则已安装成功
> geth -h
搭建私有链
1、创世区块配置
要搭建私有链,首先得创建一个创世区块。创世区块的创建需要准备一个json格式配置文件,信息可自定义,如genesis.json:
{
"config": {
"chainId": 10,
"homesteadBlock": 0,
"eip150Block": 0,
"eip155Block": 0,
"eip158Block": 0
},
"alloc": {},
"coinbase": "0x0000000000000000000000000000000000000000",
"extraData": "",
"difficulty": "0x40000",
"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 | 设置创世块的时间戳 |
2 、创世区块创建
准备好创世区块配置文件后,需要初始化区块链,将配置文件的信息写入区块链中。首先我们准备一个目录来存放区块链数据(文中的目录为:~/pchain/db)将配置文件存放到pchain目录下,执行以下命令:
> mkdir db
> geth --datadir "./db" init genesis.json
运行成功,终端会显示
Successfully wrote genesis state
同时,db目录下会新增geth和keystore两个文件夹
- geth目录:保存链上的区块数据
- keystore目录:保存链上的用户信息
注:失败总结,在创建创世块的时候,可能会失败,一般是配置文件的错误
- Fatal: Failed to write genesis block: genesis has no chain configuration
解决:原先的配置文件为加config信息,需要添加config信息 - Fatal: Failed to write genesis block: unsupported fork ordering: eip150Block not enabled, but eip155Block enabled at 0
解决:配置文件中的config未添加eip150Block,添加eip150Block信息 - 其他错误:可通过此链接排查
3、启动私有链
前面建立创世区块成功后,启动区块链程序:
> geth --datadir db --networkid 1111 console
命令最后带上console,表示启动节点并进入控制台(若需要退出控制台,输入"exit"即可),
- –datadir:指定db为数据目录
- –networkid: 指定1111为网络id。(以太坊公网的网络id是1)
运行上面的命令后,终端显示以下内容,就启动了区块链节点,并进入了Javascript Console:
Welcome to the Geth JavaScript console!
instance: Geth/v1.9.7-stable/darwin-amd64/go1.13.4
at block: 0 (Thu, 01 Jan 1970 08:00:00 CST)
datadir: ~/pchain/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
命令 | 说明 |
---|---|
admin | 节点管理api |
debug | 节点调试api |
eth | 操作区块链相关api |
ethash | Ethereum 1.0使用的PoW算法 |
miner | 挖矿相关api |
net | 查看p2p网络状态相关api |
personal | 管理账户相关api |
rpc | HTTP-RPC API接口 |
txpool | 查看交易相关api |
web3 | api |
3.1 查看账号
> eth.accounts
[]
3.2 创建账号
> personal.newAccount("123456") //括号中为密码
> personal.newAccount("123456")
执行这两条命令后,会新增两个地址,再次查看账号:
> eth.accounts
["0xf4ef158bda4958ecc8eaffd2c6b924b39333803b", "0x5db34569ffbf2738efc4f449967556a3648e9697"]
3.3 查看余额
以下两条命令都可以查看余额
> eth.getBalance("0xf4ef158bda4958ecc8eaffd2c6b924b39333803b")
0
> eth.getBalance(eth.accounts[0])
0
getBalance()返回值的单位是wei,wei是以太币的最小单位,1个以太币=10的18次方个wei。要查看有多少个以太币,可以用web3.fromWei()将返回值换算成以太币:
> web3.fromWei(eth.getBalance(eth.accounts[0]),'ether')
0
3.4 挖矿
- 开始挖矿
> miner.start()
执行挖矿命令后,则终端开始被挖矿信息刷屏,如:🔨 mined potential block 之类的信息
- 停止挖坑
> miner.stop()
此时,再次查询账户余额信息,
> eth.getBalance(eth.accounts[0])
225000000000000000000
> eth.getBalance(eth.accounts[1])
0
这里发现,账户0余额增多,账户1余额依然是0。这里涉及到coinbase的知识点。
- coinbase
挖到一个区块会奖励5个以太币,挖矿所得的奖励会进入矿工的账户,这个账户叫做coinbase,默认为本地账户中的第一个账户。当然,可以通过命令将其他账户设置成coinbase,返回true表示设置成功
> miner.setEtherbase(eth.accounts[1])
true
> eth.coinbase //重新查看coinbase账号,已更新为账户1
"0x5db34569ffbf2738efc4f449967556a3648e9697"
3.5 交易
查看本地两个账户余额,账户0已有225个以太坊,账户1余额为0。
> web3.fromWei(eth.getBalance(eth.accounts[0]),'ether')
225
> web3.fromWei(eth.getBalance(eth.accounts[1]),'ether')
0
3.5.1 发送交易
现在,我们可以从账户0转25个以太坊给账户1
> amount = web3.toWei(25,'ether')
"25000000000000000000"
> eth.sendTransaction({from:eth.accounts[0],to:eth.accounts[1],value:amount})
WARN [11-21|10:25:44.900] Served eth_sendTransaction reqid=36 t=10.684942ms err="authentication needed: password or unlock"
Error: authentication needed: password or unlock
at web3.js:3143:20
at web3.js:6347:15
at web3.js:5081:36
at <anonymous>:1:1
此处报错了,提示需要对账户0进行解锁。
> personal.unlockAccount(eth.accounts[0])
Unlock account 0xf4ef158bda4958ecc8eaffd2c6b924b39333803b
Password:
true
解锁后继续进行转账操作:
> amount = web3.toWei(25,'ether')
"25000000000000000000"
> eth.sendTransaction({from:eth.accounts[0],to:eth.accounts[1],value:amount})
INFO [11-21|10:33:01.349] Setting new local account address=0xf4EF158BdA4958ecC8eaFFd2c6B924B39333803b
INFO [11-21|10:33:01.350] Submitted transaction fullhash=0x4872eff6bf39a5fb01a5a7accf50de46ef9ce0f8bf8ed3675398492010d37788 recipient=0x5dB34569fFBf2738EFc4f449967556A3648e9697
"0x4872eff6bf39a5fb01a5a7accf50de46ef9ce0f8bf8ed3675398492010d37788"
此时交易已经提交到区块链,返回了交易的hash,可通过txpool来查询交易状态:
> txpool.status
{
pending: 1,
queued: 0
}
交易状态中有一条pending的状态(pending表示已提交但还未被处理的交易)。我们继续通过txpool查看pending信息,显而易见pending信息是上边发起的交易信息。
> txpool.inspect.pending
{
0xf4EF158BdA4958ecC8eaFFd2c6B924B39333803b: {
0: "0x5dB34569fFBf2738EFc4f449967556A3648e9697: 25000000000000000000 wei + 21000 gas × 1000000000 wei"
}
}
怎么才能处理Pending中的交易呢,得继续挖矿,才能使交易打包到区块中,即可处理。此处省略挖矿步骤。停止挖矿后,我们再次查看状态,pending状态已被处理
> txpool.status
{
pending: 0,
queued: 0
}
再次查看两个账户的余额
> web3.fromWei(eth.getBalance(eth.accounts[0]),'ether')
199.999979
> web3.fromWei(eth.getBalance(eth.accounts[1]),'ether')
55.000021
- 账户0:原先225个以太坊,转出25个以太坊及0.000021的矿工费,剩余199.999979
- 账户1:原先0个以太坊,收入25个以太坊及30个挖矿奖励(3.4已将账户1设置为coinbase,处理pending时挖矿的奖励入账该账户)
3.5.2 查看交易
发送交易后,可通过返回的hast值查看交易
> eth.getTransaction("0x4872eff6bf39a5fb01a5a7accf50de46ef9ce0f8bf8ed3675398492010d37788")
{
blockHash: "0xcf6272408a93afad0686d1c4fdf26d26baf3b113e1e7c02f54adde62c33e1865",
blockNumber: 46,
from: "0xf4ef158bda4958ecc8eaffd2c6b924b39333803b",
gas: 21000,
gasPrice: 1000000000,
hash: "0x4872eff6bf39a5fb01a5a7accf50de46ef9ce0f8bf8ed3675398492010d37788",
input: "0x",
nonce: 0,
r: "0xfdbb633e221b0b85fce7df19c025454558d4fd8e345585461e6bf628dd19c5dc",
s: "0x4942c54b74b6ccbe642e114003ab987590157044a9ea6454c08dd6bb879dca0",
to: "0x5db34569ffbf2738efc4f449967556a3648e9697",
transactionIndex: 0,
v: "0x37",
value: 25000000000000000000
}