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

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

# puppeth
gethを起動するときにdevフラグを付けない場合、gensis.jsonを作成する必要があります。
genesis.json作成については[この記事](http://tahtan.hatenablog.com/entry/2018/05/06/194148)が詳しいです

# geth init

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

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

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

### makeFullNode > makeConfigNode > SetEthConfig

```go
// 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}}
	// 省略
)
```

```sh
$ 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)にする場合のサンプル

```json
{
  "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"
}
```