ブロックチェーンアプリ開発基礎の基礎:Gethの基礎、マイニング、送金


はじめに

ブロックチェーン基礎の基礎ブロックチェーンの基礎では、ブロックチェーンの基本的な事項を確認してきました。しかし、実際に自分で触ってみないと実感が湧かない部分も多いと思うので、実際にマイニング送金をやってみます。スマートコントラクト開発のデファクトスタンダードになっているEthereumのクライアントである「Geth」を使って実装していきます。

今回の流れは下のようになります。

Gethのインストール

まずは、Gethをインストールします。

$ brew tap ethereum/ethereum
$ brew install ethereum

インストールが無事終わったかどうかは、

$ geth help

などで確認することができます。

Genesisブロックの生成

ブロックチェーンの一番最初のブロック、すなわち0番目のブロックのことをGenesisブロックと呼びますが、これを作成していきます。

まずは、自分だけが参加するネットワークとなるプライベートネットワーク用にフォルダを作成します。逆に、全世界に公開されたネットワークとして、メインネットテストネットといったパブリックネットワークもあります。

$ mkdir ~/private_net

次に、フォルダ内にGenesisブロックの情報を記述したGenesisファイルを作成します。

genesis.json
{
  "config": {
    "chainId": 42,
    "homesteadBlock": 0,
    "eip155Block": 0,
    "eip158Block": 0
  },
  "nonce": "0x0000000000000042",
  "timestamp": "0x0",
  "parentHash": "0x0000000000000000000000000000000000000000000000000000000000000000",
  "gasLimit": "0x8000000",
  "difficulty": "0x100",
  "mixhash": "0x0000000000000000000000000000000000000000000000000000000000000000",
  "coinbase": "0x3333333333333333333333333333333333333333",
  "alloc": {}
}

ブロックチェーンの初期化

続いて、ブロックチェーンを初期化します。

$ geth --datadir ~/private_net/ init ~/private_net/genesis.json

「Successfully wrote genesis state」と出れば初期化成功です。

最後に、Gethを起動します。

$ geth --networkid "10" --nodiscover --datadir ~/private_net --rpc --rpcaddr "localhost" --rpcport "8545" --rpccorsdomain "*" --rpcapi "eth,net,web3,personal"  console 2>> ~/private_net/err.log

「Welcome to the Geth JavaScript console!」と出れば起動成功です。

さっそくですが、Genesisブロックの中身を確認してみましょう。

> eth.getBlock(0)
{
  difficulty: 256,
  extraData: "0x",
  gasLimit: 134217728,
  gasUsed: 0,
  hash: "0x83b885bae699c5650394963ed8927f780cf4fea39b55d3abf430e5a95aa305f3",
  logsBloom: "0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000",
  miner: "0x3333333333333333333333333333333333333333",
  mixHash: "0x0000000000000000000000000000000000000000000000000000000000000000",
  nonce: "0x0000000000000042",
  number: 0,
  parentHash: "0x0000000000000000000000000000000000000000000000000000000000000000",
  receiptsRoot: "0x56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421",
  sha3Uncles: "0x1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347",
  size: 507,
  stateRoot: "0x56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421",
  timestamp: 0,
  totalDifficulty: 256,
  transactions: [],
  transactionsRoot: "0x56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421",
  uncles: []
}

何やら、たくさんの項目がありますが、numberの0はこのブロックが0番目のブロックであることを示しています。

これで、ブロックチェーンの一番最初のブロックを生成することができました。

新しいブロックの生成

ブロックチェーン基礎の基礎で説明したように、新しいブロックを生成することをマイニングと呼びました。実際にマイニングをやってみましょう。マイニングを行うと報酬が支払われることも確認してみます。

まず、アカウントを作成します。マイニングを行うだけなら、アカウントの作成は1つでよいのですが、次章で送金を行うので「送信者」と「受信者」の二つのアカウントを作成し、「送信者」の方でマイニングを行います。

