前回上手くいかなかったので、リベンジ
やったこと
1. gethのインストール
プライベート・ネットに接続する · Ethereum入門
上記を参考にgethをインストール。
その中で、myGenesis.json を作成する部分がある。
このjsonファイルは、下記のサイトを参考に書き換える。
ブロックチェーンEthereum入門 2 | NTTデータ先端技術株式会社
下記の値を設定し直すとよかった。
difficulty: マイニングの難易度。下げると、マイニングの時間が減る。
alloc: これを設定すると初期状態で、etherが指定のアカウントが保持している状態にできる。
gasLimit: transaction 時に必要なgasの量。
参考に作ったのがこちら
{ "config": { "chainId": 15 }, "nonce": "0x00006d6f7264656e", "difficulty": "0x0001", "mixhash": "0x00000000000000000000000000000000000000647572616c65787365646c6578", "coinbase": "0x0000000000000000000000000000000000000000", "timestamp": "0x00", "parentHash": "0x0000000000000000000000000000000000000000000000000000000000000000", "extraData": "0x", "gasLimit": "0xffffffffffff", "alloc": { "0x5F6bD87B34c3C1315aC82b3f6f84d5e1DF31422b": { "balance": "100000000000000000000" }, } }
alloc の keyの部分を何にすればいいかよくわからない方は、下記のサイトを参考にするとわかりやすいです! 一行で書くと、一度gethを起動して、アカウント作って、そのアカウントアドレスをkeyの部分に書き、再度genesisブロックの初期化を行って、もう一度gethを起動しました。
ethereum(private)の環境構築からJSON-RPC実行まで - Qiita
もし、Failed to write genesis block: database already contains ...
と出たら、下記のサイト参考に、DBを削除してもう一回実行。
2. gethの起動
自分は、下記で起動しました。
geth --networkid "15" --nodiscover --datadir "/Users/kei/eth_private_net" --rpc --rpcaddr "localhost" --rpcport "8545" --rpcapi "web3,eth,net,personal" --minerthreads 1" --rpccorsdomain "*" --mine
大事なのは、
- --mine
とつけることで、勝手にminingを行ってくれる。(miningをしないと、transactionが処理できなかった。)
- --rpcaddr "localhost" --rpcport "8545"
とつけて、http経由でアクセスできるようにする。(truffle というライブラリで、smart contractを作るときに、httpアクセスするため。)
起動オプションについては、こちらがわかりやすかったです! ethereum(private)の環境構築からJSON-RPC実行まで - Qiita
3. コンソールでログイン
geth attach http://127.0.0.1:8545
geth attach ipc:/Users/kei/eth_private_net/geth.ipc
どっちでもログインできる!
4. Railsで確認
こちらのgemをインストール
GitHub - EthWorks/ethereum.rb: Ethereum library for the Ruby language
$ bundle exec rails c > client = Ethereum::IpcClient.new('/Users/kei/eth_private_net/geth.ipc') > client.get_balance('0x5F6bD87B34c3C1315aC82b3f6f84d5e1DF31422b') => 100000000000000000000
こんな感じでアクセスできる。
5. ERC20のSmart Contract作成
下記のサイトを参考にして、tokenを作成。
【Truffle5.0対応】シンプルなERC20トークンを作成しよう! │ こじりょーの研究所
上記のサイトでは、Ganache を利用していますが、今回はgeth利用しているので、truffle-confing.jsに、起動したgethの設定を追記
development: { host: "127.0.0.1", port: 8545, network_id: "*" },
あとは、上記サイトに書いてあるように、contract をデプロイする。
その前に、geth の console 上から、アカウントのアンロックを忘れずに。これをしないと、etherを使った操作ができない。
$ geth attach http://127.0.0.1:8545 // passwordが聞かれるので、自分がアカウント作成したときに、設定しているものを入力 > personal.unlockAccount(eth.coinbase)
$ truffle migrate // 結果こんな感じ ⚠️ Important ⚠️ If you're using an HDWalletProvider, it must be Web3 1.0 enabled or your migration will hang. Starting migrations... ====================== > Network name: 'development' > Network id: 15 > Block gas limit: 208531973388668 1_initial_migration.js ====================== Deploying 'Migrations' ---------------------- > transaction hash: 0x788615947355935aa5df21b8ca16ffac7f6e562f506dd6affd4914425b9f5dc1 > Blocks: 2 Seconds: 4 > contract address: 0x4543dCf52aa78d32d667bBF39EEc7B98b56d120F > account: 0x5F6bD87B34c3C1315aC82b3f6f84d5e1DF31422b > balance: 1645 > gas used: 252758 > gas price: 20 gwei > value sent: 0 ETH > total cost: 0.00505516 ETH > Saving migration to chain. > Saving artifacts ------------------------------------- > Total cost: 0.00505516 ETH 2_deploy_contracts.js ===================== Deploying 'SimpleToken' ----------------------- > transaction hash: 0xdee089ce5f1384c5016b8f5c8d870e8fbf1fef4c4046e49f84a235d2f9f28c4e > Blocks: 0 Seconds: 8 > contract address: 0x2FA965B7d62858Dc4DBCeA965271b0D7dB780A13 > account: 0x5F6bD87B34c3C1315aC82b3f6f84d5e1DF31422b > balance: 1665 > gas used: 1387474 > gas price: 20 gwei > value sent: 0 ETH > total cost: 0.02774948 ETH > Saving migration to chain. > Saving artifacts ------------------------------------- > Total cost: 0.02774948 ETH Summary ======= > Total deployments: 2 > Final cost: 0.03280464 ETH
この結果の、「0x2FA965B7d62858Dc4DBCeA965271b0D7dB780A13」が、contract addressとなるので大事。
6. RailsからERC20Tokenの残高確認
$ bundle exec rails c > client = Ethereum::IpcClient.new('/Users/kei/eth_private_net/geth.ipc') > name = '作成したコインの名前' > contract_address = '0x2FA965B7d62858Dc4DBCeA965271b0D7dB780A13' // ERC20Tokenを保持している人のアドレス > account_address = '0x5F6bD87B34c3C1315aC82b3f6f84d5e1DF31422b' // abiとは、Application Binary Interfaceの略で、このContractは、こんなファンクションもってるよって定義するもの。 // 今回は、name と、 balanceOf 以外省略してます。 > contract_abi = [{"constant":true,"inputs":[],"name":"name","outputs":[{"name":"","type":"string"}],"payable":false,"type":"function"},{"constant":true,"inputs":[{"name":"_owner","type":"address"}],"name":"balanceOf","outputs":[{"name":"balance","type":"uint256"}],"payable":false,"type":"function"}] > contract = Ethereum::Contract.create(name: name, address: contract_address, abi: contract_abi.to_json, client: client) > contract.call.name => "作成したコインの名前" > contract.call.balance_of(account_address) => 100000000000000000000
7. Tokenの移動
$ bundle exec rails c > client = Ethereum::IpcClient.new('/Users/kei/eth_private_net/geth.ipc') > name = '作成したコインの名前' > contract_address = '0x2FA965B7d62858Dc4DBCeA965271b0D7dB780A13' // ERC20Tokenを保持している人のアドレス > account_address = '0x5F6bD87B34c3C1315aC82b3f6f84d5e1DF31422b' // ERC20Tokenを送りたい人のアドレス > target_address = '0x37543c2d55bc48d5c87c49fbdd321834ffafbf43' // ここでは、truffle で作成したときにできる、SimpleToken.json の abi部分を全部コピーしてみました。 > contract_abi =[{"constant":true,"inputs":[],"name":"name","outputs":[{"name":"","type":"string"}],"payable":false,"stateMutability":"view","type":"function","signature":"0x06fdde03"},{"constant":false,"inputs":[{"name":"spender","type":"address"},{"name":"value","type":"uint256"}],"name":"approve","outputs":[{"name":"","type":"bool"}],"payable":false,"stateMutability":"nonpayable","type":"function","signature":"0x095ea7b3"},{"constant":true,"inputs":[],"name":"totalSupply","outputs":[{"name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function","signature":"0x18160ddd"},{"constant":false,"inputs":[{"name":"from","type":"address"},{"name":"to","type":"address"},{"name":"value","type":"uint256"}],"name":"transferFrom","outputs":[{"name":"","type":"bool"}],"payable":false,"stateMutability":"nonpayable","type":"function","signature":"0x23b872dd"},{"constant":true,"inputs":[],"name":"decimals","outputs":[{"name":"","type":"uint8"}],"payable":false,"stateMutability":"view","type":"function","signature":"0x313ce567"},{"constant":false,"inputs":[{"name":"spender","type":"address"},{"name":"addedValue","type":"uint256"}],"name":"increaseAllowance","outputs":[{"name":"","type":"bool"}],"payable":false,"stateMutability":"nonpayable","type":"function","signature":"0x39509351"},{"constant":true,"inputs":[{"name":"owner","type":"address"}],"name":"balanceOf","outputs":[{"name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function","signature":"0x70a08231"},{"constant":true,"inputs":[],"name":"symbol","outputs":[{"name":"","type":"string"}],"payable":false,"stateMutability":"view","type":"function","signature":"0x95d89b41"},{"constant":false,"inputs":[{"name":"spender","type":"address"},{"name":"subtractedValue","type":"uint256"}],"name":"decreaseAllowance","outputs":[{"name":"","type":"bool"}],"payable":false,"stateMutability":"nonpayable","type":"function","signature":"0xa457c2d7"},{"constant":false,"inputs":[{"name":"to","type":"address"},{"name":"value","type":"uint256"}],"name":"transfer","outputs":[{"name":"","type":"bool"}],"payable":false,"stateMutability":"nonpayable","type":"function","signature":"0xa9059cbb"},{"constant":true,"inputs":[{"name":"owner","type":"address"},{"name":"spender","type":"address"}],"name":"allowance","outputs":[{"name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function","signature":"0xdd62ed3e"},{"inputs":[{"name":"name","type":"string"},{"name":"symbol","type":"string"},{"name":"decimals","type":"uint8"},{"name":"initSupply","type":"uint256"}],"payable":false,"stateMutability":"nonpayable","type":"constructor","signature":"constructor"},{"anonymous":false,"inputs":[{"indexed":true,"name":"from","type":"address"},{"indexed":true,"name":"to","type":"address"},{"indexed":false,"name":"value","type":"uint256"}],"name":"Transfer","type":"event","signature":"0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef"},{"anonymous":false,"inputs":[{"indexed":true,"name":"owner","type":"address"},{"indexed":true,"name":"spender","type":"address"},{"indexed":false,"name":"value","type":"uint256"}],"name":"Approval","type":"event","signature":"0x8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b925"}] > contract = Ethereum::Contract.create(name: name, address: contract_address, abi: contract_abi.to_json, client: client) > contract.call.name => "作成したコインの名前" > contract.transact_and_wait.transfer(target_address, 100) > contract.call.balance_of(account_address) => 99999999999999999900 > contract.call.balance_of(target_address) => 100
transferをしたい時は、geth上で、coinbase のunlockAccountが必要なので注意。
あと、privateで、transactionを実行する時は、自分でminingをしないといけないので忘れずに。(--mine をつけてれば大丈夫)
Tokenの移動(とあるアカウント => とあるアカウントへ)
$ bundle exec rails c > client = Ethereum::IpcClient.new('/Users/kei/eth_private_net/geth.ipc') > name = '作成したコインの名前' > contract_address = '0x2FA965B7d62858Dc4DBCeA965271b0D7dB780A13' // Tokenを保持している & etherもいっぱいもってるアドレス > master_address = '0x5F6bD87B34c3C1315aC82b3f6f84d5e1DF31422b' // さっきTokenをもらったアドレス > sender_address = '0x37543c2d55bc48d5c87c49fbdd321834ffafbf43' // 今からTokenをもらうアドレス > receiver_address = '0x7c278ea950e9af850ad089f93a94fd8fd7c62725' // abiはさっきと一緒 > abi = ... // まず、gasのために、etherがsender_addressに必要なので、master_addressから渡す > client.personal_unlock_account(master_address, 'password') > client.eth_send_transaction({ from: master_address, to: sender_address, value: "0x9184e72a"}) // デフォルトのアカウントを変更する > client.default_account = sender_address > contract = Ethereum::Contract.create(name: name, address: contract_address, abi: contract_abi.to_json, client: client) // 送る前 > contract.call.balance_of(sender_address) => 100 > contract.call.balance_of(receiver_address) => 0 // 送信! > client.personal_unlock_account(sender_address, 'password') > transact_and_wait.transfer(sender_address, 40) // 結果 > contract.call.balance_of(sender_address) => 60 > contract.call.balance_of(receiver_address) => 40
終わり
ここまでくるのに時間かかったが、etheriumとcontractについて、いくつか理解できた...
実際に、wallet を作成する時は、contract の address さえわかれば、etherscan のAPIを経由して、contract_abi、contract_name を取得ができる。
あとは、それを使ってcontractのインスタンス生成をし、ユーザーのアドレスの残高が確認できる模様。
結構理解できてきたので、まずは、wallet を自作できるようになりたい!!