仮想通貨(暗号通貨)の作り方 その2 (Gethの使い方)
2018.05.20
この記事は最終更新日から1年以上が経過しています。
どもです。
今回は、前回のこちらの記事の続きとなります。
さて早速、仮想通貨を作成していきたいのですが、一からオリジナルの仕様で作成するとなると、それなりに大変で、時間もかかりそうなので、今回は比較的容易に作成出来る、Ethereumのスマートコントラクト開発を行なっていきたいと思います。
スマートコントラクト開発で人気のクライアントアプリ「Geth (Go Ethereum)」を使って作って行きたいと思います。
開発環境構築
Gethのインストール
Geth(Go Ethereum)はGo言語によって実装されたCUIクライアントになります。
GethをインストールすることでEthereumネットワークにフル・ノードとして参加して様々な事が実行できます。
こちらのページよりGethをダウンロードしましょう。
Geth (Go Ethereum) ダウンロードページ
https://geth.ethereum.org/downloads/
Macの場合はこちらをクリック、
Windowsの場合はこちらからそれぞれ環境にあったのをインストールします。
当方は、Macなので、Macでのインストール例となります。
先程のリンクよりダウンロードし、ファイルを解凍すると、gethのbinファイルが含まれているので、こちらをクリックでgethが起動します。
任意のフォルダに含める場合は、フォルダを作成、パーミッションを変更して、 gethのbinファイルを格納します。
$ sudo mkdir /任意のフォルダ/
ルート権限でのみ実行出来ない場合は権限を付与しましょう
$ sudo chmod 777 /任意のフォルダ/
パスを通す
.bash_profile 等のファイルにパスを通す為の記述を行います。
.bash_profile 等のファイル
export PATH=/任意のフォルダ/:$PATH
パスを適応
$ source ~/.bash_profile
パスが通ったかの確認
パスが通っているかwhichコマンドで確認
$ which geth
結果
/任意のフォルダ/geth
と表示すればオッケーです。
Homebrewを使って インストール
と、少々面倒なやり方でインストールしましたが、
macにHomebrewがインストールされていれば、以下のコマンドで簡単にインストールが行えます。
$ brew tap ethereum/ethereum
$ brew install ethereum
実際にgethコマンドが使用できるか確認。
$ geth --help
gethのヘルプコマンド(geth –help)で、色々とヘルプ情報が表示すればインストール成功です。
githubのレポジトリはこちらです。
github
https://github.com/ethereum/go-ethereum
初期化ファイル作成
インストールが完了しましたら、設定を行なっていきましょう。
まず、Ethereumでは以下の3つの形態のP2Pネットワークを構築しブロックチェーンを運用していくことが可能となっております。
・パブリック・ネットワーク (本番環境)
・プライベートネット (ローカル環境)
・テストネット (他の参加者も含んだ環境)
プライベート開発を行うために、ローカル環境に一番最初のブロックを作成します。
これは、Genesisブロックと言われ、jsonファイル形式でファイルを作成をしていきます。
ディレクトリの場所は任意の場所で問題ありません。
今回は、以下にディレクトリを設け、genesis. jsonを作成しました。
~/eth_private_net/
genesis.json
{ "config": { "chainId": 15, "homesteadBlock": 0, "eip 155 Block": 0, "eip 158 Block": 0 }, "nonce": "0x0000000000000042", "mixhash": "0x0000000000000000000000000000000000000000000000000000000000000000", "difficulty": "0x00", "alloc": {}, "coinbase": "0x0000000000000000000000000000000000000000", "timestamp": "0x00", "parentHash": "0x0000000000000000000000000000000000000000000000000000000000000000", "extraData": "0x00", "gasLimit": "0x1312d00" }
次のコマンドで、ブロック チェーンの初期化処理を行います。
–datadirでデータ用のディレクトリ、initで genesisファイルを指定します。
$ geth --datadir ~/eth_private_net/ init ~/eth_private_net/genesis.json
以下の様に、Successfully wrote genesis state メッセージが、出力されれば初期化成功となります 。
結果
INFO [05-20|12:30:49] Successfully wrote genesis state database=lightchaindata hash=76d747…1a5e65
初期化のコマンドを実行すると、--datadir
で指定したディレクトリ以下に、Gethで使用するディレクトリが新規で作成され、その中にgenesisブロックのブロックチェーン情報が保存されます。
ディレクトリを確認すると、以下の様に作成されているのが確認出来ます。
genesis.json geth keystore
Gethの起動
それでは、先程用意した、「eth_private_net」や「genesis. json」を用いて、Gethを起動していきます。
$ geth --networkid "15" --nodiscover --datadir "~/eth_private_net/" --rpc --rpcaddr "localhost" --rpcport "8545" --rpccorsdomain "*" --rpcapi "eth, net, web3, personal" --targetgaslimit "20000000" console 2>> ~/eth_private_net/geth_err.log
明示的にオプションに、ポート指定など行っていますが、省略も可能となっております。
省略した場合
$ geth --networkid "15" --nodiscover --datadir "~/eth_private_net" console 2>> ~/eth_private_net/geth_err.log
上記のどちらのコマンドを入力、リターンを行い、「Welcome to the Geth JavaScript console!」のメッセージが表示され、コンソールが表示し、入力待ち状態になっていれば、Gethの起動成功となります。
Welcome to the Geth JavaScript console! instance: Geth/v1.8.8-stable/darwin-amd64/go1.10.2 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
Gathコンソール
Gethを起動すると、対話式のコンソールが起動いたしますので、色々とコマンドを実行していきましょう。
ブロック確認
eth.getBlock(number)
Eth.getBlock Numberに任意のブロック高を指定すると、そのブロック高のブロック情報を表示することができます。
Genesisiブロック内容確認
引数に0を指定すれば、genesisブロックの確認が行えます。
先程用意した「genesis. json」が適応されているか確認しましょう。
eth.getBlock(0)
実行結果
{ difficulty: 0, extraData: "0x00", gasLimit: 20000000, gasUsed: 0, hash: "0x76d747ec34337ec5677b1aba554769485e160663eee3c63486400bddc21a5e65", logsBloom: "0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", miner: "0x0000000000000000000000000000000000000000", mixHash: "0x0000000000000000000000000000000000000000000000000000000000000000", nonce: "0x0000000000000042", number: 0, parentHash: "0x0000000000000000000000000000000000000000000000000000000000000000", receiptsRoot: "0x56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421", sha3Uncles: "0x1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347", size: 505, stateRoot: "0x56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421", timestamp: 0, totalDifficulty: 0, transactions: [], transactionsRoot: "0x56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421", uncles: [] }
アカウント作成
Gethのコンソール上でGathコマンドを使って新規のアカウントを作成していきます。
EthereumにはEOA(Externally Owned Account)と、Contractの2種類のアカウントが存在します。
今回は、EOAを新規に作成して行きます。
personal.newAccount("password")
以下の様にEOAアドレスが表示されればアカウント作成完了です。
personal.newAccount("password")
結果
"0x5db7d11cafb9687131d37cc4de70a7ca97c61c0a"
あと、2つ程同様の作業で、作成しておきましょう。
作成完了しましたら、作成されたアカウントの確認を行なってみましょう。
インデックス指定で、アカウント確認
アカウントに関しては、「eth.accounts」に配列で格納されていますので、インデックスを指定することによって任意のアカウントを確認することができます。
eth.accounts[0]
結果には、EOAのアドレスが出力されます。
全てのアカウントを確認
作成さえた全てのアカウントを確認したい場合は、以下の様に指定すれば確認することができます。
eth.accounts
結果
["0x5db7d11cafb9687131d37cc4de70a7ca97c61c0a", "0xb985896b8b53f0323bd3019bc70060521e5bb00f", "0x52e48b0e2903a960937577021048440293f3f011"]
今回は上記の3つのアカウントを作成しております。
Coinbase(etherbase)アカウント
続いて、Coinbase(etherbase)アカウントの設定を行なっていきましょう。
Coinbase(etherbase)アカウントとは、各ノードで採掘を行う際にその報酬を紐づけるEOAのアドレスとなります。
以下のコマンドで、coinbase(etherbase)アカウントのEOAアドレスを確認できます。
デフォルトでは、インデックス0のアカウントに設定されております。
eth.coinbase
結果
"0x5db7d11cafb9687131d37cc4de70a7ca97c61c0a"
「setEtherbase」で、変更することも可能です。
miner.setEtherbase(eth.accounts[1])
結果
true
今回は、Coinbase(etherbase)アカウントは、eth.accounts[0]のまま進めていきます。
マイニング
作成したEOAのアドレスがcoinbase(etherbase)としてセットされていれば、etherの採掘が可能となります。
採掘のコマンドは以下のコマンドで実行出来ます。
miner.start(スレッド数)
引数には、マイニングを行うスレッド数の指定をします。
特に指定がない場合は、動作環境のCPUコア数に設定されます。
miner.start(2)
結果
null
マイニング確認
マイニング中であるかどうかの確認になります。
trueが返却されましたら、マイニング中になります。
eth.mining
結果
true
マイニング終了
採掘の終了は以下のコマンドで行えます。
miner.stop()
結果
true
今回は、止めずにそのまま進めます。
採掘状況の確認
採掘を開始するとブロックが生み出されます。
現在のブロック高の確認を行うには以下のコマンドを実行します。
eth.blockNumber
結果
164
といったように、ブロックが採掘されていることが確認できます。
今回の場合、164個のブロックが採掘されている、結果が出力されました。
残高を確認
それでは、採掘で獲得したcoinbase(etherbase)の残高確認を行なって見ましょう。
アカウント作成時は0なので、0以上になっていればマイニング成功となります。
eth.getBalance(eth.accounts[0])
結果
1.1e+21
eth.getBalance(eth.accounts[1])
結果
0
coinbaseに紐づいたアカウントに採掘の報酬が与えられているのがわかります。
eth.getBalance(address)は「wei」の単位で持ち高が表示されますので、とても大きな数字が表示したかと思います。
以下の変換用のコマンドを使うことでetherの単位で表示することも可能です。
web3.fromWei(eth.getBalance(eth.accounts[0]),"ether")
結果
1195
ロック解除
続いて、送金を行いたいのですが、アカウントがロックされている状態なので、アカウント生成時に設定したパスワードを入力してアカウントロックを解除しましょう。
personal.unlockAccount(eth.accounts[0])
personal.unlockAccount(eth.accounts[0]) Unlock account 0x5db7d11cafb9687131d37cc4de70a7ca97c61c0a Passphrase:
コマンドを入力すると、パスワードの入力を求められます。
アカウント作成時に指定した「password」を入力します。
結果
true
trueが返却されたら、解除成功となります。
プライベートのテスト環境なので、毎度入力するのは少し手間がかかりますので、Geth起動時に解除する方法もあります。
以下の様に設定したパスワードを記述したファイルを作成します。
アカウント毎に改行区切りで記述していきます。
Geth起動時作成したファイルを指定すれば、アカウントロックが解除した状態で起動できます。
各アカウントのEOSアドレスが必要となっておきますので、表示させてメモしておきます。
eth.accounts
結果
["0x5db7d11cafb9687131d37cc4de70a7ca97c61c0a", "0xb985896b8b53f0323bd3019bc70060521e5bb00f", "0x52e48b0e2903a960937577021048440293f3f011"]
Gethの終了
一度、起動しているGethを終了させます。
exit
eth_priavate_netに、新たにパスワード読み込み用のファイルを作成。
password.txt
password password password
起動時にパスワード解除するオプション
--unlock アンロックするアカウントアドレス --password "パスワードファイルのパス"
上記のオプションを付与した形で、Gethを起動すればアカウントロックが解除した状態で起動できます。
複数のアカウントに適応する場合は、カンマ区切りでアドレスを指定します。
先程、メモしておいた各アカウントのEOSアドレスをオプション指定して、Gethを起動させていきます。
$ geth --networkid "15" --nodiscover --datadir "~/eth_private_net" --rpc --rpcaddr "localhost" --rpcport "8545" --rpccorsdomain "*" --rpcapi "eth,net,web3,personal" --targetgaslimit "20000000" --unlock 0x5db7d11cafb9687131d37cc4de70a7ca97c61c0a,0xb985896b8b53f0323bd3019bc70060521e5bb00f,0x52e48b0e2903a960937577021048440293f3f011 --password "password.txt" console 2>> ~/eth_private_net/geth_err.log [code] 起動出来ましたら、再びマイニングを開始します。 [code]miner.start(2)
送金
それでは、マイニングで得たEtherの送金を行なって見ましょう。
2つ目に作成したアカウントに、5 Ether送金して見ます。
eth.sendTransaction({ from: eth.accounts[0], to: eth.accounts[1], value: web3.toWei(5, "ether")})
結果
"0xce67645e3b3234c1cf82ec47c2cd919c969ce2a5939454974c0a3395017b9c45"
エラーが出ず、送金に成功しましたらマイニングを行いトランザクションを発行しましょう。
トランザクション確認
先ほどのトランザクションハッシュを元にトランザクションの確認を行います。
eth.getTransaction関数の引数に、トランザクションハッシュを指定し、トランザクションの中身を確認していきます。
eth.getTransaction('0xce67645e3b3234c1cf82ec47c2cd919c969ce2a5939454974c0a3395017b9c45')
結果
{ blockHash: "0x0000000000000000000000000000000000000000000000000000000000000000", blockNumber: null, from: "0x5db7d11cafb9687131d37cc4de70a7ca97c61c0a", gas: 90000, gasPrice: 18000000000, hash: "0xce67645e3b3234c1cf82ec47c2cd919c969ce2a5939454974c0a3395017b9c45", input: "0x", nonce: 0, r: "0xa4b7f915d52ebce2490c3fecc98e38ac126a2dcd967212ef58913f8127a7de4e", s: "0x4da560e57e60829bd160adf0f840eba851db84758b45487276e817c97074a535", to: "0xb985896b8b53f0323bd3019bc70060521e5bb00f", transactionIndex: 0, v: 0x1b", value: 5000000000000000000 }
fromに送信元アドレスのeth.accounts[0]がひょうじされ、 toに送信先アドレスである、eth.accounts[1] が表示されているかと思います。
valueは送金額で、「5000000000000000000」と大変大きな数値となっておりますが、表示が「wei」なので、etherに換算する と 5etherとなり、想定通りのトランザクションを発行出来ているのが確認できるかと思います。
続いて eth.getTransactionReceipt関数を実行して、トランザクションのレシートを表示させます。
引数に、トランザクションハッシュを指定することによって、 該当するトランザクションのレシートを表示させることが出来ます。トランザクションのレシートは、ブロックに取り込まれると発行されます。
「null」が返却された場合は、まだブロックに取り込まれていない状態となりますので、少し待つ必要がありますが、テスト環境だと15秒もあれば取り込まれるので、いくら待っても発行されない場合は、マイニングを開始していないとか他の原因を見たほうが良さそうです。
eth.getTransactionReceipt('0xce67645e3b3234c1cf82ec47c2cd919c969ce2a5939454974c0a3395017b9c45')
結果
{ blockHash: "0xdaeee3a7bcc05dbbd959e12b690e684dc7100d475abf2b0140a3fa28fe2376e1", blockNumber: 640, contractAddress: <b>null</b>, cumulativeGasUsed: 21000, from: "0x5db7d11cafb9687131d37cc4de70a7ca97c61c0a", gasUsed: 21000, logs: [], logsBloom: "0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", root: "0x4296825f589b786f15211217fda15d358a8d34032a786ee4565941b7348acfbd", to: "0xb985896b8b53f0323bd3019bc70060521e5bb00f", transactionHash: "0xce67645e3b3234c1cf82ec47c2cd919c969ce2a5939454974c0a3395017b9c45", transactionIndex: 0 }
上記の結果のblockNumberを見ると、640ブロックで取り込まれた事が確認できます。
その他色々と項目がありますが、一旦置いて、残高が更新されたか確認していきます。
残高確認
eth.accounts[1]の残高確認を行なっていきます。
web3.fromWei( eth.getBalance( eth.accounts[1]), "ether")
結果
5
eth.accounts[1]のアカウントに、5ether送られてきているのが確認できました。
続けて、今度は10ether送金してみたいと思います。
送金
eth.sendTransaction({ from: eth.accounts[0], to: eth.accounts[1], value: web3.toWei(10, "ether")})
結果
"0x3dd23d01baf6f433ef8c4625d49b7162b62056f914c1397f91131adb5641c228"
トランザクションのレシートの確認
> eth.getTransactionReceipt('0x3dd23d01baf6f433ef8c4625d49b7162b62056f914c1397f91131adb5641c228')
結果
{ blockHash: "0x169157ec393f9c4ee345885e096f37b9b0047684b7ca08ad2e693fceb7ef64c9", blockNumber: 1181, contractAddress: <b>null</b>, cumulativeGasUsed: 21000, from: "0x5db7d11cafb9687131d37cc4de70a7ca97c61c0a", gasUsed: 21000, logs: [], logsBloom: "0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", root: "0x4694ccbbc4b47d3581fcbf350ccac955c26a41574e46231825c9edea9c8ce9a7", to: "0xb985896b8b53f0323bd3019bc70060521e5bb00f", transactionHash: "0x3dd23d01baf6f433ef8c4625d49b7162b62056f914c1397f91131adb5641c228", transactionIndex: 0 }
残高確認
web3.fromWei(eth.getBalance(eth.accounts[1]), "ether")
結果
15
前回の5etherと今回の10etherで、15etherになっているのが確認出来たかと思います。
ブロック高指定の残高確認
web3.fromWeiコマンドは、トランザクションのレシートで表示していた、アカウントと、ブロック高を引数にすることによって、ブロック高時点の残高を確認することも出来ます。
web3.fromWei(eth.getBalance(eth.accounts[1],1181),"ether")
結果
15
一つの前のブロックを指定
> web3.fromWei(eth.getBalance(eth.accounts[1],1180),"ether")
5
1180から1181のブロックで、5から15に増えたのが確認できたかと思います。
Geth終了
exit
Gethの終了コマンドは「exit」で終了することが出来ます。
と言った感じで、Gethコンソールの扱いをご紹介させて頂きました。
次回は、Solidityを用いてスマートコントラクト開発を行っていきましょう。
ではではぁ。