Quorum example触ってみる


はじめに

エンタープライズ向けEthereumのQuorumを触ってみます。
公式のquorum examplesを使います。

Quorumとは

Quorumについてはこちらの資料をみると良いです。

動かしてみる

セットアップ

Virtual BoxVagrantがインストールされていることが必須

$ git clone https://github.com/jpmorganchase/quorum-examples
$ vagrant up
$ vagrant ssh

node起動

$ cd examples/7nodes/
$ ./raft-init.sh
$ ./raft-start.sh

private transactionを試してみる

 SimpleStorageコントラクトをnode1からnode7に送ります.トランザクションの送信オプションにprivateForがつけられていてこれはnode1とnode7にしか知り得ないようになっています.

$ ./runscript.sh private-contract.js
Contract transaction send: TransactionHash: 0x9e31af66669a6602307481bf2ebff2893f9d571effa11e50760e85686414a972 waiting to be mined...
true

node1としてgethコンソール入り, トランザクションを確認します
node1として入るにはgeth attach ipc:qdata/dd1/geth.ipc
node4として入るにはgeth attach ipc:qdata/dd4/geth.ipc
node7として入るにはgeth attach ipc:qdata/dd7/geth.ipc
を実行します.

$ geth attach ipc:qdata/dd1/geth.ipc
> eth.getTransaction("0x9e31af66669a6602307481bf2ebff2893f9d571effa11e50760e85686414a972")
{
  blockHash: "0x5e31602616f28c2f2bd6075d0de08eace32a68804289179d36536d1f224d6f75",
  blockNumber: 1,
  from: "0xed9d02e382b34818e88b88a309c7fe71e65f419d",
  gas: 4700000,
  gasPrice: 0,
  hash: "0x9e31af66669a6602307481bf2ebff2893f9d571effa11e50760e85686414a972",
  input: "0x2bfd82f5cbc0666eec01e8d7faaf158e5e42b0f41c7fbf33ec20182cc29adce7863431c029ad2be5f0e9c396ac24dbe01d86c1395b688ef9edb46e58daf6ee03",
  nonce: 0,
  r: "0x854a01efdba6cb5bc5624793fd2b891b7ab97d17858f98f19e6507c9a6b9dc61",
  s: "0x412224a2d04ca3c7853533a8c7b461a08c75d972ac8e5024c44473ad37706aac",
  to: null,
  transactionIndex: 0,
  v: "0x26",
  value: 0
}

パラメータv0x26になっています. プライベートトランザクションはv0x260x27になります.

次に、コントラクトのステートを見てみます.
このコントラクトは初期化時にx42を代入しているので, node1と7はx42になっているはずです. 逆に他のノードがxをみると0になっているはずです.

eth.getTransactionReceipt(txHash)を実行するとコントラクトアドレスがわかります.

> eth.getTransactionReceipt("0x9e31af66669a6602307481bf2ebff2893f9d571effa11e50760e85686414a972")
{
  blockHash: "0x5e31602616f28c2f2bd6075d0de08eace32a68804289179d36536d1f224d6f75",
  blockNumber: 1,
  contractAddress: "0x1932c48b2bf8102ba33b4a6b545c32236e342f34",
  cumulativeGasUsed: 0,
  from: "0xed9d02e382b34818e88b88a309c7fe71e65f419d",
  gasUsed: 0,
  logs: [],
  logsBloom: "0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000",
  status: "0x1",
  to: null,
  transactionHash: "0x9e31af66669a6602307481bf2ebff2893f9d571effa11e50760e85686414a972",
  transactionIndex: 0
}
> var address = "0x1932c48b2bf8102ba33b4a6b545c32236e342f34"
> var abi = [{"constant":true,"inputs":[],"name":"storedData","outputs":[{"name":"","type":"uint256"}],"payable":false,"type":"function"},{"constant":false,"inputs":[{"name":"x","type":"uint256"}],"name":"set","outputs":[],"payable":false,"type":"function"},{"constant":true,"inputs":[],"name":"get","outputs":[{"name":"retVal","type":"uint256"}],"payable":false,"type":"function"},{"inputs":[{"name":"initVal","type":"uint256"}],"type":"constructor"}];
> var private = eth.contract(abi).at(address)

node1として実行すると

> private.get()
42

node4として実行すると

> private.get()
0

node7として実行すると

> private.get()
42

が返ってきます.

コントラクトを変更して試してみる

こんな感じのコントラクトに送金するコントラクトでプライベートトランザクションを試します

pragma solidity >=0.4.22 <0.6.0;

contract Bank {
    mapping(address => uint256) public UserToAmount;

    function deposit() payable public {
        UserToAmount[msg.sender] += msg.value;
    }

    function withdraw(uint256 amount) public {
        require(UserToAmount[msg.sender] >= amount);
        UserToAmount[msg.sender] -= amount;
        msg.sender.transfer(amount);
    }
}
ABI
[
    {
        "constant": false,
        "inputs": [],
        "name": "deposit",
        "outputs": [],
        "payable": true,
        "stateMutability": "payable",
        "type": "function"
    },
    {
        "constant": false,
        "inputs": [
            {
                "name": "amount",
                "type": "uint256"
            }
        ],
        "name": "withdraw",
        "outputs": [],
        "payable": false,
        "stateMutability": "nonpayable",
        "type": "function"
    },
    {
        "constant": true,
        "inputs": [
            {
                "name": "",
                "type": "address"
            }
        ],
        "name": "UserToAmount",
        "outputs": [
            {
                "name": "",
                "type": "uint256"
            }
        ],
        "payable": false,
        "stateMutability": "view",
        "type": "function"
    }
]
bytecode
"608060405234801561001057600080fd5b50610275806100206000396000f3fe608060405260043610610051576000357c0100000000000000000000000000000000000000000000000000000000900480632e1a7d4d14610056578063d0e30db014610091578063ebfb4d531461009b575b600080fd5b34801561006257600080fd5b5061008f6004803603602081101561007957600080fd5b8101908080359060200190929190505050610100565b005b6100996101e3565b005b3480156100a757600080fd5b506100ea600480360360208110156100be57600080fd5b81019080803573ffffffffffffffffffffffffffffffffffffffff169060200190929190505050610231565b6040518082815260200191505060405180910390f35b806000803373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020541015151561014d57600080fd5b806000803373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020600082825403925050819055503373ffffffffffffffffffffffffffffffffffffffff166108fc829081150290604051600060405180830381858888f193505050501580156101df573d6000803e3d6000fd5b5050565b346000803373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060008282540192505081905550565b6000602052806000526040600020600091509050548156fea165627a7a72305820a406a09d0c1ed38eca8e89b9ab68ee75f667463a5bf92f87749eac7058143a240029"

保留

まとめ

プライベートトランザクションを使用すると対象となるノード以外でもトランザクションの存在は確認できる.
コントラクトなどのステートには対象のノードしかアクセスできない感じ.