智能合约开发 - 如何更好的与合约交互

我们从一个简单的例子开始:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
pragma solidity ^0.4.0;

contract Calc{
uint count;

function add(uint a, uint b) returns(uint){
count++;
return a + b;
}

function getCount() constant returns (uint){
return count;
}
}

上面是 Solidity 智能合约,我们将合约编译发布后,会通过 web3.js 调用,如调用 getCount()

1
myContract.getCount.call()

web3.js 可以很方便的调用 json-rpc 接口来获得想要的数据,或者发起交易。

不过如果要进一步开发产品的话,会发现只依赖现存的一些调用函数会比较麻烦,举个例子:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
pragma solidity ^0.4.0;

contract Item{
mapping(address => uint256[]) public ownedItems;

function ListItem() returns(mapping){
return ownedItems[msg.sender];
}

function addItem(_itemId) returns (uint256){
ownedItems[msg.sender].push(_itemId);
return _itemId
}
}

如果我们先获得某个地址的 item, 可以通过函数 Item.ListItem.call() 获得数据,前端获得数据后展示即可。但需求加上根据条件过滤出 item,根据个人喜好推荐 item,这些原本在传统开发中很容易实现的功能,在智能合约的交互中会变的相对麻烦。

这里面我提供一种思路供大家参考,利用智能合约的 event 事件来同步数据。

event 也可以称为日志,是交易收据(Transaction Receipts)的一部分,他可以用来异步通知客户端交易的执行结果。

1
2
3
4
5
6
7
8
9
10
11
12
13
pragma solidity ^0.4.0;

contract Item{
mapping(address => uint256[]) public ownedItems;

event AddItem(address, itemID); // event

function addItem(_itemId) returns (uint256){
ownedItems[msg.sender].push(_itemId);
AddItem(msg.sender, _itemId);
return _itemId;
}
}

比如我们可以加个 AddItem 的事件,然后客户端监听事件结果,同步数据到 server 端,server 端保存到数据库后,可以根据需求开发 http 接口供前端调用,如过滤前三个月的,根据浏览量排行。

1
2
3
4
5
6
7
def handle(self, *args, **options):
event_filter = w3.eth.filter({"address": contract_address})
poll_interval = 2
while True:
for event in event_filter.get_new_entries():
handle_event(event)
time.sleep(poll_interval)

event 可以给参数加 indexed 属性,这样这些参数值会存到日志结构的 topic 部分,有助于过滤和查找。

参考链接:

  1. http://me.tryblockchain.org/blockchain-solidity-event.html
  2. http://web3.tryblockchain.org/web3-js-in-action.html