写在前面
使用系统版本:Ubuntu 18.04
go 版本: go1.17.3
go-ethereum 版本:1.10.18-unstable
一、安装以太坊
1. 下载 Go Ethereum
注1:先安装 Go 和 C 编译器,C 编译器一般 Linux 系统自带,Go 安装比 go-ethereum 版本要求版本更高版本即可。
git clone https://github.com/ethereum/go-ethereum.git
cd go-ethereum
make geth # or make all (构建全套实用程序)
# 查看版本以验证是否安装成功
./build/bin/geth version
# 打印如下即为成功
# Geth
# Version: 1.10.18-unstable
# Git Commit: bb5633c5ee3975ce016636066ec790054ec469e4
# Git Commit Date: 20220417
# Architecture: amd64
# Go Version: go1.17.3
# Operating System: linux
# GOPATH=/home/jie/goproject
# GOROOT=/usr/local/go1.17.3
2. 配置环境
第一步结束后已经可以使用以太坊客户端 geth 了,但每次必须使用去 go-ethereum//build/bin/
下运行 geth
,可以把它配个环境,这个直接使用 geth
命令即可运行。
# 配置在 .bashrc 或者 /etc/profile 下均可,看个人习惯
sudo vim ~/.bashrc
# 在其中添加以下环境
export PATH=$PATH:$HOME/path/go-ethereum/build/bin # path 是具体安装的路径,$HOME 表示首页,即 ~
# 令环境立即生效
source ~/.bashrc
# 查看版本以验证是否安装成功
geth version
二、初始化创世区块
1. 创建 genesis.json
注2:建议使用 Go Ethereum 官方给的你安装版本对应的 genesis.json
,直接使用网上的脚本可以后续会有错误。
注3:可以自己新建一个文件夹进行以下操作,最好不要直接在 go-ethereum
文件夹中直接操作。
{
"config": {
# 这里输入链的网络 ID,建议设置大一点的数,如 22
"chainId": 22,
"homesteadBlock": 0,
"eip150Block": 0,
"eip155Block": 0,
"eip158Block": 0,
"byzantiumBlock": 0,
"constantinopleBlock": 0,
"petersburgBlock": 0,
"istanbulBlock": 0,
"berlinBlock": 0,
"londonBlock": 0
},
# alloc 包含初始化的账户信息以及以太币,这里为空,也可添加。
"alloc": {},
"coinbase": "0x0000000000000000000000000000000000000000",
# difficulty 代表挖矿难度,数值越小难度反而越大,所以为了挖矿更加简单,可以把这个值设置大一点。
"difficulty": "0x20000",
"extraData": "",
"gasLimit": "0x2fefd8",
"nonce": "0x0000000000000042",
"mixhash": "0x0000000000000000000000000000000000000000000000000000000000000000",
"parentHash": "0x0000000000000000000000000000000000000000000000000000000000000000",
"timestamp": "0x00"
}
2. 初始化传世区块
# ./ 代表当前目录,init genesis.json 表示使用这个文件初始化创世区块
geth --datadir ./ init genesis.json
执行后会在 genesis.json
的当前目录下初始化,然后执行完后会生成两个文件夹,geth
以及 keystore
,分别存放该链数据以及用户密钥。也可以将 ./
替换成你想放的目录下。
# 如果成功最后一句会是 Succsessfully,不使用官方给的就有可能会失败
# Successfully wrote genesis state database=lightchaindata hash=d9f9b7..32048b
三、启动私有链
1. 启动私有链
geth --datadir ./ console 2>>geth.log
# 如果 exit 退出后想要重新进入该链,执行以下命令
geth --datadir --networkid 22 ./ console 2>>geth.log
2>>geth.log
命令是指将日志输出到 geth.log
文件上,如果不加这个参数日志将会在控制台输出,会看起来很乱,建议加上。
networkid
后为在创世区块中设置的 chainId
。
2. (可选)查看实时日志输出
# 可以打开一个新的终端查看输出的日志
# 进入私有链所在目录
taif -f geth.log
3. 重新进入该链
geth --datadir --networkid 22 ./ console 2>>geth.log
四、一些基本命令
1. 查看账户
# 返回一个空数组说明当前并无账户
eth.accounts
# 输出:
# []
2. 创建账户
# 创建两个账户,回车后会要求输入两次密码,该密码即为该账户的私钥
# 同时会返回账户哈希,并将账户信息存储到 keystore 文件中
personal.newAccount()
personal.newAccount()
# 查看账户,会返回创建的两个账户,返回为数组类型,可通过下标查看对应账户,如 eth.accounts[0]
eth.accounts
eth.accounts[0]
# 输出
# ["0x3113384d0968f6e1adafa677c7b8b5007f827e83", "0xa0b65c2f4130676eb5cccef52fbaf3b03cb7684f"]
3. 查看账户余额
# 查看第一个账户余额
eth.getBalance(eth.accounts[0])
# or
eth.getBalance("0x3113384d0968f6e1adafa677c7b8b5007f827e83") # 后面为所创建的账户地址
4. 查看当前区块总数
eth.blockNumber
5. 启动&停止挖矿
- 通过
miner.start()
来启动挖矿 - 通过
miner.stop()
来停止挖矿
其中 start 的参数表示挖矿使用的线程数,如使用一个线程:miner.start(1)
。
# 启动挖矿(这里使用一个线程,反正挖的太快)
miner.start(1)
# 停止挖矿
miner.stop()
# 当前区块总数
eth.blockNumber
# 查看账户余额
eth.getBalance(eth.accounts[0])
eth.getBalance(eth.accounts[1])
# 挖出一个区块后后停止挖矿
miner.start(1);admin.sleepBlocks(1);miner.stop()
注4:挖到一个区块会奖励以太币,挖矿所得的奖励会进入矿工的账户,这个账户叫做 coinbase
,默认情况下 coinbase
是本地账户中的第一个账户,通过 miner.setEtherbase()
可将其他账户设置成 coinbase
。
注5: getBalance()
返回值的单位是 wei
,wei
是以太币的最小单位,$1 eth = 10^{18} wei$。要查看有多少个以太币,可以用 web3.fromWei()
将返回值换算成以太币
web3.fromWei(eth.getBalance(eth.accounts[0]),'ether')
# 以下命令与以上命令等效
web3.fromWei(eth.getBalance(eth.accounts[0]))
6. 发送交易
可以通过发送一笔交易,从 A
账户转移 x wei
到 B
账户
注6:以太坊区块链中,交易过程转移金额的默认单位为 wei
,可以通过 web3.toWei(5,'ether')
命令来转移以 eth
为单位的金额,这里即为 5 eth
。
注7:账户默认是锁住的,想要发送交易,必须先解锁账户。
# 由于我们要从账户0 发送交易,所以要解锁账户0
# 执行以下命令,会要求输入创建账户时设置的密码,输入后即可成功解锁账户。然后再发送交易
personal.unlockAccount(eth.accounts[0])
# 账户0 向账户1 转账 5以太
# 这里如果在创建创世区块时没有使用官方给的 genesis.json,就很可能会报 invalid sender 错误
# 如果没有解锁账户直接执行以下命令,可能会报 authentication needed: password or unlock 错误
eth.sendTransaction({from:eth.accounts[0], to:eth.accounts[1], value:web3.toWei(5,'ether')})
# 输出,即交易哈希
# "0x3b446dd1241a0caaac0c33c66770205fa01368b2772ab391f9526436817402a8"
注8:发送交易命令执行后会返回一串交易哈希,即交易 ID,证明可以转账,但还未被处理,这可以通过查看 txpool
或查看账户1 和 2 的余额来验证。
# 查看 txpool
txpool.status
# 输出:
#{
# pending: 1,
# queued: 0
#}
# 查看账户 1 和 2 的余额,余额并未变化
web3.fromWei(eth.getBalance(eth.accounts[0]))
web3.fromWei(eth.getBalance(eth.accounts[1]))
注9:其中有一条 pending
交易,pending
表示已提交但还未被处理的交易。要使交易被处理,必须要挖矿。
# 启动挖矿,挖一个区块停止
miner.start(1);admin.sleepBlocks(1);miner.stop()
# 查看 txpool
txpool.status
# 输出
#{
# pending: 0,
# queued: 0
#}
# 查看账户 1 和 2 的余额,余额并未变化
web3.fromWei(eth.getBalance(eth.accounts[0]))
web3.fromWei(eth.getBalance(eth.accounts[1]))
# 当前区块总数
eth.blockNumber
7. 通过区块号(高度)查看区块信息
eth.getBlock(6)
输出:
> eth.getBlock(6)
{
baseFeePerGas: 448795319,
difficulty: 131072,
extraData: "0xd883010a12846765746888676f312e31372e33856c696e7578",
gasLimit: 3160033,
gasUsed: 21000,
hash: "0xc1c0e97720536c772968f7e5c23d3404cb66041ae7253ff9646f2d98d67970e6",
logsBloom: "0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000",
# miner 即为账户0,也就是 coinbase
miner: "0x3113384d0968f6e1adafa677c7b8b5007f827e83",
mixHash: "0x434d61662f34a84f9dc3eaa0d93fec0a2d3118c8a0fcc8f7688e13dad0abdecf",
nonce: "0x5dfb34e08749f62c",
number: 6,
parentHash: "0x55f65d8c3834d9e413371cf9141da3b872d3306cf22b116fb8b982300a83bb60",
receiptsRoot: "0xf78dfb743fbd92ade140711c8bbc542b5e307f0ab7984eff35d751969fe57efa",
sha3Uncles: "0x70636c369d8297576b3e53a072d9deb3c28fcdcaa9496a8a4f9b2d634eaf0eb8",
size: 663,
stateRoot: "0xc4f5adf03bb3b1202d66b2492f7c4c361bc253a1f1528ecd4f28e5362dbaa38c",
timestamp: 1650461496,
totalDifficulty: 918144,
# transactions 中即为前面发送交易的交易哈希
transactions: ["0x3b446dd1241a0caaac0c33c66770205fa01368b2772ab391f9526436817402a8"],
transactionsRoot: "0x6b1e64b5e6957fab09c03a8a3e49eda3a50e642d1d4177e43cc0c03b4b73f639",
uncles: []
}
8. 通过交易 hash 查看交易
eth.getTransaction("0x3b446dd1241a0caaac0c33c66770205fa01368b2772ab391f9526436817402a8")
输出:
{
accessList: [],
blockHash: "0xc1c0e97720536c772968f7e5c23d3404cb66041ae7253ff9646f2d98d67970e6",
# 该交易位于块高为 6 的区块上
blockNumber: 6,
# chainId 0x16 即为 22
chainId: "0x16",
# from: 账户 1
from: "0x3113384d0968f6e1adafa677c7b8b5007f827e83",
gas: 21000,
gasPrice: 1448795319,
# 交易哈希
hash: "0x3b446dd1241a0caaac0c33c66770205fa01368b2772ab391f9526436817402a8",
input: "0x",
maxFeePerGas: 2025817872,
maxPriorityFeePerGas: 1000000000,
nonce: 0,
r: "0x8f06eeb98ed23ccbf9d1cd3e8a73e900189c42caa5c9ea50500f95cf4dbeda2c",
s: "0x402728e7af7d11166fa0813a1febcaff1f7a217d2e3a646284633c85f313a1f2",
# to: 账户 2
to: "0xa0b65c2f4130676eb5cccef52fbaf3b03cb7684f",
transactionIndex: 0,
type: "0x2",
v: "0x1",
# 发送 5 以太币
value: 5000000000000000000
}