玩转Web3:Geth搭建联盟链

玩转Web3:Geth搭建联盟链

开篇

从本篇开始,我们准备更新 《玩转Web3》 系统文章,web3 的技术圈非常有趣,有很多思想的迭代,接下来就让我们开始 《玩转Web3》 吧!

本章主要内容

  • 了解 Geth 的作用以及使用方法
  • 搭建 Geth 联盟链,让区块链中的各个节点进行账本同步
  • 使用 Metamask 在搭建好的联盟链中进行交易转账

初识Geth

Geth 是以太坊的客户端,客户端是能够与其他客户端建立 p2p 通信信道、签署广播交易、挖矿、部署和与智能合约交的软件。 以太坊节点必须遵循的功能的正式定义在以太坊黄皮书中定义。
黄皮书定义了网络上节点所需的函数,挖矿算法、私钥/公钥ECDSA 参数等,它定义了使节点与以太坊客户端完全兼容的全部功能。

大家按照自己的操作系统去官网上下载 Geth 就可以了,安装好后按如下教程进行使用

初始化创世块

  • genesis.json 区块链初始文件
{
  "alloc": { // 创世时,一开始的代币分配(非必须)
  },
  "config": {
    "chainId": 6668,  // 该链的ID。在用geth 启动区块链时,还需要指定一个network 参数。只有当network、chainID、创世区块配置都相同时,才是同一条链。
    "homesteadBlock": 0, // 相关协议机制的升级区块所在的高度,签名算法是homestead ->eip155 -> eip158,所以从homesteadBlock 之前区块都通过homestead 相关算法机制来验证,homesteadBlock 到eip155Block 之间的用eip155 算法来验证,依次类推
    "eip150Block": 0,
    "eip150Hash": "0x0000000000000000000000000000000000000000000000000000000000000000",
    "eip155Block": 0,
    "eip158Block": 0,
    "byzantiumBlock": 0,
    "constantinopleBlock": 0,
    "petersburgBlock": 0,
    "istanbulBlock": 0,
    "ethash": {}
  },
  "nonce": "0x000000000000002a", // 预定一个随机数,这是一个与PoW 机制有关的值
  "difficulty": "0x020000",  // 定义了每次挖矿时,最终确定nonce 的难度
  "mixhash": "0x0000000000000000000000000000000000000000000000000000000000000000", // 一个与PoW 机制有关的值
  "coinbase": "0x0000000000000000000000000000000000000000", // 每挖出一个区块,都会获得奖励。该值指定默认情况下把奖励给到哪个账户。实际上,我们每次挖矿开始之前,都会自己指定miner.setEtherbase(UserAddress),一般都会把奖励给自己
  "timestamp": "0x00", // 时间戳,规定创世区块开始的时间
  "parentHash": "0x0000000000000000000000000000000000000000000000000000000000000000", // 在区块链中,区块是相连的,parentHash 指定了本区块的上一个区块Hash。对于创世区块来说,parentHash 为0
  "extraData": "0x", // 扩展数据
  "gasLimit": "0x2fefd8" // 规定该区块链中,gas 的上限
}
  • 利用 Geth 初始化区块链
# 初始化
geth --datadir "D:\block\gt\data0" init genesis.json

# 启动
geth --identity "node0" --datadir "D:\block\gt\data" --http --http.port 8545 --http.corsdomain="*" --http.addr "0.0.0.0" --http.api "eth,web3,miner,admin,personal,net"  --nodiscover --networkid 15 --allow-insecure-unlock --port 30303 --ipcdisable

# 通过http协议加入进入 console
geth attach http://127.0.0.1:8545
  • 命令参数说明
