Help us understand the problem. What is going on with this article?

go-ethereumを読む(2) geth init編

More than 1 year has passed since last update.

go-ethereumを読む(1) 準備編の続きで、
今回はローカルでgethを起動するために必要なGemesisブロックの生成辺りを解説します。
ローカルで動かすときはPOAで動かした方が処理が早いのでPOAの説明がメインです。
v1.8.15ベースに解説します

puppeth

gethを起動するときにdevフラグを付けない場合、gensis.jsonを作成する必要があります。
genesis.json作成についてはこの記事が詳しいです

geth init

gethをdevフラグをつけて起動する場合 geth init は必要ありません。
その場合下記の状態で起動されます。

  • POAになる
  • アカウントを作成・アンロックする
  • GasPriceが1になる

geth init実行時に処理されるコードを追っていきます。

makeFullNode > makeConfigNode > SetEthConfig

// cmd/utils/flags.go
func SetEthConfig(ctx *cli.Context, stack *node.Node, cfg *eth.Config) {
    // 省略
    // Override any default configs for hard coded networks.
    switch {
    // 省略
    case ctx.GlobalBool(DeveloperFlag.Name):
        if !ctx.GlobalIsSet(NetworkIdFlag.Name) {
            cfg.NetworkId = 1337
        }
        // Create new developer account or reuse existing one
        var (
            developer accounts.Account
            err       error
        )
        if accs := ks.Accounts(); len(accs) > 0 {
            developer = ks.Accounts()[0]
        } else {
            developer, err = ks.NewAccount("")
            if err != nil {
                Fatalf("Failed to create developer account: %v", err)
            }
        }
        if err := ks.Unlock(developer, ""); err != nil {
            Fatalf("Failed to unlock developer account: %v", err)
        }
        log.Info("Using developer account", "address", developer.Address)

        cfg.Genesis = core.DeveloperGenesisBlock(uint64(ctx.GlobalInt(DeveloperPeriodFlag.Name)), developer.Address)
        if !ctx.GlobalIsSet(MinerGasPriceFlag.Name) && !ctx.GlobalIsSet(MinerLegacyGasPriceFlag.Name) {
            cfg.MinerGasPrice = big.NewInt(1)
        }
    }
    // 省略
}

// core/genesis.go
func DeveloperGenesisBlock(period uint64, faucet common.Address) *Genesis {
    // POAになる(Clique)
    // Override the default period to the user requested one
    config := *params.AllCliqueProtocolChanges
    config.Clique.Period = period

    // Assemble and return the genesis with the precompiles and faucet pre-funded
    return &Genesis{
        Config:     &config,
        ExtraData:  append(append(make([]byte, 32), faucet[:]...), make([]byte, 65)...),
        GasLimit:   6283185,
        Difficulty: big.NewInt(1),
        Alloc: map[common.Address]GenesisAccount{
            common.BytesToAddress([]byte{1}): {Balance: big.NewInt(1)}, // ECRecover
            common.BytesToAddress([]byte{2}): {Balance: big.NewInt(1)}, // SHA256
            common.BytesToAddress([]byte{3}): {Balance: big.NewInt(1)}, // RIPEMD
            common.BytesToAddress([]byte{4}): {Balance: big.NewInt(1)}, // Identity
            common.BytesToAddress([]byte{5}): {Balance: big.NewInt(1)}, // ModExp
            common.BytesToAddress([]byte{6}): {Balance: big.NewInt(1)}, // ECAdd
            common.BytesToAddress([]byte{7}): {Balance: big.NewInt(1)}, // ECScalarMul
            common.BytesToAddress([]byte{8}): {Balance: big.NewInt(1)}, // ECPairing
            faucet: {Balance: new(big.Int).Sub(new(big.Int).Lsh(big.NewInt(1), 256), big.NewInt(9))},
        },
    }
}

// 下のURLが詳しいので、ほとんど、ここを読めば事足りる
// https://arvanaghi.com/blog/explaining-the-genesis-block-in-ethereum/
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

