知世金融网专注于股票行情,期货开户,外汇储备等最新相关资讯信息提供投资者参考学习!

当前位置:网站首页 > 区块链 > 正文

本体技术视点 | 使用C++进行Wasm合约开发

原创
文章作者
知世-金融领域资深作者
知名金融领域作者,从事金融超过十余年,在行业内有一定影响力。
金融风险管理师认证证书 常识职业资格认证 特许金融分析师 国际金融理财师认证证书
发布时间:2020-02-16 18:35:59 发布来源:本体研究院 文章点击:96

Ontology Wasm 自从上线测试网以来便受到了社区开发人员的极大关注。Ontology Wasm 的上线将使得业务逻辑复杂的 dApp 合约上链成本降低,极大丰富 dApp 生态。在进行 Ontology Wasm 合约开发时,...

目录

    本文标题本体技术视点 | 使用C++进行Wasm合约开发,作者:知世,本文有2612个文字,大小约为10KB,预计阅读时间7分钟,请您欣赏。知世金融网众多优秀文章,如果想要浏览更多相关文章,请使用网站导航的搜索进行搜索。本站虽然不乏优秀之作,但仅作为投资者学习参考。

    Ontology Wasm 自从上线测试网以来便受到了社区开发人员的极大关注。Ontology Wasm 的上线将使得业务逻辑复杂的 dApp 合约上链成本降低,极大丰富 dApp 生态。在进行 Ontology Wasm 合约开发时,开发者不仅可以使用 Rust,还可以使用 C++ 作为合约开发语言。本期我们将通过两个简单的示例来示范如何使用 C++ 进行Ontology Wasm 合约开发。

    一、Hello World

    按照惯例,我们还是从一个 Hello world 开始

    #include<ontiolib/ontio.hpp>#include<stdio.h>
    using namespace ontio;class hello:public contract {
    public:
    using contract::contract:
    void sayHello(){
    printf("hello world!");
    }
    };
    ONTIO_DISPATCH(hello, (sayHello));

    1.1 合约入口

    Ontology Wasm CDT 编译器已经对入口和参数解析进行了封装,所以开发者不需要重新定义入口方法。接下来是定义合约的对外接口,这是智能合约对外提供服务的方法。

    ONTIO_DISPATCH(hello, (sayHello));

    在上面的例子中, 我们暂时只支持 sayHello 这个方法:

    printf("hello world!");

    这个“Hello world!”会在节点的日志中以调试信息打印出来。在实际的应用中, printf 只能用作调试的目的, 一个实际的智能合约,需要实现更多更复杂的功能。

    1.2 智能合约 API

    Ontology Wasm 提供如下 API 与区块链的底层进行交互:

    二、红包合约

    下面我们通过一个更加复杂的例子来演示如何通过这些 API 来开发一个完整的 Wasm 智能合约。

    很多情况下我们都会通过各种 App,如微信等聊天工具发红包。我们可以给朋友发送红包,也可以抢其他人发送的红包,收到的钱会记入到个人微信账户中。

    类似于微信的流程,我们将尝试创建一个智能合约。用户使用该合约,可以发送 ONT,ONG 或者是标准的 OEP-4的 Token 资产红包给他的朋友们,而朋友们抢到的红包可以直接转入到他们的钱包账户中。

    2.1 创建合约

    首先,我们需要新建合约的源文件,暂且命名为 redEnvelope.cpp。这个合约我们需要三个接口:

    · createRedEnvelope: 创建红包
    · queryEnvelope: 查询红包信息
    · claimEnvelope: 抢红包

    #include<ontiolib/ontio.hpp>
    using namespace ontio;
    class redEnvelope: public contract{
    }
    ONTIO_DISPATCH(redEnvelope, (createRedEnvelope)(queryEnvelope)(claimEnvelope));

    我们需要在存储中保存一些关键的数据。在智能合约中, 数据以 KV 的形式保存在该合约的上下文空间中,这些数据的 KEY 需要设置前缀以便于后面的查询。下面定义了三个不同的前缀供使用:

    std::string rePrefix = "RE_PREFIX_";
    std::string sentPrefix = "SENT_COUNT_";
    std::string claimPrefix = "CLAIM_PREFIX_";

    因为我们的合约支持 ONT 和 ONG 这两种 Ontology 的原生资产, 我们可以预先定义好这两种资产的合约地址。不同于标准的智能合约, Ontology 原生合约(native contract)的合约地址是固定的,而不是根据合约代码的 hash 计算而来的。

    address ONTAddress = {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1};
    address ONGAddress = {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2};

    我们需要在合约中保存红包的信息, 如红包的资产信息(token 的合约地址, 红包的总金额, 红包的个数等等)。

    struct receiveRecord{
    address account; //用户地址
    asset amount; //抢到的金额
    ONTLIB_SERIALIZE(receiveRecord,(account)(amount))
    };
    struct EnvelopeStruct{
    address tokenAddress; //资产token的地址
    asset totalAmount; //红包总金额
    asset totalPackageCount; //红包总数
    asset remainAmount; //当前剩余的金额
    asset remainPackageCount; //当前剩余的红包数
    std::vector<struct receiveRecord> records; //已经抢完的记录
    ONTLIB_SERIALIZE( EnvelopeStruct, (tokenAddress)(totalAmount)(totalPackageCount)(remainAmount)(remainPackageCount)(records) )
    };

    其中,

    ONTLIB_SERIALIZE(receiveRecord,(account)(amount))

    是由 Ontology Wasm CDT 定义的宏操作,用于在将 struct 存储前进行序列化的操作。

    2.2 创建红包

    准备工作差不多了,下面我们开始开发具体的接口逻辑。

    1. 创建红包需要指定创建者地址, 红包数量, 红包金额和资产的合约地址:

    bool createRedEnvelope(address owner,asset packcount, asset amount,address tokenAddr ){
    return true;
    }

    2. 检查是否有创建者的签名, 否则交易回滚退出:

    ontio_assert(check_witness(owner),"checkwitness failed");

    NOTE: ontio_assert(expr, errormsg):当 expr 为 false 时, 抛出异常并退出。

    3. 如果红包资产是 ONT,由于 ONT 的不可分割性(最小为1个 ONT), 红包的金额要大于或等于红包的数量,保证每个红包最少有1个 ONT:

    if (isONTToken(tokenAddr)){
    ontio_assert(amount >= packcount,"ont amount should greater than packcount");
    }

    4. 对于每个红包的创建者,我们需要记录一下他发送红包的总数量:

    key sentkey = make_key(sentPrefix,owner.tohexstring());
    asset sentcount = 0;
    storage_get(sentkey,sentcount);
    sentcount += 1;
    storage_put(sentkey,sentcount);

    5. 生成红包 hash, 这个 hash 就是之后标识这个红包的唯一 ID:

    H256 hash ;
    hash256(make_key(owner,sentcount),hash) ;
    key rekey = make_key(rePrefix,hash256ToHexstring(hash));

    6. 根据 token 资产的类型,将资产转入合约中,self_address()可以取得当前执行的合约地址, 我们根据用户输入的 token 类型,将指定数量的 token 转入合约:

    address selfaddr = self_address();
    if (isONTToken(tokenAddr)){
    bool result = ont::transfer(owner,selfaddr ,amount);
    ontio_assert(result,"transfer native token failed!");
    }else if (isONGToken(tokenAddr)){
    bool result = ong::transfer(owner,selfaddr ,amount);
    ontio_assert(result,"transfer native token failed!");
    }else{
    std::vector<char> params = pack(std::string("transfer"),owner,selfaddr,amount);
    bool res;
    call_contract(tokenAddr,params, res );
    ontio_assert(res,"transfer oep4 token failed!");
    }

    NOTE 1:对于 ONT 和 ONG 这两种原生资产, Ontology Wasm CDT 提供了ont::transfer API 进行转账操作;而 OEP-4类的资产,需要按照普通的跨合约调用方法来转账。

    NOTE 2:和普通的钱包地址一样, 合约地址也可以接受任意类型的资产。但是合约地址是由合约编译后的二进制代码 hash 产生的,所以没有对应的私钥,也就无法随意操作合约中的资产,如果你没有在合约中设置对资产的操作,就意味着你将无法控制这部分资产。

    7. 将合约的信息保存在存储中:

    struct EnvelopeStruct es ;
    es.tokenAddress = tokenAddr;
    es.totalAmount = amount;
    es.totalPackageCount = packcount;
    es.remainAmount = amount;
    es.remainPackageCount = packcount;
    es.records = {};
    storage_put(rekey, es);

    8. 发送创建红包的事件。对于智能合约的调用是一个异步的过程,合约会在执行成功后发送一个事件来通知客户端执行结果,这个事件的格式可以由合约的编写者来指定。

    char buffer [100];
    sprintf(buffer, "{\"states\":[\"%s\", \"%s\", \"%s\"]}","createEnvelope",owner.tohexstring().c_str(),hash256ToHexstring(hash).c_str());
    notify(buffer);
    return true;

    一个简单的红包就创建完成了, 下一步我们需要实现如何查询这个红包的信息.

    2.3 查询红包

    查询红包的逻辑非常简单, 只需要将存储中的红包信息取出并格式化返回即可:

    std::string queryEnvelope(std::string hash){
    key rekey = make_key(rePrefix, hash);
    struct EnvelopeStruct es;
    storage_get(rekey, es);
    return formatEnvelope(es);
    }

    NOTE:对于智能合约的只读操作(例如查询), 可以通过预执行(pre-exec)来读取结果。不同于普通的合约调用,预执行不需要钱包的签名,同时也就无需花费 ONG。最后,其他用户可以根据 hash(红包的 ID)来领取(抢)这个红包了。

    2.4 领取红包

    我们已经把资产成功地转入到智能合约中了, 接下来就可以把这个红包的 ID 发送给你的朋友们让他们去抢红包了。

    1. 领取红包需要输入领取人的账户和红包的hash:

    bool claimEnvelope(address account, std::string hash){
    return true;
    }

    2. 同样, 我们需要验证领取账户的签名, 不允许替其他人抢红包, 而且每个账户每个红包只能抢一次:

    ontio_assert(check_witness(account),"checkwitness failed");
    key claimkey = make_key(claimPrefix,hash,account);
    asset claimed = 0 ;
    storage_get(claimkey,claimed);
    ontio_assert(claimed == 0,"you have claimed this Envelope!");

    3. 按照 hash 从存储中取出红包的信息, 判断这个红包是否没有被抢完:

    key rekey = make_key(rePrefix,hash);
    struct EnvelopeStruct es;
    storage_get(rekey,es);
    ontio_assert(es.remainAmount > 0, "the Envelope has been claimed over!");
    ontio_assert(es.remainPackageCount > 0, "the Envelope has been claimed over!");

    4. 新建一条领取的记录:

    struct receiveRecord record ;
    record.account = account;
    asset claimAmount = 0;

    5. 计算本次领取红包的资产数量。如果是最后一个红包, 数量为剩余的金额, 否则根据当前区块 hash 计算随机数,确定本次领取的数量, 并更新红包信息:

    if (es.remainPackageCount == 1){
    claimAmount = es.remainAmount;
    record.amount = claimAmount;
    }else{
    H256 random = current_blockhash() ;
    char part[8];
    memcpy(part,&random,8);
    uint64_t random_num = *(uint64_t*)part;
    uint32_t percent = random_num % 100 + 1;
    claimAmount = es.remainAmount * percent / 100;
    //ont case
    if (claimAmount == 0){
    claimAmount = 1;
    }else if(isONTToken(es.tokenAddress)){
    if ( (es.remainAmount - claimAmount) < (es.remainPackageCount - 1)){
    claimAmount = es.remainAmount - es.remainPackageCount + 1;
    }
    }
    record.amount = claimAmount;
    }
    es.remainAmount -= claimAmount;
    es.remainPackageCount -= 1;
    es.records.push_back(record);

    6. 根据计算结果, 将对应资产从合约中转到领取的账户:

    address selfaddr = self_address();
    if (isONTToken(es.tokenAddress)){
    bool result = ont::transfer(selfaddr,account ,claimAmount);
    ontio_assert(result,"transfer ont token failed!");
    } else if (isONGToken(es.tokenAddress)){
    bool result = ong::transfer(selfaddr,account ,claimAmount);
    ontio_assert(result,"transfer ong token failed!");
    } else{
    std::vector<char> params = pack(std::string("transfer"),selfaddr,account,claimAmount);
    bool res = false;
    call_contract(es.tokenAddress,params, res );
    ontio_assert(res,"transfer oep4 token failed!");
    }

    7. 记录领取的信息, 将更新后的红包信息写回存储并发送通知事件:

    storage_put(claimkey,claimAmount);
    storage_put(rekey,es);
    char buffer [100];
    std::sprintf(buffer, "{\"states\":[\"%s\",\"%s\",\"%s\",\"%lld\"]}","claimEnvelope",hash.c_str(),account.tohexstring().c_str(),claimAmount);
    notify(buffer);
    return true;

    如前面所说,这个合约只能通过 claimEnvelope 这个接口将资产转出合约。所以,合约中的资产是安全的,任何人都无法随意的取走里面的资产。至此, 一个简单的红包合约逻辑完成, 完整的合约代码如下: https://github.com/JasonZhouPW/pubdocs/blob/master/redEnvelope.cpp

    2.5 合约测试

    合约测试可以有两种方法:

    1. 使用 CLI
    请参考:https://github.com/ontio/ontology-wasm-cdt-cpp/blob/master/How_To_Run_ontologywasm_node.md

    2. 使用 Golang SDK
    请参考:https://github.com/ontio/ontology-wasm-cdt-cpp/blob/master/example/other/main.go

    三、总结

    本示例只是为了展示如何编写一个完整的 Ontology Wasm 智能合约, 如何通过调用 API 和底层的区块链进行交互。如果要作为正式的产品, 还需要解决红包的隐私问题: 所有人都可以通过监控合约的事件来取得红包的 hash, 意味着每个人都可以抢这个红包。一种比较简单的解决方法,就是在创建红包时指定哪些账户能够领取。如果有兴趣, 您也可以尝试修改测试一下。

    Ontology 作为领先公链,率先支持 Wasm 合约,为 Wasm 技术的成熟贡献自己的一份力量。我们欢迎更多的 Wasm 技术爱好者加入本体开发社区,共同打造技术生态。

    本文相关推荐: 本体技术视点 | 解析本体双通证模型

    以上便是知世金融网给大家分享的关于本体技术视点 | 使用C++进行Wasm合约开发/qkl/27135.html的相关信息了,希望能帮助到大家,更多金融相关信息,敬请关注知世金融网!

    网站内容均来自互联网,如侵害您的利益联系客服进行删除!

    关键词:本体
    (0)
    (0)

    上一篇:Forge 框架简介 | ArcBlock 博客

    下一篇:读心术:从零知识证明中提取「知识」

    本文标题:本体技术视点 | 使用C++进行Wasm合约开发

    本文地址:/index.php?s=article&c=search&keyword=%E6%9C%AC%E4%BD%93

    金融知名领域

    南方财富网 | 金融界 | 金融界 |

    更多推荐

    • 茅台吃饱,经销商哭倒
      茅台吃饱,经销商哭倒
    • 汇金的五次增持从短期看具有一定的“稳定器“作用,但从市场表现看效果逐次递减
      汇金的五次增持从短期看具有一定的“稳定器“作用,但从市场表现看效果逐次递减
    • 158亿元!比亚迪收购!
      158亿元!比亚迪收购!
    • 9月价格回落近五成 “冷静期”酒店业备战“十一”市场
      9月价格回落近五成 “冷静期”酒店业备战“十一”市场
    • 2023哈马博览会哈尔滨银行展区精彩纷呈
      2023哈马博览会哈尔滨银行展区精彩纷呈
    • 大额解禁撂倒股价 医疗影像龙头跌出千亿俱乐部 葛兰二季度大幅减仓
      大额解禁撂倒股价 医疗影像龙头跌出千亿俱乐部 葛兰二季度大幅减仓
    • A股,又上了热搜!数字要素概念走高多股涨停,锂电池板块走低恩捷股份大举跌停
      A股,又上了热搜!数字要素概念走高多股涨停,锂电池板块走低恩捷股份大举跌停
    • 最新!巨头出手,加仓宁王51%
      最新!巨头出手,加仓宁王51%
    • 600亿巨头暴雷
      600亿巨头暴雷
    • 一天32家!科创板回购潮涌来
      一天32家!科创板回购潮涌来
    • 提振信心实招来了!30余家上市公司密集出手 最高要买10亿
      提振信心实招来了!30余家上市公司密集出手 最高要买10亿
    • 高盛再发50年后预测:2075年印度股市全球市值占比将升4倍 中国升3成
      高盛再发50年后预测:2075年印度股市全球市值占比将升4倍 中国升3成

    新闻资讯栏目

    站长QQ: 2397470084