Ethereum スマートコントラクト開発日記(1)
「はじめてのブロックチェーン・アプリケーション Ethereumによるスマートコントラクト開発入門」を読みました。
とりあえずサンプルを動かす所からできれば自分で書いてみる所まで、作業記録を兼ねて残していきたいと思います。
環境構築
ソースを眺める機会もあるだろうしせっかくなのでソースから入れてみる。
$ brew upgrade go
$ git clone https://github.com/ethereum/go-ethereum.git
$ cd go-ethereum
$ make geth
...
$ ./build/bin/geth -h
NAME:
geth - the go-ethereum command line interface
Copyright 2013-2017 The go-ethereum Authors
USAGE:
geth [options] command [command options] [arguments...]
VERSION:
1.8.4-unstable-50dbe8e2
unstableかー、まあ勉強用だし問題ないだろうという事でパスだけ通して進める。
テストネットワークを動かす
データディレクトリ作成 & genesis.json 作成
$ mkdir ~/eth/data
$ vi ~/eth/data/genesis.json
{
"config": {},
"nonce": "0x0000000000000042",
"timestamp": "0x0",
"parentHash": "0x0000000000000000000000000000000000000000000000000000000000000000",
"gasLimit": "0x8000000",
"difficulty": "0x4000",
"mixhash": "0x0000000000000000000000000000000000000000000000000000000000000000",
"alloc": {}
}
init コマンドで geth を初期化。
$ geth --datadir ~/eth/data init ~/eth/data/genesis.json
~/eth/data に geth, keystore が生成される。
そして起動
$ geth --networkid 4649 --nodiscover --maxpeers 0 --datadir ~/eth/data console 2>> ~/eth/data/eth.log
Welcome to the Geth JavaScript console!
instance: Geth/v1.8.4-unstable-50dbe8e2/darwin-amd64/go1.10.1
modules: admin:1.0 debug:1.0 eth:1.0 miner:1.0 net:1.0 personal:1.0 rpc:1.0 txpool:1.0 web3:1.0
>
動いたっぽい。
コンソールで色々遊ぶ
本の通りにコマンド打って結果を乗せてもアレなので省略。
とりあえず試してみたコマンドのまとめ。
コマンド | 機能 |
---|---|
personal.newAccount("pass") | アカウントの作成 |
eth.accounts | アカウントの確認 |
eth.coinbase | Etherbaseの確認 |
eth.setEtherbase | Etherbaseの設定 |
eth.getBalance(account) | アカウントの残高確認 |
eth.blockNumber | ブロック数の確認 |
miner.start(thread) | マイニングの開始 |
miner.stop() | マイニングの停止 |
eth.mining | マイニング状態の確認 |
eth.hashrate | ハッシュレートの確認 |
マイニングの開始
まず最初に personal.newAccount でアカウントを作成。
最初に作ったアカウントがマイニング報酬を受け取るアカウント(Etherbase)として設定される。Etherbaseは eth.setEtherbase で後で変更が可能。
miner.start() を行うとマイニングを開始する。初回はDAGというものが生成されるため結構時間がかかる。
ログを tail -f して終わるまでじっと待つ。
マイニングしつつログを見てると
INFO [04-06|00:09:58] Starting mining operation
INFO [04-06|00:09:58] Commit new mining work number=1 txs=0 uncles=0 elapsed=6.058ms
INFO [04-06|00:11:20] Successfully sealed new block number=1 hash=f5f9b6…656e5b
INFO [04-06|00:11:20] 🔨 mined potential block number=1 hash=f5f9b6…656e5b
これが出ると1ブロックマイニング完了かな?
コンソールで残高を見ると報酬が加算されている。
> eth.getBalance(eth.accounts[0])
5000000000000000000
> web3.fromWei(eth.getBalance(eth.accounts[0]), "ether")
5
> eth.blockNumber
1
getBalance だと wei(Ethereumの最小単位)で出るので fromWei で ether に単位を変換。
つまり 1 ブロックマイニングして 5ether 掘れた事になる。
送金
掘った ether を accounts[0] から accounts[1] に送金してみる。
> personal.unlockAccount(eth.accounts[0])
Unlock account 0xabd487d109bda50256f13e10a8d429ce0c46411a
Passphrase:
true
> eth.sendTransaction({from: eth.accounts[0], to: eth.accounts[1], value: web3.toWei(1, "ether")})
"0xeab28a85c7e23bd5d7a7f9e520c8b42c8c5f5e7d7806cbb5326221d90cfe5216"
> eth.getTransaction("0xeab28a85c7e23bd5d7a7f9e520c8b42c8c5f5e7d7806cbb5326221d90cfe5216")
{
blockHash: "0x0000000000000000000000000000000000000000000000000000000000000000",
blockNumber: null,
from: "0xabd487d109bda50256f13e10a8d429ce0c46411a",
gas: 90000,
gasPrice: 18000000000,
hash: "0xeab28a85c7e23bd5d7a7f9e520c8b42c8c5f5e7d7806cbb5326221d90cfe5216",
input: "0x",
nonce: 0,
r: "0x34db0a8283f9340e4cc2a190dd5d612a1005b3d6d52fda8517a0c002521925b3",
s: "0x55de88eceabd0521e9f9a9fe15993804d60c410e36f24dd0ee66749cf4491509",
to: "0x3663245e711b896a9d9dd0b0281b00be3a8d25b2",
transactionIndex: 0,
v: "0x1b",
value: 1000000000000000000
}
送金元アカウントは personal.unlockAccount() でアンロックしないと送金できない。
eth.sendTransaction() で送金。↑の例だと accounts[0] から accounts[1] へ 1ether を送信、 "0xeab28..." のトランザクションが発行される。
この時点ではまだトランザクションは実行されておらず、accounts[0]/[1] の残高はまだ変更されていない。
getTransaction() でトランザクションの内容を表示しているが、blockNumber = null は未処理である事を示している。
> miner.start(1)
null
> miner.stop()
true
> eth.pendingTransactions
[]
> eth.getTransaction("0xeab28a85c7e23bd5d7a7f9e520c8b42c8c5f5e7d7806cbb5326221d90cfe5216")
{
blockHash: "0x0901af7fe2d98b398cf898e7b374e6e2b15d3cdcbd99a42f7a7ad6c6cf6d7cda",
blockNumber: 153,
from: "0xabd487d109bda50256f13e10a8d429ce0c46411a",
gas: 90000,
gasPrice: 18000000000,
hash: "0xeab28a85c7e23bd5d7a7f9e520c8b42c8c5f5e7d7806cbb5326221d90cfe5216",
input: "0x",
nonce: 0,
r: "0x34db0a8283f9340e4cc2a190dd5d612a1005b3d6d52fda8517a0c002521925b3",
s: "0x55de88eceabd0521e9f9a9fe15993804d60c410e36f24dd0ee66749cf4491509",
to: "0x3663245e711b896a9d9dd0b0281b00be3a8d25b2",
transactionIndex: 0,
v: "0x1b",
value: 1000000000000000000
}
> web3.fromWei(eth.getBalance(eth.accounts[0]), "ether")
769
> web3.fromWei(eth.getBalance(eth.accounts[1]), "ether")
1
マイニングを再度開始し、ブロックが追加されたらマイニングを停止。
先程のトランザクション情報を表示すると blockNumber が設定され、トランザクションが実行済みである事がわかる。送金元・送金先の残高を取得すると送金ができている事も確認できる。
手数料
送金には手数料が発生するが、↑の例だと Etherbase のアカウントからの送金なのでブロック作成時に同時に手数料の受け取りを行っている為、結果手数料が発生していないように見える。
もう一つアカウントを作成し、accounts[1] から送金してみる。
> personal.newAccount("pass2")
"0xc675f84b6cdbf2f8d089ce634d0d3fc1b9860e18"
> personal.unlockAccount(eth.accounts[1])
Unlock account 0x3663245e711b896a9d9dd0b0281b00be3a8d25b2
Passphrase:
true
> eth.sendTransaction({from: eth.accounts[1], to: eth.accounts[2], value: web3.toWei(0.5, "ether")})
"0x8476d0f8eb8e903062799e5cda1a6b245c36d2a4d02cd946dfbcb83d91a0b050"
> miner.start(1)
null
> miner.stop()
true
> eth.pendingTransactions
[]
> web3.fromWei(eth.getBalance(eth.accounts[0]), "ether")
804.000378
> web3.fromWei(eth.getBalance(eth.accounts[1]), "ether")
0.499622
> web3.fromWei(eth.getBalance(eth.accounts[2]), "ether")
0.5
accounts[1] → accounts[2] に 0.5 ether 送金、更に手数料 0.000378 ether が accounts[1] から引かれ、ブロックを採掘した accounts[0] の残高に足されている。
> eth.getTransaction("0x8476d0f8eb8e903062799e5cda1a6b245c36d2a4d02cd946dfbcb83d91a0b050")
{
blockHash: "0xf52ba4950288da835bb126a15b360b930b3b6ecfdf7df7bd83cacebbff508beb",
blockNumber: 155,
from: "0x3663245e711b896a9d9dd0b0281b00be3a8d25b2",
gas: 90000,
gasPrice: 18000000000,
hash: "0x8476d0f8eb8e903062799e5cda1a6b245c36d2a4d02cd946dfbcb83d91a0b050",
input: "0x",
nonce: 0,
r: "0x529689e538608912d5111d9e53ac45474a8d791a1ea4dcb9abacc75d372473e",
s: "0x26c6f1f2e51872e352e5d46db752030540030efc2507256c3eb6d5a577e20edc",
to: "0xc675f84b6cdbf2f8d089ce634d0d3fc1b9860e18",
transactionIndex: 0,
v: "0x1b",
value: 500000000000000000
}
支払った手数料は 0.000378 ether (378000000000000 wei)、実際に支払った Gas は手数料を gasPrice で割って、「378,000,000,000,000 (wei) / 18,000,000,000 (gasPrice) = 21,000(gas)」という事になるらしい。
まとめ
ここまでは本に従ってコマンドを叩いていっただけですね。
次回からスマートコントラクトの開発に入っていきたいと思います。