edo1z blog

プログラミングなどに関するブログです

イーサリアムやってみる

この本みながら、イーサリアムやってみます。この無料サイトも色々詳しく書いてありそうなので、後で見てみる。

イーサリアムをインストール

Goのクライアントはgo-ethereumです。通称Gethです。Gethはここからダウンロードできます。今のバージョンは1.6.7です。今回はWindows版をインストールしてみます。ダウンロードしたexeファイルを起動すれば勝手にインストールされます。gethコマンドで色々できるようですが、パスが通ってなかったのでパスを通します。パスを通してバージョン確認して動いたら成功です。

$ geth version
Geth
Version: 1.6.7-stable
Git Commit: ab5646c532292b51e319f290afccf6a44f874372
Architecture: amd64
Protocol Versions: [63 62]
Network Id: 1
Go Version: go1.8.3
Operating System: windows
GOPATH=C:/Users/hoge/go
GOROOT=D:/go

テスト環境でGethを起動する

テスト環境で起動させるには、データディレクトリとGenesisファイルが必要だそうです。Windowsだと、デフォルトのdatadirは~/AppData/Roaming/Ethereumになるようなので、テスト用は~/AppData/Roaming/EthTestにしてみます。Genesisファイルは、最初のブロックの情報を書いたjsonファイルだそうです。genesis.jsonというファイル名です。現状では下記のようなフォーマットになるようです。

{
  "config": {
        "chainId": 0,
        "homesteadBlock": 0,
        "eip155Block": 0,
        "eip158Block": 0
    },
  "alloc"      : {},
  "coinbase"   : "0x0000000000000000000000000000000000000000",
  "difficulty" : "0x20000",
  "extraData"  : "",
  "gasLimit"   : "0x2fefd8",
  "nonce"      : "0x0000000000000042",
  "mixhash"    : "0x0000000000000000000000000000000000000000000000000000000000000000",
  "parentHash" : "0x0000000000000000000000000000000000000000000000000000000000000000",
  "timestamp"  : "0x00"
}

これを、~/AppData/Roaming/EthTest/genesis.jsonに作成します。

初期化

テスト環境を初期化します。--datadirでデータディレクトリを指定して、init genesis.jsonで初期化できます。

$ cd ~/AppData/Roaming/EthTest
$ geth --datadir . init genesis.json
WARN [09-06|16:59:34] No etherbase set and no accounts found as default
INFO [09-06|16:59:35] Allocated cache and file handles         database=C:\\Users\\hoge\\AppData\\Roaming\\EthTest\\geth\\chaindata cache=16 handles=16
INFO [09-06|16:59:35] Writing custom genesis block
INFO [09-06|16:59:35] Successfully wrote genesis state         database=chaindata                                                    hash=5e1fc7…d790e0
INFO [09-06|16:59:35] Allocated cache and file handles         database=C:\\Users\\hoge\\AppData\\Roaming\\EthTest\\geth\\lightchaindata cache=16 handles=16
INFO [09-06|16:59:35] Writing custom genesis block
INFO [09-06|16:59:35] Successfully wrote genesis state         database=lightchaindata                                                    hash=5e1fc7…d790e0

起動

gethを起動します。

$ geth --networkid 4649 --nodiscover --maxpeers 0 --datadir . console 2>> ./geth.log
Welcome to the Geth JavaScript console!

instance: Geth/v1.6.7-stable-ab5646c5/windows-amd64/go1.8.3
 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('hoge')
"0x4bdda1d508c3809c29728f0c6c54c54d8a30e749"

アカウントの確認は下記でできる。

> eth.accounts
["0x4bdda1d508c3809c29728f0c6c54c54d8a30e749"]

こんな感じで配列で表示される。 下記のようにインデックス指定も可能。

> eth.accounts[0]

マイニング

マイニングの報酬を受け取るアカウントをEtherbaseと呼ぶらしい。デフォルトではeth.accounts[0]が設定される。eth.coinbaseで現在のEtherbaseを確認できて、miner.setEtherbase(eth.accounts[1])で変更できる。

マイニングは、下記でできる。

> miner.start(1)

これだけ。簡単だなー。しかし、nullが返ってきてマイニングされない。バージョン変わって何かしよう変わったのかな。。 いやされてた。nullと返ってきた理由は分からないけど、すでに500以上のブロックを作っている。

> eth.mining
true

> eth.hashrate
73453

> eth.blockNumber
509

とりあえず、マイ二ングをとめてみる。

> miner.stop()
true

> eth.mining
false

> eth.hashrate
66670

> eth.blockNumber
564

トランザクションなくてもマイングはできるんだなあ。これでマイニング報酬が沢山もらえてるはずなので、残高確認。

> eth.getBalance(eth.coinbase)
2.82e+21

これはwei表記らしい。1etherは、10の18乗weiだそうです。これをetherに変換することもできる。

> web3.fromWei(eth.getBalance(eth.coinbase), 'ether')
2820

2820イーサもってるのかー。うらやましい。 本だとマイニング報酬は1ブロック5イーサと書いてある。現時点でも変わっていない。

イーサを送金

送金するには、アカウントをアンロックしておく必要がある。

>  personal.unlockAccount(eth.accounts[0])

Unlock account 0x8f3681ee1f54c9271972d962e95b55edd27f05ea
!! Unsupported terminal, password will be echoed.
Passphrase: hoge

true

アンロック後、下記で送れる。

> eth.sendTransaction({from: eth.coinbase, to: eth.accounts[1], value: web3.toWei(10, 'ether')})

