主页 > imtoken官网钱包app > 以太坊创世区块链配置加载分析
以太坊创世区块链配置加载分析
原文链接:
请到深入浅出的区块链主站获取最新内容。
创世块是第零个块,其他块直接或间接引用创世块。 因此节点启动之初必须加载正确的创世块信息,不能随意修改。
以太坊允许通过创世配置文件或选择使用内置多网络环境的创世配置来初始化创世块。 默认情况下以太坊全节点钱包,使用以太坊主网创世配置。
创世配置文件
如果你需要搭建一条私有以太坊链,那么了解创建配置是很有必要的,否则你根本不用关心创建配置。 以下是 JSON 格式的 Genesis 配置示例:
{
“配置”:{
“链号”:1,
“家园块”:1150000,
“daoForkBlock”:1920000,
“daoForkSupport”:真实的,
“eip150块”:2463000,
“eip150哈希”:“0x2086799aeebeae135c246c65021c82b4e15a2c451340993aacfd2751886514f0”,
“eip155Block”:2675000,
“eip158Block”:2675000,
“拜占庭区块”:4370000,
“君士坦丁堡区块”:7280000,
“圣彼得堡街区”:7280000,
“以太坊”:{}
},
“随机数”:“0x42”,
“时间戳”:“0x0”,
“额外数据”:“0x11bbe8db4e347b4e8c937c1c8370e4b5ed33adb3db69cbdb7a38e1e50b1b82fa”,
“气体限制”:“0x1388”,
“难度”:“0x400000000”,
“混合哈希”:“0x0000000000000000000000000000000000000000000000000000000000000000”,
“币库”:“0x0000000000000000000000000000000000000000”,
“数字”:“0x0”,
“gasUsed”:“0x0”,
"parentHash": "0x0000000000000000000000000000000000000000000000000000000000000000",
“分配”:{
“000d836201318ec6899a67540690382780743280”:{
“余额”:“0xad78ebc5ac6200000”
},
“001762430ea9c3a26e5749afdb70da5f78ddbb8c”:{
“余额”:“0xad78ebc5ac6200000”
}
}
}
根据配置目的,可分为三类:
链配置
config项是定义链的配置,会影响共识协议。 虽然链的配置对创建影响不大,但是新区块的出块规则都取决于链的配置。
创世区块头信息配置
nonce:随机数,对应创世块的Nonce字段。
timestamp:UTC时间戳,对应创世块的Time字段。
extraData:额外数据,对应创世块的额外字段。
gasLimit:必填,gas limit,对应创世块的GasLimit字段。
Difficulty:必填,难度系数,对应创世块的Difficulty字段。 在构建私有链时,需要根据情况选择合适的难度值,以调整区块生成。
minHash:对应创世块MixDigest字段的哈希值。 与 nonce 值一起,证明已经对该块进行了足够的计算。
coinbase:对应创世块Coinbase字段的地址。
初始账户资产配置
alloc项是Genesis中的初始账户资产配置。 当生成创世块时,将这个数据集中的账户资产写入区块,相当于预挖。 这对于开发测试和私链非常有用,资产可以直接分配给任意数量的账户,无需挖矿。
定制创世纪
如果您打算部署以太坊私有网络或单独的测试环境,那么您需要自定义 Genesis 并对其进行初始化。 为了统一交流,建议先在用户根目录下创建一个文件夹,作为《以太坊设计与实现》电子书学习的工作目录。
mkdir $HOME/深度 && cd $HOME/深度
再准备两个以太坊账户以太坊全节点钱包,用于在创世纪存入资产。
geth --datadir $HOME/deepeth 新账户
因为是学习和使用,所以建议使用统一密码foobar,执行两次命令,创建两个账号。 这里使用--datadir参数来指定以太坊运行时的数据存放目录,方便大家将本课程的数据存放在一个学习文件夹中。
然后将以下配置内容保存到$HOME/deepeth/genesis.json文件中,其中alloc项替换为刚才创建的两个以太坊账户的地址。
{
“配置”:{
“链号”:8888,
“家园块”:0,
“daoForkBlock”:0,
“daoForkSupport”:真实的,
“eip150块”:0,
“eip155块”:0,
“eip158Block”:0,
“拜占庭块”:0,
“君士坦丁堡街区”:0,
“圣彼得堡街区”:0,
“以太坊”:{}
},
“随机数”:“0x42”,
“时间戳”:“0x0”,
“额外数据”:“0x11bbe8db4e347b4e8c937c1c8370e4b5ed33adb3db69cbdb7a38e1e50b1b82fa”,
“气体限制”:“0x1388”,
“难度”:“0x1”,
“分配”:{
“093f59f1d91017d30d8c2caa78feb5beb0d2cfaf”:{
“余额”:“0xffffffffffffffff”
},
“ddf7202cbe0aaed1c2d5c4ef05e386501a054406”:{
“余额”:“0xffffffffffffffff”
}
}
}
然后,执行 geth 子命令 init 来初始化创世块。
geth --datadir $HOME/deepeth init genesis.json
执行成功后,就可以启动私有链了:
geth --maxpeers 0 --datadir $HOME/deepeth 控制台
执行以下命令查看上面创建的两个账户,这两个账户都有资产:
伦理。 getBalance(eth.accounts[0])
//18446744073709551615
伦理。 getBalance(eth.accounts[1])
//18446744073709551615
至此,我们完成了定制版的Genesis。
内置创世配置
上面自定义创建我已经完成了,但是以太坊作为一个去中心化的平台,需要很多节点共同参与。 只是为了测试,搭建多节点私有链比较麻烦。 想和别人联合调试,或者需要在测试网测试DAPP怎么办? 嗯,以太坊测试网络可用。 以太坊共有 5 个公共测试网络,其中 4 个仍在运行。 详情见下表。
测试网共识机制 区块间隔 提供商上线时间 备注状态
MordenPoW Ethereum 官方 2015.7 因难度炸弹停止而被迫退出
RopstenPoW30秒以太坊官方2016.11接替Mordenrunning
KovanPoA4秒以太坊钱包Parity开发组2017.3不支持gethrunning
RinkebyPoA15秒以太坊官方2017.4最常用,只支持gethrunning
SokolPoA5秒以太坊官方POA.network团队2017.12不支持gethrunning
Görli PoA 15秒以太坊柏林社区 2018.9 第一个以太坊2.0实验田运行
支持geth的三个测试网络的genesis配置已经内置到以太坊代码中,详见core/genesis.go文件:
// DefaultTestnetGenesisBlock 返回 Ropsten 网络创世块。
func DefaultTestnetGenesisBlock() *Genesis{}
// 默认 RinkebyGenesisBlock 返回 Rinkeby 网络创世块。
func DefaultRinkebyGenesisBlock() *Genesis
// 默认 GoerliGenesisBlock 返回 Görli 网络创世块。
func DefaultGoerliGenesisBlock() *Genesis{}
当然不会缺少以太坊主网创世配置,这也是geth运行的默认配置。
// DefaultGenesisBlock 返回以太坊主网创世块。
func DefaultGenesisBlock() *Genesis{}
如果不想自定义genesis配置文件进行开发和测试,以太坊也提供了本地开发专用的配置。
// DeveloperGenesisBlock 返回 'geth --dev' 创世块。 注意,这个必须
// 播种
func DeveloperGenesisBlock(period uint64, faucet common.Address) *Genesis
运行 geth --dev console 可以暂时使用。 但如果需要长期使用该模式,则需要指定datadir。
geth --dev --datadir $HOME/deepeth/开发控制台
首次运行开发者模式会自动创建一个空密码的账户并开始挖矿。 当有新的交易时,会立即打包。
geth创世区块加载过程
运行geth时,需要根据配置文件加载创世配置和创世块,并验证其有效性。 如果随意更改配置信息,很容易导致共识验证失败等问题。 程序只有在加载并通过检查后才能继续运行。
上图是一个简单的流程,下面分别解释“加载创世配置”和“安装创世块”两个子流程。
加载创世配置
应使用哪个创世配置由用户在启动 geth 时确定。 下图是Genesis配置选择的流程图:
通过geth命令参数可以选择不同的网络配置,可以通过networkid选择,也可以通过网络名启用。
使用网络标识:
不同的网络使用不同的 ID。
1=Frontier,主要网络环境,是默认选项。
2=现代测试网络,但已禁用。
3=Ropsten 测试网络。
4=Rinkeby 测试网络。
直接使用网络名称:
测试网:Ropsten 测试网。
rinkeby:Rinkeby 测试网络。
goerli:Görli 测试网络。
dev:本地开发环境。
geth启动时会根据不同的参数选择加载不同的网络配置,对应不同的网络环境。 如果不做选择,这里虽然不做选择,但是后面的过程会默认使用主网配置。
安装创世块
上面已经初步选择了genesis配置,这一步根据配置加载或初始化genesis unit。 下图是处理流程:
首先需要从区块高度为0的数据库中读取创世区块hash,如果不存在,说明本地是第一次启动,直接使用runtime创世配置构建创世区块。 第一次,创世块和链配置也需要存储。
如果存在,则需要使用运行时创世配置来构建创世块,并将其与存储的创世块哈希进行比较。 一旦不一致,则返回错误,不允许进一步的工作。
随后,还需要检查链配置。 先从数据库中获取链配置,如果不存在,不验证直接使用运行时链配置。 否则需要检查runtime chain配置是否正确,正确才能更换更新。 但有一个例外:主网配置不能随意更改,由代码控制,不能人为指定。
一般来说,以太坊默认使用主网配置,仅在首次运行时创建并存储创世块,其他时间仅用于验证。 除主网外,链配置可根据规则随时更改。
积木
上面的整体流程我们已经知道了,这里我们就详细说说以太坊是如何根据创世配置生成创世块的。 核心代码位于core/genesis.go:229。
func (g *Genesis) ToBlock(db ethdb.Database) *types.Block{
如果数据库 == 无 {
数据库 = 原始数据库。 新内存数据库()
}
statedb, _ := state.New(common.Hash{}, state.NewDatabase(db))//❶
对于 addr, account := range g.Alloc { //❷
statedb. AddBalance(地址,账户。余额)
statedb. SetCode(addr, account.Code)
statedb. SetNonce(addr, account.Nonce)
对于键,值:=范围帐户。 贮存 {
statedb. SetState(地址,键,值)
}
}
root := statedb.IntermediateRoot(false)//❸
head := &types.Header{//❹
编号:new(big.Int).SetUint64(g.Number),
Nonce: types.EncodeNonce(g.Nonce),
时间:克。 时间戳,
ParentHash:g。 父哈希,
额外:g。 额外数据,
气体限制:g。 气体限制,
使用的气体:g。 使用的气体,
难度:g。 困难,
混合文摘:g.Mixhash,
Coinbase:g。 币库,
根:根,
}
//❺
如果克。 气体限制 == 0 {
head.GasLimit = params.GenesisGasLimit
}
如果克。 难度 == 无 {
head.Difficulty = params.GenesisDifficulty
}
statedb.Commit(false)//❻
statedb.Database().TrieDB().Commit(root, true)//❼
返回类型。 NewBlock(head, nil, nil, nil)//❽
}
上述代码是根据创世配置生成创世块的代码逻辑,具体如下:
❶ 创世块没有父块,从零开始初始化一个新的状态(状态对象会在后续文章中详细讲解)。
❷ 遍历配置中Alloc项的账户收款数据,直接写入状态。
这里不仅可以设置balance,还可以设置code、nonce和任意数量的存储数据。
这意味着智能合约可以在创世时直接部署。 例如,以下配置在创世纪部署了一个名为 093f59f1d91017d30d8c2caa78feb5beb0d2cfaf 的智能合约。
“分配”:{
“093f59f1d91017d30d8c2caa78feb5beb0d2cfaf”:{
“余额”:“0xffffffffffffffff”,
“随机数”:“0x3”,
“代码”:“0x606060”,
“贮存”: {
“11bbe8db4e347b4e8c937c1c8370e4b5ed33adb3db69cbdb7a38e1e50b1b82fa”:“1234ff”
}
}
}
❸ 账户数据写入状态后,可以计算出状态数据Merkle树的根值,称为StateRoot。
该值记录在块头的 Root 字段中。
❹ 部分创世配置直接映射到区块头,完成创世区块头的构建。
❺ 因为 GasLimit 和 Difficulty 直接影响下一个区块的处理。
所以不设置时使用默认配置(Difficulty=131072,GasLimit=4712388)。
❻ 提交状态,将状态数据提交给底层内存trie数据。
❼ 更新内存trie数据到db。
这是一个额外的步骤,因为提交到数据库是在外部完成的,这里只负责生成块。
❽ 使用区块头创建区块,区块中没有交易记录。
深入浅出区块链——系统地学习区块链,在这里学习区块链,打造最好的区块链技术博客。
----------------------