许多开发人员在开发Solidity之前实现了Java,Go,Python ......感觉就像回到80年代后期的DeLorean一样。 但是Solidity的稳定性非常有限。 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); } } —- 编译者/作者:不详 玩币族申明:玩币族作为开放的资讯翻译/分享平台,所提供的所有资讯仅代表作者个人观点,与玩币族平台立场无关,且不构成任何投资理财建议。文章版权归原作者所有。 |
Solidity编写的智能合约的异步交易模式
2019-07-10 不详 来源:网络
LOADING...
相关阅读:
- DeFi新玩法 | 人人都能创建保险合约,一分钟了解Protekt Protocol想做什么2020-10-26
- 大多数欧洲专业投资者购买了数字资产或计划2020-10-26
- CoinAgenda Global宣布首次面向比特币和加密货币投资者和企业家的虚拟会议2020-10-26
- 【跟着勇哥柒学知识119】DEFI还会不会再次呈现一种爆发式的增长,可能2020-10-26
- Vitalik Buterin:以太坊协议面临着协议升级和去中心化治理可能被攻击的2020-10-26