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(&params.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  }