参数 说明
--datadir 指定节点数据目录
init 指定初始化节点使用的配置文件 genesis.json
--identity 设定节点标识
--http 开启http rpc 服务
--http.port 指定http rpc端口
--http.corsdomain 指定跨域
--http.addr 监听地址,默认为127.0.0.1,只能本地访问
--http.api 设置节点上启用RPC接口
--nodiscover 使用此选项可确保未手动添加您的人员无法发现您的节点。否则,如果您的节点具有相同的创世纪文件和网络ID,则可能无意中将您的节点添加到陌生人的区块链中
--networkid 设定网络ID,当创建的链的 genesis block 和 network id 刚好与网络上其他人的链相同,那么就看哪条链长,如果比对方的短,那么链上的数据会全部被覆盖,变成对方的链。
--allow-insecure-unlock 允许使用 http 协议进行账户解锁
--port 网络侦听端口,对等端连接端口
--ipcdisable 指定跨域

这样一个单节点就搭建好了,这里我们就可以利用刚刚启动后的 console 操作里面的模块了

console 模块

模块 作用
eth 区块操作
web3 包含了其他模块对象中的方法外,还包含一些单位换算的方法
miner 挖矿操作
admin 节点操作
personal 账户操作
net 网络操作

我们主要了解 mineradmin以及personal模块,我们先简单实现创建一个账户,然后将这个账户设置为矿工,获取以太币收益

# 创建账户 会让输入密码 会返回一个地址
personal.newAccount()   # "0x9c0e89ab86f0874e9977f89c64e2eb6bfd981322"

# 设置矿工 返回true
miner.setEtherbase("0x9c0e89ab86f0874e9977f89c64e2eb6bfd981322")

# 开始挖矿获取收益 返回 null
miner.start()

# 稍等一会就可以 停止挖矿
miner.stop()

# 然后我们查看账户余额
eth.getBalance("0x9c0e89ab86f0874e9977f89c64e2eb6bfd981322")

# 以以太为单位查看,默认是 wei 
web3.fromWei(eth.getBalance("0x9c0e89ab86f0874e9977f89c64e2eb6bfd981322"),'ether')

现在我们已经可以进行单节点交互了,但是我们区块链主要是要交易记账,所以我们接下来要再新建一个账户,然后利用之前账户的以太进行转账

personal.newAccount()   # "0x035bafe05b4a7a4eba9accf2c692785798b7132c"

# 转账 from -> to  value 付多少
eth.sendTransaction({from:"0x9c0e89ab86f0874e9977f89c64e2eb6bfd981322",to:"0x035bafe05b4a7a4eba9accf2c692785798b7132c",value:1000000000000})

# 但是在进行转账之前,我们需要先解锁我们的账户,相当于证明这个账户是我们自己的
personal.unlockAccount("0x9c0e89ab86f0874e9977f89c64e2eb6bfd981322")

# 交易创建之后 每笔交易都会写入在区块中,但是需要挖矿才会被确认,所以我们发起了一笔交易,还需要进行挖矿才能使交易成功
miner.start()
miner.stop()
eth.getBalance("0x035bafe05b4a7a4eba9accf2c692785798b7132c") # 1000000000000

到这里,我们就看到了关于区块链的基本操作啦,但是单节点的区块链很明显信任度是不够的,而且单点故障问题也存在,所以我们需要构建一个分布式点对点系统。

搭建联盟链

我们准备在本机中,再启动两个节点,和之前流程一样,先初始化节点,然后去主节点上添加那两个节点(因为我们把自动发现给关闭了,所以我们需要手动去加入,正常是不用的)

# 指定新的数据目录 新的端口
geth --datadir "D:\block\gt\data1" init genesis.json
geth --identity "node1" --datadir "D:\block\gt\data1" --http --http.port 8546 --http.corsdomain="*" --http.addr "0.0.0.0" --http.api "eth,web3,miner,admin,personal,net" --nodiscover   --networkid 15 --allow-insecure-unlock --port 30304 --ipcdisable

# 指定新的数据目录 新的端口
geth --datadir "D:\block\gt\data2" init genesis.json
geth --identity "node2" --datadir "D:\block\gt\data2" --http --http.port 8547 --http.corsdomain="*" --http.addr "0.0.0.0" --http.api "eth,web3,miner,admin,personal,net" --nodiscover   --networkid 15 --allow-insecure-unlock --port 30305 --ipcdisable