type ChainConfig struct {
    // blockchainの識別ID geth起動時に networkidとはべつもの
    // EIP155に定義されているのとは被らないようにする https://github.com/ethereum/EIPs/blob/master/EIPS/eip-155.md
    ChainId *big.Int `json:"chainId"`
    HomesteadBlock *big.Int `json:"homesteadBlock,omitempty"` // 0に設定しておけばHomesteadになる main netも0らしい

    DAOForkBlock   *big.Int `json:"daoForkBlock,omitempty"`   // 指定の必要なし。TheDAO事件のHard Forkしたblock番号
    DAOForkSupport bool     `json:"daoForkSupport,omitempty"` // 指定の必要なし。TheDAO事件のHard Forkに賛成か反対かを指定

    // EIP150で Gas priceの変更があったのでそのための項目  (https://github.com/ethereum/EIPs/issues/150)
    // storage readのGas priceが他と比べて安すぎてトランザクション拒否攻撃やトランザクションspamを防ぐため?
    EIP150Block *big.Int    `json:"eip150Block,omitempty"` // 0を指定しておけばOK
    EIP150Hash  common.Hash `json:"eip150Hash,omitempty"`  // 指定の必要なし。 main netで --syncmode=fastで使用する  --syncmode=fastがデフォルト

    EIP155Block *big.Int `json:"eip155Block,omitempty"` // 0を指定しておけばOK EIP155 Hard Fork 別環境のtransactionが使えてしまう問題があって、TransactionHashにChainIdを付けるようになった
    EIP158Block *big.Int `json:"eip158Block,omitempty"` // 0を指定しておけばOK EIP158 Hard Fork 空のアカウントを無視して容量を削減するようにした

    ByzantiumBlock      *big.Int `json:"byzantiumBlock,omitempty"`      // 指定の必要なし。 Byzantiumに切り替えたブロック
    ConstantinopleBlock *big.Int `json:"constantinopleBlock,omitempty"` // 指定の必要なし。 Constantinopleに切り替えたブロック

    Ethash *EthashConfig `json:"ethash,omitempty"` // 指定の必要なし。 Ethashの設定 今のところ無し
    Clique *CliqueConfig `json:"clique,omitempty"` // POAにするときに必要
}

type CliqueConfig struct {
    Period uint64 `json:"period"` // ブロックの生成時間のインターバル
    // Epoch 投票(vote)のリセット間隔 checkpointはcheckpointIntervalだと思うけど、プログラムが怪しい?
    // 投票はblockのheaderのNonceを使って正しい署名者かをチェックする?
    // checkpointInterval毎のblockでsnapshotをdbに書き出す
    // それまでは、lruにインメモリで持っている
    Epoch  uint64 `json:"epoch"`                
}

// params/config.go
var (
    // 省略
    // AllEthashProtocolChanges contains every protocol change (EIPs) introduced
    // and accepted by the Ethereum core developers into the Ethash consensus.
    //
    // This configuration is intentionally not using keyed fields to force anyone
    // adding flags to the config to also have to set these fields.
    AllEthashProtocolChanges = &ChainConfig{big.NewInt(1337), big.NewInt(0), nil, false, big.NewInt(0), common.Hash{}, big.NewInt(0), big.NewInt(0), big.NewInt(0), nil, new(EthashConfig), nil}

    // AllCliqueProtocolChanges contains every protocol change (EIPs) introduced
    // and accepted by the Ethereum core developers into the Clique consensus.
    //
    // This configuration is intentionally not using keyed fields to force anyone
    // adding flags to the config to also have to set these fields.
    AllCliqueProtocolChanges = &ChainConfig{big.NewInt(1337), big.NewInt(0), nil, false, big.NewInt(0), common.Hash{}, big.NewInt(0), big.NewInt(0), big.NewInt(0), nil, nil, &CliqueConfig{Period: 0, Epoch: 30000}}
    // 省略
)
$ geth --datadir testnet init genesis.json

普通の場合のサンプル

{
  "config": {
    "chainId": 33,
    "homesteadBlock": 0,
    "eip150Block": 0,
    "eip155Block": 0,
    "eip158Block": 0,
    "byzantiumBlock": 0,
    "clique": {
      "period": 33,
      "epoch": 30000
    }
  },
  "difficulty": "0x400000",
  "gasLimit": "0x8000000",
  "alloc": {}
  }
}

POA(clique)にする場合のサンプル

{
  "config": {
    "chainId": 33,
    "homesteadBlock": 1,
    "eip150Block": 2,
    "eip150Hash": "0x0000000000000000000000000000000000000000000000000000000000000000",
    "eip155Block": 3,
    "eip158Block": 3,
    "byzantiumBlock": 4,
    "clique": {
      "period": 15,
      "epoch": 30000
    }
  },
  "nonce": "0x0",
  "timestamp": "0x5afe4952",
  "extraData": "0x00000000000000000000000000000000000000000000000000000000000000004528fc478bb156f0e79988a1f5fca25bfa43039c0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000",
  "gasLimit": "0x47b760",
  "difficulty": "0x1",
  "mixHash": "0x0000000000000000000000000000000000000000000000000000000000000000",
  "coinbase": "0x0000000000000000000000000000000000000000",
  "alloc": {
    "0000000000000000000000000000000000000000": {
      "balance": "0x1"
    },
  },
  "number": "0x0",
  "gasUsed": "0x0",
  "parentHash": "0x0000000000000000000000000000000000000000000000000000000000000000"
}
Why not register and get more from Qiita?
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
Comments
Sign up for free and join this conversation.
If you already have a Qiita account
Why do not you register as a user and use Qiita more conveniently?
You need to log in to use this function. Qiita can be used more conveniently after logging in.
You seem to be reading articles frequently this month. Qiita can be used more conveniently after logging in.
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away