Ethereum に触れてみた
Ethereum 入門 サイト内チュートリアルの「まずは 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をビルドする」はチュートリアルを参照ください。
プライベート・ネットに接続する
自分のみのプライベート・ネットを起動してチュートリアルを進めます。プライベート・ネットを起動する前に最初のブロックとなる 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"]
2つの 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
参考記事