1. 为什么要构建私链?
构建私链有多个理由,主要包括:
- 数据隐私与安全性
- 控制数据访问:私链允许组织对谁可以访问和参与区块链网络进行控制,从而保护敏感数据。
- 防止恶意行为:与公链相比,私链更容易限制恶意攻击,因为只有经过授权的参与者才能加入。
- 高性能与可扩展性
- 快速交易处理:由于参与者数量较少,私链通常可以处理更高的交易速度,减少交易确认时间。
- 定制化配置:可以根据特定需求优化网络参数(如区块生成时间、共识算法等)。
- 定制化特性
- 灵活性:可以根据组织的需求定制共识机制、合约功能和网络架构,适应特定的业务场景。
- 专有协议:可实现专门的协议或应用,与公链的标准化和限制不同。
- 合规性与监管
- 满足合规要求:私链能够帮助企业遵循行业法规和标准,比如金融行业的合规要求。
- 审计和监管:能够更容易地实施审计和监控机制,确保遵循法律和规定。
- 低成本与资源优化
- 资源节省:在私链中,通常只需要维护少量的节点,减少了硬件和网络带宽的需求。
- 控制网络费用:由于没有激励机制(如矿工奖励),运营成本通常较低。
- 业务合作与联盟链
- 跨组织协作:私链可用于多个组织之间的合作,尤其是在供应链管理和金融交易中。
- 联盟链:可以构建联盟链,让特定合作伙伴共同参与,确保数据的透明性和可追溯性。
- 测试与开发:开发人员可以在私链上进行测试,验证智能合约和应用程序的功能,而不必担心对公共网络的影响。
2. 构建基于PoA的ethereum私链
2.1 创建账户
创建两个账户,分别为account 1
和account 2
,用做初始的验证者地址。
# node
# account 1
$ geth --datadir ./node account new
INFO [09-27|09:40:38.644] Maximum peer count ETH=50 total=50
INFO [09-27|09:40:38.645] Smartcard socket not found, disabling err="stat /run/pcscd/pcscd.comm: no such file or directory"
Your new account is locked with a password. Please give a password. Do not forget this password.
Password:
Repeat password:
Your new key was generated
Public address of the key: 0x51C4d2FeEBBAd01c2202d7CE772de1D953571201
Path of the secret key file: node/keystore/UTC--2024-09-27T01-40-44.544853516Z--51c4d2feebbad01c2202d7ce772de1d953571201
- You can share your public address with anyone. Others need it to interact with you.
- You must NEVER share the secret key with anyone! The key controls access to your funds!
- You must BACKUP your key file! Without the key, it's impossible to access account funds!
- You must REMEMBER your password! Without the password, it's impossible to decrypt the key!
# account 2
$ geth --datadir ./node account new
INFO [09-27|09:41:29.078] Maximum peer count ETH=50 total=50
INFO [09-27|09:41:29.079] Smartcard socket not found, disabling err="stat /run/pcscd/pcscd.comm: no such file or directory"
Your new account is locked with a password. Please give a password. Do not forget this password.
Password:
Repeat password:
Your new key was generated
Public address of the key: 0x19Eac074dba9BBa2Eb97FFE7BBA80A9E9E83EcBe
Path of the secret key file: node/keystore/UTC--2024-09-27T01-41-34.412585202Z--19eac074dba9bba2eb97ffe7bba80a9e9e83ecbe
- You can share your public address with anyone. Others need it to interact with you.
- You must NEVER share the secret key with anyone! The key controls access to your funds!
- You must BACKUP your key file! Without the key, it's impossible to access account funds!
- You must REMEMBER your password! Without the password, it's impossible to decrypt the key!
2.2 创建创世区块
配置创世区块的配置文件genesis.json
,内容如下:
{
"config": {
"chainId": 377777,
"homesteadBlock": 0,
"eip150Block": 0,
"eip155Block": 0,
"eip158Block": 0,
"byzantiumBlock": 0,
"constantinopleBlock": 0,
"petersburgBlock": 0,
"istanbulBlock": 0,
"berlinBlock": 0,
"clique": {
"period": 5,
"epoch": 30000
}
},
"difficulty": "1",
"gasLimit": "8000000",
"extradata": "0x000000000000000000000000000000000000000000000000000000000000000051C4d2FeEBBAd01c2202d7CE772de1D95357120119Eac074dba9BBa2Eb97FFE7BBA80A9E9E83EcBe0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000",
"alloc": {
"51C4d2FeEBBAd01c2202d7CE772de1D953571201": {
"balance": "100000000000000000000"
},
"19Eac074dba9BBa2Eb97FFE7BBA80A9E9E83EcBe": {
"balance": "100000000000000000000"
}
}
}
代码语言:bash复制初始验证者地址必须通过
extradata
字段指定。
$ geth --datadir ./node init ./genesis.json
2.3 启动节点
创世区块创建后,就可以启动私链节点了。
代码语言:bash复制# networkid 是genesis.json中指定的chainId
$ geth --datadir ./node --networkid 377777
2.4 进入 Geth 控制台测试
代码语言:bash复制$ geth attach ./node/geth.ipc
Welcome to the Geth JavaScript console!
instance: Geth/v1.13.15-stable-c5ba367e/linux-amd64/go1.22.7
at block: 1 (Fri Sep 27 2024 10:01:07 GMT 0800 (CST))
datadir: /root/vscode/ethereum/node
modules: admin:1.0 clique:1.0 debug:1.0 engine:1.0 eth:1.0 miner:1.0 net:1.0 rpc:1.0 txpool:1.0 web3:1.0
To exit, press ctrl-d or type exit
# 获取最新区块高度
> eth.blockNumber
1
# 获取最新区块信息
> eth.getBlock('latest')
{
difficulty: 2,
extraData: "0xd883010d0f846765746888676f312e32312e39856c696e757800000000000000ebcda637df33928e4ce34051f777ccac21c643a8dcd1984b019984af41d99d5c41ff73559c837b0204c7764c71d8b5b49ecf63a555ee127e3d0cc86673d3214100",
gasLimit: 8007811,
gasUsed: 0,
hash: "0xe4c14eb995dbcc9652a53fa8d47402dead30fa82af57b11399f9db23b06ab78b",
logsBloom: "0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000",
miner: "0x0000000000000000000000000000000000000000",
mixHash: "0x0000000000000000000000000000000000000000000000000000000000000000",
nonce: "0x0000000000000000",
number: 1,
parentHash: "0xb2ad7555b68d5c1e334d44033ef78c869fa4248a64a976a172318126a3db55a7",
receiptsRoot: "0x56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421",
sha3Uncles: "0x1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347",
size: 606,
stateRoot: "0xc5f02ccb91cfbde9f92912bb02aac9b2601e9a6e41ea9335343fa1991d277a5a",
timestamp: 1727402467,
totalDifficulty: 3,
transactions: [],
transactionsRoot: "0x56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421",
uncles: []
}
# 获取账户余额
> eth.getBalance("0x51C4d2FeEBBAd01c2202d7CE772de1D953571201")
100000000000000000000
> eth.getBalance("0x19Eac074dba9BBa2Eb97FFE7BBA80A9E9E83EcBe")
100000000000000000000
# 获取账户列表
> eth.accounts
["0x51c4d2feebbad01c2202d7ce772de1d953571201", "0x19eac074dba9bba2eb97ffe7bba80a9e9e83ecbe"]
curl
命令测试:
# 获取最新区块高度,result 为十六进制字符串
$ curl -X POST -H "Content-Type: application/json" --data '{"jsonrpc":"2.0","method":"eth_blockNumber","params":[],"id":1}' http://localhost:8545
{"jsonrpc":"2.0","id":1,"result":"0x1"}
# 获取账户余额
curl -X POST -H "Content-Type: application/json" --data '{"jsonrpc":"2.0","method":"eth_getBalance","params":["0x19Eac074dba9BBa2Eb97FFE7BBA80A9E9E83EcBe","latest"],"id":1}' http://localhost:8545
{"jsonrpc":"2.0","id":1,"result":"0x56bc75e2d63100000"}
3. 扩展:extradata 字段介绍
extradata
字段是以太坊区块头的一部分,主要用于 Proof of Authority (PoA) 共识机制(如 Clique)。它包含特定的信息,以便于节点之间的共识和验证。以下是对 extradata
字段的详细介绍:
3.1 功能
- 签名者信息:
extradata
通常包含当前区块的签名者(或验证者)地址。这些地址是网络中被授权生成区块的节点。 - 额外元数据:在某些情况下,可以包括其他自定义信息,如版本号或链的特定参数。
3.2 格式
extradata
是一个字节数组,其结构通常如下:
- 32个零字节:用于预留空间。
- 签名者地址:包含网络中所有签名者的地址,每个地址占 20 字节(40 个十六进制字符)。
- 65个零字节:用于填充,确保
extradata
的总字节长度符合要求。
3.3 示例
假设你有三个签名者地址,extradata
的构建步骤如下:
- 32个零字节(在十六进制表示为):0000000000000000000000000000000000000000000000000000000000000000
- 签名者地址:0xD22688d01E3345Cc2911C95447a3a1bcE32CB741 0x9A265B5Ef402813ae057e53f12D2B19d9aA5CEb4 0x843D259ab8C380FA576Cb013503CF961B63d12BB
- 65个零字节:00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
- 拼接结果:0x0000000000000000000000000000000000000000000000000000000000000000D22688d01E3345Cc2911C95447a3a1bcE32CB7419A265B5Ef402813ae057e53f12D2B19d9aA5CEb4843D259ab8C380FA576Cb013503CF961B63d12BB00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
3.4 使用场景
- 共识机制:在 PoA 网络中,
extradata
用于确定哪个节点在某一时刻被授权生成新区块。 - 数据完整性:由于
extradata
是区块头的一部分,确保了与块的其他信息一起传递,增强了数据的完整性和一致性。
3.5 注意事项
- 字节长度:确保
extradata
的字节长度符合预期,错误的格式可能导致链启动失败。 - 动态更新:在网络运行过程中,可以使用相应的 API 更新签名者信息,确保网络的正常运作。