如何使用Solidity编写智能合约的异步交易模式

许多开发人员在开发solidity之前实现了java,go,python 感觉就像回到80年代后期的delorean一样。 但是solidity的稳定性非常有限。
我正在使用名为#scriptit的队长的nodejs oracle用于以下用例:
1. 新用户获得256分
2. 每次新呼叫,用户的积分将减少log2
船长将直接从docker容器中的solidity运行nodejs调用,并将结果返回给您的合约。
智能合约
异步联系将派生自usingcaptainjs,其中包括异步调用和回调功能。
要在回调发生时记住异步调用,您需要一个jobcounter以及作业id和发件人地址的映射:
uint jobcounter = 0;
mapping (uint =》 address) jobtosendermap;
事件
在以太坊中,当同步事务处于挂起状态,事务只有失败或成功两种状态。异步事务将要求发出事件时,通知用户事务是否挂起、成功或失败。
因此,您定义三个这些事件,并且每个事件至少应包含发件人地址:
event getpoints_success(address sender, uint points);
event getpoints_pending(address sender);
event getpoints_failed(address sender, string errormsg);
函数
以太坊的默认模式是每个用户调用一个合约函数,并支付在一个同步事务环境中执行代码所需的gas。
但现在我们有了一个异步事务环境, 这意味着在同步函数调用终止后将需要额外的气体。
因此,您的函数必须是payable,您的首次检查必须是验证用户是否转移了足够的额外gas费用:
uint gasrequired = default_gas_units * tx.gasprice + 70 szabo;
require(msg.value 》= gasrequired, “please send some extra gas.。.”);
在这个演示用例中,我们将要求使用usingcaptainjs中定义的默认gas单位乘以当前的交易gas价格加上70 szabo的交易费。
一旦用户输送了足够gas,你可以根据船长在github上的描述来调用mathjs的log2函数:
run(
jobcounter,
concat(“math:log2(”,uinttostring(pointsperuser[msg.sender]), “)”),
“”, “”, 1, default_gas_units, tx.gasprice
);
emit getpoints_pending(msg.sender);
在调用run(。..)之后,您必须发出pending事件。如果调用run(。..)失败,则同步调用将失败。
回调
一旦船长计算了用户积分的log2值,他就会通过调用captainsresult函数将结果发送回合约。通过仅添加captainsordersallowed确保只有队长调用此功能。
确保在函数结束时发出成功事件。
function captainsresult(uint jobcounter, string log2result)
external onlycaptainsordersallowed {
// the return of the async call
address sender = jobtosendermap[jobcounter];
uint points = stringtouint(log2result);
pointsperuser[sender] = points;
emit getpoints_success(sender, points);
}
果队长无法调用您提交的代码(也许您的javascript代码中有拼写错误),他会通过调用合同的captainserror函数通知您。
确保在函数结束时发出失败的事件。
function captainserror(uint jobcounter, string errormsg)
external onlycaptainsordersallowed {
// the return of the async call
address sender = jobtosendermap[jobcounter];
emit getpoints_failed(sender, errormsg);
}
这是完整的代码:
pragma solidity ^0.4.25;
import “。/usingcaptainjs_v2.sol”;
contract asyncpattern is usingcaptainjs {
// to identify async calls
uint jobcounter = 0;
mapping (uint =》 address) jobtosendermap;
// demo use case: points per sender
mapping (address =》 uint) pointsperuser;
event getpoints_success(address sender, uint points);
event getpoints_pending(address sender);
event getpoints_failed(address sender, string errormsg);
function getpoints() public payable {
// make sure to have enough gas for the async callback
uint gasrequired = default_gas_units * tx.gasprice + 70 szabo;
require(msg.value 》= gasrequired, “please send some extra gas.。.”);
// remember this call
jobtosendermap[++jobcounter] = msg.sender;
// now do the math - but mix async + async.。.
// every user has 256 points at the beginning and with every next
// call it is log2 of his points
if(pointsperuser[msg.sender] == 0) {
// first call!
pointsperuser[msg.sender] = 256;
emit getpoints_success(msg.sender, 256);
}
else {
// every other call
run(
jobcounter, concat(“math:log2(”, uinttostring(pointsperuser[msg.sender]), “)”),
“”, “”, 1, default_gas_units, tx.gasprice
);
emit getpoints_pending(msg.sender);
}
}
function captainsresult(uint jobcounter, string log2result) external onlycaptainsordersallowed {
// the return of the async call
address sender = jobtosendermap[jobcounter];
uint points = stringtouint(log2result);
pointsperuser[sender] = points;
emit getpoints_success(sender, points);
}
function captainserror(uint jobcounter, string errormsg) external onlycaptainsordersallowed {
// the return of the async call
address sender = jobtosendermap[jobcounter];
emit getpoints_failed(sender, errormsg);
}
}

5G标准被推迟 芯片格局将发生怎样的改变
贴片式绕线电感应用中出现不良的原因分析
如何使用电路板视觉指示器实现可维护性?
中科曙光联合雅捷信息面向金融行业发布数据智能一体机
2018年全国集成电路最新政策汇总及解读
如何使用Solidity编写智能合约的异步交易模式
TMS320VC54x处理器McBSP接口的设计和实现
由11000个led组成的固态照明项目将提供动态但柔和的照明和动画
回顾2018国外机器人10大技术发展成果
总线概述之AMBA总线
AMD EPYC处理器提供性能卓越且性价更高的云计算解决方案
51单片机和STM32单片机之间的优缺点比较及功能体现
电源噪声测不准?请检查一下你的探针!
大容量接触器为什么要更换小容量的
一个正负5v稳压电源的简单制作
NVIDIA创下6项人工智能性能
为什么 Apple Watch SE 值得期待?
亚马逊安防业务正抓住机会开疆辟土
户内交流高压六氟化硫环网开关设备的介绍
库力索法与友达数位合作打造智慧制造解决方案,加速迈向工业4.0