PlatON Cross| PlatON上的WASM智能合约开发(三)——事件机制

本文转载自微信公众号 PlatON Cross

原创作者:PlatON Cross小编

PlatON Cross| PlatON上的WASM智能合约开发(三)——事件机制

智能合约是部署在区块链上 DApp 生态应用的“后台”,DApp 客户端程序在与合约协同工作时,必然会涉及到消息的交互,这些消息可能是所请求的数据、处理结果、控制指令等。交互方式包括同步调用(CONST)类型的接口,这类接口不能改变链上的状态,可直接获取到处理返回值;异步调用(ACTION)类型的接口,这些接口需要通过发送交易完成调用,可以改变链上的状态。事件机制一般在ACTION类型的接口中使用(CONST类型接口中也可使用事件机制),调用返回值可通过事件的emit发送出来,使用者可通过异步调用获取到处理结果。

区块链是去中心化的系统,智能合约也是链上状态的一种,每个节点都保存了链上的状态。本质上,CONST类型的接口,其执行实际是在client注册的节点上直接执行的(因为不会修改链上状态);而ACTION类型的接口,由于会修改链上状态,因此需要通过发起交易,由链上打包该交易的共识节点来执行。

WASM合约的事件机制

#include <platon/platon.hpp>

#include <string>

#include <vector>

using namespace std;

class inputParams

{

public:

    inputParams(){}

    inputParams(std::vector<int> vParams)

    {

        myParams = vParams;

    }

public:

    std::vector<int> myParams;

    PLATON_SERIALIZE(inputParams, (myParams))

};

CONTRACT simpleOps: public platon::Contract{

public:

    //PLATON事件机制,这里采用EVENT1,需要在事件名称后面,包含一个std::string类型的topic_type

    PLATON_EVENT1(Add, std::string, uint32_t)

    PLATON_EVENT1(call2, std::string, int)

    PLATON_EVENT1(put, std::string, int)

    PLATON_EVENT1(clear, std::string, uint32_t)

    ACTION void init(const inputParams& ipa){

        iParams.self() = ipa;

    }

    CONST std::vector<int> getParams(){

        return iParams.self().myParams;

    }

    CONST int makeCall(){

        std::vector<int> params = iParams.self().myParams;

        int rst = 0;

        for (auto itr = params.begin(); itr != params.end(); ++itr)

        {

            rst += *itr;

        }

        return rst;

    }

    ACTION void putElement(int ele){

        iParams.self().myParams.push_back(ele);

        //emit事件,在sdk中可以捕捉该事件,一般可将需要传递的信息作为第三个参数

        PLATON_EMIT_EVENT1(put, “putElement” , ele);

    }

    ACTION void clearElement(){

        if (!iParams.self().myParams.empty())

        {

            iParams.self().myParams.clear();

        }

        uint32_t returnValue = 73;

        PLATON_EMIT_EVENT1(clear, “clearElement” , returnValue);

    }

    ACTION int AddCalc(){

        int rst = 0;

        for (auto itr = iParams.self().myParams.begin(); itr != iParams.self().myParams.end(); ++itr)

        {

            rst += *itr;

        }

        PLATON_EMIT_EVENT1(Add, “AddCalc”, rst);

        return rst;

    }

    CONST int makeCall2(int a, int b){

        int c = a + b;

        PLATON_EMIT_EVENT1(call2, “makeCall2”, c);

        return c;

    }

private:

    platon::StorageType<“Params”_n, inputParams> iParams;

};

//platon wasm合约的外部入口

PLATON_DISPATCH(simpleOps, (init)(getParams)(makeCall)(putElement)(clearElement)(AddCalc)(makeCall2))

说明:

1)合约源文件名为main.cpp;

2)PlatON提供了四种合约事件:PLATON_EVENT0、PLATON_EVENT1、PLATON_EVENT2、PLATON_EVENT3,其区别在于需要输入的topic_type的数量,本文中的合约采用了PLATON_EVENT1,仅需要1个std::string类型的topic_type;

3)上面的WASM合约非常简单,具有一定的代表性,可保存多个int型的元素,提供对这些元素求和的操作接口。


在platon-truffle进行合约部署与调用

● 合约部署

PlatON Cross| PlatON上的WASM智能合约开发(三)——事件机制

说明:

1)合约需要编译和部署后才能使用,编译和部署方式详见https://mp.weixin.qq.com/s/66mdamOzGBYGrNy09m_GHg,这里需要注意的是,init方法需要传入inputParams类型,而inputParams的构造函数需要传入std::vector<int> vParams作为参数,因此在部署合约时,需要以'[[[73, 8]]]’做为初始化参数;

2)部署成功的信息如上图中所示。

● 创建合约对象实例

PlatON Cross| PlatON上的WASM智能合约开发(三)——事件机制

说明:

1)创建合约对象实例需要abi、合约地址、合约类型作为参数,{vmType:1}表示所创建的是wasm合约;

2)创建成功后,在console中调用getParams接口,可以看到当前存在的元素为部署合约是传入的初始化元素集合。

● 调用接口(向合约中插入元素)

PlatON Cross| PlatON上的WASM智能合约开发(三)——事件机制

说明:

1)调用putElement,插入元素;

2)当交易尚未完成时,虽然插入操作已经返回,但链上状态尚未改变。

● 执行加法操作(AddCalc、makeCall、makeCall2)

PlatON Cross| PlatON上的WASM智能合约开发(三)——事件机制

说明:

