Advanced EOS 008 - Deferred Transactions

EOS not only allows you to call actions between contracts, but also schedule transactions to be executed a set duration after your action has executed, like a background task. This example will illustrate how to simply schedule a transaction to be executed 10 seconds after our action completes. The full example code can be found on GitHub.

Before we start…

Executing inline actions requires custom account permissions

Due to security reasons, the release version of EOS now requires the eosio.code permission on the contract invoking an inline action.

Modifying Account Permissions
We first need to modify the permissions of our defer account before we can schedule delayed transactions. We’re going to overwrite our active key on our defer account with the eosio.code permission and use this later to invoke our inline action. Let’s use the cleos set account permission command to achieve this.

cleos set account permission defer active
'{
  "threshold":1,
  "keys":[{
    "key":"YOUR_PUBLIC_KEY",
    "weight":1
  }],
  "accounts":[{
    "permission":{
      "actor":"defer",
      "permission":"eosio.code"
    },"weight":1
  }]
}'
owner -p defer@owner

Deferred Transactions

Technically there’s no guarantee a deferred transaction will ever execute.

Deferred transactions are actions which execute after the invoking transaction has completed executing. This means the invoking transaction is not notified and does not rollback if the deferred transaction asserts.

Creating an instance
The transaction class is part of the eosiolib and needs to first be included with #include <eosiolib/transaction.hpp> in the head of your file. Now we can initialize a transaction instance and call it “tx”.

eosio::transaction tx;

Adding actions
The transaction’s actions vector will hold a list of action objects which will be invoked after the delay elapses. Let’s add our spam action to our tx object. We will construct a tuple with all our variables, and increment our index counter for the next iteration.

tx.actions.emplace_back(
  permission_level{_self, N(active)},
  _self,
  N(spam),
  std::make_tuple(sender, _self, msg_str, interval, ++index, iterations)
);

Setting Delay
Now we have an action to execute, we can now set our delay. The delay_sec property controls how long to wait before the list of actions should execute. The value is in seconds and defaults to zero, which executes immediately after it’s parent transaction completes. We will set this to our uint64_t interval property passed through the arguments.

tx.delay_sec = 10;

Executing the transaction
Now we’re ready to publish the deferred transaction by sending it to the blockchain. Sending a deferred transaction requires both a uint64_t sender_id to reference the transaction, and an account_name payer which will provide the RAM to store our delayed transaction until it’s executed.

tx.send(sender_id, payer);