|
| 1 | +genesis 是创世区块的意思. 一个区块链就是从同一个创世区块开始,通过规则形成的.不同的网络有不同的创世区块, 主网络和测试网路的创世区块是不同的. |
| 2 | + |
| 3 | +这个模块根据传入的genesis的初始值和database,来设置genesis的状态,如果不存在创世区块,那么在database里面创建它。 |
| 4 | + |
| 5 | +数据结构 |
| 6 | + |
| 7 | + // Genesis specifies the header fields, state of a genesis block. It also defines hard |
| 8 | + // fork switch-over blocks through the chain configuration. |
| 9 | + // Genesis指定header的字段,起始块的状态。 它还通过配置来定义硬叉切换块。 |
| 10 | + type Genesis struct { |
| 11 | + Config *params.ChainConfig `json:"config"` |
| 12 | + Nonce uint64 `json:"nonce"` |
| 13 | + Timestamp uint64 `json:"timestamp"` |
| 14 | + ExtraData []byte `json:"extraData"` |
| 15 | + GasLimit uint64 `json:"gasLimit" gencodec:"required"` |
| 16 | + Difficulty *big.Int `json:"difficulty" gencodec:"required"` |
| 17 | + Mixhash common.Hash `json:"mixHash"` |
| 18 | + Coinbase common.Address `json:"coinbase"` |
| 19 | + Alloc GenesisAlloc `json:"alloc" gencodec:"required"` |
| 20 | + |
| 21 | + // These fields are used for consensus tests. Please don't use them |
| 22 | + // in actual genesis blocks. |
| 23 | + Number uint64 `json:"number"` |
| 24 | + GasUsed uint64 `json:"gasUsed"` |
| 25 | + ParentHash common.Hash `json:"parentHash"` |
| 26 | + } |
| 27 | + |
| 28 | + // GenesisAlloc specifies the initial state that is part of the genesis block. |
| 29 | + // GenesisAlloc 指定了最开始的区块的初始状态. |
| 30 | + type GenesisAlloc map[common.Address]GenesisAccount |
| 31 | + |
| 32 | + |
| 33 | +SetupGenesisBlock, |
| 34 | + |
| 35 | + // SetupGenesisBlock writes or updates the genesis block in db. |
| 36 | + // |
| 37 | + // The block that will be used is: |
| 38 | + // |
| 39 | + // genesis == nil genesis != nil |
| 40 | + // +------------------------------------------ |
| 41 | + // db has no genesis | main-net default | genesis |
| 42 | + // db has genesis | from DB | genesis (if compatible) |
| 43 | + // |
| 44 | + // The stored chain configuration will be updated if it is compatible (i.e. does not |
| 45 | + // specify a fork block below the local head block). In case of a conflict, the |
| 46 | + // error is a *params.ConfigCompatError and the new, unwritten config is returned. |
| 47 | + // 如果存储的区块链配置不兼容那么会被更新(). 为了避免发生冲突,会返回一个错误,并且新的配置和原来的配置会返回. |
| 48 | + // The returned chain configuration is never nil. |
| 49 | + |
| 50 | + // genesis 如果是 testnet dev 或者是 rinkeby 模式, 那么不为nil。如果是mainnet或者是私有链接。那么为空 |
| 51 | + func SetupGenesisBlock(db ethdb.Database, genesis *Genesis) (*params.ChainConfig, common.Hash, error) { |
| 52 | + if genesis != nil && genesis.Config == nil { |
| 53 | + return params.AllProtocolChanges, common.Hash{}, errGenesisNoConfig |
| 54 | + } |
| 55 | + |
| 56 | + // Just commit the new block if there is no stored genesis block. |
| 57 | + stored := GetCanonicalHash(db, 0) //获取genesis对应的区块 |
| 58 | + if (stored == common.Hash{}) { //如果没有区块 最开始启动geth会进入这里。 |
| 59 | + if genesis == nil { |
| 60 | + //如果genesis是nil 而且stored也是nil 那么使用主网络 |
| 61 | + // 如果是test dev rinkeby 那么genesis不为空 会设置为各自的genesis |
| 62 | + log.Info("Writing default main-net genesis block") |
| 63 | + genesis = DefaultGenesisBlock() |
| 64 | + } else { // 否则使用配置的区块 |
| 65 | + log.Info("Writing custom genesis block") |
| 66 | + } |
| 67 | + // 写入数据库 |
| 68 | + block, err := genesis.Commit(db) |
| 69 | + return genesis.Config, block.Hash(), err |
| 70 | + } |
| 71 | + |
| 72 | + // Check whether the genesis block is already written. |
| 73 | + if genesis != nil { //如果genesis存在而且区块也存在 那么对比这两个区块是否相同 |
| 74 | + block, _ := genesis.ToBlock() |
| 75 | + hash := block.Hash() |
| 76 | + if hash != stored { |
| 77 | + return genesis.Config, block.Hash(), &GenesisMismatchError{stored, hash} |
| 78 | + } |
| 79 | + } |
| 80 | + |
| 81 | + // Get the existing chain configuration. |
| 82 | + // 获取当前存在的区块链的genesis配置 |
| 83 | + newcfg := genesis.configOrDefault(stored) |
| 84 | + // 获取当前的区块链的配置 |
| 85 | + storedcfg, err := GetChainConfig(db, stored) |
| 86 | + if err != nil { |
| 87 | + if err == ErrChainConfigNotFound { |
| 88 | + // This case happens if a genesis write was interrupted. |
| 89 | + log.Warn("Found genesis block without chain config") |
| 90 | + err = WriteChainConfig(db, stored, newcfg) |
| 91 | + } |
| 92 | + return newcfg, stored, err |
| 93 | + } |
| 94 | + // Special case: don't change the existing config of a non-mainnet chain if no new |
| 95 | + // config is supplied. These chains would get AllProtocolChanges (and a compat error) |
| 96 | + // if we just continued here. |
| 97 | + // 特殊情况:如果没有提供新的配置,请不要更改非主网链的现有配置。 |
| 98 | + // 如果我们继续这里,这些链会得到AllProtocolChanges(和compat错误)。 |
| 99 | + if genesis == nil && stored != params.MainnetGenesisHash { |
| 100 | + return storedcfg, stored, nil // 如果是私有链接会从这里退出。 |
| 101 | + } |
| 102 | + |
| 103 | + // Check config compatibility and write the config. Compatibility errors |
| 104 | + // are returned to the caller unless we're already at block zero. |
| 105 | + // 检查配置的兼容性,除非我们在区块0,否则返回兼容性错误. |
| 106 | + height := GetBlockNumber(db, GetHeadHeaderHash(db)) |
| 107 | + if height == missingNumber { |
| 108 | + return newcfg, stored, fmt.Errorf("missing block number for head header hash") |
| 109 | + } |
| 110 | + compatErr := storedcfg.CheckCompatible(newcfg, height) |
| 111 | + // 如果区块已经写入数据了,那么就不能更改genesis配置了 |
| 112 | + if compatErr != nil && height != 0 && compatErr.RewindTo != 0 { |
| 113 | + return newcfg, stored, compatErr |
| 114 | + } |
| 115 | + // 如果是主网络会从这里退出。 |
| 116 | + return newcfg, stored, WriteChainConfig(db, stored, newcfg) |
| 117 | + } |
| 118 | + |
| 119 | + |
| 120 | +ToBlock, 这个方法使用genesis的数据,使用基于内存的数据库,然后创建了一个block并返回。 |
| 121 | + |
| 122 | + |
| 123 | + // ToBlock creates the block and state of a genesis specification. |
| 124 | + func (g *Genesis) ToBlock() (*types.Block, *state.StateDB) { |
| 125 | + db, _ := ethdb.NewMemDatabase() |
| 126 | + statedb, _ := state.New(common.Hash{}, state.NewDatabase(db)) |
| 127 | + for addr, account := range g.Alloc { |
| 128 | + statedb.AddBalance(addr, account.Balance) |
| 129 | + statedb.SetCode(addr, account.Code) |
| 130 | + statedb.SetNonce(addr, account.Nonce) |
| 131 | + for key, value := range account.Storage { |
| 132 | + statedb.SetState(addr, key, value) |
| 133 | + } |
| 134 | + } |
| 135 | + root := statedb.IntermediateRoot(false) |
| 136 | + head := &types.Header{ |
| 137 | + Number: new(big.Int).SetUint64(g.Number), |
| 138 | + Nonce: types.EncodeNonce(g.Nonce), |
| 139 | + Time: new(big.Int).SetUint64(g.Timestamp), |
| 140 | + ParentHash: g.ParentHash, |
| 141 | + Extra: g.ExtraData, |
| 142 | + GasLimit: new(big.Int).SetUint64(g.GasLimit), |
| 143 | + GasUsed: new(big.Int).SetUint64(g.GasUsed), |
| 144 | + Difficulty: g.Difficulty, |
| 145 | + MixDigest: g.Mixhash, |
| 146 | + Coinbase: g.Coinbase, |
| 147 | + Root: root, |
| 148 | + } |
| 149 | + if g.GasLimit == 0 { |
| 150 | + head.GasLimit = params.GenesisGasLimit |
| 151 | + } |
| 152 | + if g.Difficulty == nil { |
| 153 | + head.Difficulty = params.GenesisDifficulty |
| 154 | + } |
| 155 | + return types.NewBlock(head, nil, nil, nil), statedb |
| 156 | + } |
| 157 | + |
| 158 | +Commit方法和MustCommit方法, Commit方法把给定的genesis的block和state写入数据库, 这个block被认为是规范的区块链头。 |
| 159 | + |
| 160 | + // Commit writes the block and state of a genesis specification to the database. |
| 161 | + // The block is committed as the canonical head block. |
| 162 | + func (g *Genesis) Commit(db ethdb.Database) (*types.Block, error) { |
| 163 | + block, statedb := g.ToBlock() |
| 164 | + if block.Number().Sign() != 0 { |
| 165 | + return nil, fmt.Errorf("can't commit genesis block with number > 0") |
| 166 | + } |
| 167 | + if _, err := statedb.CommitTo(db, false); err != nil { |
| 168 | + return nil, fmt.Errorf("cannot write state: %v", err) |
| 169 | + } |
| 170 | + // 写入总难度 |
| 171 | + if err := WriteTd(db, block.Hash(), block.NumberU64(), g.Difficulty); err != nil { |
| 172 | + return nil, err |
| 173 | + } |
| 174 | + // 写入区块 |
| 175 | + if err := WriteBlock(db, block); err != nil { |
| 176 | + return nil, err |
| 177 | + } |
| 178 | + // 写入区块收据 |
| 179 | + if err := WriteBlockReceipts(db, block.Hash(), block.NumberU64(), nil); err != nil { |
| 180 | + return nil, err |
| 181 | + } |
| 182 | + // 写入 headerPrefix + num (uint64 big endian) + numSuffix -> hash |
| 183 | + if err := WriteCanonicalHash(db, block.Hash(), block.NumberU64()); err != nil { |
| 184 | + return nil, err |
| 185 | + } |
| 186 | + // 写入 "LastBlock" -> hash |
| 187 | + if err := WriteHeadBlockHash(db, block.Hash()); err != nil { |
| 188 | + return nil, err |
| 189 | + } |
| 190 | + // 写入 "LastHeader" -> hash |
| 191 | + if err := WriteHeadHeaderHash(db, block.Hash()); err != nil { |
| 192 | + return nil, err |
| 193 | + } |
| 194 | + config := g.Config |
| 195 | + if config == nil { |
| 196 | + config = params.AllProtocolChanges |
| 197 | + } |
| 198 | + // 写入 ethereum-config-hash -> config |
| 199 | + return block, WriteChainConfig(db, block.Hash(), config) |
| 200 | + } |
| 201 | + |
| 202 | + // MustCommit writes the genesis block and state to db, panicking on error. |
| 203 | + // The block is committed as the canonical head block. |
| 204 | + func (g *Genesis) MustCommit(db ethdb.Database) *types.Block { |
| 205 | + block, err := g.Commit(db) |
| 206 | + if err != nil { |
| 207 | + panic(err) |
| 208 | + } |
| 209 | + return block |
| 210 | + } |
| 211 | + |
| 212 | +返回各种模式的默认Genesis |
| 213 | + |
| 214 | + // DefaultGenesisBlock returns the Ethereum main net genesis block. |
| 215 | + func DefaultGenesisBlock() *Genesis { |
| 216 | + return &Genesis{ |
| 217 | + Config: params.MainnetChainConfig, |
| 218 | + Nonce: 66, |
| 219 | + ExtraData: hexutil.MustDecode("0x11bbe8db4e347b4e8c937c1c8370e4b5ed33adb3db69cbdb7a38e1e50b1b82fa"), |
| 220 | + GasLimit: 5000, |
| 221 | + Difficulty: big.NewInt(17179869184), |
| 222 | + Alloc: decodePrealloc(mainnetAllocData), |
| 223 | + } |
| 224 | + } |
| 225 | + |
| 226 | + // DefaultTestnetGenesisBlock returns the Ropsten network genesis block. |
| 227 | + func DefaultTestnetGenesisBlock() *Genesis { |
| 228 | + return &Genesis{ |
| 229 | + Config: params.TestnetChainConfig, |
| 230 | + Nonce: 66, |
| 231 | + ExtraData: hexutil.MustDecode("0x3535353535353535353535353535353535353535353535353535353535353535"), |
| 232 | + GasLimit: 16777216, |
| 233 | + Difficulty: big.NewInt(1048576), |
| 234 | + Alloc: decodePrealloc(testnetAllocData), |
| 235 | + } |
| 236 | + } |
| 237 | + |
| 238 | + // DefaultRinkebyGenesisBlock returns the Rinkeby network genesis block. |
| 239 | + func DefaultRinkebyGenesisBlock() *Genesis { |
| 240 | + return &Genesis{ |
| 241 | + Config: params.RinkebyChainConfig, |
| 242 | + Timestamp: 1492009146, |
| 243 | + ExtraData: hexutil.MustDecode("0x52657370656374206d7920617574686f7269746168207e452e436172746d616e42eb768f2244c8811c63729a21a3569731535f067ffc57839b00206d1ad20c69a1981b489f772031b279182d99e65703f0076e4812653aab85fca0f00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000"), |
| 244 | + GasLimit: 4700000, |
| 245 | + Difficulty: big.NewInt(1), |
| 246 | + Alloc: decodePrealloc(rinkebyAllocData), |
| 247 | + } |
| 248 | + } |
| 249 | + |
| 250 | + // DevGenesisBlock returns the 'geth --dev' genesis block. |
| 251 | + func DevGenesisBlock() *Genesis { |
| 252 | + return &Genesis{ |
| 253 | + Config: params.AllProtocolChanges, |
| 254 | + Nonce: 42, |
| 255 | + GasLimit: 4712388, |
| 256 | + Difficulty: big.NewInt(131072), |
| 257 | + Alloc: decodePrealloc(devAllocData), |
| 258 | + } |
| 259 | + } |
0 commit comments