1)AddCalc属于ACTION接口(需要通过交易完成),执行了求元素和的操作,但其结果无法直接通过取返回值获得;

2)makeCall和makeCall2属于CONST接口,执行后可直接通过返回值获得结果。

在platon-truffle中能够进行基本的操作。捕捉到事件中真正想要的信息,这一点需要通过client-sdk实现。注:通过node.js的SDK使用事件机制,需要采用websocket连接。


在 client-sdk 中进行合约调用,使用事件机制

注:本文的用例都基于 python 的 client-sdk 进行编写,关于 python SDK 的官方文档参见:

https://devdocs.platon.network/docs/zh-CN/Python_SDK/

● 需要导入的模块如下

from client_sdk_python import Web3, HTTPProvider, WebsocketProvider

from client_sdk_python.eth import PlatON

from hexbytes import HexBytes

● 执行 clear 操作,清空合约上的列表,并捕获 clear 事件

def testClear():

    w3 = Web3(HTTPProvider(“http://47.105.180.114:6789”))

    platon = PlatON(w3)

hello = platon.wasmcontract(address=contractAddr, abi=cabi,vmtype=1)

 tx_hash = hello.functions.clearElement().transact({‘from’: from_address, ‘gas’: 999999})

    tx_receipt = platon.waitForTransactionReceipt(tx_hash)

    topic_param = hello.events.clear().processReceipt(tx_receipt)

    print(topic_param)

说明:

1)tx_hash为交易哈希值,通过它可以获取到tx_receipt交易收据,交易收据用于获取事件主题名称以及事件值;

2)topic_param的具体形式如下文输出所示;

3)由于涉及到交易的合约调用,需要通过waitForTransactionReceipt来等待相关交易的完成;

4)clear()即为想要捕获的事件。输出:

(AttributeDict({‘args’: AttributeDict({‘topic’: ‘clearElement’, ‘arg1’: 73}), ‘event’: ‘clear’, ‘logIndex’: 0, ‘transactionIndex’: 0, ‘transactionHash’: HexBytes(‘0x988c09572de8af93884daf2ed00a701835d3e9029fd780e3ed9ef5c5201b46dd’), ‘address’: ‘lat1ktum8z9m9j4pz0l0gytqqrfgt8uv9sxnptxg9d’, ‘blockHash’: HexBytes(‘0xa8595637bf8c5a12038a3c06cae28726f83f36201fec6270599a5a0d9ade432f’), ‘blockNumber’: 4689207}),)

说明:

1)”‘arg1’: 73″即为捕获的clear事件中,传递出来的我们感兴趣的结果;

2)”‘topic’: ‘clearElement'”为返回的事件topic_type。

● 执行putElement向合约插入元素,通过事件返回所插入的值

def testOps():

    w3 = Web3(HTTPProvider(“http://47.105.180.114:6789”))

    platon = PlatON(w3)

    hello = platon.wasmcontract(address=contractAddr, abi=cabi,vmtype=1)

    tx_hash = hello.functions.putElement(11).transact({‘from’: from_address, ‘gas’: 999999})

    tx_receipt = platon.waitForTransactionReceipt(tx_hash)

    topic_param = hello.events.put().processReceipt(tx_receipt)

    print(topic_param)

说明:

    通过捕获”put”事件,获取合约调用所传递出来的我们感兴趣的结果。

输出:

PlatON Cross| PlatON上的WASM智能合约开发(三)——事件机制

说明:

    在本用例中,三次调用了putElement操作,分别传入了数值13、12、11。

● 调用AddCalc操作,计算元素的和

def testAdd():

    w3 = Web3(HTTPProvider(“http://47.105.180.114:6789”))

    platon = PlatON(w3)

    hello = platon.wasmcontract(address=contractAddr, abi=cabi,vmtype=1)

    tx_hash = hello.functions.AddCalc().transact({‘from’: from_address, ‘gas’: 999999})

    tx_receipt = platon.waitForTransactionReceipt(tx_hash)

    topic_param = hello.events.Add().processReceipt(tx_receipt)

    print(topic_param)

说明:

    实际上,在执行完hello.functions.AddCalc().transact(…)后,可以根据自身业务需求,进行其他操作,并行等待waitForTransactionReceipt(…)的执行,成功后可通过事件”Add”获取执行结果。

输出:

(AttributeDict({‘args’: AttributeDict({‘topic’: ‘AddCalc’, ‘arg1’: 36}), ‘event’: ‘Add’, ‘logIndex’: 0, ‘transactionIndex’: 0, ‘transactionHash’: HexBytes(‘0x9a609d616de9d1243ca75fac8e41268e9b83744418460080fafb38bb1a63b0f9’), ‘address’: ‘lat1ktum8z9m9j4pz0l0gytqqrfgt8uv9sxnptxg9d’, ‘blockHash’: HexBytes(‘0x566e03fa9a8581945c53970ea18ba769502d29bfdecda5c50a5437b68f029463’), ‘blockNumber’: 4690710}),)

说明:

    事件中获取的”‘arg1’: 36″,为事件传递信息中用户感兴趣的结果,在本例中为元素的和。


目前,PlatON官方正在对python的client sdk进行持续的优化,相信未来将能够更加高效的支撑多样化应用生态的开发!

本文转载自https://mp.weixin.qq.com/s/pqymU4G9sF1xYo2UgwR7dw

(0)
PlatON Cross的头像PlatON Cross编辑
上一篇 7 5 月, 2021 16:50
下一篇 8 5 月, 2021 15:23

相关推荐

发表回复

登录后才能评论