加入其它节点

当启动新的两个节点 console 后,查看 enode,到 node0 上面去加入 node1node2enode

# node1操作
admin.nodeInfo.enode # enode://5a0e1b6a2c4232a5e774a69a7c660acfa5cb7f573e89e55283c5a438c8d6280539c23cfe68bfdf4873b62da463eae4bc0add8adb9e806e261b875a32b83c7a7c@127.0.0.1:30304?discport=0
# node2操作
admin.nodeInfo.enode # enode://afd9e6d63588bcb070c8245f4c78612c8dd9a57def78aed85e135318397f43bbc01a47fdbb44f990304eefa59bdaae2d91ec5c2190f02bc52d7fdcec26c86a12@127.0.0.1:30305?discport=0

# node0操作
admin.addPeer("enode://afd9e6d63588bcb070c8245f4c78612c8dd9a57def78aed85e135318397f43bbc01a47fdbb44f990304eefa59bdaae2d91ec5c2190f02bc52d7fdcec26c86a12@127.0.0.1:30305?discport=0")
admin.addPeer("enode://5a0e1b6a2c4232a5e774a69a7c660acfa5cb7f573e89e55283c5a438c8d6280539c23cfe68bfdf4873b62da463eae4bc0add8adb9e806e261b875a32b83c7a7c@127.0.0.1:30304?discport=0")
admin.peers # 查看加入的节点

看到如下状态即成功

加入成功

查看区块同步是否正常

我们通过在 node0 上挖矿,查看其他节点的日志是否处于同步状态,然后在 node1node2 上去查看 node0 里面的账户余额

miner.start()
miner.stop()

看到其他节点都有成功日志

成功

  • node0node1 查看挖矿账户的余额
# node1
geth attach http://127.0.0.1:8546
web3.fromWei(eth.getBalance("0x9c0e89ab86f0874e9977f89c64e2eb6bfd981322"),'ether')  # 85.999998
# node2
geth attach http://127.0.0.1:8547
web3.fromWei(eth.getBalance("0x9c0e89ab86f0874e9977f89c64e2eb6bfd981322"),'ether')  # 85.999998

通过 Metamask 在联盟链中转账

我们通过下面流程进行操作:

  • metamask 中添加我们的测试网络
  • 导入我们之前创建的挖矿账户,在 node2 中创建一个账户,然后通过 metamask 进行转账
  • 然后挖矿查看结果

添加测试网络

利用 metamask 转账

node0 的数据目录中,找到 keystore ,里面都是账户的 json 文件,找到我们的矿工账户文件

去 metamask 中进行导入,输入创建账户时的密码

点击确定之后,可能会出现卡顿,过几分钟重新打开,会发现账户已经导入成功

node2中创建账户

geth attach http://127.0.0.1:8547

personal.newAccount()  # "0xc1864e1f2b262ef89228eb1ebde9be6a6165cbe7"

使用 metamask 向地址转账

挖矿确认这笔交易

miner.start()
miner.stop()

成功,查询一下余额

web3.fromWei(eth.getBalance("0xc1864e1f2b262ef89228eb1ebde9be6a6165cbe7"),'ether') # 20

踩坑

  • Erro starting protocol stack:Access is denied

增加参数 --ipcdisable,禁用 ipc

  • 为什么我使用了 admin.addPeer 加入了正确的 enode ,而且结果也返回了 true ,通过 admin.peers 还是看不到加入的节点呢?

这个原因很简单,因为其他节点的初始化与主节点不一致,例如,忘记执行 init 步骤了,或者 init 选择的配置不一致,一定要保证和主节点初始化启动保持一致

  • Error: The method personal_newAccount does not exist/is not available

--http.api 没有开启 personal 模块

总结

本章,我们搭建了私有联盟链,利用 metamask 进行操作,这个系统我们需要保留下来,之后可以用来部署合约,发布 ERC 系列货币,深入研究区块链原理和结构。

玩转Web3:Geth搭建联盟链

开篇

