LearnSolidity4 — CrowdSensing

Solidity学习笔记(4) — Crowdsensing

作者:孔令坤,转载请注明出处

在本文中,我开发了一个使用区块链来做群智感知系统的智能合约。其中,区块链代替了传统的集中式第三方机构,给用户们提供了一个更加安全,更加经济的发布群智感知任务的平台。

1.背景介绍

群智感知即利用目前普及化的移动设备有效地收集数据,在近年来已经引起了人们的广泛兴趣并出现了大量的工程应用。

然而,大多数现有的群智感知系统都依赖于中央服务器,这些服务器受传统基于信任模型的缺陷的影响,容易发生单点故障和隐私泄露的问题。另外,在考虑到恶意用户存在的情况下,这些系统容易遭受分布式拒绝服务(DDoS)和Sybil攻击。此外,群智感知平台收取的高额服务费可能会阻碍这项技术的发展。如何解决这些潜在问题仍然是一个巨大的挑战。

本文提出了一种基于区块链的群智感知应用方案。我们希望借助区块链的科技,将存储、处理数据的数据平台去中心化,提供一种更加安全,并且更加经济的选择。具体而言,我们希望能借助区块链系统,让矿工代替中心化的数据管理平台,并帮助处理来自数据提供方的信息,从而确保用户信息的安全性。同时,由于这个时候数据需求者仅仅需要给矿工和用户提供相应的挖矿和上传数据的报酬,不需经过中心化数据管理平台,从而在经济上有了更多的选择,也避免了由于中心化数据管理平台的垄断而被索取高额的数据提供费用。

2.具体实现

在实际的工程应用中,我们使用智能合约(smart contract)开发出了基于区块链的群智感知系统的框架。

如上图所示,图中的数字标号简单记录了在一次大数据分享任务中整个框架的流程顺序。其中流程标号2*代表此流程2*可以与流程2同步进行,而流程标号x表示此流程可以在流程2后的任意时刻执行。另外,图中的实线代表了必然会发生的流程,而虚线代表了可能在框架流程执行中并不会被执行的流程。

3.核心代码

本文利用一个感知学校wifi信号强度的例子来介绍如何开发类似的群智感知智能合约。

需要注意的是,这里我对核心代码进行了大量的化简,比如忽略了数据提供方对原始数据的加密以及数据需求方广播程序的代码。所以,以下的代码仅仅是一个帮助学习smart contract的例子。

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
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
pragma solidity ^0.4.21;

contract SensingWifi{
uint public rewardUnit;
uint public rewardNum;
uint public dataCount;
bytes32 public wifiName;
address public requester;
enum State {Uncreated, Created, Inactive}
State public state;

mapping(bytes32 => string) dataStatuses; // Either '' or 'Committed'

modifier condition(bool _condition) {
require(_condition);
_;
}

modifier onlyRequester() {
require(msg.sender == requester);
_;
}

modifier inState(State _state) {
require(state == _state);
_;
}

event Aborted();
event TaskInited();
event DataCommited(bytes32 l, bytes32 w, int s);
event TaskDone();

// The requester initiates the task.
// He needs to set the value of rewards for each sensing data,
// as well as the maximum number of data he requires.
function initTask(uint _rewardUnit, uint _rewardNum, bytes32 _wifiName)
public
inState(State.Uncreated)
condition(msg.value >= _rewardUnit * _rewardNum)
payable
{
requester = msg.sender;
rewardUnit = _rewardUnit; // wei
rewardNum = _rewardNum;
wifiName = _wifiName;
state = State.Created;
emit TaskInited();

}

// Abort the Task and reclaim the ether,
// Can only be called by the requester.
function abort()
public
onlyRequester
inState(State.Created)
{
require(dataCount <= rewardNum);
state = State.Inactive;
requester.transfer(this.balance);
emit Aborted();
}

// The worker undertakes the task by obtaining and sending his sensing data,
// such as {"Student Dorm 13", "SJTU", -51}
function commitTask(bytes32 _location, bytes32 _wifiName, int _signalDegree)
public
inState(State.Created)
{
require(dataCount < rewardNum);
bytes memory sensingDataCommit = bytes(dataStatuses[_location]);
// The requester wants to get data from different location.
require(sensingDataCommit.length == 0);

// Make sure that the wifi signal sensed is exactly what requester wants.
require(wifiName == _wifiName);

// The theoretical maximum value of signal strength is -30 dBm.
require(_signalDegree < -30);

dataStatuses[_location] = "Committed";

dataCount += 1;
if(dataCount == rewardNum){
state = State.Inactive;
requester.transfer(this.balance);
emit TaskDone();
}
msg.sender.transfer(rewardUnit);

// The requster collects sensing data by
// listening the log info of DataCommited.
emit DataCommited(_location, _wifiName, _signalDegree);
}
}