首页 资讯 正文

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

本体Ontology 2019年08月29日 08:25

640?wx_fmt=jpeg&tp=webp&wxfrom=5&wx_lazy=1&wx_co=1

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

640?wx_fmt=png&tp=webp&wxfrom=5&wx_lazy=1&wx_co=1

一、Hello World

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

1.1 合约入口

eP8wZgdAyP26o0se9GNPYYmcTxtcMszqNPx2aWYA.png

在上面的例子中, 我们暂时只支持 sayHello 这个方法:pWkEvtx3uiMtoEDhsZtFjC6GhZabvw9xfpFFUoxh.png这个“Hello world!”会在节点的日志中以调试信息打印出来。在实际的应用中, printf 只能用作调试的目的, 一个实际的智能合约,需要实现更多更复杂的功能。

1.2 智能合约 API

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

640?wx_fmt=png&tp=webp&wxfrom=5&wx_lazy=1&wx_co=1

二、红包合约

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

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

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

2.1 创建合约

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

  •  createRedEnvelope: 创建红包

  •  queryEnvelope: 查询红包信息

  •  claimEnvelope: 抢红包

xky5Von57G8mtrnsXHIpAPEoPrubHkBkXVstUc7o.png

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

tQXCmeT3XtnKU1GVpcgbOK105ZOntiIvfI10cUUm.png

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

CUW3CEOrARSOe74SKBBIIKcMdmLxHBYkPZgCk8jd.png

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

u0FHrwTb2Lm777hj5hMeR0zSaQIKzXAWt8ObEIqn.png

其中,

XxmE2rtoKg5DgAznkKxyNOrL60VAFpXXrtzQ9KOe.png

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

2.2 创建红包

准备工作差不多了,下面我们开始开发具体的接口逻辑。1. 创建红包需要指定创建者地址, 红包数量, 红包金额和资产的合约地址:R6svsKUvvv6RKpCd7TZBpUmQz8pQQGz2mhwx1XoY.png2. 检查是否有创建者的签名, 否则交易回滚退出:

tN4ao150WBkTXL9qo2DZHVOSgOen55JvxeYVPRzU.png

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

36IjkVFsN9UHAMqxuVKR0yLQkvUSqN5VVGhnAL3G.png

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

tQ5Kw05ZCnUWswPWIcvfAd7rkbhxTjRBFKDQe1Ja.png

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

eInsRNlg0gC4dhmmZJoSzjkkRtqxXURoAqbcLFrH.png

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

43SXuFUXhdZ7V0CHn5aAQ5xdbiqKiWNy75s9MDm0.png

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

1gBeH2pUEQpjJk89I9e2lls4a47AvJEwAkCPDngo.png

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

jmTGH3qbnc6qX9cKC7FOG8oEckkul1dUbglaCk8D.png

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

2.3 查询红包

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

2.4 领取红包

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

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

pjoj99jLpZqejGBTT0jY04InTOapz3u8jiYzOpNR.png

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

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

MOZWZykp1sASuQglrosno5iKsFiDDbrE1PJgvEPI.png

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

cPz09X75YpXM1zocGbw8Mur0OEaeYGoVi3cMnjIw.png

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

ix1IFXKfn3Kf6n7JFCic4f6TefBpBzqw0Gha8v4q.png

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

pwaUZbMwoPRD1jv604SYmcUVavUPmPVG32zGpXcK.png

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

N6nG3AaHafSTrQtP608HoujvoiUtHXAEtu6hkPOE.png

如前面所说,这个合约只能通过 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 技术爱好者加入本体开发社区,共同打造技术生态。

*详细代码信息可能显示不全,可参考:https://mp.weixin.qq.com/s/LlvuX4NzZackasuvQyBDlg