从本篇开始,我们准备更新 《玩转Web3》 系统文章,web3 的技术圈非常有趣,有很多思想的迭代,接下来就让我们开始 《玩转Web3》 吧!

本章主要内容

  • 了解 Geth 的作用以及使用方法
  • 搭建 Geth 联盟链,让区块链中的各个节点进行账本同步
  • 使用 Metamask 在搭建好的联盟链中进行交易转账

初识Geth

Geth 是以太坊的客户端,客户端是能够与其他客户端建立 p2p 通信信道、签署广播交易、挖矿、部署和与智能合约交的软件。 以太坊节点必须遵循的功能的正式定义在以太坊黄皮书中定义。
黄皮书定义了网络上节点所需的函数,挖矿算法、私钥/公钥ECDSA 参数等,它定义了使节点与以太坊客户端完全兼容的全部功能。

大家按照自己的操作系统去官网上下载 Geth 就可以了,安装好后按如下教程进行使用

初始化创世块

  • genesis.json 区块链初始文件
{
  "alloc": { // 创世时,一开始的代币分配(非必须)
  },
  "config": {
    "chainId": 6668,  // 该链的ID。在用geth 启动区块链时,还需要指定一个network 参数。只有当network、chainID、创世区块配置都相同时,才是同一条链。
    "homesteadBlock": 0, // 相关协议机制的升级区块所在的高度,签名算法是homestead ->eip155 -> eip158,所以从homesteadBlock 之前区块都通过homestead 相关算法机制来验证,homesteadBlock 到eip155Block 之间的用eip155 算法来验证,依次类推
    "eip150Block": 0,
    "eip150Hash": "0x0000000000000000000000000000000000000000000000000000000000000000",
    "eip155Block": 0,
    "eip158Block": 0,
    "byzantiumBlock": 0,
    "constantinopleBlock": 0,
    "petersburgBlock": 0,
    "istanbulBlock": 0,
    "ethash": {}
  },
  "nonce": "0x000000000000002a", // 预定一个随机数,这是一个与PoW 机制有关的值
  "difficulty": "0x020000",  // 定义了每次挖矿时,最终确定nonce 的难度
  "mixhash": "0x0000000000000000000000000000000000000000000000000000000000000000", // 一个与PoW 机制有关的值
  "coinbase": "0x0000000000000000000000000000000000000000", // 每挖出一个区块,都会获得奖励。该值指定默认情况下把奖励给到哪个账户。实际上,我们每次挖矿开始之前,都会自己指定miner.setEtherbase(UserAddress),一般都会把奖励给自己
  "timestamp": "0x00", // 时间戳,规定创世区块开始的时间
  "parentHash": "0x0000000000000000000000000000000000000000000000000000000000000000", // 在区块链中,区块是相连的,parentHash 指定了本区块的上一个区块Hash。对于创世区块来说,parentHash 为0
  "extraData": "0x", // 扩展数据
  "gasLimit": "0x2fefd8" // 规定该区块链中,gas 的上限
}
  • 利用 Geth 初始化区块链
# 初始化
geth --datadir "D:\block\gt\data0" init genesis.json

# 启动
geth --identity "node0" --datadir "D:\block\gt\data" --http --http.port 8545 --http.corsdomain="*" --http.addr "0.0.0.0" --http.api "eth,web3,miner,admin,personal,net"  --nodiscover --networkid 15 --allow-insecure-unlock --port 30303 --ipcdisable

# 通过http协议加入进入 console
geth attach http://127.0.0.1:8545
  • 命令参数说明
参数 说明
--datadir 指定节点数据目录
init 指定初始化节点使用的配置文件 genesis.json
--identity 设定节点标识
--http 开启http rpc 服务
--http.port 指定http rpc端口
--http.corsdomain 指定跨域
--http.addr 监听地址,默认为127.0.0.1,只能本地访问
--http.api 设置节点上启用RPC接口
--nodiscover 使用此选项可确保未手动添加您的人员无法发现您的节点。否则,如果您的节点具有相同的创世纪文件和网络ID,则可能无意中将您的节点添加到陌生人的区块链中
--networkid 设定网络ID,当创建的链的 genesis block 和 network id 刚好与网络上其他人的链相同,那么就看哪条链长,如果比对方的短,那么链上的数据会全部被覆盖,变成对方的链。
--allow-insecure-unlock 允许使用 http 协议进行账户解锁
--port 网络侦听端口,对等端连接端口
--ipcdisable 指定跨域

