Gethのコードを理解する①（デバッグ環境構築編）

## はじめに
Ethereumを理解するには、Geth（Go-ethereum）の理解が必須と感じるので、Gethを勉強する。
第一弾はGethのデバッグ環境構築編。

※間違っている情報があれば、ご指摘いただければ幸いです。


## Geth環境構築の目標
+ **Gethコードの変数をデバッグする**（変数の中身を確認できる状態にする）
+ Gethでプライベートネットワークを起動する


## バージョンなど
#### 開発環境
+ OS: Ubuntu20.04
+ Geth Version: 1.9.25-stable （最新バージョンだとエラーが出たため、古いバージョンを選択）
+ Geth Git Commit: e7872729012a4871397307b12cc3f4772ffcbec6
#### 依存ツールのバージョン
+ golang: version go1.19.3 linux/amd64
+ make: GNU Make 4.2.1
+ git: version 2.25.1


## Geth環境構築の方針

### Gethを動かすOS
以下のOSで動かせる。([Gethのドキュメント](https://geth.ethereum.org/docs/install-and-build/installing-geth))
+ Windows
+ Linux
+ MacOS

後々、AWSのEC2でGethを動かしてみたいので、OSは**Linux** **(Ubuntu)** を選択する。

### Gethのインストール方法
以下のインストール方法がある。([Gethのドキュメント](https://geth.ethereum.org/docs/install-and-build/installing-geth))
+ パッケージマネージャを利用
+ Standalone bundleを[ダウンロード](https://geth.ethereum.org/downloads/)
+ ソースコードからビルド

変数のデバッグを行いたいので、**ソースコードからビルドする方法**を選択する。


## Geth環境構築の手順

### ①依存ツールの準備
Gethをソースコードからビルドする場合、Ubuntuでgolang, make, git を使える必要がある。

```ubuntu20.04
// 2022年11月時点の最新版をインストール
$ go version
go version go1.19.3 linux/amd64 
```
```ubuntu20.04
$ make -v
GNU Make 4.2.1
```
```ubuntu20.04
$ git version
git version 2.25.1
```


### ②Gethソースコードの取得
任意のディレクトリにGethソースコードをcloneする。
自分の場合は、~/GOPATH/src/github.com/とした。
Gethの最新バージョンだとエラーが発生したため、 Versionv 1.9 をcloneした.
（Ethereumのマージ以降のGethを利用すると、プライベートネットに接続できなかった....）

```ubuntu20.04
$ git clone -b release/1.9 https://github.com/ethereum/go-ethereum.git
Cloning into 'go-ethereum'...
remote: Enumerating objects: 111489, done.
remote: Counting objects: 100% (58/58), done.
remote: Compressing objects: 100% (46/46), done.
remote: Total 111489 (delta 17), reused 33 (delta 9), pack-reused 111431
Receiving objects: 100% (111489/111489), 186.75 MiB | 12.98 MiB/s, done.
Resolving deltas: 100% (66865/66865), done.
```
```ubuntu20.04
$ cd go-ethereum
$ git branch
* release/1.9
```

### ③Gethソースコードのビルド
go-ethereumディレクトリで、makeを実行する。
```ubuntu20.04
$ make geth
env GO111MODULE=on go run build/ci.go install ./cmd/geth
>>> /usr/lib/go-1.19/bin/go build -ldflags -X main.gitCommit=e7872729012a4871397307b12cc3f4772ffcbec6 -X main.gitDate=20201211 -trimpath -v -o /home/USERHOME/GOPATH/src/github.com/go-ethereum/build/bin/geth ./cmd/geth
github.com/ethereum/go-ethereum/crypto/secp256k1
Done building.
Run "./build/bin/geth" to launch geth.
```

go-ethereum/build/bin/ に、コンパイルされたgethファイルが存在すれば、ビルドは完了している。
```ubuntu20.04
$ ls build/bin
geth
```

### ④データディレクトリの作成
プライベートネットワークのブロック情報などを格納するデータディレクトリを作成する。
自分の場合は、~/eth_private_net/ に作成した。（ディレクトリ名は自由）


### ⑤プライベートネットワークの初期化
プライベートネットワークのGenesisブロック（1番最初のブロック）の情報を、genesis.jsonに記載する。
genesis.jsonは、任意のディレクトリに作成する。
自分の場合は、~/GOPATH/src/github.com/go-ethereum/build/bin/ に作成した。

genesis.jsonの中身は、Ethereum入門のサイトを参考にした。
[Ethereum入門](https://book.ethereum-jp.net/first_use/connect_to_private_net)

``` genesis.json
{
    "config": {
        "chainId": 15,
        "homesteadBlock": 0,
        "eip150Block": 0,
        "eip155Block": 0,
        "eip158Block": 0,
        "byzantiumBlock": 0,
        "constantinopleBlock": 0,
        "petersburgBlock": 0,
        "istanbulBlock": 0,
        "berlinBlock": 0
    },
    "nonce": "0x0000000000000042",
    "timestamp": "0x0",
    "parentHash": "0x0000000000000000000000000000000000000000000000000000000000000000",
    "extraData": "",
    "gasLimit": "0x8000000",
    "difficulty": "0x4000",
    "mixhash": "0x0000000000000000000000000000000000000000000000000000000000000000",
    "coinbase": "0x3333333333333333333333333333333333333333",
    "alloc": {}
}
```

genesis.jsonの作成後、プライベートネットワークの初期化を行う。

```ubuntu20.04
$ cd go-ethereum/build/bin
$  ./geth --datadir ~/eth_private_net --nousb init ./genesis.json
INFO [11-29|23:15:22.420] Maximum peer count                       ETH=50 LES=0 total=50
INFO [11-29|23:15:22.420] Smartcard socket not found, disabling    err="stat /run/pcscd/pcscd.comm: no such file or directory"
INFO [11-29|23:15:22.421] Set global gas cap                       cap=25000000
INFO [11-29|23:15:22.421] Allocated cache and file handles         database=/home/USERHOME/eth_private_net/geth/chaindata cache=16.00MiB handles=16
INFO [11-29|23:15:22.427] Writing custom genesis block
INFO [11-29|23:15:22.427] Persisted trie from memory database      nodes=0 size=0.00B time="3.5µs" gcnodes=0 gcsize=0.00B gctime=0s livenodes=1 livesize=0.00B
INFO [11-29|23:15:22.428] Successfully wrote genesis state         database=chaindata hash="7b2e8b…7e0432"
INFO [11-29|23:15:22.428] Allocated cache and file handles         database=/home/USERHOME/eth_private_net/geth/lightchaindata cache=16.00MiB handles=16
INFO [11-29|23:15:22.433] Writing custom genesis block
INFO [11-29|23:15:22.433] Persisted trie from memory database      nodes=0 size=0.00B time="16.5µs" gcnodes=0 gcsize=0.00B gctime=0s livenodes=1 livesize=0.00B
INFO [11-29|23:15:22.434] Successfully wrote genesis state         database=lightchaindata hash="7b2e8b…7e0432"
```

データディレクトリに、「geth」「keystore」というディレクトリが作成されていれば、プライベートネットワークの初期化は完了している。
```ubuntu20.04
$ ls ~/eth_private_net
geth  keystore
```


### ⑥Gethプライベートネットワークの起動
Gethでプライベートネットワークを起動する。

``` ubuntu20.04
$ ./geth --datadir ~/eth_private_net --networkid 15 --nousb console 2>> ./geth_err.log
Welcome to the Geth JavaScript console!

instance: Geth/v1.9.25-stable-e7872729/linux-amd64/go1.19.3
at block: 0 (Thu Jan 01 1970 09:00:00 GMT+0900 (JST))
 datadir: /home/USERHOME/eth_private_net
 modules: admin:1.0 debug:1.0 eth:1.0 ethash:1.0 miner:1.0 net:1.0 personal:1.0 rpc:1.0 txpool:1.0 web3:1.0

To exit, press ctrl-d
>
```

起動に成功すると、GethのJavascriptコンソールが使えるようになる。
プライベートネットワークの情報を取得してみる。

``` :GethのJavascriptコンソール
> eth.chainId()
"0xf"     // chainIdに15が設定されている
> eth.blockNumber
0         // ブロックの高さは0
```

### ⑦変数のデバッグ
デバッグのために、go-thereum/internal/ethapi/api.goのSendTransaction関数を変更する。（SendTransaction関数は2つあるので注意）
SendTransaction関数の先頭に、デバッグのコードを2行追加。

``` go: go-thereum/internal/ethapi/api.go
func (s *PublicTransactionPoolAPI) SendTransaction(ctx context.Context, args SendTxArgs) (common.Hash, error) {
	fmt.Printf("デバッグを挿入！\n") // 追加
	fmt.Printf("SendTransactionのargs: %v\n", args) // 追加 
	
	// Look up the wallet containing the requested signer
	account := accounts.Account{Address: args.From}

	wallet, err := s.b.AccountManager().Find(account)
	if err != nil {
		return common.Hash{}, err
	}

	if args.Nonce == nil {
		// Hold the addresse's mutex around signing to prevent concurrent assignment of
		// the same nonce to multiple accounts.
		s.nonceLock.LockAddr(args.From)
		defer s.nonceLock.UnlockAddr(args.From)
	}

	// Set some sanity defaults and terminate on failure
	if err := args.setDefaults(ctx, s.b); err != nil {
		return common.Hash{}, err
	}
	// Assemble the transaction and sign with the wallet
	tx := args.toTransaction()
    ...
    ...
    ...
```

ソースコードの変更を反映させるために、Gethを再ビルドしてから、プライベートネットワークを起動し直す。
```ubuntu20.04
// ビルドのコマンド
$ make geth

//プライベートネットワークの起動コマンド
$ ./geth --datadir ~/eth_private_net --networkid 15 --nousb console 2>> ./geth_err.log
```

SendTransaction関数に入れたデバッグが、GethのJavascriptコンソールに表示されるかを確認する。
``` :GethのJavascriptコンソール
> eth.sendTransaction({from: eth.accounts[0], to: eth.accounts[1], ChainID: 15, nonce: 8, gas: 0x100000, gasPrice: 0x10
0, value: web3.toWei(2, "ether") })
デバッグを挿入！
SendTransactionのargs: {0x6364294FbF6BAcC9D7A591274A42Ed3fd982436f 0xb76Fbd02341eeaA40e2a5ec472cCDCE69d81944E 0x100000 0x100 0x1bc16d674ec80000 0x8 <nil> <nil>}
"0x3dc6bc6f13123e9b91b69d552766be8f40fbe288d6814a93565d82e503f5ae4f"
```
「デバッグを挿入！」と表示され、argsの中身を表示させることができた。


## まとめ
なんとかGethの変数をデバッグする環境を構築できた。
Gethの動作確認を行い、Ethereumの理解を深めたい。



## 参考にしたサイト
https://medium.com/@hyoungsungkim/build-private-ethereum-network-and-test-step-by-step-ff50a2c88eca