EOS延期交易(也有叫延迟交易、延时交易)

EOS有两种发送操作的方式,内联和延迟(延时)。内联操作可以直观地视为同步执行,而延迟操作则视为异步代码。内联操作可以从合约派生,然后在与原始操作相同的交易中执行。它们是可靠的,因为它们可以保证执行,并且可以使整个交易失败,从而恢复同一交易之前操作的任何更改。(交易可以认为是在同一块中执行的操作的列表。)

延迟操作是指合约计划在未来某个时间执行的操作。与内联操作的最大区别在于它们甚至不能保证运行。交易也可以由节点删除。此外,如果失败,则调度延迟操作的交易不会恢复。事实上,没有办法恢复它们,它们在执行延期交易时已经应用到前一块的区块链中。延迟的交易也可以从代码中再次取消。

EOS官网开发门户说:推迟的操作被安排后,最好的情况下是在以后的时间里,由生产商决定运行。无法保证将执行延期交易。

由于延期交易的巨大缺点,人们可能会怀疑是否应该使用它们。延期交易绝对有其存在的理由。除了在将来以编程方式安排操作的明显原因之外,它们还可以用于任何不重要的事情。EOSIO软件只提供执行交易所需的一定毫秒(30毫秒)。请注意,此限制适用于交易、其操作列表和派生的内联操作。延期交易提供了一种在新交易中运行时绕过此限制的方法。非必要的操作(如日志记录)或用户在未执行时可再次手动触发的操作(如在赌博合约跟踪余额中提取资金)可作为延迟操作执行。

EOS官网开发门户说:每个交易必须在30毫秒或更短时间内执行。如果一个交易包含多个操作,并且这些操作的总和大于30毫秒,则整个交易将失败。在没有动作并发性要求的情况下,可以通过将CPU消耗动作包括在单独的交易中来规避这一点。

这里是如何在EOS中创建延期交易:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
#include <eosiolib/transaction.hpp> // include this for transactions

class deferred_example : public eosio::contract
{
public:
using contract::contract;

// this action will be called by the deferred transaction
ACTION deferred(name from, const string &message)
{
require_auth(from);
print("Printing deferred ", from, message);
}

ACTION send(name from, const string &message, uint64_t delay)
{
require_auth(from);

eosio::transaction t{};
// always double check the action name as it will fail silently
// in the deferred transaction
t.actions.emplace_back(
// when sending to _self a different authorization can be used
// otherwise _self must be used
permission_level(from, "active"_n),
// account the action should be send to
_self,
// action to invoke
"deferred"_n,
// arguments for the action
std::make_tuple(from, message));

// set delay in seconds
t.delay_sec = delay;

// first argument is a unique sender id
// second argument is account paying for RAM
// third argument can specify whether an in-flight transaction
// with this senderId should be replaced
// if set to false and this senderId already exists
// this action will fail
t.send(now(), from /*, false */);

print("Scheduled with a delay of ", delay);
}
};

EOSIO_DISPATCH(deferred_example, (send)(deferred))

代码类似于发送内联操作的代码。区别在于我们需要先创建一个新的空交易。发送交易时,需要指定发送方ID。此ID在合约发送的所有延期交易中必须是唯一的。它可用于识别对错误处理有用的交易,以及在取消仍在运行的延期交易(即尚未执行的交易)时所需的交易。如果无法根据合约上下文创建唯一的发送方ID,则可以为延迟的交易ID创建一个计数器,并将其存储在合约中的eosio::singleton中。调度延迟的交易是通过将交易存入depositing区块链来实现的,区块链需要与交易规模相同的RAM。可以指定付款人,需要其授权。

要用sender_id取消执行中的交易,只需调用cancel_deferred(sender_id)

当延期交易失败时,eosio会向你的合约发送onError操作,其中包含sender_id和交易数据:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
class deferred_example : public eosio::contract
{
// ...

void onError(const onerror &error)
{
// this function should have a counter to not retry forever
print("Resending Transaction: ", error.sender_id);
transaction dtrx = error.unpack_sent_trx();
dtrx.delay_sec = 3;
dtrx.send(now(), _self);
}

// ...
};

extern "C" void apply(uint64_t receiver, uint64_t code, uint64_t action)
{
if (code == "eosio"_n.value && action == "onerror"_n.value)
{
eosio::execute_action(eosio::name(receiver), eosio::name(code), &deferred_example::onError);
}
// ...
}

延迟的交易导致防御编程技术。你永远无法确定该操作是否实际执行,因此你的协定需要在其表中表示当前状态,然后重试该操作。如果延迟的交易会影响用户,比如发送资金,那么你应该始终有一个单独的操作,它以非延迟的方式实现逻辑,并且可以由用户手动触发,比如撤销操作。必要的核心逻辑应该通过初始操作或内联操作来处理。延迟的交易在调度它的合约的许可下运行。此合约还为生成的操作支付CPU/净带宽成本。

EOS官网开发门户上说:延期交易具有发送它们的合约的权限。

请注意,延期交易只能提前45天安排。但是,你可以通过使延迟操作重复地调度新的延期交易,直到达到所需的时间跨度来绕过这一点。同样,这很容易失败,如果可能的话应该避免。

