Ethereum(19) - IoTで利用するスイッチを制御するコントラクト(実装編)

スマートコントラクトはIoTの領域でも活用が期待されています。

カーシェアリングを例にとってみます。

カーシェアリングでは、利用者は車を利用するたびに利用時間に応じた金額を支払う必要があります。

スマートコントラクトを使うと、そのコントラクトに送金することで車が送金状況を確認してドアを自動で開けるようなことが可能になります。

実装

IoTで利用するスイッチを制御するコントラクトを実装します。

[ソースコード]

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
pragma solidity ^0.4.11;
contract SmartSwitch {
// スイッチ用の構造体
struct Switch {
address addr; // 利用者のアドレス
uint endTime; // 利用終了時刻(UnixTime)
bool status; // trueの場合は利用可能
}

address public owner; // サービスオーナーのアドレス
address public iot; // IoTのアドレス

mapping (uint => Switch) public switches; // Switchを格納するマップ
uint public numPaid; // 支払いが行われた回数

/// サービスオーナーの権限チェック
modifier onlyOwner() {
require(msg.sender == owner);
_;
}

/// IoTの権限チェック
modifier onlyIoT() {
require(msg.sender == iot);
_;
}

/// コンストラクタ
/// IoTのアドレスを登録
function SmartSwitch(address _iot) {
owner = msg.sender;
iot = _iot;
numPaid = 0;
}

/// 支払い時に呼ばれる
function payToSwitch() public payable {
// 1 etherでなければ処理を終了
require(msg.value == 1000000000000000000);

// Switchを設定
Switch s = switches[numPaid++];
s.addr = msg.sender;
s.endTime = now + 300; // 300秒⇒5分使用可能にする
s.status = true;
}

/// statusを変更する
/// 利用終了時刻になったら呼び出される。引数はswitchesのkey値
function updateStatus(uint _index) public onlyIoT {
// 対象のindexに対してSwitchが設定されていなければ処理を終了
require(switches[_index].addr != 0);

// 利用終了時刻に達していなければ処理を終了
require(now > switches[_index].endTime);

// statusを更新
switches[_index].status = false;
}

/// 支払われたetherを引き出す
function withdrawFunds() public onlyOwner {
if (!owner.send(this.balance))
throw;
}

/// コントラクトを破棄
function kill() public onlyOwner {
selfdestruct(owner);
}
}

このコンストラクトの仕様は次の通りです。

  • サービスオーナーがコンストラクタでIoTスイッチを登録します。
  • IoTスイッチの利用者はpayToSwitch関数でetherを支払います。
    1etherを支払うと5分間使用できるIoTスイッチを想定しています。
  • IoTスイッチは利用終了時刻になるとupdateStatus関数でstatusを更新してサービスを利用できなくします。
  • サービスオーナーはwithdrawFunds関数をコールし、支払われたetherを引き出すことができます。

次回から、このスマートコントラクトの動作を確認していきます。

Ethereum(18) - コントラクト名とアドレスを管理するスマートコントラクト(実行編②)

前回は、コントラクト名とアドレスを管理するスマートコントラクトの動作確認をMist Walletを使って実施しましたがうまくいきませんでした。

今回は、gethコンソールを使って動作確認を行ってみます。

事前準備

動作確認を行うために、下記のような準備をしておきます。

  • geth起動
  • マイニング開始
  • スマートコントラクトをデプロイ

コンストラクト名の登録

まずはコントラクト名の登録を行います。登録するコントラクト名はcon1です。

登録する前に、アドレスのロックを解除する必要があります。

[コントラクト名の登録]

1
2
3
4
5
6
7
> personal.unlockAccount(eth.accounts[0])
Unlock account 0xec3b01f36b44182746ca109230567c4915512e35
Passphrase:
true

> nr.register.sendTransaction("con1",{from:eth.accounts[0], gas:5000000})
"0xc81cfecc89a0f698859249eb03a7a2b8560cdea437dcfa7df4a90bcfc5a11ea2"

問題なくトランザクションを発行できました。

ブロックに取り込まれるまで少し待って登録内容を確認します。

[登録内容の確認]

1
2
3
4
5
6
7
8
> nr.numContracts()
1

> nr.getOwner("con1")
"0xec3b01f36b44182746ca109230567c4915512e35"