这样一个单节点就搭建好了,这里我们就可以利用刚刚启动后的 console 操作里面的模块了

console 模块

模块 作用
eth 区块操作
web3 包含了其他模块对象中的方法外,还包含一些单位换算的方法
miner 挖矿操作
admin 节点操作
personal 账户操作
net 网络操作

我们主要了解 mineradmin以及personal模块,我们先简单实现创建一个账户,然后将这个账户设置为矿工,获取以太币收益

# 创建账户 会让输入密码 会返回一个地址
personal.newAccount()   # "0x9c0e89ab86f0874e9977f89c64e2eb6bfd981322"

# 设置矿工 返回true
miner.setEtherbase("0x9c0e89ab86f0874e9977f89c64e2eb6bfd981322")

# 开始挖矿获取收益 返回 null
miner.start()

# 稍等一会就可以 停止挖矿
miner.stop()

# 然后我们查看账户余额
eth.getBalance("0x9c0e89ab86f0874e9977f89c64e2eb6bfd981322")

# 以以太为单位查看,默认是 wei 
web3.fromWei(eth.getBalance("0x9c0e89ab86f0874e9977f89c64e2eb6bfd981322"),'ether')

现在我们已经可以进行单节点交互了,但是我们区块链主要是要交易记账,所以我们接下来要再新建一个账户,然后利用之前账户的以太进行转账

personal.newAccount()   # "0x035bafe05b4a7a4eba9accf2c692785798b7132c"

# 转账 from -> to  value 付多少
eth.sendTransaction({from:"0x9c0e89ab86f0874e9977f89c64e2eb6bfd981322",to:"0x035bafe05b4a7a4eba9accf2c692785798b7132c",value:1000000000000})

# 但是在进行转账之前,我们需要先解锁我们的账户,相当于证明这个账户是我们自己的
personal.unlockAccount("0x9c0e89ab86f0874e9977f89c64e2eb6bfd981322")

# 交易创建之后 每笔交易都会写入在区块中,但是需要挖矿才会被确认,所以我们发起了一笔交易,还需要进行挖矿才能使交易成功
miner.start()
miner.stop()
eth.getBalance("0x035bafe05b4a7a4eba9accf2c692785798b7132c") # 1000000000000

到这里,我们就看到了关于区块链的基本操作啦,但是单节点的区块链很明显信任度是不够的,而且单点故障问题也存在,所以我们需要构建一个分布式点对点系统。

搭建联盟链

我们准备在本机中,再启动两个节点,和之前流程一样,先初始化节点,然后去主节点上添加那两个节点(因为我们把自动发现给关闭了,所以我们需要手动去加入,正常是不用的)

# 指定新的数据目录 新的端口
geth --datadir "D:\block\gt\data1" init genesis.json
geth --identity "node1" --datadir "D:\block\gt\data1" --http --http.port 8546 --http.corsdomain="*" --http.addr "0.0.0.0" --http.api "eth,web3,miner,admin,personal,net" --nodiscover   --networkid 15 --allow-insecure-unlock --port 30304 --ipcdisable

# 指定新的数据目录 新的端口
geth --datadir "D:\block\gt\data2" init genesis.json
geth --identity "node2" --datadir "D:\block\gt\data2" --http --http.port 8547 --http.corsdomain="*" --http.addr "0.0.0.0" --http.api "eth,web3,miner,admin,personal,net" --nodiscover   --networkid 15 --allow-insecure-unlock --port 30305 --ipcdisable

加入其它节点

当启动新的两个节点 console 后,查看 enode,到 node0 上面去加入 node1node2enode

