プライベート・ネットの Ethereum に触れてみた

# Ethereum に触れてみた
[Ethereum 入門](https://book.ethereum-jp.net/first_use) サイト内チュートリアルの「まずは Ethereum に触れてみる」でプライベート・ネットの Ethereum に触れたときの備忘録です。
ブロックチェーン・Ethereum・コード等の詳細な説明はチュートリアルを参照いただければと思います。

# 目次
* Ethereum クライアント「Geth」をインストール
* プライベート・ネットに接続する
* Externally Owned Account を作成する
* ether を採掘する
* ether を送金する

# Ethereum クライアント「Geth」をインストール
環境は、`Windows 10 の WSL Ubuntu 22.04.LTS` になります。Ubuntu に Geth クライアントをインストールしていきます。
```
$ sudo add-apt-repository -y ppa:ethereum/ethereum
$ sudo apt-get update
$ sudo apt-get install ethereum
```
Geth クライアントのコマンドを実行してインストールの正常終了を確認しておきます。
```
$ geth version
Geth
Version: 1.10.26-stable
Git Commit: e5eb32acee19cc9fca6a03b10283b7484246b15a
Architecture: amd64
Go Version: go1.18.5
Operating System: linux
GOPATH=
GOROOT=go
```

頻繁にアップデートされるとのことですのでアップデートも実施しておきます。
```
$ sudo apt-get update
$ sudo apt-get upgrade
```
「Mac OS へのGethのインストール」「ソースからGethをビルドする」はチュートリアルを参照ください。

https://book.ethereum-jp.net/first_use/installing_geth


# プライベート・ネットに接続する
自分のみのプライベート・ネットを起動してチュートリアルを進めます。プライベート・ネットを起動する前に最初のブロックとなる `Genesisファイル` を作成します。

ブロック情報やノード情報など各種データを格納するディレクトリ（データ・ディレクトリ）を作成します。
```
$ mkdir ~/eth_private_net
$ cd ~/eth_private_net
```
次に上記ディレクトリ内にjson形式の下記の内容 を記述した `myGenesis.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 ファイルを作成したら、以下のコマンドを実行しブロックチェーン情報を genesis ファイルの内容で初期化します。
```
$ geth --datadir ~/eth_private_net init ~/eth_private_net/myGenesis.json
```
`Successfully wrote genesis state` のログがあるので初期化に成功しました。
```
INFO [01-20|09:42:37.410] Maximum peer count                       ETH=50 LES=0 total=50
INFO [01-20|09:42:37.413] Smartcard socket not found, disabling    err="stat /run/pcscd/pcscd.comm: no such file or directory"
INFO [01-20|09:42:37.424] Set global gas cap                       cap=50,000,000
INFO [01-20|09:42:37.426] Allocated cache and file handles         database=/home/bc-user/eth_private_net/geth/chaindata cache=16.00MiB handles=16
INFO [01-20|09:42:37.473] Opened ancient database                  database=/home/bc-user/eth_private_net/geth/chaindata/ancient/chain readonly=false
INFO [01-20|09:42:37.474] Writing custom genesis block
INFO [01-20|09:42:37.477] Persisted trie from memory database      nodes=0 size=0.00B time="249.9µs" gcnodes=0 gcsize=0.00B gctime=0s livenodes=1 livesize=0.00B
INFO [01-20|09:42:37.481] Successfully wrote genesis state         database=chaindata hash=7b2e8b..7e0432
INFO [01-20|09:42:37.481] Allocated cache and file handles         database=/home/bc-user/eth_private_net/geth/lightchaindata cache=16.00MiB handles=16
INFO [01-20|09:42:37.521] Opened ancient database                  database=/home/bc-user/eth_private_net/geth/lightchaindata/ancient/chain readonly=false
INFO [01-20|09:42:37.521] Writing custom genesis block
INFO [01-20|09:42:37.525] Persisted trie from memory database      nodes=0 size=0.00B time="5.2µs"   gcnodes=0 gcsize=0.00B gctime=0s livenodes=1 livesize=0.00B
INFO [01-20|09:42:37.526] Successfully wrote genesis state         database=lightchaindata hash=7b2e8b..7e0432
```
次に以下のコマンドを実行することで Geth を起動し、プライベート・ネットに接続します。
```
$ geth --networkid "15" --nodiscover --datadir "~/eth_private_net" console 2>> ~/eth_private_net/geth_err.log
```
`Welcome to the Geth JavaScript console!` と表示されているのでプライベート・ネットに接続できたようです。`console` オプションを指定することで採掘やトランザクションの生成などのコマンドを対話的に進めることができます。
```
Welcome to the Geth JavaScript console!

instance: Geth/v1.10.26-stable-e5eb32ac/linux-amd64/go1.18.5
at block: 0 (Thu Jan 01 1970 09:00:00 GMT+0900 (JST))
 datadir: /home/bc-user/eth_private_net
 modules: admin:1.0 debug:1.0 engine: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
>
```

# Externally Owned Account（以下、「EOA」）を作成する
ether を採掘したときの報酬を紐づける EOA を準備します。また ether の送金先 EOA も準備しておきます。ethereum では EOA と CA という 2 種類のアカウントがあるようです。
* EOA は、コードをもたないアカウント
* CA （Contract Account）は、自動執行プログラム（スマートコントラクト）のコードをもつアカウント

ノード内に作成済みの EOA があるか確認しておきます。
```
> eth.accounts
[]
```
EOA が存在しないので 2 つの EOA を作成しておきます。`account1` `account2` は、パスワードになりますので任意のパスワードを指定ください。`パスワードを忘れると復元する手段がありませんのでご注意ください。`
```
> personal.newAccount("account1")
"0x710dd29a46ae9e359f566ba278f8b23df79171b8"
> personal.newAccount("account2")
"0x710dd29a46ae9e359f566ba278f8b23df79171b8"
```
`0x710dd29a46ae9e359f566ba278f8b23df79171b8` `0x710dd29a46ae9e359f566ba278f8b23df79171b8` は、EOA のアドレスとなります。
作成された EOA を確認してみます。確認できるコマンドが複数ありました。
```
> eth.accounts
["0x710dd29a46ae9e359f566ba278f8b23df79171b8", "0x710dd29a46ae9e359f566ba278f8b23df79171b8"]
> eth.accounts[0]
"0x710dd29a46ae9e359f566ba278f8b23df79171b8"
> eth.accounts[1]
"0x710dd29a46ae9e359f566ba278f8b23df79171b8"
> personal.listAccounts
["0x710dd29a46ae9e359f566ba278f8b23df79171b8", "0xe579643a40dc6451f6dff649bdb9f0f0edc71d15"]
```
２つの EOA が無事確認できました。`eth.accounts[0]` `eth.accounts[1]`で個々のアドレスを確認できます。
次に個々の ether 残高を確認してみます。
```
> eth.getBalance(eth.accounts[0])
0
> eth.getBalance(eth.accounts[1])
0
```
まだなにもしていないので残高は、`0` になりますね。

### etherbase の設定
各ノードで採掘を行う際にその報酬を紐づける EOA を `eth.coinbase` コマンドで設定することができます。
まず現在の etherbase 設定を確認します。
```
> eth.coinbase
"0x710dd29a46ae9e359f566ba278f8b23df79171b8"
> eth.accounts[0]
"0x710dd29a46ae9e359f566ba278f8b23df79171b8"
```
`eth.accounts[0]` に設定されているのを `eth.accounts[1]` に変更します。
```
> miner.setEtherbase(eth.accounts[1])
true
> eth.coinbase
"0x91919f2da17599ef3752b153f668e5a99d1ba4dd"
> eth.accounts[1]
"0x91919f2da17599ef3752b153f668e5a99d1ba4dd"
```
`eth.accounts[1]` に変更されました。このままにして報酬が `eth.accounts[1]` に入るようにしておきます。

# ether を採掘（マイニング）する
`eth.accounts[1]` の EOA アドレスを etherbase に設定した状態で ether の採掘を始めます。`miner.start()` で開始し `miner.stop()` で終了します。
採掘中は、ブロックが次々に作成されます。このブロックがどのくらい作成されているかを `eth.blockNumber` コマンドで確認することができます。`eth.blockNumber` の結果が `0` より大きくなったら採掘を終了して報酬を確認してみましょう。
```
> miner.start()
null
> eth.blockNumber
0
> eth.blockNumber
0
> eth.blockNumber
17
> eth.blockNumber
43
> eth.blockNumber
49
> miner.stop()
null
> eth.blockNumber
87
```
私の環境下では、ブロックが作成されるまで 30 秒ほどかかりましたが無事ブロックが作成されました。
採掘終了後にブロック高を確認するとブロックが 87 番目まで連なっていることになります。ブロック数を　`ブロック高` `ブロックの高さ` と表現するようです。

### 特定ブロックの内容を確認する
`eth.getBlock(number) コマンド` で任意のブロック内容を確認することができます。
```
> eth.getBlock(7)
{
  difficulty: 131456,
  extraData: "0xd883010a1a846765746888676f312e31382e35856c696e7578",
  gasLimit: 133302917,
  gasUsed: 0,
  hash: "0x46a0a9363f5ac79a59724bb30bffbdaeab88ac302affc8b60defae66ea5d6af5",
  logsBloom: "0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000",
  miner: "0xe579643a40dc6451f6dff649bdb9f0f0edc71d15",
  mixHash: "0x920a9fce0263a44550382b909a406e1dfa58b55114c93c97fc3176e6f141cdb0",
  nonce: "0x29b993f17017e122",
  number: 7,
  parentHash: "0x993805384fe1b167dd31f473a3d0f104a21ed41ea0a2e69fb1010a4d45668343",
  receiptsRoot: "0x56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421",
  sha3Uncles: "0x1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347",
  size: 537,
  stateRoot: "0xab784de0c26c397e3a732b1d69e19870708dbf89c54f998da053c22afccc4533",
  timestamp: 1674604508,
  totalDifficulty: 935232,
  transactions: [],
  transactionsRoot: "0x56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421",
  uncles: []
}
```
`miner` が先ほど設定した etherbase の EOA アドレスと一致していることがわかります。`number` はブロック高になり、`eth.getBlock(7)` コマンドで指定したブロック高と一致しますね。`hash` はそのブロックのブロック・ヘッダ・ハッシュ、`parentHash` は、親ブロックのブロック・ヘッダ・ハッシュになります。


`eth.getBlock(0)` は、genesis ブロックになりますので `parentHash` は、`0` になります。
指定したブロック高のブロックが存在しない場合、`null` が返却されます。

### 報酬を確認する

採掘による報酬が得られているか確認します。`eth.getBalance()` の単位は、`wei` になります。ether 単位に変換する場合は、`web3.fromWei()` で変換できるようです。
`wei` とは Ether（ETH）の最小単位で `1 wei = 0.000000000000000001 ETH` となるそうです。
```
> eth.getBalance(eth.accounts[1])
174000000000000000000
> web3.fromWei(eth.getBalance(eth.accounts[1]),"ether")
174
```

# ether を送金する

報酬を得たので `eth.accounts[0]` EOA に送金してみます。個々の EOA アカウントから ETH の残高を確認しておきます。
```
> eth.getBalance(eth.accounts[0])
0
> eth.getBalance(eth.accounts[1])
254000000000000000000
```
`accounts[1]` から `accounts[0]` に 10 ETH を送金します。送金前に `送金元 EOA のロックを解除` しておきます。

```
> personal.unlockAccount(eth.accounts[1])
Unlock account 0xe579643a40dc6451f6dff649bdb9f0f0edc71d15
Passphrase:
true
```
採掘を開始してから送金コマンドを実行します。成功するとトランザクションIDが返却されます。
送金前に採掘を開始していない場合、送金後に採掘を開始することで送金を完了することができるようです。
```
> miner.start()
null
> eth.sendTransaction({from: eth.accounts[1], to: eth.accounts[0], value: web3.toWei(10, "ether")})
"0x6a67fb2098c0d17c1b213bc10aab6c8519b1edc182e8c02684fd4069d3de09c0"
> miner.stop()
null
```
送金結果を確認します。`eth.accounts[0]` には、`10 ETH` が入りました。
`eth.accounts[1]` は送金する為に採掘しているので採掘の報酬分が増えました。
```
> eth.getBalance(eth.accounts[0])
10000000000000000000
> web3.fromWei(eth.getBalance(eth.accounts[0]),"ether")
10
> eth.getBalance(eth.accounts[1])
338000000000000000000
> web3.fromWei(eth.getBalance(eth.accounts[1]),"ether")
338
```

# 参考記事

https://book.ethereum-jp.net/first_use