主页 > imtoken官方app > 以太坊创世区块
以太坊创世区块
创世块是第零个块,其他块直接或间接引用创世块。 因此节点启动之初必须加载正确的创世块信息,不能随意修改。
以太坊允许通过创世配置文件或使用选项初始化创世块...
创世块是第零个块,其他块直接或间接引用创世块。 因此节点启动之初必须加载正确的创世块信息,不能随意修改。
以太坊允许通过创世配置文件或选择使用内置多网络环境的创世配置来初始化创世块。 默认情况下,使用以太坊主网创世配置。
创世配置文件
如果你需要搭建一条私有以太坊链,那么了解创建配置是很有必要的,否则你根本不用关心创建配置。 以下是 JSON 格式的 Genesis 配置示例:
{
"config": {
"chainId": 1,
"homesteadBlock": 1150000,
"daoForkBlock": 1920000,
"daoForkSupport": true,
"eip150Block": 2463000,
"eip150Hash": "0x2086799aeebeae135c246c65021c82b4e15a2c451340993aacfd2751886514f0",
"eip155Block": 2675000,
"eip158Block": 2675000,
"byzantiumBlock": 4370000,
"constantinopleBlock": 7280000,
"petersburgBlock": 7280000,
"ethash": {}
},
"nonce": "0x42",
"timestamp": "0x0",
"extraData": "0x11bbe8db4e347b4e8c937c1c8370e4b5ed33adb3db69cbdb7a38e1e50b1b82fa",
"gasLimit": "0x1388",
"difficulty": "0x400000000",
"mixHash": "0x0000000000000000000000000000000000000000000000000000000000000000",
"coinbase": "0x0000000000000000000000000000000000000000",
"number": "0x0",
"gasUsed": "0x0",
"parentHash": "0x0000000000000000000000000000000000000000000000000000000000000000",
"alloc": {
"000d836201318ec6899a67540690382780743280": {
"balance": "0xad78ebc5ac6200000"
},
"001762430ea9c3a26e5749afdb70da5f78ddbb8c": {
"balance": "0xad78ebc5ac6200000"
}
}
}
根据配置目的,可分为三类:
链配置
config项是定义链的配置,会影响共识协议。 虽然链的配置对创建影响不大,但是新区块的出块规则都取决于链的配置。 更多链配置请查看文章《链参数配置》。创世区块头信息配置 初始账户资产配置
alloc项是Genesis中的初始账户资产配置。 当生成创世块时,将这个数据集中的账户资产写入区块,相当于预挖。 这对于开发测试和私链非常有用,资产可以直接分配给任意数量的账户,无需挖矿。自定义创世
如果您打算部署以太坊私有网络或单独的测试环境,那么您需要自定义 Genesis 并对其进行初始化。 为了统一交流,建议先在用户根目录下创建一个文件夹,作为《以太坊设计与实现》电子书学习的工作目录。
mkdir $HOME/deepeth && cd $HOME/deepeth
再准备两个以太坊账户,用于在创世纪存入资产。
geth --datadir $HOME/deepeth account new
因为是学习和使用,所以建议使用统一密码foobar,执行两次命令,创建两个账号。 这里使用--datadir参数来指定以太坊运行时的数据存放目录,方便大家将本课程的数据存放在一个学习文件夹中。
然后将以下配置内容保存到$HOME/deepeth/genesis.json文件中,其中alloc项替换为刚才创建的两个以太坊账户的地址。
{
"config": {
"chainId": 8888,
"homesteadBlock": 0,
"daoForkBlock": 0,
"daoForkSupport": true,
"eip150Block": 0,
"eip155Block": 0,
"eip158Block": 0,
"byzantiumBlock": 0,
"constantinopleBlock": 0,
"petersburgBlock": 0,
"ethash": {}
},
"nonce": "0x42",
"timestamp": "0x0",
"extraData": "0x11bbe8db4e347b4e8c937c1c8370e4b5ed33adb3db69cbdb7a38e1e50b1b82fa",
"gasLimit": "0x1388",
"difficulty": "0x1",
"alloc": {
"093f59f1d91017d30d8c2caa78feb5beb0d2cfaf": {
"balance": "0xffffffffffffffff"
},
"ddf7202cbe0aaed1c2d5c4ef05e386501a054406": {
"balance": "0xffffffffffffffff"
}
}
}
然后,执行 geth 子命令 init 来初始化创世块。
geth --datadir $HOME/deepeth init genesis.json
执行成功后,就可以启动私有链了:
geth --maxpeers 0 --datadir $HOME/deepeth console
执行以下命令查看上面创建的两个账户以太坊创世区块不能挖矿了,这两个账户都有资产:
eth.getBalance(eth.accounts[0])
// 18446744073709551615
eth.getBalance(eth.accounts[1])
// 18446744073709551615
至此,我们完成了定制版的Genesis。
内置创世配置
上面自定义创建我已经完成了,但是以太坊作为一个去中心化的平台,需要很多节点共同参与。 只是为了测试,搭建多节点私有链比较麻烦。 想和别人联合调试,或者需要在测试网测试DAPP怎么办? 嗯,以太坊测试网络可用。 以太坊共有 5 个公共测试网络,其中 4 个仍在运行。 详情见下表。
测试网共识机制 区块间隔 提供商上线时间 备注状态
摩登
工作量证明
以太坊官方
2015.7
因难度炸弹被迫退役
停止
罗普斯滕
工作量证明
30秒
以太坊官方
2016.11
接替莫登
跑步
科万
行动计划
4秒
以太坊钱包
平价开发团队
2017.3
不支持geth
跑步
伦克比
行动计划
15秒
以太坊官方
2017.4
最常用的,只支持geth
跑步
索科尔
行动计划
5秒
以太坊官方 POA.network 团队
2017.12
不支持geth
跑步
格尔利
行动计划
15秒
以太坊柏林社区
2018.9
第一个以太坊2.0实验田
跑步
支持geth的三个测试网络的genesis配置已经内置到以太坊代码中,详见core/genesis.go文件:
// DefaultTestnetGenesisBlock returns the Ropsten network genesis block.
func DefaultTestnetGenesisBlock() *Genesis{}
// DefaultRinkebyGenesisBlock returns the Rinkeby network genesis block.
func DefaultRinkebyGenesisBlock() *Genesis
// DefaultGoerliGenesisBlock returns the Görli network genesis block.
func DefaultGoerliGenesisBlock() *Genesis{}
当然不会缺少以太坊主网创世配置,这也是geth运行的默认配置。
// DefaultGenesisBlock returns the Ethereum main net genesis block.
func DefaultGenesisBlock() *Genesis{}
如果不想自定义genesis配置文件进行开发和测试,以太坊也提供了本地开发专用的配置。
// DeveloperGenesisBlock returns the 'geth --dev' genesis block. Note, this must
// be seeded with the
func DeveloperGenesisBlock(period uint64, faucet common.Address) *Genesis
运行 geth --dev console 可以暂时使用。 但如果需要长期使用该模式,则需要指定datadir。
geth --dev --datadir $HOME/deepeth/dev console
首次运行开发者模式会自动创建一个空密码的账户并开始挖矿。 当有新的交易时,会立即打包。
geth创世区块加载过程
运行geth时,需要根据配置文件加载创世配置和创世块,并验证其有效性。 如果随意更改配置信息,很容易导致共识验证失败等问题。 程序只有在加载并通过检查后才能继续运行。
上图是一个简单的流程,下面分别解释“加载创世配置”和“安装创世块”两个子流程。
加载创世配置
应使用哪个创世配置由用户在启动 geth 时确定。 下图是Genesis配置选择的流程图:
通过geth命令参数可以选择不同的网络配置,可以通过networkid选择,也可以通过网络名启用。
使用网络标识:
不同的网络使用不同的 ID。
直接使用网络名称:
geth启动时会根据不同的参数选择加载不同的网络配置,对应不同的网络环境。 如果不做选择,这里虽然不做选择,但是后面的过程会默认使用主网配置。
安装创世块
上面已经初步选择了genesis配置,这一步根据配置加载或初始化genesis unit。 下图是处理流程:
首先需要从区块高度为0的数据库中读取创世区块hash,如果不存在,说明本地是第一次启动以太坊创世区块不能挖矿了,直接使用runtime创世配置构建创世区块。 第一次,创世块和链配置也需要存储。
如果存在,则需要使用运行时创世配置来构建创世块,并将其与存储的创世块哈希进行比较。 一旦不一致,则返回错误,不允许进一步的工作。
随后,还需要检查链配置。 先从数据库中获取链配置,如果不存在,不验证直接使用运行时链配置。 否则需要检查runtime chain配置是否正确,正确才能更换更新。 但有一个例外:主网配置不能随意更改,由代码控制,不能人为指定。
一般来说,以太坊默认使用主网配置,仅在首次运行时创建并存储创世块,其他时间仅用于验证。 除主网外,链配置可根据规则随时更改。
积木
上面的整体流程我们已经知道了,这里我们就详细说说以太坊是如何根据创世配置生成创世块的。 核心代码位于core/genesis.go:229。
func (g *Genesis) ToBlock(db ethdb.Database) *types.Block{
if db == nil {
db = rawdb.NewMemoryDatabase()
}
statedb, _ := state.New(common.Hash{}, state.NewDatabase(db))//❶
for addr, account := range g.Alloc { //❷
statedb.AddBalance(addr, account.Balance)
statedb.SetCode(addr, account.Code)
statedb.SetNonce(addr, account.Nonce)
for key, value := range account.Storage {
statedb.SetState(addr, key, value)
}
}
root := statedb.IntermediateRoot(false)//❸
head := &types.Header{//❹
Number: new(big.Int).SetUint64(g.Number),
Nonce: types.EncodeNonce(g.Nonce),
Time: g.Timestamp,
ParentHash: g.ParentHash,
Extra: g.ExtraData,
GasLimit: g.GasLimit,
GasUsed: g.GasUsed,
Difficulty: g.Difficulty,
MixDigest: g.Mixhash,
Coinbase: g.Coinbase,
Root: root,
}
//❺
if g.GasLimit == 0 {
head.GasLimit = params.GenesisGasLimit
}
if g.Difficulty == nil {
head.Difficulty = params.GenesisDifficulty
}
statedb.Commit(false)//❻
statedb.Database().TrieDB().Commit(root, true)//❼
return types.NewBlock(head, nil, nil, nil)//❽
}
上述代码是根据创世配置生成创世块的代码逻辑,具体如下:
本文参与登联社区写作激励计划,好文章好收益,欢迎正在阅读的你加入。