Dockerを使ってGethをプライベートネットワークで実行してみる
Gethとはイーサリアムクライアントの一つです。
ブロックチェーンアプリケーション開発の教科書(リフロー版)
書籍ではWindowsとmacOSを使った方法しかないのでDockerでの利用方法と、
書籍に書かれている情報がいくつか古いものがあるので現時点での動かし方について書いていきます。
docker-composeでGethを利用できるようにする
docker run
でも動きますがオプションの指定を楽にしたかったのでdokcer-compose
を使っています。
イメージはethereum/client-go
というのがあるのでこれを使います。
version: "3"
services:
app:
image: ethereum/client-go
entrypoint: "/bin/sh"
tty: true
volumes:
- .:/geth
entrypoint: "/bin/sh"
について。
ethereum/client-go
のentrypointが
ENTRYPOINT ["geth"]
となっている。
そのためそのままdocker-compose up
するとgethのネットワークが起動してしまう。
一旦コンテナ内で自由にgethコマンドを使えるようにしたいので、
entrypoint: "/bin/sh"
としてdocker-compose up
でネットワークが起動しないようにしている。
起動
mbazuki:geth-sandbox hide$ docker-compose up
Recreating geth-sandbox_app_1 ... done
Attaching to geth-sandbox_app_1
コンテナの中に入る
mbazuki:geth-sandbox hide$ docker-compose exec app /bin/sh
/ # ls
bin etc home media opt root sbin sys usr
dev geth lib mnt proc run srv tmp var
/ #
/ # geth version
Geth
Version: 1.10.18-unstable
Git Commit: f94e23ca66eef8fdac2473ce99ca6ad57324aaa2
Architecture: amd64
Go Version: go1.18.1
Operating System: linux
GOPATH=
GOROOT=go
これでDockerコンテナ内でgeth
コマンドが使えるようになりました。
Gethの初期化
プライベートネットワークはブロックが一つもない状態です。
そのため最初のブロック(ジェネシスブロック)を作成し初期化する必要があります。
プライベートネットワーク用のディレクトリprivate_net
を作成しその中にgenesis.json
を作成します。
{
"config": {
"chainId": 22,
"homesteadBlock": 0,
"eip150Block": 0,
"eip155Block": 0,
"eip158Block": 0,
"byzantiumBlock": 0,
"constantinopleBlock": 0,
"petersburgBlock": 0,
"istanbulBlock": 0,
"berlinBlock": 0,
"londonBlock": 0
},
"alloc": {},
"coinbase": "0x0000000000000000000000000000000000000000",
"difficulty": "0x20000",
"extraData": "",
"gasLimit": "0x2fefd8",
"nonce": "0x00000000000000031",
"mixhash": "0x0000000000000000000000000000000000000000000000000000000000000000",
"parentHash": "0x0000000000000000000000000000000000000000000000000000000000000000",
"timestamp": "0x00"
}
ここは書籍だともっと項目は少ないですが、変更されているためGithubに書いてあるものを使います。
chainId
は適当に22
。
nonce
も適当な値にしています。
初期化のコマンドは以下です。
geth --datadir /geth/private_net/ init /geth/private_net/genesis.json
datadir
はデータの保存先などで使われるディレクトリの指定です。
指定なしだと~/.ethereum
なので作成しておいたprivate_net/
を指定しておきます。
/geth/private_net # geth --datadir /geth/private_net/ init /geth/private_net/genesis.json
INFO [05-02|06:43:33.332] Maximum peer count ETH=50 LES=0 total=50
INFO [05-02|06:43:33.332] Smartcard socket not found, disabling err="stat /run/pcscd/pcscd.comm: no such file or directory"
WARN [05-02|06:43:33.465] Sanitizing cache to Go's GC limits provided=1024 updated=662
INFO [05-02|06:43:33.465] Set global gas cap cap=50,000,000
INFO [05-02|06:43:33.468] Allocated cache and file handles database=/geth/private_net/geth/chaindata cache=16.00MiB handles=16
INFO [05-02|06:43:33.583] Writing custom genesis block
INFO [05-02|06:43:33.583] Persisted trie from memory database nodes=0 size=0.00B time="27.7µs" gcnodes=0 gcsize=0.00B gctime=0s livenodes=1 livesize=0.00B
INFO [05-02|06:43:33.613] Successfully wrote genesis state database=chaindata hash=119a56..09b937
INFO [05-02|06:43:33.613] Allocated cache and file handles database=/geth/private_net/geth/lightchaindata cache=16.00MiB handles=16
INFO [05-02|06:43:33.724] Writing custom genesis block
INFO [05-02|06:43:33.726] Persisted trie from memory database nodes=0 size=0.00B time="22.3µs" gcnodes=0 gcsize=0.00B gctime=0s livenodes=1 livesize=0.00B
INFO [05-02|06:43:33.763] Successfully wrote genesis state database=lightchaindata hash=119a56..09b937
Successfully wrote genesis state
が出力されれば成功。
private_net/
にgeth/
とkeystore/
が生成されています。
Gethの起動
書籍でのコマンドは以下となっています。
geth --networkid "10" --nodiscover --datadir ~/geth/private_net --rpc --rpcaddr "localhost" --rpcport "8545" --rpccorsdomain "*" --rpcapi "eth,net,web3,personal" --targetgaslimit "20000000" console 2>> ~/geth/private_net/error.log
rpc
関連のコマンドはhttp
と名前が置き換わっています。
また、プルリク見つけられませんでしたがtargetgaslimit
もminer.gaslimit
に変わっています。
そのため以下となります。
geth --networkid "22" --nodiscover --datadir /geth/private_net \
--http --http.addr "localhost" --http.port "8545" --http.corsdomain "*" \
--http.api "eth,net,web3,personal" --miner.gaslimit "20000000" \
console 2>> /geth/private_net/error.log
(ディレクトリもこの記事では/geth/private_net
としているので変えてます)
パラメータの説明は以下です。
- networkid
-
genesis.json
のchainId
に指定した整数を指定
-
- nodiscover
- Gethはデフォルトで他のノードへの接続を試みる(他のノードからの接続も受け入れる)のでそれを無効にします
- https://geth.ethereum.org/docs/interface/peer-to-peer#how-peers-are-found
- datadir
- Gethの初期化時に指定したディレクトリを指定
- http関連
- サーバーを立てるイメージ
- 今回の記事では使用しないのでなくても問題ない
- console 2
実際は以下のようにエラー以外のログも出力されているのでファイル名はerror.log
でなくてもいいかもです。
INFO [05-02|07:26:09.346] Maximum peer count ETH=50 LES=0 total=50
INFO [05-02|07:26:09.349] Smartcard socket not found, disabling err="stat /run/pcscd/pcscd.comm: no such file or directory"
WARN [05-02|07:26:09.382] Sanitizing cache to Go's GC limits provided=1024 updated=662
起動
/geth # geth --networkid "22" --nodiscover --datadir /geth/private_net --miner.gaslimit "20000000" console 2>> /get
h/private_net/error.log
Welcome to the Geth JavaScript console!
instance: Geth/v1.10.18-unstable-f94e23ca/linux-amd64/go1.18.1
at block: 0 (Thu Jan 01 1970 00:00:00 GMT+0000 (UTC))
datadir: /geth/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 or type exit
>
Welcome to the Geth JavaScript console!
を出力されれば成功。
アカウントの作成・マイニング
上記でGethを起動するとコンソールが起動しているのでそのままコマンドを入力していきます。
以下は書籍そのままなので簡単に書いていきます。
> personal.newAccount("hogehoge1234")
"0xdcfc0837e489ead966ecdb00abce38d72267c474"
> personal.newAccount("hoge")
"0xac5a53981b38eb63134dfee19934742542ef5874"
出力されているのはアカウント。
アカウント一覧は以下。
> eth.accounts
["0xdcfc0837e489ead966ecdb00abce38d72267c474", "0xac5a53981b38eb63134dfee19934742542ef5874"]
ブロック生成の報酬を受け取るコインベースアカウントというものが存在します。
ここでは一つ目に作成したアカウントが担っています。
> eth.coinbase
"0xdcfc0837e489ead966ecdb00abce38d72267c474"
↑一つ目のアカウントと同じであることが確認できます。
マイニング
最初はまだブロックがないので0
> eth.blockNumber
0
開始
> miner.start(1)
null
初回はマインニングが開始されるまで時間がかかります。
数分かかりました。
ブロックが生成されています。
> eth.blockNumber
82
コインベースアカウントに報酬としてEtherが入っています。
> eth.getBalance(eth.accounts[0])
178000000000000000000
最初、だれも(というかこのネットワークには自分しかいないので自分が)取引をしていないのにどうして勝手にブロックが生成されるんだろうと思いました。
実際は、取引(トランザクション)がなくてもブロックは生成されるということでした。
ブロックに含まれているゼロから複数のトランザクションは、TransactionTreeと呼ばれる木構造に入っています。ブロックは常に時間が経つごとに生成され続けるので、ネットワーク初期やたまたま利用が少ない場合は、トランザクションが入っていない場合もありえます。トランザクションには、メッセージコールとコントラクト生成の2種類が存在します。
加嵜 長門,篠原 航. ブロックチェーンアプリケーション開発の教科書(リフロー版) (Japanese Edition) (p.324). Kindle 版.
Discussion