Error: invalid sender
    at web3.js:3104:20
    at web3.js:6191:15
    at web3.js:5004:36

エラー。invalid senderってなんだ。 ここに書いてあった。genesis.jsonのchainIdと起動時のネットワークIDを合わせないといけないらしい。0~3は予約済みとか書いてあるので、30にすることにした。でも、それだとgeth initしなおさないといけないのかな?? genesis.jsonを修正して、initしなおして、送ったら成功した。

トランザクション確認してみる

送金するというのは、トランザクションを作成して、ブロックチェーンのP2Pネットワークに送信するということで、トランザクションをみんなが受信したとしても、それをブロックに誰かが入れて、マイニングを成功させないと、ブロックチェーン上でコインの移動は完了したことにならない。とういことで、まだマイニング停止中のため、ブロックチェーン上で取引完了になっていない状態のはずです。とりあえず残高確認と対象トランザクションを確認してみます。

> eth.getBalance(eth.coinbase)
2.82e+21

> eth.getBalance(eth.accounts[1])
0

残高は変わってません。未反映トランザクションは、下記で確認できます。

> eth.pendingTransactions
[{
    blockHash: null,
    blockNumber: null,
    from: "0x8f3681ee1f54c9271972d962e95b55edd27f05ea",
    gas: 90000,
    gasPrice: 18000000000,
    hash: "0x0830a8510f81554aa5a509752d6a3c17be419af40a983b03142441751cf55949",
    input: "0x",
    nonce: 0,
    r: "0x384187dbafe8afea81bce1f69b2c2b6681f9c65babfafaecf64457e4ce9c27de",
    s: "0x6261a1a8a37439c9a10f0ce092789c1e58cc386eaaef2bd63343ce63a746020",
    to: "0x8c20fb9625715dba4be7f32a99ae6577bd90ef11",
    transactionIndex: 0,
    v: "0x5f",
    value: 10000000000000000000
}]

これです。これを反映させるために、マイニングしてみます。

> eth.mining
false

> miner.start(1)
null

> eth.mining
true

> eth.blockNumber
571

> miner.stop()
true

miner.stop(1)の1という引数はスレッド数なのか。ブロック数かと思ってたわ。これで、ブロックに取り込まれてるはずです。さっき564ブロックまでできてたので、恐らく565ブロックに入ってるんじゃないかと思いますが、どうなんでしょうか?

> eth.pendingTransactions
[]

> eth.getTransaction("0x0830a8510f81554aa5a509752d6a3c17be419af40a983b03142441751cf55949")
{
  blockHash: "0x710c101911c4968f018dae9895b87fd5f0b566f084b6c664d40fe7fced4a9b69",
  blockNumber: 565,
  from: "0x8f3681ee1f54c9271972d962e95b55edd27f05ea",
  gas: 90000,
  gasPrice: 18000000000,
  hash: "0x0830a8510f81554aa5a509752d6a3c17be419af40a983b03142441751cf55949",
  input: "0x",
  nonce: 0,
  r: "0x384187dbafe8afea81bce1f69b2c2b6681f9c65babfafaecf64457e4ce9c27de",
  s: "0x6261a1a8a37439c9a10f0ce092789c1e58cc386eaaef2bd63343ce63a746020",
  to: "0x8c20fb9625715dba4be7f32a99ae6577bd90ef11",
  transactionIndex: 0,
  v: "0x5f",
  value: 10000000000000000000
}

おー565ブロックにいるようです。565ブロックを確認してみます。

> eth.getBlock(565)
{
  difficulty: 163725,
  extraData: "0xd983010607846765746887676f312e382e338777696e646f7773",
  gasLimit: 4712388,
  gasUsed: 21000,
  hash: "0x710c101911c4968f018dae9895b87fd5f0b566f084b6c664d40fe7fced4a9b69",
  logsBloom: "0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000",
  miner: "0x8f3681ee1f54c9271972d962e95b55edd27f05ea",
  mixHash: "0x9be7d924c11fdc0bcc2a0f8e8dfb62b314e9aa6bfe2f2f4c6394c2eac06004a1",
  nonce: "0x0f03712b427ee71d",
  number: 565,
  parentHash: "0x42452b71c03e4988c94b69dafe67e7d695bd65d55df026eecaa7ee59be412ea2",
  receiptsRoot: "0x8b25764a2e684220c00101bb69092e0fb95408faf6c03cefc4cf6f0689ebbbb6",
  sha3Uncles: "0x1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347",
  size: 653,
  stateRoot: "0x2f606c7dec70bcdfa22af5a772c6d3b74ba4f8f9638f1e41881e900719d76173",
  timestamp: 1504694101,
  totalDifficulty: 85246548,
  transactions: ["0x0830a8510f81554aa5a509752d6a3c17be419af40a983b03142441751cf55949"],
  transactionsRoot: "0x0d883ee7730dc5224f2e7e3abae9b2bde3b90122282467518e551665acdcb21a",
  uncles: []
}

transactionsに入ってます。ちなみに、他のトランザクションが空のはずのブロックも一応確認してみたら、transactionsは空でした。当たり前だけど。これで残高を確認すると反映されているはずです。

> web3.fromWei(eth.getBalance(eth.coinbase))
2865

> web3.fromWei(eth.getBalance(eth.accounts[1]))
10

coinbaseが送信したので、coinbaseから手数料が引かれたけど、マイニングしたから増えたって感じなのかな?とりあえず、accounts[1]にはしっかり10が反映されています。