はじめに
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のドキュメント)
- Windows
- Linux
- MacOS
後々、AWSのEC2でGethを動かしてみたいので、OSはLinux (Ubuntu) を選択する。
Gethのインストール方法
以下のインストール方法がある。(Gethのドキュメント)
- パッケージマネージャを利用
- Standalone bundleをダウンロード
- ソースコードからビルド
変数のデバッグを行いたいので、ソースコードからビルドする方法を選択する。
Geth環境構築の手順
①依存ツールの準備
Gethをソースコードからビルドする場合、Ubuntuでgolang, make, git を使える必要がある。
// 2022年11月時点の最新版をインストール
$ go version
go version go1.19.3 linux/amd64
$ make -v
GNU Make 4.2.1
$ git version
git version 2.25.1
②Gethソースコードの取得
任意のディレクトリにGethソースコードをcloneする。
自分の場合は、~/GOPATH/src/github.com/とした。
Gethの最新バージョンだとエラーが発生したため、 Versionv 1.9 をcloneした.
(Ethereumのマージ以降のGethを利用すると、プライベートネットに接続できなかった....)
$ 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.
$ cd go-ethereum
$ git branch
* release/1.9
③Gethソースコードのビルド
go-ethereumディレクトリで、makeを実行する。
$ 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ファイルが存在すれば、ビルドは完了している。
$ 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入門
{
"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の作成後、プライベートネットワークの初期化を行う。
$ 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」というディレクトリが作成されていれば、プライベートネットワークの初期化は完了している。
$ ls ~/eth_private_net
geth keystore
⑥Gethプライベートネットワークの起動
Gethでプライベートネットワークを起動する。
$ ./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コンソールが使えるようになる。
プライベートネットワークの情報を取得してみる。
> eth.chainId()
"0xf" // chainIdに15が設定されている
> eth.blockNumber
0 // ブロックの高さは0
⑦変数のデバッグ
デバッグのために、go-thereum/internal/ethapi/api.goのSendTransaction関数を変更する。(SendTransaction関数は2つあるので注意)
SendTransaction関数の先頭に、デバッグのコードを2行追加。
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を再ビルドしてから、プライベートネットワークを起動し直す。
// ビルドのコマンド
$ make geth
//プライベートネットワークの起動コマンド
$ ./geth --datadir ~/eth_private_net --networkid 15 --nousb console 2>> ./geth_err.log
SendTransaction関数に入れたデバッグが、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の理解を深めたい。
参考にしたサイト