From 06a3c518fe290d45c6f076ebe56a708293387bf0 Mon Sep 17 00:00:00 2001 From: kevin Heifner Date: Wed, 27 Aug 2025 08:20:04 -0500 Subject: [PATCH] Move deferred transaction into deferred_transaction.hpp --- .../contracts/eosio/deferred_transaction.hpp | 138 ++++++++++++++++++ .../eosiolib/contracts/eosio/transaction.hpp | 107 +------------- tests/unit/test_contracts/simple_tests.cpp | 4 +- 3 files changed, 147 insertions(+), 102 deletions(-) create mode 100644 libraries/eosiolib/contracts/eosio/deferred_transaction.hpp diff --git a/libraries/eosiolib/contracts/eosio/deferred_transaction.hpp b/libraries/eosiolib/contracts/eosio/deferred_transaction.hpp new file mode 100644 index 00000000..c6d0ab46 --- /dev/null +++ b/libraries/eosiolib/contracts/eosio/deferred_transaction.hpp @@ -0,0 +1,138 @@ +/** + * @file + * @copyright defined in eos/LICENSE + */ +#pragma once +#include "system.hpp" +#include "transaction.hpp" +#include "../../core/eosio/serialize.hpp" + +#include + +namespace eosio { + namespace internal_use_do_not_use { + extern "C" { + __attribute__((eosio_wasm_import)) + void send_deferred(const uint128_t&, uint64_t, const char*, size_t, uint32_t); + + __attribute__((eosio_wasm_import)) + int cancel_deferred(const uint128_t&); + } + } + + /** + * @defgroup deferred_transaction Transaction + * @ingroup contracts + * @brief Type-safe C++ wrappers for transaction C API + * + * deferred_transaction is no longer supported on Vaulta. This class is provided to + * support legacy test contracts that use deferred transactions. + * + * @details An inline message allows one contract to send another contract a message + * which is processed immediately after the current message's processing + * ends such that the success or failure of the parent transaction is + * dependent on the success of the message. If an inline message fails in + * processing then the whole tree of transactions and actions rooted in the + * block will me marked as failing and none of effects on the database will + * persist. + * + * Inline actions and Deferred transactions must adhere to the permissions + * available to the parent transaction or, in the future, delegated to the + * contract account for future use. + * + * @note There are some methods from the @ref transactioncapi that can be used directly from C++ + */ + + /** + * Class transaction contains the actions, context_free_actions and extensions type for a transaction + * + * @ingroup transaction + */ + class deferred_transaction : public transaction { + public: + + /** + * Construct a new deferred_transaction with an expiration of now + 60 seconds. + */ + deferred_transaction(time_point_sec exp = time_point_sec(current_time_point()) + 60) : transaction( exp ) {} + + /** + * Sends this transaction, packs the transaction then sends it as a deferred transaction + * + * @details Writes the symbol_code as a string to the provided char buffer + * @param sender_id - ID of sender + * @param payer - Account paying for RAM + * @param replace_existing - Defaults to false, if this is `0`/false then if the provided sender_id is already in use by an in-flight transaction from this contract, which will be a failing assert. If `1` then transaction will atomically cancel/replace the inflight transaction + */ + void send(const uint128_t& sender_id, name payer, bool replace_existing = false) const { + auto serialize = pack(*static_cast(this)); + internal_use_do_not_use::send_deferred(sender_id, payer.value, serialize.data(), serialize.size(), replace_existing); + } + + }; + + /** + * Struct onerror contains and sender id and packed transaction + * + * @ingroup transaction + */ + struct onerror { + uint128_t sender_id; + std::vector sent_trx; + + /** + * from_current_action unpacks and returns a onerror struct + * + * @ingroup transaction + */ + static onerror from_current_action() { + return unpack_action_data(); + } + + /** + * Unpacks and returns a transaction + */ + transaction unpack_sent_trx() const { + return unpack(sent_trx); + } + + EOSLIB_SERIALIZE( onerror, (sender_id)(sent_trx) ) + }; + + /** + * Send a deferred transaction + * + * @ingroup transaction + * @param sender_id - Account name of the sender of this deferred transaction + * @param payer - Account name responsible for paying the RAM for this deferred transaction + * @param serialized_transaction - The packed transaction to be deferred + * @param size - The size of the packed transaction, required for persistence. + * @param replace - If true, will replace an existing transaction. + */ + inline void send_deferred(const uint128_t& sender_id, name payer, const char* serialized_transaction, size_t size, bool replace = false) { + internal_use_do_not_use::send_deferred(sender_id, payer.value, serialized_transaction, size, replace); + } + + /** + * Cancels a deferred transaction. + * + * @ingroup transaction + * @param sender_id - The id of the sender + * + * @pre The deferred transaction ID exists. + * @pre The deferred transaction ID has not yet been published. + * @post Deferred transaction canceled. + * + * @return 1 if transaction was canceled, 0 if transaction was not found + * + * Example: +* + * @code + * id = 0xffffffffffffffff + * cancel_deferred( id ); + * @endcode + */ + inline int cancel_deferred(const uint128_t& sender_id) { + return internal_use_do_not_use::cancel_deferred(sender_id); + } +} diff --git a/libraries/eosiolib/contracts/eosio/transaction.hpp b/libraries/eosiolib/contracts/eosio/transaction.hpp index b1306ddf..efb8e03f 100644 --- a/libraries/eosiolib/contracts/eosio/transaction.hpp +++ b/libraries/eosiolib/contracts/eosio/transaction.hpp @@ -13,12 +13,6 @@ namespace eosio { namespace internal_use_do_not_use { extern "C" { - __attribute__((eosio_wasm_import)) - void send_deferred(const uint128_t&, uint64_t, const char*, size_t, uint32_t); - - __attribute__((eosio_wasm_import)) - int cancel_deferred(const uint128_t&); - __attribute__((eosio_wasm_import)) size_t read_transaction(char*, size_t); @@ -47,17 +41,7 @@ namespace eosio { * @ingroup contracts * @brief Type-safe C++ wrappers for transaction C API * - * @details An inline message allows one contract to send another contract a message - * which is processed immediately after the current message's processing - * ends such that the success or failure of the parent transaction is - * dependent on the success of the message. If an inline message fails in - * processing then the whole tree of transactions and actions rooted in the - * block will me marked as failing and none of effects on the database will - * persist. - * - * Inline actions and Deferred transactions must adhere to the permissions - * available to the parent transaction or, in the future, delegated to the - * contract account for future use. + * @details See action for the ability to send an inline action. * * @note There are some methods from the @ref transactioncapi that can be used directly from C++ */ @@ -83,17 +67,17 @@ namespace eosio { public: /** - * Construct a new transaction_header with an expiration of now + 60 seconds. + * Construct a new transaction_header * * @brief Construct a new transaction_header object initialising the transaction header expiration to now + 60 seconds */ - transaction_header( time_point_sec exp = time_point_sec(current_time_point()) + 60) + transaction_header( time_point_sec exp = time_point_sec{} ) :expiration(exp) {} time_point_sec expiration; - uint16_t ref_block_num; - uint32_t ref_block_prefix; + uint16_t ref_block_num = 0UL; + uint32_t ref_block_prefix = 0UL; unsigned_int max_net_usage_words = 0UL; /// number of 8 byte words this transaction can serialize into after compressions uint8_t max_cpu_usage_ms = 0UL; /// number of CPU usage units to bill transaction for unsigned_int delay_sec = 0UL; /// number of seconds to delay transaction, default: 0 @@ -110,22 +94,9 @@ namespace eosio { public: /** - * Construct a new transaction with an expiration of now + 60 seconds. + * Construct a new transaction */ - transaction(time_point_sec exp = time_point_sec(current_time_point()) + 60) : transaction_header( exp ) {} - - /** - * Sends this transaction, packs the transaction then sends it as a deferred transaction - * - * @details Writes the symbol_code as a string to the provided char buffer - * @param sender_id - ID of sender - * @param payer - Account paying for RAM - * @param replace_existing - Defaults to false, if this is `0`/false then if the provided sender_id is already in use by an in-flight transaction from this contract, which will be a failing assert. If `1` then transaction will atomically cancel/replace the inflight transaction - */ - void send(const uint128_t& sender_id, name payer, bool replace_existing = false) const { - auto serialize = pack(*this); - internal_use_do_not_use::send_deferred(sender_id, payer.value, serialize.data(), serialize.size(), replace_existing); - } + transaction(time_point_sec exp = time_point_sec{}) : transaction_header( exp ) {} std::vector context_free_actions; std::vector actions; @@ -134,47 +105,6 @@ namespace eosio { EOSLIB_SERIALIZE_DERIVED( transaction, transaction_header, (context_free_actions)(actions)(transaction_extensions) ) }; - /** - * Struct onerror contains and sender id and packed transaction - * - * @ingroup transaction - */ - struct onerror { - uint128_t sender_id; - std::vector sent_trx; - - /** - * from_current_action unpacks and returns a onerror struct - * - * @ingroup transaction - */ - static onerror from_current_action() { - return unpack_action_data(); - } - - /** - * Unpacks and returns a transaction - */ - transaction unpack_sent_trx() const { - return unpack(sent_trx); - } - - EOSLIB_SERIALIZE( onerror, (sender_id)(sent_trx) ) - }; - - /** - * Send a deferred transaction - * - * @ingroup transaction - * @param sender_id - Account name of the sender of this deferred transaction - * @param payer - Account name responsible for paying the RAM for this deferred transaction - * @param serialized_transaction - The packed transaction to be deferred - * @param size - The size of the packed transaction, required for persistence. - * @param replace - If true, will replace an existing transaction. - */ - inline void send_deferred(const uint128_t& sender_id, name payer, const char* serialized_transaction, size_t size, bool replace = false) { - internal_use_do_not_use::send_deferred(sender_id, payer.value, serialized_transaction, size, replace); - } /** * Retrieve the indicated action from the active transaction. * @@ -204,29 +134,6 @@ namespace eosio { return internal_use_do_not_use::read_transaction( ptr, sz ); } - /** - * Cancels a deferred transaction. - * - * @ingroup transaction - * @param sender_id - The id of the sender - * - * @pre The deferred transaction ID exists. - * @pre The deferred transaction ID has not yet been published. - * @post Deferred transaction canceled. - * - * @return 1 if transaction was canceled, 0 if transaction was not found - * - * Example: -* - * @code - * id = 0xffffffffffffffff - * cancel_deferred( id ); - * @endcode - */ - inline int cancel_deferred(const uint128_t& sender_id) { - return internal_use_do_not_use::cancel_deferred(sender_id); - } - /** * Gets the size of the currently executing transaction. * diff --git a/tests/unit/test_contracts/simple_tests.cpp b/tests/unit/test_contracts/simple_tests.cpp index 285d9347..08685a69 100644 --- a/tests/unit/test_contracts/simple_tests.cpp +++ b/tests/unit/test_contracts/simple_tests.cpp @@ -1,5 +1,5 @@ #include -#include +#include #include #include "transfer.hpp" @@ -52,7 +52,7 @@ class [[eosio::contract]] simple_tests : public contract { [[eosio::action]] void testd(name nm) { - transaction t; + deferred_transaction t; action act; act.account = "other"_n; act.name = "testc"_n;