github.com/amazechain/amc@v0.1.3/internal/genesis_block.go (about) 1 // Copyright 2022 The AmazeChain Authors 2 // This file is part of the AmazeChain library. 3 // 4 // The AmazeChain library is free software: you can redistribute it and/or modify 5 // it under the terms of the GNU Lesser General Public License as published by 6 // the Free Software Foundation, either version 3 of the License, or 7 // (at your option) any later version. 8 // 9 // The AmazeChain library is distributed in the hope that it will be useful, 10 // but WITHOUT ANY WARRANTY; without even the implied warranty of 11 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 // GNU Lesser General Public License for more details. 13 // 14 // You should have received a copy of the GNU Lesser General Public License 15 // along with the AmazeChain library. If not, see <http://www.gnu.org/licenses/>. 16 17 package internal 18 19 import ( 20 "bytes" 21 "context" 22 "embed" 23 "encoding/binary" 24 "encoding/json" 25 "errors" 26 "fmt" 27 "github.com/amazechain/amc/params/networkname" 28 "math/big" 29 "sync" 30 31 "github.com/amazechain/amc/modules" 32 "github.com/amazechain/amc/modules/rawdb" 33 "github.com/amazechain/amc/modules/state" 34 "github.com/amazechain/amc/params" 35 "github.com/c2h5oh/datasize" 36 "github.com/holiman/uint256" 37 "github.com/ledgerwatch/erigon-lib/kv" 38 "github.com/ledgerwatch/erigon-lib/kv/mdbx" 39 40 block2 "github.com/amazechain/amc/common/block" 41 "github.com/amazechain/amc/common/types" 42 "github.com/amazechain/amc/conf" 43 ) 44 45 var ErrGenesisNoConfig = errors.New("genesis has no chain configuration") 46 47 //go:embed allocs 48 var allocs embed.FS 49 50 func readGenesisAlloc(filename string) conf.GenesisAlloc { 51 f, err := allocs.Open(filename) 52 if err != nil { 53 panic(fmt.Sprintf("Could not open GenesisAlloc for %s: %v", filename, err)) 54 } 55 defer f.Close() 56 decoder := json.NewDecoder(f) 57 spec := conf.GenesisAlloc{} 58 err = decoder.Decode(&spec) 59 if err != nil { 60 panic(fmt.Sprintf("Could not parse GenesisAlloc for %s: %v", filename, err)) 61 } 62 return spec 63 } 64 65 type GenesisBlock struct { 66 Hash string 67 GenesisConfig *conf.Genesis 68 // ChainConfig *params.ChainConfig 69 } 70 71 func (g *GenesisBlock) Write(tx kv.RwTx) (*block2.Block, *state.IntraBlockState, error) { 72 block, statedb, err2 := g.WriteGenesisState(tx) 73 if err2 != nil { 74 return block, statedb, err2 75 } 76 77 if err := rawdb.WriteTd(tx, block.Hash(), block.Number64().Uint64(), uint256.NewInt(0)); err != nil { 78 return nil, nil, err 79 } 80 if err := rawdb.WriteBlock(tx, block); err != nil { 81 return nil, nil, err 82 } 83 //if err := rawdb.TxNums.WriteForGenesis(tx, 1); err != nil { 84 // return nil, nil, err 85 //} 86 if err := rawdb.WriteReceipts(tx, block.Number64().Uint64(), nil); err != nil { 87 return nil, nil, err 88 } 89 90 if err := rawdb.WriteCanonicalHash(tx, block.Hash(), block.Number64().Uint64()); err != nil { 91 return nil, nil, err 92 } 93 94 rawdb.WriteHeadBlockHash(tx, block.Hash()) 95 if err := rawdb.WriteHeadHeaderHash(tx, block.Hash()); err != nil { 96 return nil, nil, err 97 } 98 if err := rawdb.WriteChainConfig(tx, block.Hash(), g.GenesisConfig.Config); err != nil { 99 return nil, nil, err 100 } 101 // We support ethash/serenity for issuance (for now) 102 //if g.Config.Consensus != params.EtHashConsensus { 103 return block, statedb, nil 104 //} 105 } 106 107 func (g *GenesisBlock) ToBlock() (*block2.Block, *state.IntraBlockState, error) { 108 _ = g.GenesisConfig.Alloc //nil-check 109 110 var root types.Hash 111 var statedb *state.IntraBlockState 112 wg := sync.WaitGroup{} 113 wg.Add(1) 114 go func() { // we may run inside write tx, can't open 2nd write tx in same goroutine 115 defer wg.Done() 116 //TODO 117 tmpDB := mdbx.NewMDBX(nil).InMem("").MapSize(2 * datasize.GB).MustOpen() 118 defer tmpDB.Close() 119 tx, err := tmpDB.BeginRw(context.Background()) 120 if err != nil { 121 panic(err) 122 } 123 defer tx.Rollback() 124 r, w := state.NewPlainStateReader(tx), state.NewPlainStateWriter(tx, tx, 0) 125 statedb = state.New(r) 126 127 for address, account := range g.GenesisConfig.Alloc { 128 b, ok := new(big.Int).SetString(account.Balance, 10) 129 balance, _ := uint256.FromBig(b) 130 if !ok { 131 panic("overflow at genesis allocs") 132 } 133 statedb.AddBalance(address, balance) 134 statedb.SetCode(address, account.Code) 135 statedb.SetNonce(address, account.Nonce) 136 for key, value := range account.Storage { 137 k := key 138 val := uint256.NewInt(0).SetBytes(value.Bytes()) 139 statedb.SetState(address, &k, *val) 140 } 141 if len(account.Code) > 0 || len(account.Storage) > 0 { 142 statedb.SetIncarnation(address, state.FirstContractIncarnation) 143 } 144 } 145 146 if err := statedb.FinalizeTx(g.GenesisConfig.Config.Rules(0), w); err != nil { 147 panic(err) 148 } 149 root = statedb.GenerateRootHash() 150 }() 151 wg.Wait() 152 153 var ExtraData []byte 154 155 switch g.GenesisConfig.Config.Consensus { 156 case params.CliqueConsensus, params.AposConsensu: 157 158 var signers []types.Address 159 160 for _, miner := range g.GenesisConfig.Miners { 161 addr, err := types.HexToString(miner) 162 if err != nil { 163 return nil, nil, fmt.Errorf("invalid miner: %s", miner) 164 } 165 signers = append(signers, addr) 166 } 167 // Sort the signers and embed into the extra-data section 168 for i := 0; i < len(signers); i++ { 169 for j := i + 1; j < len(signers); j++ { 170 if bytes.Compare(signers[i][:], signers[j][:]) > 0 { 171 signers[i], signers[j] = signers[j], signers[i] 172 } 173 } 174 } 175 ExtraData = make([]byte, 32+len(signers)*types.AddressLength+65) 176 for i, signer := range signers { 177 copy(ExtraData[32+i*types.AddressLength:], signer[:]) 178 } 179 } 180 181 head := &block2.Header{ 182 ParentHash: g.GenesisConfig.ParentHash, 183 Coinbase: g.GenesisConfig.Coinbase, 184 Root: root, 185 TxHash: types.Hash{0}, 186 ReceiptHash: types.Hash{0}, 187 Difficulty: g.GenesisConfig.Difficulty, 188 Number: uint256.NewInt(g.GenesisConfig.Number), 189 GasLimit: g.GenesisConfig.GasLimit, 190 GasUsed: g.GenesisConfig.GasUsed, 191 Time: uint64(g.GenesisConfig.Timestamp), 192 Extra: g.GenesisConfig.ExtraData, 193 MixDigest: g.GenesisConfig.Mixhash, 194 Nonce: block2.EncodeNonce(g.GenesisConfig.Nonce), 195 BaseFee: g.GenesisConfig.BaseFee, 196 } 197 head.Extra = ExtraData 198 199 if g.GenesisConfig.GasLimit == 0 { 200 head.GasLimit = params.GenesisGasLimit 201 } 202 if g.GenesisConfig.Difficulty == nil { 203 head.Difficulty = params.GenesisDifficulty 204 } 205 if g.GenesisConfig.Config != nil && (g.GenesisConfig.Config.IsLondon(0)) { 206 if g.GenesisConfig.BaseFee != nil { 207 head.BaseFee = g.GenesisConfig.BaseFee 208 } else { 209 head.BaseFee = uint256.NewInt(params.InitialBaseFee) 210 } 211 } 212 213 return block2.NewBlock(head, nil).(*block2.Block), statedb, nil 214 } 215 216 func (g *GenesisBlock) WriteGenesisState(tx kv.RwTx) (*block2.Block, *state.IntraBlockState, error) { 217 block, statedb, err := g.ToBlock() 218 if err != nil { 219 return nil, nil, err 220 } 221 for address, account := range g.GenesisConfig.Alloc { 222 if len(account.Code) > 0 || len(account.Storage) > 0 { 223 // Special case for weird tests - inaccessible storage 224 var b [2]byte 225 binary.BigEndian.PutUint16(b[:], state.FirstContractIncarnation) 226 if err := tx.Put(modules.IncarnationMap, address[:], b[:]); err != nil { 227 return nil, nil, err 228 } 229 } 230 } 231 if block.Number64().Uint64() != 0 { 232 return nil, statedb, fmt.Errorf("can't commit genesis block with number > 0") 233 } 234 235 blockWriter := state.NewPlainStateWriter(tx, tx, g.GenesisConfig.Number) 236 if err := statedb.CommitBlock(¶ms.Rules{}, blockWriter); err != nil { 237 return nil, statedb, fmt.Errorf("cannot write state: %w", err) 238 } 239 if err := blockWriter.WriteChangeSets(); err != nil { 240 return nil, statedb, fmt.Errorf("cannot write change sets: %w", err) 241 } 242 if err := blockWriter.WriteHistory(); err != nil { 243 return nil, statedb, fmt.Errorf("cannot write history: %w", err) 244 } 245 246 return block, statedb, nil 247 } 248 249 func GenesisByChainName(chain string) *conf.Genesis { 250 switch chain { 251 case networkname.MainnetChainName: 252 return mainnetGenesisBlock() 253 case networkname.TestnetChainName: 254 return testnetGenesisBlock() 255 default: 256 return nil 257 } 258 } 259 260 // DefaultGenesisBlock returns the Ethereum main net genesis block. 261 func mainnetGenesisBlock() *conf.Genesis { 262 return &conf.Genesis{ 263 Config: params.MainnetChainConfig, 264 Nonce: 0, 265 Alloc: readGenesisAlloc("allocs/mainnet.json"), 266 Timestamp: 1678174066, 267 Miners: []string{"AMCA2142AB3F25EAA9985F22C3F5B1FF9FA378DAC21"}, 268 Number: 0, 269 // genesisBlock Difficulty = params.GenesisDifficulty 270 //Difficulty: uint256.NewInt(0), 271 } 272 } 273 274 // DefaultGenesisBlock returns the Ethereum main net genesis block. 275 func testnetGenesisBlock() *conf.Genesis { 276 return &conf.Genesis{ 277 Config: params.TestnetChainConfig, 278 Nonce: 0, 279 Alloc: readGenesisAlloc("allocs/testnet.json"), 280 Number: 0, 281 Timestamp: 1678174066, 282 Miners: []string{"AMCA2142AB3F25EAA9985F22C3F5B1FF9FA378DAC21"}, 283 } 284 }