> personal.newAccount("sender")
"0xfb814cf6d7deae6d68d9dea8f8cef23b9ce63e5f"
> personal.newAccount("receiver")
"0x9e495cc88b7d99c28918efb641f564f896eec6f5"

自分のGethにどんなアカウントがあるかは次のようにして確認することができます。送信者と受信者2つのアカウントがあることが確認できます。

> eth.accounts
["0xfb814cf6d7deae6d68d9dea8f8cef23b9ce63e5f", "0x9e495cc88b7d99c28918efb641f564f896eec6f5"]

ちなみに、インデックスでアカウントを指定して確認することもできます。1番目に作った送信者のアカウントはeth.accounts[0]で、2番目に作った受信者のアカウントはeth.accounts[1]で指定することができます。

それではさっそくマイニングを始めましょう。

> miner.start(1)
null

しばらくすると、ブロックが生成され、受信者(eth.accounts[0])に報酬が支払われます。アカウントの残高は、次のようにして確認できます。以下の例では、Etherumで使う通貨「Ether」で25etherほど残高が生じていることが確認できます。

> web3.fromWei(eth.getBalance(eth.accounts[0]), "ether")
25

しばらくして、ある程度etherが貯まったことが確認できたらマイニングを中断しましょう。

> miner.stop()
true

送金

それでは、マイニングの報酬で得られたetherを送金してみましょう。今、受信者は何もしていてないので残高は0etherとなっています。

> web3.fromWei(eth.getBalance(eth.accounts[1]), "ether")
0

この状態から送信者から受信者に5ether送金してみましょう。まずは、誤送金を防ぐために設定されている送信者のロックを解除してやります。

> personal.unlockAccount(eth.accounts[0], "sender")

ロックが解除できたらいよいよ送金です。from誰から送金するかを、to誰に送金するかを、valueいくら送金するかを指定してやります。今は、「送信者から受信者5ether送金する」というようにしてみます。

> eth.sendTransaction({from: eth.accounts[0], to: eth.accounts[1], value:web3.toWei(5, "ether")})
"0x02ee9a1765636d9a452f44c987a48b013f3404bec13b584b715c31d7275b856e"

送金を行うとトランザクション(取引履歴)のアドレスが返ってきます。しかし、このままでは取引は完了しません。トランザクションはブロックに格納されてはじめて取引完了となるからです。よって、再度マイニングによって新しいブロックを生成してやります。

> miner.start(1)
null

しばらくすると、取引が完了するので、トランザクションを確認してみましょう。引数には、さきほど得られたトランザクションのアドレスを与えてやります。

> eth.getTransaction("0x02ee9a1765636d9a452f44c987a48b013f3404bec13b584b715c31d7275b856e")
{
  blockHash: "0x1d91d02ccde8ae04a53838ace4603bf7efd52a59ce9e20f772fa945d9e2b863e",
  blockNumber: 6,
  from: "0xfb814cf6d7deae6d68d9dea8f8cef23b9ce63e5f",
  gas: 90000,
  gasPrice: 18000000000,
  hash: "0x02ee9a1765636d9a452f44c987a48b013f3404bec13b584b715c31d7275b856e",
  input: "0x",
  nonce: 0,
  r: "0x2508ddd4b79fe2fa1b01a86d5114a36fed003ff48d718c3c4c5b0205698ab2c",
  s: "0x6f2270a81fcf878b3e6f7fac80d74c6fe63addc34d3a6e61ee1773be58c3c9bd",
  to: "0x9e495cc88b7d99c28918efb641f564f896eec6f5",
  transactionIndex: 0,
  v: "0x78",
  value: 5000000000000000000
}

トランザクションも様々な項目がありますが、blockNumberはこのトランザクションが格納されているブロックの番号を示しており、この場合6番目のブロックであることが分かります。

最後に、受信者の残金が増えているか確認しておきましょう。

> web3.fromWei(eth.getBalance(eth.accounts[1]), "ether")
5

無事、5etherが入金されていることが分かります。これで、送信者から受信者の送金が完了しました。

さいごに、exitでGethを終了しておきましょう。

> exit