RealPath:
WebPath:
2016/11/26 15:08 (JST) 更新
契約プログラム >>

契約プログラムの利用

Contents

簡単なサンプル

書式は Solidity 固有の言語。JavaScript に似た書式。(このサンプルスクリプトは http://book.ethereum-jp.net/first_use/contract.html より拝借)

contract SingleNumRegister {
    uint storedData;
    function set(uint x) {
        storedData = x;
    }
    function get() constant returns (uint retVal) {
        return storedData;
    }
}

ソースコード文字列の準備

geth コンソール上で上記 Solidity コードをビルドするために、以下のようにコードを1つの文字列変数にあらかじめ格納しておく。

> var source = "contract SingleNumRegister { uint storedData; function set(uint x) { storedData = x; } function get() constant returns (uint retVal) { return storedData; }}"

しかしこれはあんまりにもめんどいのでもう少しマシな代替策として以下のようなファイルを準備しておくという手もある。

sample.js
var source = "contract SingleNumRegister {" +
"    uint storedData;" +
"    function set(uint x) {" +
"        storedData = x;" +
"    }" +
"    function get() constant returns (uint retVal) {" +
"        return storedData;" +
"    }" +
"}";

geth コンソール上では loadScript というメソッドにより任意 js を読み込むことができるので、上記 sample.js を準備した上で、

> loadScript("sample.js")

を実行すると、sample.js が実行され、変数 source に Solidity コードが代入された状態になる。

コンパイル

> contract = eth.compile.solidity(source).SingleNumRegister
{
  code: "0x60606040…b6000545b9056", ← バイトコード(これが定義実体)
  info: {
    abiDefinition: [{
        constant: false,
        inputs: [...],
        name: "set",
        outputs: [],
        payable: false,
        type: "function"
    }, {
        constant: true,
        inputs: [],
        name: "get",
        outputs: [...],
        payable: false,
        type: "function"
    }],
    compilerOptions: "--combined-json bin,abi,userdoc,devdoc --add-std --optimize",
    compilerVersion: "0.4.5",
    developerDoc: {
      methods: {}
    },
    language: "Solidity",
    languageVersion: "0.4.5",
    source: "contract SingleNumRegister {    uint storedData;    function set(uint x) {        storedData = x;    }    function get() constant returns (uint retVal) {        return storedData;    }}", ← 生コード
    userDoc: {
      methods: {}
    }
  }
}

バイトコード長

> contract.code.length
240

Contract をトランザクションに乗せる

※Contract をトランザクション送信するためには送信元アカウントが必要であり、
また、トランザクション送信のためにはいくらかの ether を消費するため、それに必要な残高を持っている必要がある。

> personal.unlockAccount(eth.accounts[0])
Unlock account 0x1c4cfba7ba14d299acbe41ebf7a4bdac7e3d2194
Passphrase: ← パスフレーズ入力
true

> txhash = eth.sendTransaction({from: eth.accounts[0], data: contract.code})
"0xef17aef017bbcb27fa1f6985eae9cbca3141562e0c426591dcd913558a921e17" ← トランザクション識別子

登録済み Contract の情報確認

sendTransaction を行った直後ではまだアドレスは存在しない。採掘が進むことによりトランザクションはブロックに取り込まれ、アドレスが割り当てられる。

> contractReceipt = eth.getTransactionReceipt(txhash)
null

採掘が進み、アドレスが確定した状態↓

> contractReceipt = eth.getTransactionReceipt(txhash)
{
  blockHash: "0xac2da73d8af735562a2f8384d4eabd5bbb8f220e0e1e1068e6eb5a8f76958240", ← ブロック識別子
  blockNumber: 14824, ← ブロック番号
  contractAddress: "0x23eaac2891b2b582c1b070f135efda0daa785b66", ← Contract のアドレス
  cumulativeGasUsed: 47855,
  from: "0x1c4cfba7ba14d299acbe41ebf7a4bdac7e3d2194", ← 送信元アカウント
  gasUsed: 47855,
  logs: [],
  logsBloom: "0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000",
  root: "0x348986b2c5201ca61d0efd17b5a3ec65362a82e55a15903841abd6139b92763f",
  to: null,
  transactionHash: "0xef17aef017bbcb27fa1f6985eae9cbca3141562e0c426591dcd913558a921e17", ← トランザクション識別子
  transactionIndex: 0
}

Contract へ情報を送る

登録済み Contract へ情報を送るために必要なパラメータは以下の2つ。

> contractAddress = contractReceipt.contractAddress
"0x23eaac2891b2b582c1b070f135efda0daa785b66" ← Contract のアドレス

> contractAbi = contract.info.abiDefinition ← Contract の ABI (Application Binary Interface)
[{
    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"
}]

上記2つを用いて Contract の実体にアクセスします。

> contractInstance = eth.contract(contractAbi).at(contractAddress)
{
  abi: [{
      constant: false,
      inputs: [{...}],
      name: "set",
      outputs: [],
      payable: false,
      type: "function"
  }, {
      constant: true,
      inputs: [],
      name: "get",
      outputs: [{...}],
      payable: false,
      type: "function"
  }],
  address: "0x23eaac2891b2b582c1b070f135efda0daa785b66",
  transactionHash: null,
  allEvents: function(),
  get: function(),
  set: function()
}

 
※Contract に情報を送信するためには送信元アカウントが必要であり、
また、情報送信のためにはいくらかの ether を消費するため、それに必要な残高を持っている必要がある。

情報送信

> personal.unlockAccount(eth.accounts[0])
Unlock account 0x1c4cfba7ba14d299acbe41ebf7a4bdac7e3d2194
Passphrase: ← パスフレーズ入力
true

> txhash20 = contractInstance.set.sendTransaction(20, {from: eth.accounts[0]}) … 今回は 20 という数値をこの Contract に送ってみる
"0x10ca4a20fd25147a26c7554acfed1e4311e8cb3c1028b166ab320c78ff5910e3" … トランザクション識別子

採掘が進んでいない状態ではまだ結果には反映されない。

> contractInstance.get()
0

採掘が進んだ後

> contractInstance.get()
20 ← 指定の数値が代入された

> contractInstance
{
  abi: [{
      constant: false,
      inputs: [{...}],
      name: "set",
      outputs: [],
      payable: false,
      type: "function"
  }, {
      constant: true,
      inputs: [],
      name: "get",
      outputs: [{...}],
      payable: false,
      type: "function"
  }],
  address: "0x23eaac2891b2b582c1b070f135efda0daa785b66",
  transactionHash: null,
  allEvents: function(),
  get: function(),
  set: function()
}

> eth.getTransaction(txhash20) ← トランザクション詳細
{
  blockHash: "0x8ae42253387db4ebf9556ad1022822562d7b0ef07ad1eb422815e8edcd369536",
  blockNumber: 14825,
  from: "0x1c4cfba7ba14d299acbe41ebf7a4bdac7e3d2194",
  gas: 90000,
  gasPrice: 20000000000,
  hash: "0x10ca4a20fd25147a26c7554acfed1e4311e8cb3c1028b166ab320c78ff5910e3",
  input: "0x60fe47b10000000000000000000000000000000000000000000000000000000000000014",
  nonce: 1,
  r: "0x6655109bf2a780e229fbe0637a61f3342b0678c7a0c65a364390af87acb8fb75",
  s: "0x1d28d723c5016b5eff51e02f4abb66245e2309fbc4d0a3f67e092f0b2bbeb53f",
  to: "0x23eaac2891b2b582c1b070f135efda0daa785b66",
  transactionIndex: 0,
  v: "0x1b",
  value: 0
}