以下是EOS主网络上关于交易的一些其他有趣的配置设置

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
{
"initial_configuration": {
// ...
// the maximum billable cpu usage (in microseconds) that the chain will allow regardless of account limits
"max_transaction_cpu_usage": 150000,
// the minimum billable cpu usage (in microseconds) that the chain requires
"min_transaction_cpu_usage": 100,
// the maximum number of seconds that an input transaction's expiration can be ahead of the time of the block in which it is first included
"max_transaction_lifetime": 3600,
// the number of seconds _after_ the time a deferred transaction can first execute until it expires
"deferred_trx_expiration_window": 600,
// the maximum number of seconds that can be imposed as a delay requirement by authorization checks
// 45 days
"max_transaction_delay": 3888000,
"max_inline_action_size": 4096,
"max_inline_action_depth": 4,
"max_authority_depth": 6
}
}

也就是说,我们可以提前45天安排交易,节点在交易到期前有10分钟时间执行交易。不幸的是,如果某个交易过期且从未执行,那么在合约的OnError回调中不会通知你未执行的情况。只有首先执行交易,然后由于断言错误而失败时,才会调用此OnError操作。

如果你想了解更多关于EOS通信模型的信息,本文将非常有帮助。

======================================================================

分享一些比特币、以太坊、EOS等区块链相关的交互式在线编程实战教程:

  • EOS入门教程,本课程帮助你快速入门EOS区块链去中心化应用的开发,内容涵盖EOS工具链、账户与钱包、发行代币、智能合约开发与部署、使用代码与智能合约交互等核心知识点,最后综合运用各知识点完成一个便签DApp的开发。
  • 深入浅出玩转EOS钱包开发,本课程以手机EOS钱包的完整开发过程为主线,深入学习EOS区块链应用开发,课程内容即涵盖账户、计算资源、智能合约、动作与交易等EOS区块链的核心概念,同时也讲解如何使用eosjs和eosjs-ecc开发包访问EOS区块链,以及如何在React前端应用中集成对EOS区块链的支持。课程内容深入浅出,非常适合前端工程师深入学习EOS区块链应用开发。
  • java比特币开发教程,本课程面向初学者,内容即涵盖比特币的核心概念,例如区块链存储、去中心化共识机制、密钥与脚本、交易与UTXO等,同时也详细讲解如何在Java代码中集成比特币支持功能,例如创建地址、管理钱包、构造裸交易等,是Java工程师不可多得的比特币开发学习课程。
  • php比特币开发教程,本课程面向初学者,内容即涵盖比特币的核心概念,例如区块链存储、去中心化共识机制、密钥与脚本、交易与UTXO等,同时也详细讲解如何在Php代码中集成比特币支持功能,例如创建地址、管理钱包、构造裸交易等,是Php工程师不可多得的比特币开发学习课程。
  • c#比特币开发教程,本课程面向初学者,内容即涵盖比特币的核心概念,例如区块链存储、去中心化共识机制、密钥与脚本、交易与UTXO等,同时也详细讲解如何在C#代码中集成比特币支持功能,例如创建地址、管理钱包、构造裸交易等,是C#工程师不可多得的比特币开发学习课程。
  • java以太坊开发教程,主要是针对java和android程序员进行区块链以太坊开发的web3j详解。
  • python以太坊,主要是针对python工程师使用web3.py进行区块链以太坊开发的详解。
  • php以太坊,主要是介绍使用php进行智能合约开发交互,进行账号创建、交易、转账、代币开发以及过滤器和交易等内容。
  • 以太坊入门教程,主要介绍智能合约与dapp应用开发,适合入门。
  • 以太坊开发进阶教程,主要是介绍使用node.js、mongodb、区块链、ipfs实现去中心化电商DApp实战,适合进阶。
  • ERC721以太坊通证实战,课程以一个数字艺术品创作与分享DApp的实战开发为主线,深入讲解以太坊非同质化通证的概念、标准与开发方案。内容包含ERC-721标准的自主实现,讲解OpenZeppelin合约代码库二次开发,实战项目采用Truffle,IPFS,实现了通证以及去中心化的通证交易所。
  • C#以太坊,主要讲解如何使用C#开发基于.Net的以太坊应用,包括账户管理、状态与交易、智能合约开发与交互、过滤器和交易等。
  • Hyperledger Fabric 区块链开发详解,本课程面向初学者,内容即包含Hyperledger Fabric的身份证书与MSP服务、权限策略、通道配置与启动、链码通信接口等核心概念,也包含Fabric网络设计、nodejs链码与应用开发的操作实践,是Nodejs工程师学习Fabric区块链开发的最佳选择。
  • Hyperledger Fabric java 区块链开发详解,课程面向初学者,内容即包含Hyperledger Fabric的身份证书与MSP服务、权限策略、频道配置与启动、链码通信接口等核心概念,也包含Fabric网络设计、java链码与应用开发的操作实践,是java工程师学习Fabric区块链开发的最佳选择。
  • tendermint区块链开发详解,本课程适合希望使用tendermint进行区块链开发的工程师,课程内容即包括tendermint应用开发模型中的核心概念,例如ABCI接口、默克尔树、多版本状态库等,也包括代币发行等丰富的实操代码,是go语言工程师快速入门区块链开发的最佳选择。

汇智网原创翻译,转载请标明出处。这里是EOS延期交易