# node1操作
admin.nodeInfo.enode # enode://5a0e1b6a2c4232a5e774a69a7c660acfa5cb7f573e89e55283c5a438c8d6280539c23cfe68bfdf4873b62da463eae4bc0add8adb9e806e261b875a32b83c7a7c@127.0.0.1:30304?discport=0
# node2操作
admin.nodeInfo.enode # enode://afd9e6d63588bcb070c8245f4c78612c8dd9a57def78aed85e135318397f43bbc01a47fdbb44f990304eefa59bdaae2d91ec5c2190f02bc52d7fdcec26c86a12@127.0.0.1:30305?discport=0

# node0操作
admin.addPeer("enode://afd9e6d63588bcb070c8245f4c78612c8dd9a57def78aed85e135318397f43bbc01a47fdbb44f990304eefa59bdaae2d91ec5c2190f02bc52d7fdcec26c86a12@127.0.0.1:30305?discport=0")
admin.addPeer("enode://5a0e1b6a2c4232a5e774a69a7c660acfa5cb7f573e89e55283c5a438c8d6280539c23cfe68bfdf4873b62da463eae4bc0add8adb9e806e261b875a32b83c7a7c@127.0.0.1:30304?discport=0")
admin.peers # 查看加入的节点

看到如下状态即成功

加入成功

查看区块同步是否正常

我们通过在 node0 上挖矿,查看其他节点的日志是否处于同步状态,然后在 node1node2 上去查看 node0 里面的账户余额

miner.start()
miner.stop()

看到其他节点都有成功日志

成功

  • node0node1 查看挖矿账户的余额
# node1
geth attach http://127.0.0.1:8546
web3.fromWei(eth.getBalance("0x9c0e89ab86f0874e9977f89c64e2eb6bfd981322"),'ether')  # 85.999998
# node2
geth attach http://127.0.0.1:8547
web3.fromWei(eth.getBalance("0x9c0e89ab86f0874e9977f89c64e2eb6bfd981322"),'ether')  # 85.999998

通过 Metamask 在联盟链中转账

我们通过下面流程进行操作:

  • metamask 中添加我们的测试网络
  • 导入我们之前创建的挖矿账户,在 node2 中创建一个账户,然后通过 metamask 进行转账
  • 然后挖矿查看结果

添加测试网络

利用 metamask 转账

node0 的数据目录中,找到 keystore ,里面都是账户的 json 文件,找到我们的矿工账户文件

去 metamask 中进行导入,输入创建账户时的密码

点击确定之后,可能会出现卡顿,过几分钟重新打开,会发现账户已经导入成功

node2中创建账户

geth attach http://127.0.0.1:8547

personal.newAccount()  # "0xc1864e1f2b262ef89228eb1ebde9be6a6165cbe7"

使用 metamask 向地址转账

挖矿确认这笔交易

miner.start()
miner.stop()

成功,查询一下余额

web3.fromWei(eth.getBalance("0xc1864e1f2b262ef89228eb1ebde9be6a6165cbe7"),'ether') # 20

踩坑

  • Erro starting protocol stack:Access is denied

增加参数 --ipcdisable,禁用 ipc

  • 为什么我使用了 admin.addPeer 加入了正确的 enode ,而且结果也返回了 true ,通过 admin.peers 还是看不到加入的节点呢?

这个原因很简单,因为其他节点的初始化与主节点不一致,例如,忘记执行 init 步骤了,或者 init 选择的配置不一致,一定要保证和主节点初始化启动保持一致

  • Error: The method personal_newAccount does not exist/is not available

--http.api 没有开启 personal 模块

总结

本章,我们搭建了私有联盟链,利用 metamask 进行操作,这个系统我们需要保留下来,之后可以用来部署合约,发布 ERC 系列货币,深入研究区块链原理和结构。

您的支持是对我最大的鼓励!

发表于: 作者:憧憬。
关注互联网以及分享全栈工作经验的原创个人博客和技术博客,热爱编程,极客精神
Github 新浪微博 SegmentFault 掘金专栏