github.com/MetalBlockchain/subnet-evm@v0.4.9/core/genesis.go (about) 1 // (c) 2019-2020, Ava Labs, Inc. 2 // 3 // This file is a derived work, based on the go-ethereum library whose original 4 // notices appear below. 5 // 6 // It is distributed under a license compatible with the licensing terms of the 7 // original code from which it is derived. 8 // 9 // Much love to the original authors for their work. 10 // ********** 11 // Copyright 2014 The go-ethereum Authors 12 // This file is part of the go-ethereum library. 13 // 14 // The go-ethereum library is free software: you can redistribute it and/or modify 15 // it under the terms of the GNU Lesser General Public License as published by 16 // the Free Software Foundation, either version 3 of the License, or 17 // (at your option) any later version. 18 // 19 // The go-ethereum library is distributed in the hope that it will be useful, 20 // but WITHOUT ANY WARRANTY; without even the implied warranty of 21 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 22 // GNU Lesser General Public License for more details. 23 // 24 // You should have received a copy of the GNU Lesser General Public License 25 // along with the go-ethereum library. If not, see <http://www.gnu.org/licenses/>. 26 27 package core 28 29 import ( 30 "bytes" 31 _ "embed" 32 "encoding/hex" 33 "encoding/json" 34 "errors" 35 "fmt" 36 "math/big" 37 "time" 38 39 "github.com/MetalBlockchain/subnet-evm/core/rawdb" 40 "github.com/MetalBlockchain/subnet-evm/core/state" 41 "github.com/MetalBlockchain/subnet-evm/core/types" 42 "github.com/MetalBlockchain/subnet-evm/ethdb" 43 "github.com/MetalBlockchain/subnet-evm/params" 44 "github.com/MetalBlockchain/subnet-evm/trie" 45 "github.com/ethereum/go-ethereum/common" 46 "github.com/ethereum/go-ethereum/common/hexutil" 47 "github.com/ethereum/go-ethereum/common/math" 48 "github.com/ethereum/go-ethereum/crypto" 49 "github.com/ethereum/go-ethereum/log" 50 ) 51 52 //go:generate go run github.com/fjl/gencodec -type Genesis -field-override genesisSpecMarshaling -out gen_genesis.go 53 //go:generate go run github.com/fjl/gencodec -type GenesisAccount -field-override genesisAccountMarshaling -out gen_genesis_account.go 54 55 var errGenesisNoConfig = errors.New("genesis has no chain configuration") 56 57 type Airdrop struct { 58 // Address strings are hex-formatted common.Address 59 Address common.Address `json:"address"` 60 } 61 62 // Genesis specifies the header fields, state of a genesis block. It also defines hard 63 // fork switch-over blocks through the chain configuration. 64 type Genesis struct { 65 Config *params.ChainConfig `json:"config"` 66 Nonce uint64 `json:"nonce"` 67 Timestamp uint64 `json:"timestamp"` 68 ExtraData []byte `json:"extraData"` 69 GasLimit uint64 `json:"gasLimit" gencodec:"required"` 70 Difficulty *big.Int `json:"difficulty" gencodec:"required"` 71 Mixhash common.Hash `json:"mixHash"` 72 Coinbase common.Address `json:"coinbase"` 73 Alloc GenesisAlloc `json:"alloc" gencodec:"required"` 74 AirdropHash common.Hash `json:"airdropHash"` 75 AirdropAmount *big.Int `json:"airdropAmount"` 76 AirdropData []byte `json:"-"` // provided in a separate file, not serialized in this struct. 77 78 // These fields are used for consensus tests. Please don't use them 79 // in actual genesis blocks. 80 Number uint64 `json:"number"` 81 GasUsed uint64 `json:"gasUsed"` 82 ParentHash common.Hash `json:"parentHash"` 83 BaseFee *big.Int `json:"baseFeePerGas"` 84 } 85 86 // GenesisAlloc specifies the initial state that is part of the genesis block. 87 type GenesisAlloc map[common.Address]GenesisAccount 88 89 func (ga *GenesisAlloc) UnmarshalJSON(data []byte) error { 90 m := make(map[common.UnprefixedAddress]GenesisAccount) 91 if err := json.Unmarshal(data, &m); err != nil { 92 return err 93 } 94 *ga = make(GenesisAlloc) 95 for addr, a := range m { 96 (*ga)[common.Address(addr)] = a 97 } 98 return nil 99 } 100 101 // GenesisAccount is an account in the state of the genesis block. 102 type GenesisAccount struct { 103 Code []byte `json:"code,omitempty"` 104 Storage map[common.Hash]common.Hash `json:"storage,omitempty"` 105 Balance *big.Int `json:"balance" gencodec:"required"` 106 Nonce uint64 `json:"nonce,omitempty"` 107 PrivateKey []byte `json:"secretKey,omitempty"` // for tests 108 } 109 110 // field type overrides for gencodec 111 type genesisSpecMarshaling struct { 112 Nonce math.HexOrDecimal64 113 Timestamp math.HexOrDecimal64 114 ExtraData hexutil.Bytes 115 GasLimit math.HexOrDecimal64 116 GasUsed math.HexOrDecimal64 117 Number math.HexOrDecimal64 118 Difficulty *math.HexOrDecimal256 119 BaseFee *math.HexOrDecimal256 120 Alloc map[common.UnprefixedAddress]GenesisAccount 121 AirdropAmount *math.HexOrDecimal256 122 } 123 124 type genesisAccountMarshaling struct { 125 Code hexutil.Bytes 126 Balance *math.HexOrDecimal256 127 Nonce math.HexOrDecimal64 128 Storage map[storageJSON]storageJSON 129 PrivateKey hexutil.Bytes 130 } 131 132 // storageJSON represents a 256 bit byte array, but allows less than 256 bits when 133 // unmarshaling from hex. 134 type storageJSON common.Hash 135 136 func (h *storageJSON) UnmarshalText(text []byte) error { 137 text = bytes.TrimPrefix(text, []byte("0x")) 138 if len(text) > 64 { 139 return fmt.Errorf("too many hex characters in storage key/value %q", text) 140 } 141 offset := len(h) - len(text)/2 // pad on the left 142 if _, err := hex.Decode(h[offset:], text); err != nil { 143 fmt.Println(err) 144 return fmt.Errorf("invalid hex storage key/value %q", text) 145 } 146 return nil 147 } 148 149 func (h storageJSON) MarshalText() ([]byte, error) { 150 return hexutil.Bytes(h[:]).MarshalText() 151 } 152 153 // GenesisMismatchError is raised when trying to overwrite an existing 154 // genesis block with an incompatible one. 155 type GenesisMismatchError struct { 156 Stored, New common.Hash 157 } 158 159 func (e *GenesisMismatchError) Error() string { 160 return fmt.Sprintf("database contains incompatible genesis (have %x, new %x)", e.Stored, e.New) 161 } 162 163 // SetupGenesisBlock writes or updates the genesis block in db. 164 // The block that will be used is: 165 // 166 // genesis == nil genesis != nil 167 // +------------------------------------------ 168 // db has no genesis | main-net default | genesis 169 // db has genesis | from DB | genesis (if compatible) 170 171 // The argument [genesis] must be specified and must contain a valid chain config. 172 // If the genesis block has already been set up, then we verify the hash matches the genesis passed in 173 // and that the chain config contained in genesis is backwards compatible with what is stored in the database. 174 // 175 // The stored chain configuration will be updated if it is compatible (i.e. does not 176 // specify a fork block below the local head block). In case of a conflict, the 177 // error is a *params.ConfigCompatError and the new, unwritten config is returned. 178 func SetupGenesisBlock( 179 db ethdb.Database, genesis *Genesis, lastAcceptedHash common.Hash, skipChainConfigCheckCompatible bool, 180 ) (*params.ChainConfig, error) { 181 if genesis == nil { 182 return nil, ErrNoGenesis 183 } 184 if genesis.Config == nil { 185 return nil, errGenesisNoConfig 186 } 187 // Make sure genesis gas limit is consistent in SubnetEVM fork 188 gasLimitConfig := genesis.Config.FeeConfig.GasLimit.Uint64() 189 if gasLimitConfig != genesis.GasLimit { 190 return nil, fmt.Errorf("gas limit in fee config (%d) does not match gas limit in header (%d)", gasLimitConfig, genesis.GasLimit) 191 } 192 193 // Verify config 194 if err := genesis.Config.Verify(); err != nil { 195 return nil, err 196 } 197 // Just commit the new block if there is no stored genesis block. 198 stored := rawdb.ReadCanonicalHash(db, 0) 199 if (stored == common.Hash{}) { 200 log.Info("Writing genesis to database") 201 _, err := genesis.Commit(db) 202 if err != nil { 203 return genesis.Config, err 204 } 205 return genesis.Config, nil 206 } 207 // We have the genesis block in database but the corresponding state is missing. 208 header := rawdb.ReadHeader(db, stored, 0) 209 if _, err := state.New(header.Root, state.NewDatabase(db), nil); err != nil { 210 // Ensure the stored genesis matches with the given one. 211 hash := genesis.ToBlock(nil).Hash() 212 if hash != stored { 213 return genesis.Config, &GenesisMismatchError{stored, hash} 214 } 215 _, err := genesis.Commit(db) 216 return genesis.Config, err 217 } 218 // Check whether the genesis block is already written. 219 hash := genesis.ToBlock(nil).Hash() 220 if hash != stored { 221 return genesis.Config, &GenesisMismatchError{stored, hash} 222 } 223 // Get the existing chain configuration. 224 newcfg := genesis.Config 225 if err := newcfg.CheckConfigForkOrder(); err != nil { 226 return newcfg, err 227 } 228 storedcfg := rawdb.ReadChainConfig(db, stored) 229 // If there is no previously stored chain config, write the chain config to disk. 230 if storedcfg == nil { 231 // Note: this can happen since we did not previously write the genesis block and chain config in the same batch. 232 log.Warn("Found genesis block without chain config") 233 rawdb.WriteChainConfig(db, stored, newcfg) 234 return newcfg, nil 235 } 236 237 // Check config compatibility and write the config. Compatibility errors 238 // are returned to the caller unless we're already at block zero. 239 240 // we use last accepted block for cfg compatibility check. Note this allows 241 // the node to continue if it previously halted due to attempting to process blocks with 242 // an incorrect chain config. 243 lastBlock := ReadBlockByHash(db, lastAcceptedHash) 244 // this should never happen, but we check anyway 245 // when we start syncing from scratch, the last accepted block 246 // will be genesis block 247 if lastBlock == nil { 248 return newcfg, fmt.Errorf("missing last accepted block") 249 } 250 251 height := lastBlock.NumberU64() 252 timestamp := lastBlock.Time() 253 if skipChainConfigCheckCompatible { 254 log.Info("skipping verifying activated network upgrades on chain config") 255 } else { 256 compatErr := storedcfg.CheckCompatible(newcfg, height, timestamp) 257 if compatErr != nil && height != 0 && compatErr.RewindTo != 0 { 258 return newcfg, compatErr 259 } 260 } 261 rawdb.WriteChainConfig(db, stored, newcfg) 262 return newcfg, nil 263 } 264 265 // ToBlock creates the genesis block and writes state of a genesis specification 266 // to the given database (or discards it if nil). 267 func (g *Genesis) ToBlock(db ethdb.Database) *types.Block { 268 if db == nil { 269 db = rawdb.NewMemoryDatabase() 270 } 271 statedb, err := state.New(common.Hash{}, state.NewDatabase(db), nil) 272 if err != nil { 273 panic(err) 274 } 275 if g.AirdropHash != (common.Hash{}) { 276 t := time.Now() 277 h := common.BytesToHash(crypto.Keccak256(g.AirdropData)) 278 if g.AirdropHash != h { 279 panic(fmt.Sprintf("expected standard allocation %s but got %s", g.AirdropHash, h)) 280 } 281 airdrop := []*Airdrop{} 282 if err := json.Unmarshal(g.AirdropData, &airdrop); err != nil { 283 panic(err) 284 } 285 for _, alloc := range airdrop { 286 statedb.SetBalance(alloc.Address, g.AirdropAmount) 287 } 288 log.Debug( 289 "applied airdrop allocation", 290 "hash", h, "addrs", len(airdrop), "balance", g.AirdropAmount, 291 "t", time.Since(t), 292 ) 293 } 294 295 head := &types.Header{ 296 Number: new(big.Int).SetUint64(g.Number), 297 Nonce: types.EncodeNonce(g.Nonce), 298 Time: g.Timestamp, 299 ParentHash: g.ParentHash, 300 Extra: g.ExtraData, 301 GasLimit: g.GasLimit, 302 GasUsed: g.GasUsed, 303 BaseFee: g.BaseFee, 304 Difficulty: g.Difficulty, 305 MixDigest: g.Mixhash, 306 Coinbase: g.Coinbase, 307 } 308 309 // Configure any stateful precompiles that should be enabled in the genesis. 310 g.Config.CheckConfigurePrecompiles(nil, types.NewBlockWithHeader(head), statedb) 311 312 // Do custom allocation after airdrop in case an address shows up in standard 313 // allocation 314 for addr, account := range g.Alloc { 315 statedb.SetBalance(addr, account.Balance) 316 statedb.SetCode(addr, account.Code) 317 statedb.SetNonce(addr, account.Nonce) 318 for key, value := range account.Storage { 319 statedb.SetState(addr, key, value) 320 } 321 } 322 root := statedb.IntermediateRoot(false) 323 head.Root = root 324 325 if g.GasLimit == 0 { 326 head.GasLimit = params.GenesisGasLimit 327 } 328 if g.Difficulty == nil { 329 head.Difficulty = params.GenesisDifficulty 330 } 331 if g.Config != nil && g.Config.IsSubnetEVM(common.Big0) { 332 if g.BaseFee != nil { 333 head.BaseFee = g.BaseFee 334 } else { 335 head.BaseFee = new(big.Int).Set(g.Config.FeeConfig.MinBaseFee) 336 } 337 } 338 statedb.Commit(false, false) 339 if err := statedb.Database().TrieDB().Commit(root, true, nil); err != nil { 340 panic(fmt.Sprintf("unable to commit genesis block: %v", err)) 341 } 342 343 return types.NewBlock(head, nil, nil, nil, trie.NewStackTrie(nil)) 344 } 345 346 // Commit writes the block and state of a genesis specification to the database. 347 // The block is committed as the canonical head block. 348 func (g *Genesis) Commit(db ethdb.Database) (*types.Block, error) { 349 block := g.ToBlock(db) 350 if block.Number().Sign() != 0 { 351 return nil, errors.New("can't commit genesis block with number > 0") 352 } 353 config := g.Config 354 if config == nil { 355 return nil, errGenesisNoConfig 356 } 357 if err := config.CheckConfigForkOrder(); err != nil { 358 return nil, err 359 } 360 batch := db.NewBatch() 361 rawdb.WriteBlock(batch, block) 362 rawdb.WriteReceipts(batch, block.Hash(), block.NumberU64(), nil) 363 rawdb.WriteCanonicalHash(batch, block.Hash(), block.NumberU64()) 364 rawdb.WriteHeadBlockHash(batch, block.Hash()) 365 rawdb.WriteHeadHeaderHash(batch, block.Hash()) 366 rawdb.WriteChainConfig(batch, block.Hash(), config) 367 if err := batch.Write(); err != nil { 368 return nil, fmt.Errorf("failed to write genesis block: %w", err) 369 } 370 return block, nil 371 } 372 373 // MustCommit writes the genesis block and state to db, panicking on error. 374 // The block is committed as the canonical head block. 375 func (g *Genesis) MustCommit(db ethdb.Database) *types.Block { 376 block, err := g.Commit(db) 377 if err != nil { 378 panic(err) 379 } 380 return block 381 } 382 383 // GenesisBlockForTesting creates and writes a block in which addr has the given wei balance. 384 func GenesisBlockForTesting(db ethdb.Database, addr common.Address, balance *big.Int) *types.Block { 385 g := Genesis{ 386 Config: params.TestChainConfig, 387 Alloc: GenesisAlloc{addr: {Balance: balance}}, 388 BaseFee: new(big.Int).Set(params.TestMaxBaseFee), 389 } 390 return g.MustCommit(db) 391 } 392 393 // ReadBlockByHash reads the block with the given hash from the database. 394 func ReadBlockByHash(db ethdb.Reader, hash common.Hash) *types.Block { 395 blockNumber := rawdb.ReadHeaderNumber(db, hash) 396 if blockNumber == nil { 397 return nil 398 } 399 return rawdb.ReadBlock(db, hash, *blockNumber) 400 }