ブロックチェーンを自分でも動かしてみたかったので、イーサリアムの環境を構築して、送金処理まで実施してみました。
コマンドラインベースで実行してみたかったので、今回はGethを利用します。
環境
MacBook Air M1 2020
メモリ16GB
macOS 13.0
Gethインストール
事前にHomebrewをセットアップしてください。
Gethをインストールする為に以下コマンドを実行してください。
$ brew tap ethereum/ethereum
$ brew install ethereum
準備
任意の場所に作業用フォルダを作成します。私は以下の通り作成しました。
$ mkdir ~/projects/ethereum/
$ mkdir ~/projects/ethereum/node1
$ cd ~/projects/ethereum/
ブロックチェーンのGenesisブロック(最初のブロック)を作成します。
genesis.jsonを以下の通り作成します。
{
"config": {
"chainId": 100,
"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": "0x0000000000000042",
"mixhash": "0x0000000000000000000000000000000000000000000000000000000000000000",
"parentHash": "0x0000000000000000000000000000000000000000000000000000000000000000",
"timestamp": "0x00"
}
chainIdには任意のIDを指定することができますが、以下は予約されているため避けた方が良いと思います。今回は100を指定しました。
1, 2, 3, 4, 5, 42, 1337
allocにユーザ(アドレス)を指定すると、最初にETHを割り当てできるようです。今回はGenesisブロックを作成した後にユーザを作成するので指定していません。
Geth初期化
イーサリアムノードを作成します。
以下コマンドを実行します。
$ geth --datadir ~/projects/ethereum/node1 init ~/projects/ethereum/genesis.json
INFO [12-04|18:18:51.854] Maximum peer count ETH=50 LES=0 total=50
(省略)
INFO [11-09|19:24:48.796] Successfully wrote genesis state database=lightchaindata hash=d118bd..7a409f
node1フォルダが生成され、その下にはgethとkeystoreフォルダが生成されます。
Geth起動
Gethを起動します。
以下コマンドを実行します。
$ geth --networkid 100 --nodiscover --maxpeers 0 --datadir ~/projects/ethereum/node1 console 2>> ~/projects/ethereum/node1/geth.log
Welcome to the Geth JavaScript console!
(省略)
To exit, press ctrl-d or type exit
>
Genesisブロックが生成されているか確認します。
以下コマンドを実行します。
> eth.getBlock(0)
{
baseFeePerGas: 1000000000,
difficulty: 131072,
extraData: "0x",
gasLimit: 3141592,
gasUsed: 0,
hash: "0xd118bd9c6cdf4be6844c7af2b5d86e0d23e91cbe46955c0c23a61dfa577a409f",
logsBloom: "0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000",
miner: "0x0000000000000000000000000000000000000000",
mixHash: "0x0000000000000000000000000000000000000000000000000000000000000000",
nonce: "0x0000000000000042",
number: 0,
parentHash: "0x0000000000000000000000000000000000000000000000000000000000000000",
receiptsRoot: "0x56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421",
sha3Uncles: "0x1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347",
size: 512,
stateRoot: "0x56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421",
timestamp: 0,
totalDifficulty: 131072,
transactions: [],
transactionsRoot: "0x56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421",
uncles: []
}
アカウントの作成
Etherの採掘や送金処理を行うにはアカウントの作成が必要になります。
今回は2つアカウントを作成します。
以下コマンドを実行します。引数はパスワードになります。
> personal.newAccount("pass0")
"0xf53ac86545559b81188c48ecfd89183e74a05ba5"
> personal.newAccount("pass1")
"0x3732e0d588244ea6d233e41b0e3facfda0010627"
作成したアカウントを確認します。
> eth.accounts
["0xf53ac86545559b81188c48ecfd89183e74a05ba5", "0x3732e0d588244ea6d233e41b0e3facfda0010627"]
アカウントの残高を確認します。どちらも0のはずです。
> eth.getBalance(eth.accounts[0])
0
> eth.getBalance(eth.accounts[1])
0
マイニングを行う
マイニング成功時に報酬を受け取るアカウントを確認します。
このアカウントはEtherbaseと呼ばれます。
最初に作ったアカウントが表示されるはずです。
> eth.coinbase
"0xf53ac86545559b81188c48ecfd89183e74a05ba5"
マイニングを開始します。
> miner.start(1)
null
少し待ってからブロック数が増えていることを確認します。
> eth.mining
true
> eth.blockNumber
3
ブロック数が増えていたら一旦マイニングを止めます。
> miner.stop()
null
先ほどGenesisブロック(最初のブロック)が作成されていることを確認しました。今度は2番目のブロックを確認してみます。
> eth.getBlock(1)
{
baseFeePerGas: 875000000,
difficulty: 131072,
extraData: "0xd983010a1a846765746888676f312e31392e338664617277696e",
gasLimit: 3144658,
gasUsed: 0,
hash: "0x5e52e90aedaf2aae18a13952aa574f3005b3e523e4c1740f3d1ce2a45f2b59e8",
logsBloom: "0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000",
miner: "0xf53ac86545559b81188c48ecfd89183e74a05ba5",
mixHash: "0x26642ebcc7510e2539394d6f14e7c98609251b7e2da01c4109f1453df389eb27",
nonce: "0x2b5b574a136d247e",
number: 1,
parentHash: "0xd118bd9c6cdf4be6844c7af2b5d86e0d23e91cbe46955c0c23a61dfa577a409f",
receiptsRoot: "0x56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421",
sha3Uncles: "0x1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347",
size: 542,
stateRoot: "0xeab84264a580d4d66d1353c60d39ddbda0a6ef5be87c8f04ed761f4c35e8b964",
timestamp: 1670146603,
totalDifficulty: 262144,
transactions: [],
transactionsRoot: "0x56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421",
uncles: []
}
ブロックチェーンなので、parentHashの値とGenesisブロックのhashの値が同じはずです。
マイニングを行ったのでアカウントの残高を確認します。
Etherbaseがマイニングの報酬を受け取っているはずです。
> eth.getBalance(eth.accounts[0])
12000000000000000000
> eth.getBalance(eth.accounts[1])
0
Etherの送金
受け取った報酬をもう一つのアカウントに送金してみます。
送信元アカウントをアンロックします。(300秒間だけEtherの送金が可能になります)
コマンド実行時にアカウントのパスワードを求められます。
> personal.unlockAccount(eth.accounts[0])
Unlock account 0xf53ac86545559b81188c48ecfd89183e74a05ba5
Passphrase:
true
accounts[0]からaccounts[1]に10ether送金します。
戻り値はトランザクションのhash値です。
> eth.sendTransaction({from: eth.accounts[0], to: eth.accounts[1], value: web3.toWei(10, "ether")})
"0xb7f3394596a2baab10f279442bdc8eaf4a2f43675665159aa5eb54e56ef9062a"
この時点ではトランザクションはまだ処理されていません。
未処理のトランザクションを確認します。
> eth.pendingTransactions
[{
accessList: [],
blockHash: null,
blockNumber: null,
chainId: "0x64",
from: "0xf53ac86545559b81188c48ecfd89183e74a05ba5",
gas: 21000,
gasPrice: 1897590638,
hash: "0xb7f3394596a2baab10f279442bdc8eaf4a2f43675665159aa5eb54e56ef9062a",
input: "0x",
maxFeePerGas: 1897590638,
maxPriorityFeePerGas: 1000000000,
nonce: 0,
r: "0xb02fc9f6bd98a3d73e43513b2c55bf9ee2c1d951969c08f56c322f626fd97d65",
s: "0x638d333999a15494c8d8acffba732641ec4dc1cf15db068feff79368f234a5da",
to: "0x3732e0d588244ea6d233e41b0e3facfda0010627",
transactionIndex: null,
type: "0x2",
v: "0x0",
value: 10000000000000000000
}]
送金実行時の戻り値とhashが同じはずです。
このトランザクションをブロックチェーンに書き込みます。
マイニングを開始して、トランザクションを処理されたら(未処理のトランザクションが無くなる)、マイニングを止めます。
> miner.start(1)
null
> eth.pendingTransactions
[]
> miner.stop()
null
送金結果を確認する為に、アカウントの残高を確認します。
> eth.getBalance(eth.accounts[0])
23999991753385995000
> eth.getBalance(eth.accounts[1])
10000000000000000000
送金処理のトランザクションを確認します。
引数のトランザクションのhashを指定します。
> eth.getTransaction("0xb7f3394596a2baab10f279442bdc8eaf4a2f43675665159aa5eb54e56ef9062a")
{
accessList: [],
blockHash: "0x5fb6ce98cfa6aab051de0faf81b4d53ae4e32426a8c0928d4c1a1ce791124cb8",
blockNumber: 7,
chainId: "0x64",
from: "0xf53ac86545559b81188c48ecfd89183e74a05ba5",
gas: 21000,
gasPrice: 1392695905,
hash: "0xb7f3394596a2baab10f279442bdc8eaf4a2f43675665159aa5eb54e56ef9062a",
input: "0x",
maxFeePerGas: 1897590638,
maxPriorityFeePerGas: 1000000000,
nonce: 0,
r: "0xb02fc9f6bd98a3d73e43513b2c55bf9ee2c1d951969c08f56c322f626fd97d65",
s: "0x638d333999a15494c8d8acffba732641ec4dc1cf15db068feff79368f234a5da",
to: "0x3732e0d588244ea6d233e41b0e3facfda0010627",
transactionIndex: 0,
type: "0x2",
v: "0x0",
value: 10000000000000000000
}
7番目のブロックにトランザクションが書き込まれました。
念の為、7番目のブロックも確認してみます。
> eth.getBlock(7)
{
baseFeePerGas: 392695905,
difficulty: 131072,
extraData: "0xd983010a1a846765746888676f312e31392e338664617277696e",
gasLimit: 3163117,
gasUsed: 21000,
hash: "0x5fb6ce98cfa6aab051de0faf81b4d53ae4e32426a8c0928d4c1a1ce791124cb8",
logsBloom: "0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000",
miner: "0xf53ac86545559b81188c48ecfd89183e74a05ba5",
mixHash: "0xfce094b0ed426ef4d2a444a6393abc72f6c3d59f65a7e1cea2822f3339081943",
nonce: "0x2130afc1acf78b8b",
number: 7,
parentHash: "0xec7af5f1bcf59844f13f100341135bea3f09d448e86661cbd19c520c275bf9cc",
receiptsRoot: "0xf78dfb743fbd92ade140711c8bbc542b5e307f0ab7984eff35d751969fe57efa",
sha3Uncles: "0x1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347",
size: 664,
stateRoot: "0x9e23b2f61c6a9fe7473c13e4f34757d695155e67cd71b28a352de04b969252a9",
timestamp: 1670147647,
totalDifficulty: 1049536,
transactions: ["0xb7f3394596a2baab10f279442bdc8eaf4a2f43675665159aa5eb54e56ef9062a"],
transactionsRoot: "0x1210d01d8d3e48286c3e6a7f3d4ee8db81222411595e6dae53378109300034cd",
uncles: []
}
送金トランザクションのblockHashとブロック(7)のhashが同じであることが確認できました。
また、ブロック(7)のtransactionsに送金トランザクションのhashが書き込まれています。
参考サイト