aboutsummaryrefslogtreecommitdiff
path: root/core/genesis.go
diff options
context:
space:
mode:
authorDeterminant <[email protected]>2020-07-30 14:18:44 -0400
committerDeterminant <[email protected]>2020-07-30 14:18:44 -0400
commit0444e66f640999c15496066637841efcc0433934 (patch)
treec19aec2dced2e9129c880c19c52ca0f87b3d62f6 /core/genesis.go
parentcffa0954bbdb43821d1b71d00f99fb705cecd25b (diff)
parent1f49826de2bb8bb4f5f99f69fd2beb039b1172d9 (diff)
Merge branch 'multi-coin'
Diffstat (limited to 'core/genesis.go')
-rw-r--r--core/genesis.go168
1 files changed, 161 insertions, 7 deletions
diff --git a/core/genesis.go b/core/genesis.go
index 78249a7..ef490bf 100644
--- a/core/genesis.go
+++ b/core/genesis.go
@@ -19,28 +19,96 @@ package core
import (
"bytes"
"encoding/hex"
+ "encoding/json"
"errors"
"fmt"
"math/big"
"strings"
+ "github.com/ava-labs/coreth/core/rawdb"
+ "github.com/ava-labs/coreth/core/state"
+ "github.com/ava-labs/coreth/core/types"
+ "github.com/ava-labs/coreth/params"
"github.com/ava-labs/go-ethereum/common"
"github.com/ava-labs/go-ethereum/common/hexutil"
- "github.com/ava-labs/go-ethereum/core"
- "github.com/ava-labs/go-ethereum/core/rawdb"
- "github.com/ava-labs/go-ethereum/core/state"
+ "github.com/ava-labs/go-ethereum/common/math"
"github.com/ava-labs/go-ethereum/crypto"
"github.com/ava-labs/go-ethereum/ethdb"
"github.com/ava-labs/go-ethereum/log"
- "github.com/ava-labs/go-ethereum/params"
"github.com/ava-labs/go-ethereum/rlp"
)
+//go:generate gencodec -type Genesis -field-override genesisSpecMarshaling -out gen_genesis.go
+//go:generate gencodec -type GenesisAccount -field-override genesisAccountMarshaling -out gen_genesis_account.go
+
var errGenesisNoConfig = errors.New("genesis has no chain configuration")
-type Genesis = core.Genesis
-type GenesisAlloc = core.GenesisAlloc
-type GenesisAccount = core.GenesisAccount
+// Genesis specifies the header fields, state of a genesis block. It also defines hard
+// fork switch-over blocks through the chain configuration.
+type Genesis struct {
+ Config *params.ChainConfig `json:"config"`
+ Nonce uint64 `json:"nonce"`
+ Timestamp uint64 `json:"timestamp"`
+ ExtraData []byte `json:"extraData"`
+ GasLimit uint64 `json:"gasLimit" gencodec:"required"`
+ Difficulty *big.Int `json:"difficulty" gencodec:"required"`
+ Mixhash common.Hash `json:"mixHash"`
+ Coinbase common.Address `json:"coinbase"`
+ Alloc GenesisAlloc `json:"alloc" gencodec:"required"`
+
+ // These fields are used for consensus tests. Please don't use them
+ // in actual genesis blocks.
+ Number uint64 `json:"number"`
+ GasUsed uint64 `json:"gasUsed"`
+ ParentHash common.Hash `json:"parentHash"`
+}
+
+// GenesisAlloc specifies the initial state that is part of the genesis block.
+type GenesisAlloc map[common.Address]GenesisAccount
+
+func (ga *GenesisAlloc) UnmarshalJSON(data []byte) error {
+ m := make(map[common.UnprefixedAddress]GenesisAccount)
+ if err := json.Unmarshal(data, &m); err != nil {
+ return err
+ }
+ *ga = make(GenesisAlloc)
+ for addr, a := range m {
+ (*ga)[common.Address(addr)] = a
+ }
+ return nil
+}
+
+type GenesisMultiCoinBalance map[common.Hash]*big.Int
+
+// GenesisAccount is an account in the state of the genesis block.
+type GenesisAccount struct {
+ Code []byte `json:"code,omitempty"`
+ Storage map[common.Hash]common.Hash `json:"storage,omitempty"`
+ Balance *big.Int `json:"balance" gencodec:"required"`
+ MCBalance GenesisMultiCoinBalance `json:"mcbalance,omitempty"`
+ Nonce uint64 `json:"nonce,omitempty"`
+ PrivateKey []byte `json:"secretKey,omitempty"` // for tests
+}
+
+// field type overrides for gencodec
+type genesisSpecMarshaling struct {
+ Nonce math.HexOrDecimal64
+ Timestamp math.HexOrDecimal64
+ ExtraData hexutil.Bytes
+ GasLimit math.HexOrDecimal64
+ GasUsed math.HexOrDecimal64
+ Number math.HexOrDecimal64
+ Difficulty *math.HexOrDecimal256
+ Alloc map[common.UnprefixedAddress]GenesisAccount
+}
+
+type genesisAccountMarshaling struct {
+ Code hexutil.Bytes
+ Balance *math.HexOrDecimal256
+ Nonce math.HexOrDecimal64
+ Storage map[storageJSON]storageJSON
+ PrivateKey hexutil.Bytes
+}
// storageJSON represents a 256 bit byte array, but allows less than 256 bits when
// unmarshaling from hex.
@@ -182,6 +250,92 @@ func configOrDefault(g *Genesis, ghash common.Hash) *params.ChainConfig {
}
}
+// ToBlock creates the genesis block and writes state of a genesis specification
+// to the given database (or discards it if nil).
+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)
+ }
+ if account.MCBalance != nil {
+ statedb.ForceEnableMultiCoin(addr)
+ for coinID, value := range account.MCBalance {
+ statedb.AddBalanceMultiCoin(addr, coinID, 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)
+}
+
+// Commit writes the block and state of a genesis specification to the database.
+// The block is committed as the canonical head block.
+func (g *Genesis) Commit(db ethdb.Database) (*types.Block, error) {
+ block := g.ToBlock(db)
+ if block.Number().Sign() != 0 {
+ return nil, fmt.Errorf("can't commit genesis block with number > 0")
+ }
+ rawdb.WriteTd(db, block.Hash(), block.NumberU64(), g.Difficulty)
+ rawdb.WriteBlock(db, block)
+ rawdb.WriteReceipts(db, block.Hash(), block.NumberU64(), nil)
+ rawdb.WriteCanonicalHash(db, block.Hash(), block.NumberU64())
+ rawdb.WriteHeadBlockHash(db, block.Hash())
+ rawdb.WriteHeadFastBlockHash(db, block.Hash())
+ rawdb.WriteHeadHeaderHash(db, block.Hash())
+
+ config := g.Config
+ if config == nil {
+ config = params.AllEthashProtocolChanges
+ }
+ rawdb.WriteChainConfig(db, block.Hash(), config)
+ return block, nil
+}
+
+// MustCommit writes the genesis block and state to db, panicking on error.
+// The block is committed as the canonical head block.
+func (g *Genesis) MustCommit(db ethdb.Database) *types.Block {
+ block, err := g.Commit(db)
+ if err != nil {
+ panic(err)
+ }
+ return block
+}
+
+// GenesisBlockForTesting creates and writes a block in which addr has the given wei balance.
+func GenesisBlockForTesting(db ethdb.Database, addr common.Address, balance *big.Int) *types.Block {
+ g := Genesis{Alloc: GenesisAlloc{addr: {Balance: balance}}}
+ return g.MustCommit(db)
+}
+
// DefaultGenesisBlock returns the Ethereum main net genesis block.
func DefaultGenesisBlock() *Genesis {
return &Genesis{