> eth.accounts[0]
"0xec3b01f36b44182746ca109230567c4915512e35"

コントラクト名が1つ登録され、登録されたコントラクト名のオーナーアドレス(eth.accounts[0])であることが分かります。

アドレスの登録

次にコンストラクタ名にアドレスを結びつけます。

登録するアドレス情報はダミーです。

[アドレスの登録]

1
2
> nr.setAddr.sendTransaction("con1", "0xAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA",{from:eth.accounts[0], gas:5000000})
"0x68df1e01241aa57f5e12ba5f419400b03bbb6b993d95b8d9294ea9396ed76667"

問題なくトランザクションを発行できました。

ブロックに取り込まれるまで少し待って登録内容を確認します。

[登録内容の確認]

1
2
> nr.getAddr("con1")
"0x00000000aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"

問題なくアドレスが登録されています。

説明の登録

コントラクト名に対応する説明を登録します。

[説明の登録]

1
2
> nr.setDescription.sendTransaction("con1", "This is description of con1.",{from:eth.accounts[0], gas:5000000})
"0xe838840f9e5f8e37414b731a0d0a9065c6b0fdab04f10f6692570d6aa4f92bf4"

問題なくトランザクションを発行できました。

ブロックに取り込まれるまで少し待って登録内容を確認します。

[登録内容の確認]

1
2
3
4
5
> nr.getDescription("con1")
"0x54686973206973206465736372697074696f6e206f6620636f6e312e00000000"

> web3.toUtf8(nr.getDescription("con1"))
"This is description of con1."

こちらも問題なく登録されていることを確認できました。

オーナーの変更

オーナーの変更を行います。

accounts[0]からaccounts[1]へ変更します。

[オーナーの変更]

1
2
> nr.changeOwner.sendTransaction("con1", eth.accounts[1],{from:eth.accounts[0], gas:5000000})
"0x905b2a21fd1741b51c86fd11b56cae0b68b9e04985ae69473601ddabfda7ce3f"

問題なくトランザクションを発行できました。

ブロックに取り込まれるまで少し待って変更内容を確認します。

[オーナーの変更]

1
2
3
4
5
> nr.getOwner("con1")
"0x63f25b9bbd974fdfa07477cb99c60d2073cfe560"

> eth.accounts[1]
"0x63f25b9bbd974fdfa07477cb99c60d2073cfe560"

オーナー情報がeth.accounts[1]のアドレスに変更されていることを確認できました。

登録内容の解除

最後に登録内容の解除を行います。

オーナーがeth.accounts[1]に変更されているので、そのアドレスのロックを解除しておく必要があります。

[登録解除]

1
2
3
4
5
6
7
> personal.unlockAccount(eth.accounts[1])
Unlock account 0x63f25b9bbd974fdfa07477cb99c60d2073cfe560
Passphrase:
true

> nr.unregister.sendTransaction("con1",{from:eth.accounts[1], gas:5000000})
"0x9615b4f95c35c771f2b8f07dd7d1ebb61172497f0096a01dbeb6e3552f684ca1"

問題なくトランザクションを発行できました。

ブロックに取り込まれるまで少し待って内容を確認します。

[解除内容確認]

1
2
> nr.numContracts()
0

登録されているコントラクトがなくなっていることを確認できます。

前回Mist Walletでうまくいかなかった理由

gethコンソールでの動作確認では全く問題がありませんでした。

ではどうしてMist Walletでは同じコントラクタの動作確認ができなかったのでしょうか?

gethコンソールで正常に動作確認している最中に、Mist Walletでもコントラクト情報を参照してみたのですが、情報が全く反映されていませんでした・・・いやNum Contractsだけはきちんと反映されてました。

また、Mist Walletで各登録処理を行ってみたところ、Mist Wallet画面では登録内容が確認できませんでしたが、gethコンソール上では登録内容の確認ができました

つまりMist Walletだと構造体のステートや引数のある関数の情報は表示できないということになります。

まとめて情報を参照できるMist Walletは大変便利だと思っていたのですが、ちょっと残念です。


次回は、また別のスマートコントラクトを作成していきたいと思います。


Your browser is out-of-date!

Update your browser to view this website correctly. Update my browser now

×