diff --git a/contracts/eosio.system/delegate_bandwidth.hpp b/contracts/eosio.system/delegate_bandwidth.hpp index 1e54188bda578b1daa675c7155e31d4983478060..07c7de6886a7b29ae7dec728ddff26b29eba3ff2 100644 --- a/contracts/eosio.system/delegate_bandwidth.hpp +++ b/contracts/eosio.system/delegate_bandwidth.hpp @@ -262,7 +262,8 @@ namespace eosiosystem { act.owner = del.from; transaction out( now() + refund_delay + refund_expiration_time ); out.actions.emplace_back( permission_level{ del.from, N(active) }, self, N(refund), act ); - out.send( del.from, receiver, now() + refund_delay ); + out.delay_sec = refund_delay; + out.send( del.from, receiver ); if ( asset(0) < del.unstake_net_quantity + del.unstake_cpu_quantity ) { voting::decrease_voting_power( del.from, del.unstake_net_quantity + del.unstake_cpu_quantity ); diff --git a/contracts/eosio.system/eosio.system.hpp b/contracts/eosio.system/eosio.system.hpp index 8787f26bb1bc41088b221be109ce74a0c3037868..1122e74206e62e01b43017cb88ca0780c7035b0b 100644 --- a/contracts/eosio.system/eosio.system.hpp +++ b/contracts/eosio.system/eosio.system.hpp @@ -183,7 +183,6 @@ namespace eosiosystem { typename native::setabi, typename native::onerror, typename native::canceldelay, - typename native::mindelay, nonce>( code, act) ) { //TODO: Small hack until we refactor eosio.system like eosio.token using undelegatebw = typename delegate_bandwidth::undelegatebw; diff --git a/contracts/eosio.system/native.hpp b/contracts/eosio.system/native.hpp index 4037539cb9b2367ccf2e360e6a56e176f050a67f..254c9e8f3b021aa82a8852def40f31e0b8eabb1e 100644 --- a/contracts/eosio.system/native.hpp +++ b/contracts/eosio.system/native.hpp @@ -15,14 +15,14 @@ namespace eosiosystem { struct permission_level_weight { permission_level permission; weight_type weight; - + EOSLIB_SERIALIZE( permission_level_weight, (permission)(weight) ) }; struct key_weight { public_key key; weight_type weight; - + EOSLIB_SERIALIZE( key_weight, (key)(weight) ) }; @@ -30,7 +30,7 @@ namespace eosiosystem { uint32_t threshold; std::vector keys; std::vector accounts; - + EOSLIB_SERIALIZE( authority, (threshold)(keys)(accounts) ) }; @@ -52,14 +52,14 @@ namespace eosiosystem { type_name name; type_name base; std::vector fields; - + EOSLIB_SERIALIZE( struct_def, (name)(base)(fields) ) }; struct action_def { action_name name; type_name type; - + EOSLIB_SERIALIZE(action_def, (name)(type) ) }; @@ -69,7 +69,7 @@ namespace eosiosystem { std::vector key_names; std::vector key_types; type_name type; - + EOSLIB_SERIALIZE(table_def, (name)(index_type)(key_names)(key_types)(type) ) }; @@ -78,7 +78,7 @@ namespace eosiosystem { std::vector structs; std::vector actions; std::vector tables; - + EOSLIB_SERIALIZE( abi_def, (types)(structs)(actions)(tables) ) }; @@ -131,12 +131,12 @@ namespace eosiosystem { static void on( const linkauth& ) { } - + ACTION( SystemAccount, unlinkauth ) { account_name account; account_name code; action_name type; - + EOSLIB_SERIALIZE( unlinkauth, (account)(code)(type) ) }; @@ -175,7 +175,7 @@ namespace eosiosystem { ACTION( SystemAccount, setabi ) { account_name account; abi_def abi; - + EOSLIB_SERIALIZE( setabi, (account)(abi) ) }; @@ -188,23 +188,15 @@ namespace eosiosystem { static void on( const onerror& ) { } - + ACTION( SystemAccount, canceldelay ) { transaction_id_type trx_id; - + EOSLIB_SERIALIZE( canceldelay, (trx_id) ) }; - + static void on( const canceldelay& ) { } - - ACTION ( SystemAccount, mindelay ) { - uint32_t delay; - - EOSLIB_SERIALIZE( mindelay, (delay) ) - }; - - static void on( const mindelay& ) { - } + }; } diff --git a/contracts/eosiolib/transaction.h b/contracts/eosiolib/transaction.h index 2e054ed51794a76f3238bf8b07bb5c8c516bc5d0..89252743dce35816b08493b73641d84edb1e47ce 100644 --- a/contracts/eosiolib/transaction.h +++ b/contracts/eosiolib/transaction.h @@ -20,46 +20,46 @@ extern "C" { * message messages[]; ///< accounts that have approved this message * }; * ``` - * + * * This API enables your contract to construct and send transactions * * Deferred transactions will not be processed until a future block. They - * can therefore have no effect on the success of failure of their parent + * can therefore have no effect on the success of failure of their parent * transaction so long as they appear well formed. If any other condition * causes the parent transaction to be marked as failing, then the deferred - * transaction will never be processed. + * transaction will never be processed. * - * Deferred transactions must adhere to the permissions available to the - * parent transaction or, in the future, delegated to the contract account + * Deferred transactions must adhere to the permissions available to the + * parent transaction or, in the future, delegated to the contract account * for future use. - * + * * 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 + * 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 messages rooted in the * block will me marked as failing and none of effects on the database will - * persist. + * persist. * - * Because of this and the parallel nature of transaction application, - * inline messages may not affect any `scope` which is not listed in + * Because of this and the parallel nature of transaction application, + * inline messages may not affect any `scope` which is not listed in * their parent transaction's `scope`. They also may not read any `scope` * not listed in either their parent transaction's `scope` or `readScope`. * * Inline messages and Deferred transactions must adhere to the permissions - * available to the parent transaction or, in the future, delegated to the + * available to the parent transaction or, in the future, delegated to the * contract account for future use. */ - /** + /** * @defgroup transactioncapi Transaction C API * @ingroup transactionapi - * @brief Define API for sending transactions + * @brief Define API for sending transactions * * @{ */ - void send_deferred(const uint128_t& sender_id, account_name payer, time delay_until, char *serialized_transaction, size_t size); + void send_deferred(const uint128_t& sender_id, account_name payer, char *serialized_transaction, size_t size); void cancel_deferred(const uint128_t& sender_id); diff --git a/contracts/eosiolib/transaction.hpp b/contracts/eosiolib/transaction.hpp index 4a3398139b05dc6f3dabd359c0c6833df0d48fbd..92ee3079f5e26beef245d3c61861b99add995eb0 100644 --- a/contracts/eosiolib/transaction.hpp +++ b/contracts/eosiolib/transaction.hpp @@ -28,9 +28,9 @@ namespace eosio { :expiration(exp),region(r) {} - void send(uint64_t sender_id, account_name payer, time delay_until = now()) const { + void send(uint64_t sender_id, account_name payer) const { auto serialize = pack(*this); - send_deferred(sender_id, payer, delay_until, serialize.data(), serialize.size()); + send_deferred(sender_id, payer, serialize.data(), serialize.size()); } time expiration; @@ -52,13 +52,13 @@ namespace eosio { uint128_t sender_id; account_name sender; account_name payer; - time delay_until; + time execute_after; static deferred_transaction from_current_action() { return unpack_action_data(); } - EOSLIB_SERIALIZE_DERIVED( deferred_transaction, transaction, (sender_id)(sender)(payer)(delay_until) ) + EOSLIB_SERIALIZE_DERIVED( deferred_transaction, transaction, (sender_id)(sender)(payer)(execute_after) ) }; /** diff --git a/contracts/proxy/proxy.cpp b/contracts/proxy/proxy.cpp index 3fafa7afa20e4de0cc0d35b947bb17754d2edebd..fe27d159b524d93d2f7f38dda70887f26c284f55 100644 --- a/contracts/proxy/proxy.cpp +++ b/contracts/proxy/proxy.cpp @@ -52,7 +52,8 @@ namespace proxy { transaction out; out.actions.emplace_back(permission_level{self, N(active)}, N(currency), N(transfer), new_transfer); - out.send(id, self, now() + code_config.delay); + out.delay_sec = code_config.delay; + out.send(id, self); } } @@ -78,7 +79,9 @@ namespace proxy { configs::store(code_config, self); eosio::print("Resending Transaction: ", failed_dtrx.sender_id, " as ", id, "\n"); - failed_dtrx.send(id, self, now() + code_config.delay); + deferred_transaction failed_dtrx_copy = failed_dtrx; + failed_dtrx_copy.delay_sec = code_config.delay; + failed_dtrx_copy.send(id, self); } } diff --git a/contracts/test_api/test_transaction.cpp b/contracts/test_api/test_transaction.cpp index 9d4e3f7bd1667bd2b138cef19774c34a0de45a15..e0cab0db3f9e7b409a75d0ee657379bb2ce64a3a 100644 --- a/contracts/test_api/test_transaction.cpp +++ b/contracts/test_api/test_transaction.cpp @@ -237,7 +237,8 @@ void test_transaction::send_deferred_transaction(uint64_t receiver, uint64_t, ui auto trx = transaction(); test_action_action test_action; trx.actions.emplace_back(vector{{N(testapi), N(active)}}, test_action); - trx.send( 0xffffffffffffffff, receiver, now()+2 ); + trx.delay_sec = 2; + trx.send( 0xffffffffffffffff, receiver ); } void test_transaction::cancel_deferred_transaction() { diff --git a/libraries/chain/apply_context.cpp b/libraries/chain/apply_context.cpp index b8d3615339eb7392dd8e49ad88abb1672df418f4..f43b190b59b389626413cad24f2dd791674cd2e7 100644 --- a/libraries/chain/apply_context.cpp +++ b/libraries/chain/apply_context.cpp @@ -229,9 +229,9 @@ void apply_context::require_recipient( account_name code ) { void apply_context::execute_inline( action&& a ) { if ( !privileged ) { if( a.account != receiver ) { - const auto delay = controller.check_authorization({a}, vector(), flat_set(), false, {receiver}); + const auto delay = controller.check_authorization({a}, flat_set(), false, {receiver}); FC_ASSERT( trx_meta.published + delay <= controller.head_block_time(), - "inline action uses a permission that imposes a delay that is not met, add an action of mindelay with delay of at least ${delay} seconds", + "inline action uses a permission that imposes a delay that is not met, set delay_sec in transaction header to at least ${delay} seconds", ("delay", delay.to_seconds()) ); } } @@ -252,7 +252,7 @@ void apply_context::execute_deferred( deferred_transaction&& trx ) { // Any other called of this function needs to similarly meet that precondition. EOS_ASSERT( trx.execute_after < trx.expiration, transaction_exception, - "Transaction expires at ${trx.expiration} which is before the contract-imposed first allowed time to execute at ${trx.execute_after}", + "Transaction expires at ${trx.expiration} which is before the first allowed time to execute at ${trx.execute_after}", ("trx.expiration",trx.expiration)("trx.execute_after",trx.execute_after) ); controller.validate_expiration_not_too_far(trx, trx.execute_after); @@ -282,20 +282,20 @@ void apply_context::execute_deferred( deferred_transaction&& trx ) { } } if( check_auth ) { - delay = controller.check_authorization(trx.actions, vector(), flat_set(), false, {receiver}); + delay = controller.check_authorization(trx.actions, flat_set(), false, {receiver}); FC_ASSERT( trx_meta.published + delay <= controller.head_block_time(), - "deferred transaction uses a permission that imposes a delay that is not met, add an action of mindelay with delay of at least ${delay} seconds", + "deferred transaction uses a permission that imposes a delay that is not met, set delay_sec in transaction header to at least ${delay} seconds", ("delay", delay.to_seconds()) ); } } auto now = controller.head_block_time(); if( delay.count() ) { - trx.execute_after = std::max(trx.execute_after, time_point_sec(now + delay + fc::microseconds(999'999)) /* rounds up nearest second */ ); - EOS_ASSERT( trx.execute_after < trx.expiration, + auto min_execute_after_time = time_point_sec(now + delay + fc::microseconds(999'999)); // rounds up nearest second + EOS_ASSERT( min_execute_after_time <= trx.execute_after, transaction_exception, - "Transaction expires at ${trx.expiration} which is before the first allowed time to execute at ${trx.execute_after}", - ("trx.expiration",trx.expiration)("trx.execute_after",trx.execute_after) ); + "deferred transaction is specified to execute after ${trx.execute_after} which is earlier than the earliest time allowed by authorization checker", + ("trx.execute_after",trx.execute_after)("min_execute_after_time",min_execute_after_time) ); } results.deferred_transaction_requests.push_back(move(trx)); diff --git a/libraries/chain/chain_controller.cpp b/libraries/chain/chain_controller.cpp index 0702f551c421925178176fa74857aa99fa5d05bd..2897e94a62c91ea142cf73b0418150c7617667b2 100644 --- a/libraries/chain/chain_controller.cpp +++ b/libraries/chain/chain_controller.cpp @@ -290,18 +290,25 @@ transaction_trace chain_controller::_push_transaction(const packed_transaction& //idump((transaction_header(mtrx.trx()))); const transaction& trx = mtrx.trx(); - validate_transaction_with_minimal_state( packed_trx, &trx ); + mtrx.delay = fc::seconds(trx.delay_sec); + + validate_transaction_with_minimal_state( trx, mtrx.billable_packed_size ); + validate_expiration_not_too_far(trx, head_block_time() + mtrx.delay); validate_referenced_accounts(trx); validate_uniqueness(trx); - auto delay = check_transaction_authorization(trx, packed_trx.signatures, packed_trx.context_free_data); - validate_expiration_not_too_far(trx, head_block_time() + delay ); - mtrx.delay = delay; + if( should_check_authorization() ) { + auto enforced_delay = check_transaction_authorization(trx, packed_trx.signatures, mtrx.context_free_data); + EOS_ASSERT( mtrx.delay >= enforced_delay, + transaction_exception, + "authorization imposes a delay (${enforced_delay} sec) greater than the delay specified in transaction header (${specified_delay} sec)", + ("enforced_delay", enforced_delay.to_seconds())("specified_delay", mtrx.delay.to_seconds()) ); + } auto setup_us = fc::time_point::now() - start; transaction_trace result(mtrx.id); - if( delay.count() == 0 ) { + if( mtrx.delay.count() == 0 ) { result = _push_transaction( std::move(mtrx) ); } else { @@ -356,27 +363,12 @@ transaction_trace chain_controller::delayed_transaction_processing( const transa const auto& trx = mtrx.trx(); - // add in the system account authorization - action for_deferred = trx.actions[0]; - bool found = false; - for (const auto& auth : for_deferred.authorization) { - if (auth.actor == config::system_account_name && - auth.permission == config::active_name) { - found = true; - break; - } - } - if (!found) - for_deferred.authorization.push_back(permission_level{config::system_account_name, config::active_name}); - - apply_context context(*this, _db, for_deferred, mtrx); // TODO: Better solution for getting next sender_id needed. - time_point_sec execute_after = head_block_time(); execute_after += mtrx.delay; // TODO: update to better method post RC1? account_name payer; - for(const auto& act : mtrx.trx().actions ) { + for(const auto& act : trx.actions ) { if (act.authorization.size() > 0) { payer = act.authorization.at(0).actor; break; @@ -385,7 +377,15 @@ transaction_trace chain_controller::delayed_transaction_processing( const transa FC_ASSERT(!payer.empty(), "Failed to find a payer for delayed transaction!"); - deferred_transaction dtrx(transaction_id_to_sender_id( trx.id() ), config::system_account_name, payer, execute_after, trx); + auto sender_id = transaction_id_to_sender_id( mtrx.id ); + + const auto& generated_index = _db.get_index(); + auto colliding_trx = generated_index.find(boost::make_tuple(config::system_account_name, sender_id)); + FC_ASSERT( colliding_trx == generated_index.end(), + "sender_id conflict between two delayed transactions: ${cur_trx_id} and ${prev_trx_id}", + ("cur_trx_id", mtrx.id)("prev_trx_id", colliding_trx->trx_id) ); + + deferred_transaction dtrx(sender_id, config::system_account_name, payer, execute_after, trx); FC_ASSERT( dtrx.execute_after < dtrx.expiration, "transaction expires before it can execute" ); result.deferred_transaction_requests.push_back(std::move(dtrx)); @@ -478,7 +478,6 @@ transaction chain_controller::_get_on_block_transaction() trx.actions.emplace_back(std::move(on_block_act)); trx.set_reference_block(head_block_id()); trx.expiration = head_block_time() + fc::seconds(1); - trx.kcpu_usage = 0; return trx; } @@ -787,9 +786,11 @@ void chain_controller::__apply_block(const signed_block& next_block) map trx_index; for( const auto& t : next_block.input_transactions ) { input_metas.emplace_back(t, chain_id_type(), next_block.timestamp); - validate_transaction_with_minimal_state( t, &input_metas.back().trx() ); - if( should_check_signatures() ) - input_metas.back().signing_keys = input_metas.back().trx().get_signature_keys( t.signatures, chain_id_type(), t.context_free_data, false ); + validate_transaction_with_minimal_state( input_metas.back().trx(), input_metas.back().billable_packed_size ); + if( should_check_signatures() ) { + input_metas.back().signing_keys = input_metas.back().trx().get_signature_keys( t.signatures, chain_id_type(), + input_metas.back().context_free_data, false ); + } trx_index[input_metas.back().id] = input_metas.size() - 1; } @@ -848,16 +849,24 @@ void chain_controller::__apply_block(const signed_block& next_block) auto itr = trx_index.find(receipt.id); if( itr != trx_index.end() ) { auto& trx_meta = input_metas.at(itr->second); - const auto& trx = trx_meta.trx(); + const auto& trx = trx_meta.trx(); + trx_meta.delay = fc::seconds(trx.delay_sec); + + validate_expiration_not_too_far(trx, head_block_time() + trx_meta.delay); validate_referenced_accounts(trx); validate_uniqueness(trx); - FC_ASSERT( !should_check_signatures() || trx_meta.signing_keys, - "signing_keys missing from transaction_metadata of an input transaction" ); - auto delay = check_authorization( trx.actions, trx.context_free_actions, - should_check_signatures() ? *trx_meta.signing_keys : flat_set() ); - validate_expiration_not_too_far(trx, head_block_time() + delay ); + if( should_check_authorization() ) { + FC_ASSERT( !should_check_signatures() || trx_meta.signing_keys, + "signing_keys missing from transaction_metadata of an input transaction" ); + auto enforced_delay = check_authorization( trx.actions, + should_check_signatures() ? *trx_meta.signing_keys + : flat_set() ); + EOS_ASSERT( trx_meta.delay >= enforced_delay, + transaction_exception, + "authorization imposes a delay (${enforced_delay} sec) greater than the delay specified in transaction header (${specified_delay} sec)", + ("enforced_delay", enforced_delay.to_seconds())("specified_delay", trx_meta.delay.to_seconds()) ); + } - trx_meta.delay = delay; return &input_metas.at(itr->second); } else { const auto* gtrx = _db.find(receipt.id); @@ -986,7 +995,6 @@ private: }; fc::microseconds chain_controller::check_authorization( const vector& actions, - const vector& context_free_actions, const flat_set& provided_keys, bool allow_unused_signatures, flat_set provided_accounts )const @@ -1065,15 +1073,6 @@ fc::microseconds chain_controller::check_authorization( const vector& ac } } - for( const auto& act : context_free_actions ) { - if (act.account == config::system_account_name && act.name == contracts::mindelay::get_name()) { - const auto mindelay = act.data_as(); - auto delay = fc::seconds(mindelay.delay); - if( max_delay < delay ) - max_delay = delay; - } - } - if( !allow_unused_signatures && should_check_signatures() ) { EOS_ASSERT( checker.all_keys_used(), tx_irrelevant_sig, "transaction bears irrelevant signatures from these keys: ${keys}", @@ -1113,11 +1112,11 @@ fc::microseconds chain_controller::check_transaction_authorization(const transac bool allow_unused_signatures)const { if( should_check_signatures() ) { - return check_authorization( trx.actions, trx.context_free_actions, + return check_authorization( trx.actions, trx.get_signature_keys( signatures, chain_id_type{}, cfd, allow_unused_signatures ), allow_unused_signatures ); } else { - return check_authorization( trx.actions, trx.context_free_actions, flat_set(), true ); + return check_authorization( trx.actions, flat_set(), true ); } } @@ -1203,51 +1202,42 @@ static uint32_t calculate_transaction_cpu_usage( const transaction_trace& trace, } } - // charge a system controlled amount for signature verification/recovery uint32_t signature_cpu_usage = 0; if( meta.signing_keys ) { signature_cpu_usage = (uint32_t)meta.signing_keys->size() * chain_configuration.per_signature_cpu_usage; } - // charge a system discounted amount for context free cpu usage - //uint32_t context_free_cpu_commitment = (uint32_t)(meta.trx().kcpu_usage.value * 1024UL); - /* - EOS_ASSERT(context_free_actual_cpu_usage <= context_free_cpu_commitment, - tx_resource_exhausted, - "Transaction context free actions can not fit into the cpu usage committed to by the transaction's header! [usage=${usage},commitment=${commit}]", - ("usage", context_free_actual_cpu_usage)("commit", context_free_cpu_commitment) ); - */ - uint32_t context_free_cpu_usage = (uint32_t)((uint64_t)context_free_actual_cpu_usage * chain_configuration.context_free_discount_cpu_usage_num / chain_configuration.context_free_discount_cpu_usage_den); - auto actual_usage = chain_configuration.base_per_transaction_cpu_usage + - action_cpu_usage + - context_free_cpu_usage + - signature_cpu_usage; + auto actual_cpu_usage = chain_configuration.base_per_transaction_cpu_usage + + action_cpu_usage + + context_free_cpu_usage + + signature_cpu_usage; + uint32_t cpu_usage_limit = meta.trx().max_kcpu_usage.value * 1024UL; // overflow checked in validate_transaction_without_state + EOS_ASSERT( cpu_usage_limit == 0 || actual_cpu_usage <= cpu_usage_limit, tx_resource_exhausted, + "declared cpu usage limit of transaction is too low: ${actual_cpu_usage} > ${declared_limit}", + ("actual_cpu_usage", actual_cpu_usage)("declared_limit",cpu_usage_limit) ); - if( meta.trx().kcpu_usage.value == 0 ) { - return actual_usage; - } else { - EOS_ASSERT(meta.trx().kcpu_usage.value <= UINT32_MAX / 1024UL, transaction_exception, "declared kcpu usage overflows when expanded to cpu usage"); - uint32_t declared_value = (uint32_t)(meta.trx().kcpu_usage.value * 1024UL); - - EOS_ASSERT( actual_usage <= declared_value, tx_resource_exhausted, "transaction did not declare sufficient cpu usage: ${actual} > ${declared}", ("actual", actual_usage)("declared",declared_value) ); - return declared_value; - } + return actual_cpu_usage; } static uint32_t calculate_transaction_net_usage( const transaction_trace& trace, const transaction_metadata& meta, const chain_config& chain_configuration ) { // charge a system controlled per-lock overhead to account for shard bloat uint32_t lock_net_usage = uint32_t(trace.read_locks.size() + trace.write_locks.size()) * chain_configuration.per_lock_net_usage; - EOS_ASSERT(meta.trx().net_usage_words.value <= (UINT32_MAX - chain_configuration.base_per_transaction_net_usage - lock_net_usage) / 8UL, transaction_exception, "declared net_usage_words overflows when expanded to net usage"); - uint32_t trx_wire_net_usage = (uint32_t)(meta.trx().net_usage_words.value * 8UL); + auto actual_net_usage = chain_configuration.base_per_transaction_net_usage + + meta.billable_packed_size + + lock_net_usage; + - return chain_configuration.base_per_transaction_net_usage + - trx_wire_net_usage + - lock_net_usage; + uint32_t net_usage_limit = meta.trx().max_net_usage_words.value * 8UL; // overflow checked in validate_transaction_without_state + EOS_ASSERT( net_usage_limit == 0 || actual_net_usage <= net_usage_limit, tx_resource_exhausted, + "declared net usage limit of transaction is too low: ${actual_net_usage} > ${declared_limit}", + ("actual_net_usage", actual_net_usage)("declared_limit",net_usage_limit) ); + + return actual_net_usage; } void chain_controller::update_resource_usage( transaction_trace& trace, const transaction_metadata& meta ) { @@ -1344,35 +1334,25 @@ void chain_controller::validate_transaction_without_state( const transaction& tr for (const auto &act : trx.context_free_actions) { EOS_ASSERT( act.authorization.empty(), cfa_irrelevant_auth, "context-free actions cannot require authorization" ); } + + EOS_ASSERT( trx.max_kcpu_usage.value < UINT32_MAX / 1024UL, transaction_exception, "declared max_kcpu_usage overflows when expanded to max cpu usage" ); + EOS_ASSERT( trx.max_net_usage_words.value < UINT32_MAX / 8UL, transaction_exception, "declared max_net_usage_words overflows when expanded to max net usage" ); + } FC_CAPTURE_AND_RETHROW((trx)) } -void chain_controller::validate_transaction_with_minimal_state( const transaction& trx )const +void chain_controller::validate_transaction_with_minimal_state( const transaction& trx, uint32_t min_net_usage )const { try { validate_transaction_without_state(trx); validate_not_expired(trx); validate_tapos(trx); -} FC_CAPTURE_AND_RETHROW((trx)) } -void chain_controller::validate_transaction_with_minimal_state( const packed_transaction& packed_trx, const transaction* trx_ptr )const -{ try { - transaction temp; - if( trx_ptr == nullptr ) { - temp = packed_trx.get_transaction(); - trx_ptr = &temp; - } - - validate_transaction_with_minimal_state(*trx_ptr); - - // enforce that the header is accurate as a commitment to net_usage - uint32_t cfa_sig_net_usage = (uint32_t)(packed_trx.context_free_data.size() + fc::raw::pack_size(packed_trx.signatures)); - uint32_t net_usage_commitment = trx_ptr->net_usage_words.value * 8U; - uint32_t packed_size = (uint32_t)packed_trx.data.size(); - uint32_t net_usage = cfa_sig_net_usage + packed_size; - EOS_ASSERT(net_usage <= net_usage_commitment, - tx_resource_exhausted, - "Packed Transaction and associated data does not fit into the space committed to by the transaction's header! [usage=${usage},commitment=${commit}]", - ("usage", net_usage)("commit", net_usage_commitment)); -} FC_CAPTURE_AND_RETHROW((packed_trx)) } + uint32_t net_usage_limit = trx.max_net_usage_words.value * 8; // overflow checked in validate_transaction_without_state + EOS_ASSERT( net_usage_limit == 0 || min_net_usage <= net_usage_limit, + transaction_exception, + "Packed transaction and associated data does not fit into the space committed to by the transaction's header! [usage=${usage},commitment=${commit}]", + ("usage", min_net_usage)("commit", net_usage_limit)); + +} FC_CAPTURE_AND_RETHROW((trx)) } void chain_controller::require_scope( const scope_name& scope )const { switch( uint64_t(scope) ) { diff --git a/libraries/chain/contracts/chain_initializer.cpp b/libraries/chain/contracts/chain_initializer.cpp index 02bfc0453a5fb6cf1b6e44eb4b039d76b582322c..9743478472f17ddf0e8edae0cbb370361d558b97 100644 --- a/libraries/chain/contracts/chain_initializer.cpp +++ b/libraries/chain/contracts/chain_initializer.cpp @@ -46,7 +46,6 @@ void chain_initializer::register_types(chain_controller& chain, chainbase::datab SET_APP_HANDLER( eosio, eosio, passrecovery, eosio ); SET_APP_HANDLER( eosio, eosio, vetorecovery, eosio ); SET_APP_HANDLER( eosio, eosio, canceldelay, eosio ); - SET_APP_HANDLER( eosio, eosio, mindelay, eosio ); } @@ -75,7 +74,6 @@ abi_def chain_initializer::eos_contract_abi(const abi_def& eosio_system_abi) eos_abi.actions.push_back( action_def{name("onerror"), "onerror"} ); eos_abi.actions.push_back( action_def{name("onblock"), "onblock"} ); eos_abi.actions.push_back( action_def{name("canceldelay"), "canceldelay"} ); - eos_abi.actions.push_back( action_def{name("mindelay"), "mindelay"} ); // ACTION PAYLOADS @@ -166,12 +164,6 @@ abi_def chain_initializer::eos_contract_abi(const abi_def& eosio_system_abi) } }); - eos_abi.structs.emplace_back( struct_def { - "mindelay", "", { - {"delay", "uint32"}, - } - }); - // DATABASE RECORDS eos_abi.structs.emplace_back( struct_def { diff --git a/libraries/chain/contracts/eosio_contract.cpp b/libraries/chain/contracts/eosio_contract.cpp index b1856a4df80179ca61a7848be7d79d37f791ace3..b4d85b6da88ba8583dcb36db3ad9dc3ae4417215 100644 --- a/libraries/chain/contracts/eosio_contract.cpp +++ b/libraries/chain/contracts/eosio_contract.cpp @@ -593,8 +593,4 @@ void apply_eosio_canceldelay(apply_context& context) { context.cancel_deferred(context.controller.transaction_id_to_sender_id(trx_id)); } -void apply_eosio_mindelay(apply_context& context) { - // all processing is performed in chain_controller::check_authorization -} - } } } // namespace eosio::chain::contracts diff --git a/libraries/chain/include/eosio/chain/chain_controller.hpp b/libraries/chain/include/eosio/chain/chain_controller.hpp index 5ff6f940844803d3786acb015c13cf06cd08616e..838c3164e88d2f87f4f7c456c1d2d87a9f0f85b1 100644 --- a/libraries/chain/include/eosio/chain/chain_controller.hpp +++ b/libraries/chain/include/eosio/chain/chain_controller.hpp @@ -49,7 +49,7 @@ namespace eosio { namespace chain { skip_assert_evaluation = 1 << 8, ///< used while reindexing skip_undo_history_check = 1 << 9, ///< used while reindexing skip_producer_schedule_check= 1 << 10, ///< used while reindexing - skip_validate = 1 << 11, ///< used prior to checkpoint, skips validate() call on transaction + skip_validate = 1 << 11, ///< used prior to checkpoint, skips transaction validation skip_scope_check = 1 << 12, ///< used to skip checks for proper scope skip_output_check = 1 << 13, ///< used to skip checks for outputs in block exactly matching those created from apply pushed_transaction = 1 << 14, ///< used to indicate that the origination of the call was from a push_transaction, to determine time allotment @@ -286,7 +286,6 @@ namespace eosio { namespace chain { /** * @param actions - the actions to check authorization across - * @param context_free_actions - the context free actions to check for mindelays across * @param provided_keys - the set of public keys which have authorized the transaction * @param allow_unused_signatures - true if method should not assert on unused signatures * @param provided_accounts - the set of accounts which have authorized the transaction (presumed to be owner) @@ -294,7 +293,6 @@ namespace eosio { namespace chain { * @return fc::microseconds set to the max delay that this authorization requires to complete */ fc::microseconds check_authorization( const vector& actions, - const vector& context_free_actions, const flat_set& provided_keys, bool allow_unused_signatures = false, flat_set provided_accounts = flat_set() @@ -380,7 +378,7 @@ namespace eosio { namespace chain { void validate_not_expired( const transaction& trx )const; void validate_expiration_not_too_far( const transaction& trx, fc::time_point reference_time )const; void validate_transaction_without_state( const transaction& trx )const; - void validate_transaction_with_minimal_state( const transaction& trx )const; + void validate_transaction_with_minimal_state( const transaction& trx, uint32_t min_net_usage = 0 )const; void validate_transaction_with_minimal_state( const packed_transaction& packed_trx, const transaction* trx_ptr = nullptr )const; /// @} @@ -413,6 +411,7 @@ namespace eosio { namespace chain { bool should_check_for_duplicate_transactions()const { return !(_skip_flags&skip_transaction_dupe_check); } bool should_check_tapos()const { return !(_skip_flags&skip_tapos_check); } bool should_check_signatures()const { return !(_skip_flags&skip_transaction_signatures); } + bool should_check_authorization()const { return !(_skip_flags&skip_authority_check); } ///Steps involved in applying a new block ///@{ diff --git a/libraries/chain/include/eosio/chain/config.hpp b/libraries/chain/include/eosio/chain/config.hpp index 03fd983d659362e8d28b12f17c4e738777042577..74cf26faa8576b677e5808e2c14defbb5b2de656 100644 --- a/libraries/chain/include/eosio/chain/config.hpp +++ b/libraries/chain/include/eosio/chain/config.hpp @@ -48,7 +48,7 @@ const static uint32_t default_max_block_net_usage = 1024 * 1024; /// a const static int default_target_block_net_usage_pct = 10 * percent_1; /// we target 1000 TPS const static uint32_t default_max_block_cpu_usage = 100 * 1024 * 1024; /// at 500ms blocks and 20000instr trx, this enables ~10,000 TPS burst -const static int default_target_block_cpu_usage_pct = 10 * percent_1; /// target 1000 TPS +const static uint32_t default_target_block_cpu_usage_pct = 10 * percent_1; /// target 1000 TPS const static uint64_t default_max_storage_size = 10 * 1024; const static uint32_t default_max_trx_lifetime = 60*60; @@ -110,6 +110,6 @@ constexpr uint64_t billable_size_v = ((billable_size::value + billable_alignm } } } // namespace eosio::chain::config template -Number EOS_PERCENT(Number value, int percentage) { +Number EOS_PERCENT(Number value, uint32_t percentage) { return value * percentage / eosio::chain::config::percent_100; } diff --git a/libraries/chain/include/eosio/chain/contracts/abi_serializer.hpp b/libraries/chain/include/eosio/chain/contracts/abi_serializer.hpp index a5e3206284407b55098dd78900400188bd464427..dc45a37c6698148fb8f2477d25bfb8cac5041257 100644 --- a/libraries/chain/include/eosio/chain/contracts/abi_serializer.hpp +++ b/libraries/chain/include/eosio/chain/contracts/abi_serializer.hpp @@ -32,7 +32,7 @@ struct abi_serializer { typedef std::function&, bool, bool)> unpack_function; typedef std::function&, bool, bool)> pack_function; - + map> built_in_types; void configure_built_in_types(); @@ -218,12 +218,12 @@ namespace impl { static void add(mutable_variant_object &out, const char* name, const packed_transaction& ptrx, Resolver resolver) { mutable_variant_object mvo; mvo("signatures", ptrx.signatures); - mvo("context_free_data", ptrx.context_free_data); mvo("compression", ptrx.compression); - mvo("hex_data", ptrx.data); + mvo("packed_context_free_data", ptrx.packed_context_free_data); + mvo("context_free_data", ptrx.get_context_free_data()); + mvo("packed_trx", ptrx.packed_trx); + add(mvo, "transaction", ptrx.get_transaction(), resolver); - transaction trx = ptrx.get_transaction(); - add(mvo, "data", trx, resolver); out(name, std::move(mvo)); } }; @@ -346,25 +346,35 @@ namespace impl { template static void extract( const variant& v, packed_transaction& ptrx, Resolver resolver ) { const variant_object& vo = v.get_object(); + wdump((vo)); EOS_ASSERT(vo.contains("signatures"), packed_transaction_type_exception, "Missing signatures"); EOS_ASSERT(vo.contains("compression"), packed_transaction_type_exception, "Missing compression"); from_variant(vo["signatures"], ptrx.signatures); - if ( vo.contains("context_free_data")) { - from_variant(vo["context_free_data"], ptrx.context_free_data); - } from_variant(vo["compression"], ptrx.compression); - if (vo.contains("hex_data") && vo["hex_data"].is_string() && !vo["hex_data"].as_string().empty()) { - from_variant(vo["hex_data"], ptrx.data); + // TODO: Make this nicer eventually. But for now, if it works... good enough. + if( vo.contains("packed_trx") && vo["packed_trx"].is_string() && !vo["packed_trx"].as_string().empty() ) { + from_variant(vo["packed_trx"], ptrx.packed_trx); + auto trx = ptrx.get_transaction(); // Validates transaction data provided. + if( vo.contains("packed_context_free_data") && vo["packed_context_free_data"].is_string() && !vo["packed_context_free_data"].as_string().empty() ) { + from_variant(vo["packed_context_free_data"], ptrx.packed_context_free_data ); + } else if( vo.contains("context_free_data") ) { + vector context_free_data; + from_variant(vo["context_free_data"], context_free_data); + ptrx.set_transaction(trx, context_free_data, ptrx.compression); + } } else { - EOS_ASSERT(vo.contains("data"), packed_transaction_type_exception, "Missing data"); - if (vo["data"].is_string()) { - from_variant(vo["data"], ptrx.data); - } else { - transaction trx; - extract(vo["data"], trx, resolver); - ptrx.set_transaction(trx, ptrx.compression); + EOS_ASSERT(vo.contains("transaction"), packed_transaction_type_exception, "Missing transaction"); + transaction trx; + vector context_free_data; + extract(vo["transaction"], trx, resolver); + if( vo.contains("packed_context_free_data") && vo["packed_context_free_data"].is_string() && !vo["packed_context_free_data"].as_string().empty() ) { + from_variant(vo["packed_context_free_data"], ptrx.packed_context_free_data ); + context_free_data = ptrx.get_context_free_data(); + } else if( vo.contains("context_free_data") ) { + from_variant(vo["context_free_data"], context_free_data); } + ptrx.set_transaction(trx, context_free_data, ptrx.compression); } } }; diff --git a/libraries/chain/include/eosio/chain/contracts/eos_contract.hpp b/libraries/chain/include/eosio/chain/contracts/eos_contract.hpp index e8484d667f22c480a94b9f470886e6126e6d6d0e..4ddc8741aa0cfdd34863c6a7fcf84dafee9edc84 100644 --- a/libraries/chain/include/eosio/chain/contracts/eos_contract.hpp +++ b/libraries/chain/include/eosio/chain/contracts/eos_contract.hpp @@ -8,7 +8,7 @@ #include -namespace eosio { namespace chain { namespace contracts { +namespace eosio { namespace chain { namespace contracts { /** * @defgroup native_action_handlers Native Action Handlers @@ -30,7 +30,6 @@ namespace eosio { namespace chain { namespace contracts { void apply_eosio_onerror(apply_context&); void apply_eosio_canceldelay(apply_context&); - void apply_eosio_mindelay(apply_context&); ///@} end action handlers } } } /// namespace eosio::contracts diff --git a/libraries/chain/include/eosio/chain/contracts/types.hpp b/libraries/chain/include/eosio/chain/contracts/types.hpp index 946138eb8247c07103ea36ffedb4b4d316463de5..483a255b47c8b1d69e7499edafbcf1c0ce6fea47 100644 --- a/libraries/chain/include/eosio/chain/contracts/types.hpp +++ b/libraries/chain/include/eosio/chain/contracts/types.hpp @@ -281,18 +281,6 @@ struct canceldelay { } }; -struct mindelay { - uint32_t delay; - - static account_name get_account() { - return config::system_account_name; - } - - static action_name get_name() { - return N(mindelay); - } -}; - } } } /// namespace eosio::chain::contracts FC_REFLECT( eosio::chain::contracts::type_def , (new_type_name)(type) ) @@ -313,4 +301,3 @@ FC_REFLECT( eosio::chain::contracts::postrecovery , (account FC_REFLECT( eosio::chain::contracts::passrecovery , (account) ) FC_REFLECT( eosio::chain::contracts::vetorecovery , (account) ) FC_REFLECT( eosio::chain::contracts::canceldelay , (trx_id) ) -FC_REFLECT( eosio::chain::contracts::mindelay , (delay) ) diff --git a/libraries/chain/include/eosio/chain/transaction.hpp b/libraries/chain/include/eosio/chain/transaction.hpp index 6056af1643499087c05d2c915dc508934dfcf5f8..61a0b29f364545ad1f37ffccac839c266368a133 100644 --- a/libraries/chain/include/eosio/chain/transaction.hpp +++ b/libraries/chain/include/eosio/chain/transaction.hpp @@ -117,12 +117,12 @@ namespace eosio { namespace chain { */ struct transaction_header { time_point_sec expiration; ///< the time at which a transaction expires - uint16_t region = 0U; ///< the computational memory region this transaction applies to. - uint16_t ref_block_num = 0U; ///< specifies a block num in the last 2^16 blocks. - uint32_t ref_block_prefix = 0UL; ///< specifies the lower 32 bits of the blockid at get_ref_blocknum - fc::unsigned_int net_usage_words = 0UL; /// number of 8 byte words this transaction serialize too taking any compression into account - fc::unsigned_int kcpu_usage = 0UL; /// number of kilo CPU usage units to bill transaction for to process all free actions - fc::unsigned_int delay_sec = 0UL; /// number of seconds to delay this transaction for during which it may be canceled. + uint16_t region = 0U; ///< the computational memory region this transaction applies to. + uint16_t ref_block_num = 0U; ///< specifies a block num in the last 2^16 blocks. + uint32_t ref_block_prefix = 0UL; ///< specifies the lower 32 bits of the blockid at get_ref_blocknum + fc::unsigned_int max_net_usage_words = 0UL; /// upper limit on total network bandwidth (in 8 byte words) billed for this transaction + fc::unsigned_int max_kcpu_usage = 0UL; /// upper limit on the total number of kilo CPU usage units billed for this transaction + fc::unsigned_int delay_sec = 0UL; /// number of seconds to delay this transaction for during which it may be canceled. /** * @return the absolute block number given the relative ref_block_num @@ -174,8 +174,8 @@ namespace eosio { namespace chain { struct packed_transaction { enum compression_type { - none, - zlib, + none = 0, + zlib = 1, }; packed_transaction() = default; @@ -187,28 +187,31 @@ namespace eosio { namespace chain { explicit packed_transaction(const signed_transaction& t, compression_type _compression = none) :signatures(t.signatures) - ,context_free_data(t.context_free_data) { - set_transaction(t, _compression); + set_transaction(t, t.context_free_data, _compression); } explicit packed_transaction(signed_transaction&& t, compression_type _compression = none) :signatures(std::move(t.signatures)) - ,context_free_data(std::move(t.context_free_data)) { - set_transaction(t, _compression); + set_transaction(t, std::move(t.context_free_data), _compression); } - vector signatures; - vector context_free_data; - compression_type compression; - bytes data; + uint32_t get_billable_size()const; + + digest_type packed_digest()const; - bytes get_raw_transaction()const; - transaction get_transaction()const; - signed_transaction get_signed_transaction()const; - void set_transaction(const transaction& t, compression_type _compression = none); + vector signatures; + fc::enum_type compression; + bytes packed_context_free_data; + bytes packed_trx; + bytes get_raw_transaction()const; + vector get_context_free_data()const; + transaction get_transaction()const; + signed_transaction get_signed_transaction()const; + void set_transaction(const transaction& t, compression_type _compression = none); + void set_transaction(const transaction& t, const vector& cfd, compression_type _compression = none); }; @@ -244,8 +247,8 @@ namespace eosio { namespace chain { :sender(sender),sender_id(sender_id) {} - account_name sender; - uint128_t sender_id; + account_name sender; + uint128_t sender_id; }; } } // eosio::chain @@ -253,10 +256,10 @@ FC_REFLECT( eosio::chain::permission_level, (actor)(permission) ) FC_REFLECT( eosio::chain::action, (account)(name)(authorization)(data) ) FC_REFLECT( eosio::chain::transaction_receipt, (status)(id)) FC_REFLECT( eosio::chain::transaction_header, (expiration)(region)(ref_block_num)(ref_block_prefix) - (net_usage_words)(kcpu_usage)(delay_sec) ) + (max_net_usage_words)(max_kcpu_usage)(delay_sec) ) FC_REFLECT_DERIVED( eosio::chain::transaction, (eosio::chain::transaction_header), (context_free_actions)(actions) ) FC_REFLECT_DERIVED( eosio::chain::signed_transaction, (eosio::chain::transaction), (signatures)(context_free_data) ) FC_REFLECT_ENUM( eosio::chain::packed_transaction::compression_type, (none)(zlib)) -FC_REFLECT( eosio::chain::packed_transaction, (signatures)(context_free_data)(compression)(data) ) +FC_REFLECT( eosio::chain::packed_transaction, (signatures)(compression)(packed_context_free_data)(packed_trx) ) FC_REFLECT_DERIVED( eosio::chain::deferred_transaction, (eosio::chain::transaction), (sender_id)(sender)(payer)(execute_after) ) FC_REFLECT( eosio::chain::deferred_reference, (sender)(sender_id) ) diff --git a/libraries/chain/include/eosio/chain/transaction_metadata.hpp b/libraries/chain/include/eosio/chain/transaction_metadata.hpp index f22464693f96e3cbda9cd92b953c178bee88b6af..41e2b0e40360f9d05050c600563981ca5bdd3b2a 100644 --- a/libraries/chain/include/eosio/chain/transaction_metadata.hpp +++ b/libraries/chain/include/eosio/chain/transaction_metadata.hpp @@ -39,10 +39,10 @@ class transaction_metadata { transaction_id_type id; - uint32_t region_id = 0; - uint32_t cycle_index = 0; - uint32_t shard_index = 0; - uint32_t bandwidth_usage = 0; + uint32_t region_id = 0; + uint32_t cycle_index = 0; + uint32_t shard_index = 0; + uint32_t billable_packed_size = 0; time_point published; fc::microseconds delay; @@ -81,4 +81,4 @@ class transaction_metadata { } } // eosio::chain -FC_REFLECT( eosio::chain::transaction_metadata, (raw_trx)(signing_keys)(id)(region_id)(cycle_index)(shard_index)(bandwidth_usage)(published)(sender)(sender_id)(is_implicit)) +FC_REFLECT( eosio::chain::transaction_metadata, (raw_trx)(signing_keys)(id)(region_id)(cycle_index)(shard_index)(billable_packed_size)(published)(sender)(sender_id)(is_implicit)) diff --git a/libraries/chain/transaction.cpp b/libraries/chain/transaction.cpp index 80945dabddc2eafaefdcd6dd05dcdea1e3bf64d3..a8d4523c365714bb5206cb4c3d95f6526dccddc8 100644 --- a/libraries/chain/transaction.cpp +++ b/libraries/chain/transaction.cpp @@ -121,6 +121,18 @@ flat_set signed_transaction::get_signature_keys( const chain_id return transaction::get_signature_keys(signatures, chain_id, context_free_data, allow_duplicate_keys); } +uint32_t packed_transaction::get_billable_size()const { + auto size = fc::raw::pack_size(*this); + FC_ASSERT( size <= std::numeric_limits::max(), "packed_transaction is too big" ); + return static_cast(size); +} + +digest_type packed_transaction::packed_digest()const { + digest_type::encoder enc; + fc::raw::pack( enc, *this ); + return enc.result(); +} + namespace bio = boost::iostreams; template @@ -139,11 +151,17 @@ struct read_limiter { size_t _total = 0; }; +static vector unpack_context_free_data(const bytes& data) { + if( data.size() == 0 ) + return vector(); + + return fc::raw::unpack< vector >(data); +} + static transaction unpack_transaction(const bytes& data) { return fc::raw::unpack(data); } - static bytes zlib_decompress(const bytes& data) { try { bytes out; @@ -162,6 +180,14 @@ static bytes zlib_decompress(const bytes& data) { } } +static vector zlib_decompress_context_free_data(const bytes& data) { + if( data.size() == 0 ) + return vector(); + + bytes out = zlib_decompress(data); + return unpack_context_free_data(out); +} + static transaction zlib_decompress_transaction(const bytes& data) { bytes out = zlib_decompress(data); return unpack_transaction(out); @@ -171,6 +197,27 @@ static bytes pack_transaction(const transaction& t) { return fc::raw::pack(t); } +static bytes pack_context_free_data(const vector& cfd ) { + if( cfd.size() == 0 ) + return bytes(); + + return fc::raw::pack(cfd); +} + +static bytes zlib_compress_context_free_data(const vector& cfd ) { + if( cfd.size() == 0 ) + return bytes(); + + bytes in = pack_context_free_data(cfd); + bytes out; + bio::filtering_ostream comp; + comp.push(bio::zlib_compressor(bio::zlib::best_compression)); + comp.push(bio::back_inserter(out)); + bio::write(comp, in.data(), in.size()); + bio::close(comp); + return out; +} + static bytes zlib_compress_transaction(const transaction& t) { bytes in = pack_transaction(t); bytes out; @@ -187,13 +234,27 @@ bytes packed_transaction::get_raw_transaction() const try { switch(compression) { case none: - return data; + return packed_trx; + case zlib: + return zlib_decompress(packed_trx); + default: + FC_THROW("Unknown transaction compression algorithm"); + } + } FC_CAPTURE_AND_RETHROW((compression)(packed_trx)) +} + +vector packed_transaction::get_context_free_data()const +{ + try { + switch(compression) { + case none: + return unpack_context_free_data(packed_context_free_data); case zlib: - return zlib_decompress(data); + return zlib_decompress_context_free_data(packed_context_free_data); default: FC_THROW("Unknown transaction compression algorithm"); } - } FC_CAPTURE_AND_RETHROW((compression)(data)) + } FC_CAPTURE_AND_RETHROW((compression)(packed_context_free_data)) } transaction packed_transaction::get_transaction()const @@ -201,18 +262,28 @@ transaction packed_transaction::get_transaction()const try { switch(compression) { case none: - return unpack_transaction(data); + return unpack_transaction(packed_trx); case zlib: - return zlib_decompress_transaction(data); + return zlib_decompress_transaction(packed_trx); default: FC_THROW("Unknown transaction compression algorithm"); } - } FC_CAPTURE_AND_RETHROW((compression)(data)) + } FC_CAPTURE_AND_RETHROW((compression)(packed_trx)) } signed_transaction packed_transaction::get_signed_transaction() const { - return signed_transaction(get_transaction(), signatures, context_free_data); + try { + switch(compression) { + case none: + return signed_transaction(get_transaction(), signatures, unpack_context_free_data(packed_context_free_data)); + case zlib: + return signed_transaction(get_transaction(), signatures, zlib_decompress_context_free_data(packed_context_free_data)); + default: + FC_THROW("Unknown transaction compression algorithm"); + } + } FC_CAPTURE_AND_RETHROW((compression)(packed_trx)(packed_context_free_data)) + } void packed_transaction::set_transaction(const transaction& t, packed_transaction::compression_type _compression) @@ -220,10 +291,30 @@ void packed_transaction::set_transaction(const transaction& t, packed_transactio try { switch(_compression) { case none: - data = pack_transaction(t); + packed_trx = pack_transaction(t); + break; + case zlib: + packed_trx = zlib_compress_transaction(t); + break; + default: + FC_THROW("Unknown transaction compression algorithm"); + } + } FC_CAPTURE_AND_RETHROW((_compression)(t)) + packed_context_free_data.clear(); + compression = _compression; +} + +void packed_transaction::set_transaction(const transaction& t, const vector& cfd, packed_transaction::compression_type _compression) +{ + try { + switch(_compression) { + case none: + packed_trx = pack_transaction(t); + packed_context_free_data = pack_context_free_data(cfd); break; case zlib: - data = zlib_compress_transaction(t); + packed_trx = zlib_compress_transaction(t); + packed_context_free_data = zlib_compress_context_free_data(cfd); break; default: FC_THROW("Unknown transaction compression algorithm"); diff --git a/libraries/chain/transaction_metadata.cpp b/libraries/chain/transaction_metadata.cpp index 8bb1ece7bc4de6dc86b5495c5337b8c34f3ab6cd..428feb15d12ca9f7846b34f1be74b41efcce7ebb 100644 --- a/libraries/chain/transaction_metadata.cpp +++ b/libraries/chain/transaction_metadata.cpp @@ -7,9 +7,9 @@ namespace eosio { namespace chain { transaction_metadata::transaction_metadata( const packed_transaction& t, chain_id_type chainid, const time_point& published, bool implicit ) :raw_trx(t.get_raw_transaction()) ,decompressed_trx(fc::raw::unpack(*raw_trx)) - ,context_free_data(t.context_free_data) + ,context_free_data(t.get_context_free_data()) ,id(decompressed_trx->id()) - ,bandwidth_usage( (uint32_t)fc::raw::pack_size(t) ) + ,billable_packed_size( t.get_billable_size() ) ,published(published) ,raw_data(raw_trx->data()) ,raw_size(raw_trx->size()) diff --git a/libraries/chain/wasm_interface.cpp b/libraries/chain/wasm_interface.cpp index 9aa12c99c680c906daa3921b5c54676c0591399d..312b7f5e0a4d5e374b24bfb6f7253ef308c90d6f 100644 --- a/libraries/chain/wasm_interface.cpp +++ b/libraries/chain/wasm_interface.cpp @@ -1048,19 +1048,16 @@ class transaction_api : public context_aware_api { context.execute_context_free_inline(std::move(act)); } - void send_deferred( const unsigned __int128& val, account_name payer, const fc::time_point_sec& execute_after, array_ptr data, size_t data_len ) { + void send_deferred( const uint128_t& sender_id, account_name payer, array_ptr data, size_t data_len ) { try { - fc::uint128_t sender_id(val>>64, uint64_t(val) ); const auto& gpo = context.controller.get_global_properties(); FC_ASSERT(data_len < gpo.configuration.max_generated_transaction_size, "generated transaction too big"); deferred_transaction dtrx; fc::raw::unpack(data, data_len, dtrx); dtrx.sender = context.receiver; - dtrx.sender_id = (unsigned __int128)sender_id; - dtrx.execute_after = std::max( execute_after, - time_point_sec( (context.controller.head_block_time() + fc::seconds(dtrx.delay_sec)) - + fc::microseconds(999'999) ) /* rounds up to nearest second */ ); + dtrx.sender_id = sender_id; + dtrx.execute_after = time_point_sec( (context.controller.head_block_time() + fc::seconds(dtrx.delay_sec)) + fc::microseconds(999'999) ); // rounds up to nearest second dtrx.payer = payer; context.execute_deferred(std::move(dtrx)); } FC_CAPTURE_AND_RETHROW((fc::to_hex(data, data_len))); @@ -1577,10 +1574,10 @@ REGISTER_INTRINSICS(context_free_transaction_api, ); REGISTER_INTRINSICS(transaction_api, - (send_inline, void(int, int) ) - (send_context_free_inline, void(int, int) ) - (send_deferred, void(int, int64_t, int, int, int) ) - (cancel_deferred, void(int) ) + (send_inline, void(int, int) ) + (send_context_free_inline, void(int, int) ) + (send_deferred, void(int, int64_t, int, int) ) + (cancel_deferred, void(int) ) ); REGISTER_INTRINSICS(context_free_api, diff --git a/libraries/testing/include/eosio/testing/tester.hpp b/libraries/testing/include/eosio/testing/tester.hpp index 1f853b4e08612fcdbc700b128c5432f039a80f30..c80b0a306d416dfa293db041520d0631f2b7ccd8 100644 --- a/libraries/testing/include/eosio/testing/tester.hpp +++ b/libraries/testing/include/eosio/testing/tester.hpp @@ -30,7 +30,7 @@ namespace boost { namespace test_tools { namespace tt_detail { { ::operator<<( osm, v ); } - }; + }; template<> struct print_log_value { @@ -80,14 +80,14 @@ namespace eosio { namespace testing { transaction_trace push_transaction( signed_transaction& trx, uint32_t skip_flag = skip_nothing ); action_result push_action(action&& cert_act, uint64_t authorizer); - transaction_trace push_action( const account_name& code, const action_name& acttype, const account_name& actor, const variant_object& data, uint32_t expiration = DEFAULT_EXPIRATION_DELTA ); - transaction_trace push_action( const account_name& code, const action_name& acttype, const vector& actors, const variant_object& data, uint32_t expiration = DEFAULT_EXPIRATION_DELTA ); + transaction_trace push_action( const account_name& code, const action_name& acttype, const account_name& actor, const variant_object& data, uint32_t expiration = DEFAULT_EXPIRATION_DELTA, uint32_t delay_sec = 0 ); + transaction_trace push_action( const account_name& code, const action_name& acttype, const vector& actors, const variant_object& data, uint32_t expiration = DEFAULT_EXPIRATION_DELTA, uint32_t delay_sec = 0 ); void set_tapos( signed_transaction& trx, uint32_t expiration = DEFAULT_EXPIRATION_DELTA ) const; void set_transaction_headers(signed_transaction& trx, - uint32_t expiration = DEFAULT_EXPIRATION_DELTA, - uint32_t extra_cf_cpu_usage = 0) const; + uint32_t expiration = DEFAULT_EXPIRATION_DELTA, + uint32_t delay_sec = 0)const; void create_accounts( vector names, bool multisig = false ) { for( auto n : names ) create_account(n, config::system_account_name, multisig ); @@ -193,7 +193,7 @@ namespace eosio { namespace testing { } tester(chain_controller::controller_config config) { - init(config); + init(config); } signed_block produce_block( fc::microseconds skip_time = fc::milliseconds(config::block_interval_ms), uint32_t skip_flag = skip_missed_block_penalty )override { @@ -201,11 +201,11 @@ namespace eosio { namespace testing { } bool validate() { return true; } - }; + }; class validating_tester : public base_tester { public: - virtual ~validating_tester() { + virtual ~validating_tester() { produce_block(); BOOST_REQUIRE_EQUAL( validate(), true ); } @@ -240,11 +240,11 @@ namespace eosio { namespace testing { validating_node->push_block( sb ); return sb; } - + bool validate() { auto hbh = control->head_block_header(); auto vn_hbh = validating_node->head_block_header(); - return control->head_block_id() == validating_node->head_block_id() && + return control->head_block_id() == validating_node->head_block_id() && hbh.previous == vn_hbh.previous && hbh.timestamp == vn_hbh.timestamp && hbh.transaction_mroot == vn_hbh.transaction_mroot && @@ -254,7 +254,7 @@ namespace eosio { namespace testing { } unique_ptr validating_node; - }; + }; /** * Utility predicate to check whether an FC_ASSERT message ends with a given string @@ -272,6 +272,5 @@ namespace eosio { namespace testing { string expected; }; - -} } /// eosio::testing +} } /// eosio::testing diff --git a/libraries/testing/tester.cpp b/libraries/testing/tester.cpp index 275548258b1ce24ac38408e77b79530e662a982f..cad5adea686cce3e919aa0f684e0037bd4cd7ea7 100644 --- a/libraries/testing/tester.cpp +++ b/libraries/testing/tester.cpp @@ -28,7 +28,7 @@ namespace eosio { namespace testing { } return res; } - + void base_tester::init(bool push_genesis, chain_controller::runtime_limits limits) { cfg.block_log_dir = tempdir.path() / "blocklog"; cfg.shared_memory_dir = tempdir.path() / "shared"; @@ -51,29 +51,29 @@ namespace eosio { namespace testing { push_genesis_block(); } - + void base_tester::init(chain_controller::controller_config config) { cfg = config; open(); } - + public_key_type base_tester::get_public_key( name keyname, string role ) const { return get_private_key( keyname, role ).get_public_key(); } - + private_key_type base_tester::get_private_key( name keyname, string role ) const { return private_key_type::regenerate(fc::sha256::hash(string(keyname)+role)); } - + void base_tester::close() { control.reset(); chain_transactions.clear(); } - + void base_tester::open() { control.reset( new chain_controller(cfg) ); chain_transactions.clear(); @@ -90,11 +90,11 @@ namespace eosio { namespace testing { }); } - signed_block base_tester::push_block(signed_block b) { + signed_block base_tester::push_block(signed_block b) { control->push_block(b, 2); return b; } - + signed_block base_tester::_produce_block( fc::microseconds skip_time, uint32_t skip_flag) { auto head_time = control->head_block_time(); auto next_time = head_time + skip_time; @@ -104,13 +104,13 @@ namespace eosio { namespace testing { return control->generate_block( next_time, sch_pro, priv_key, skip_flag ); } - + void base_tester::produce_blocks( uint32_t n ) { for( uint32_t i = 0; i < n; ++i ) produce_block(); } - + void base_tester::produce_blocks_until_end_of_round() { uint64_t blocks_per_round; while(true) { @@ -120,23 +120,17 @@ namespace eosio { namespace testing { } } - - void base_tester::set_transaction_headers( signed_transaction& trx, uint32_t expiration, uint32_t extra_cf_cpu_usage ) const { + + void base_tester::set_transaction_headers( signed_transaction& trx, uint32_t expiration, uint32_t delay_sec ) const { trx.expiration = control->head_block_time() + fc::seconds(expiration); trx.set_reference_block( control->head_block_id() ); - // estimate the size of the uncompressed transaction - uint32_t estimated_size = (uint32_t)fc::raw::pack_size(trx); - estimated_size += trx.context_free_data.size(); - estimated_size += 4 * sizeof(signature_type); // hack to allow for 4 sigs - - trx.net_usage_words = estimated_size / 8; - - // dont estimate the cpu_usage - trx.kcpu_usage = 0; + trx.max_net_usage_words = 0; // No limit + trx.max_kcpu_usage = 0; // No limit + trx.delay_sec = delay_sec; } - + void base_tester::create_account( account_name a, account_name creator, bool multisig ) { signed_transaction trx; set_transaction_headers(trx); @@ -172,7 +166,7 @@ namespace eosio { namespace testing { return push_transaction( ptrx, skip_flag ); } FC_CAPTURE_AND_RETHROW( (transaction_header(trx)) ) } - + typename base_tester::action_result base_tester::push_action(action&& act, uint64_t authorizer) { signed_transaction trx; if (authorizer) { @@ -193,23 +187,25 @@ namespace eosio { namespace testing { return success(); } - + transaction_trace base_tester::push_action( const account_name& code, const action_name& acttype, const account_name& actor, const variant_object& data, - uint32_t expiration) + uint32_t expiration, + uint32_t delay_sec) { try { - return push_action(code, acttype, vector{ actor }, data, expiration); + return push_action(code, acttype, vector{ actor }, data, expiration, delay_sec); } FC_CAPTURE_AND_RETHROW( (code)(acttype)(actor)(data)(expiration) ) } - + transaction_trace base_tester::push_action( const account_name& code, const action_name& acttype, const vector& actors, const variant_object& data, - uint32_t expiration) + uint32_t expiration, + uint32_t delay_sec) { try { const auto& acnt = control->get_database().get(code); @@ -219,7 +215,7 @@ namespace eosio { namespace testing { string action_type_name = abis.get_action_type(acttype); FC_ASSERT( action_type_name != string(), "unknown action type ${a}", ("a",acttype) ); - + action act; act.account = code; @@ -231,7 +227,7 @@ namespace eosio { namespace testing { signed_transaction trx; trx.actions.emplace_back(std::move(act)); - set_transaction_headers(trx, expiration); + set_transaction_headers(trx, expiration, delay_sec); for (const auto& actor : actors) { trx.sign(get_private_key(actor, "active"), chain_id_type()); } @@ -239,7 +235,7 @@ namespace eosio { namespace testing { return push_transaction(trx); } FC_CAPTURE_AND_RETHROW( (code)(acttype)(actors)(data)(expiration) ) } - + transaction_trace base_tester::push_reqauth( account_name from, const vector& auths, const vector& keys ) { variant pretty_trx = fc::mutable_variant_object() ("actions", fc::variants({ @@ -262,7 +258,7 @@ namespace eosio { namespace testing { return push_transaction( trx ); } - + transaction_trace base_tester::push_reqauth(account_name from, string role, bool multi_sig) { if (!multi_sig) { return push_reqauth(from, vector{{from, config::owner_name}}, @@ -273,7 +269,7 @@ namespace eosio { namespace testing { } } - + transaction_trace base_tester::push_dummy(account_name from, const string& v) { // use reqauth for a normal action, this could be anything variant pretty_trx = fc::mutable_variant_object() @@ -310,12 +306,12 @@ namespace eosio { namespace testing { return push_transaction( trx ); } - + transaction_trace base_tester::transfer( account_name from, account_name to, string amount, string memo, account_name currency ) { return transfer( from, to, asset::from_string(amount), memo, currency ); } - + transaction_trace base_tester::transfer( account_name from, account_name to, asset amount, string memo, account_name currency ) { variant pretty_trx = fc::mutable_variant_object() ("actions", fc::variants({ @@ -344,7 +340,7 @@ namespace eosio { namespace testing { return push_transaction( trx ); } - + transaction_trace base_tester::issue( account_name to, string amount, account_name currency ) { variant pretty_trx = fc::mutable_variant_object() ("actions", fc::variants({ @@ -371,7 +367,7 @@ namespace eosio { namespace testing { return push_transaction( trx ); } - + void base_tester::link_authority( account_name account, account_name code, permission_name req, action_name type ) { signed_transaction trx; @@ -383,7 +379,7 @@ namespace eosio { namespace testing { push_transaction( trx ); } - + void base_tester::unlink_authority( account_name account, account_name code, action_name type ) { signed_transaction trx; @@ -395,7 +391,7 @@ namespace eosio { namespace testing { push_transaction( trx ); } - + void base_tester::set_authority( account_name account, permission_name perm, authority auth, @@ -420,7 +416,7 @@ namespace eosio { namespace testing { push_transaction( trx ); } FC_CAPTURE_AND_RETHROW( (account)(perm)(auth)(parent) ) } - + void base_tester::set_authority( account_name account, permission_name perm, authority auth, @@ -429,7 +425,7 @@ namespace eosio { namespace testing { } - + void base_tester::delete_authority( account_name account, permission_name perm, const vector& auths, @@ -446,18 +442,18 @@ namespace eosio { namespace testing { push_transaction( trx ); } FC_CAPTURE_AND_RETHROW( (account)(perm) ) } - + void base_tester::delete_authority( account_name account, permission_name perm ) { delete_authority(account, perm, { permission_level{ account, config::owner_name } }, { get_private_key( account, "owner" ) }); } - + void base_tester::set_code( account_name account, const char* wast ) try { set_code(account, wast_to_wasm(wast)); } FC_CAPTURE_AND_RETHROW( (account) ) - + void base_tester::set_code( account_name account, const vector wasm ) try { signed_transaction trx; trx.actions.emplace_back( vector{{account,config::active_name}}, @@ -473,7 +469,7 @@ namespace eosio { namespace testing { push_transaction( trx ); } FC_CAPTURE_AND_RETHROW( (account) ) - + void base_tester::set_abi( account_name account, const char* abi_json) { auto abi = fc::json::from_string(abi_json).template as(); signed_transaction trx; @@ -488,12 +484,12 @@ namespace eosio { namespace testing { push_transaction( trx ); } - + bool base_tester::chain_has_transaction( const transaction_id_type& txid ) const { return chain_transactions.count(txid) != 0; } - + const transaction_receipt& base_tester::get_transaction_receipt( const transaction_id_type& txid ) const { return chain_transactions.at(txid); } @@ -501,7 +497,7 @@ namespace eosio { namespace testing { /** * Reads balance as stored by generic_currency contract */ - + asset base_tester::get_currency_balance( const account_name& code, const symbol& asset_symbol, const account_name& account ) const { @@ -521,7 +517,7 @@ namespace eosio { namespace testing { return asset(result, asset_symbol); } - + vector base_tester::get_row_by_account( uint64_t code, uint64_t scope, uint64_t table, const account_name& act ) { vector data; const auto& db = control->get_database(); @@ -542,21 +538,21 @@ namespace eosio { namespace testing { return data; } - + vector base_tester::to_uint8_vector(const string& s) { vector v(s.size()); copy(s.begin(), s.end(), v.begin()); return v; }; - + vector base_tester::to_uint8_vector(uint64_t x) { vector v(sizeof(x)); *reinterpret_cast(v.data()) = x; return v; }; - + uint64_t base_tester::to_uint64(fc::variant x) { vector blob; fc::from_variant(x, blob); @@ -564,7 +560,7 @@ namespace eosio { namespace testing { return *reinterpret_cast(blob.data()); } - + string base_tester::to_string(fc::variant x) { vector v; fc::from_variant(x, v); @@ -572,8 +568,8 @@ namespace eosio { namespace testing { copy(v.begin(), v.end(), s.begin()); return s; } - - + + void base_tester::sync_with(base_tester& other) { // Already in sync? if (control->head_block_id() == other.control->head_block_id()) diff --git a/plugins/txn_test_gen_plugin/txn_test_gen_plugin.cpp b/plugins/txn_test_gen_plugin/txn_test_gen_plugin.cpp index bdc7c0a9d3cc10abba5ec3b9ffa39b3fd4b9401c..e9fe80ede44a574049f99cd81ac018c375658bf6 100644 --- a/plugins/txn_test_gen_plugin/txn_test_gen_plugin.cpp +++ b/plugins/txn_test_gen_plugin/txn_test_gen_plugin.cpp @@ -120,9 +120,8 @@ struct txn_test_gen_plugin_impl { trx.actions.emplace_back(vector{{creator,"active"}}, contracts::newaccount{creator, newaccountC, owner_auth, active_auth, recovery_auth}); } - + trx.expiration = cc.head_block_time() + fc::seconds(30); - trx.net_usage_words = 500; trx.set_reference_block(cc.head_block_id()); trx.sign(creator_priv_key, chainid); cc.push_transaction(packed_transaction(trx)); @@ -184,7 +183,7 @@ struct txn_test_gen_plugin_impl { trx.expiration = cc.head_block_time() + fc::seconds(30); trx.set_reference_block(cc.head_block_id()); - trx.net_usage_words = 5000; + trx.max_net_usage_words = 5000; trx.sign(txn_test_receiver_C_priv_key, chainid); cc.push_transaction(packed_transaction(trx)); } @@ -257,7 +256,7 @@ struct txn_test_gen_plugin_impl { trx.context_free_actions.emplace_back(action({}, config::system_account_name, "nonce", fc::raw::pack(nonce++))); trx.set_reference_block(cc.head_block_id()); trx.expiration = cc.head_block_time() + fc::seconds(30); - trx.net_usage_words = 100; + trx.max_net_usage_words = 100; trx.sign(a_priv_key, chainid); cc.push_transaction(packed_transaction(trx)); } @@ -268,7 +267,7 @@ struct txn_test_gen_plugin_impl { trx.context_free_actions.emplace_back(action({}, config::system_account_name, "nonce", fc::raw::pack(nonce++))); trx.set_reference_block(cc.head_block_id()); trx.expiration = cc.head_block_time() + fc::seconds(30); - trx.net_usage_words = 100; + trx.max_net_usage_words = 100; trx.sign(b_priv_key, chainid); cc.push_transaction(packed_transaction(trx)); } diff --git a/programs/cleos/help_text.cpp b/programs/cleos/help_text.cpp index 88729048af298e8d81fdd0808ec848ba2f839eda..a22397a1e5d0777ce846013f73c47174ce90af9b 100644 --- a/programs/cleos/help_text.cpp +++ b/programs/cleos/help_text.cpp @@ -146,7 +146,7 @@ const char* error_advice_3120006 = R"=====(Ensure that your transaction JSON fol "region": "uint16_t", "read_scope":[ "account_name" ], "write_scope":[ "account_name" ], - "actions":[{ + "actions":[{ "account":"account_name", "name":"action_name", "authorization":[{ "actor":"account_name","permission":"permission_name" }], @@ -161,7 +161,7 @@ e.g. "region": "0", "read_scope":[ "initb", "initc" ], "write_scope":[ "initb", "initc" ], - "actions":[{ + "actions":[{ "account":"eosio", "name":"transfer", "authorization":[{ "actor":"initb","permission":"active" }], @@ -203,13 +203,13 @@ const char* error_advice_3120010 = R"=====(Ensure that your packed transaction { "signatures" : [ "signature" ], "compression" : enum("none", "zlib"), - "data" : "bytes" + "hex_transaction" : "bytes" } e.g. { "signatures" : [ "EOSJze4m1ZHQ4UjuHpBcX6uHPN4Xyggv52raQMTBZJghzDLepaPcSGCNYTxaP2NiaF4yRF5RaYwqsQYAwBwFtfuTJr34Z5GJX" ], "compression" : "none", - "data" : "6c36a25a00002602626c5e7f0000000000010000001e4d75af460000000000a53176010000000000ea305500000000a8ed3232180000001e4d75af4680969800000000000443555200000000" + "hex_transaction" : "6c36a25a00002602626c5e7f0000000000010000001e4d75af460000000000a53176010000000000ea305500000000a8ed3232180000001e4d75af4680969800000000000443555200000000" })====="; const char* error_advice_3130001 = "Ensure that you have \033[2meosio::chain_api_plugin\033[0m\033[32m added to your node's configuration!"; @@ -326,7 +326,7 @@ bool print_help_text(const fc::exception& e) { auto args = smatch_to_variant(matches); for (const auto& msg: candidate.second) { std::cerr << localized_with_variant(msg, args) << std::endl; - } + } result = true; break; } @@ -335,7 +335,7 @@ bool print_help_text(const fc::exception& e) { std::cerr << localized(help_regex_error, ("code", e.code())("what", e.what())) << std::endl; } - return result; + return result; } }}} diff --git a/programs/cleos/main.cpp b/programs/cleos/main.cpp index 47d956d30395b67c52fc5853b6a92cd642745211..bf6bae8597e2475e65316e2019321a6f52693edc 100644 --- a/programs/cleos/main.cpp +++ b/programs/cleos/main.cpp @@ -145,8 +145,8 @@ bool tx_dont_broadcast = false; bool tx_skip_sign = false; bool tx_print_json = false; -uint32_t tx_cf_cpu_usage = 0; -uint32_t tx_net_usage = 0; +uint32_t tx_max_cpu_usage = 0; +uint32_t tx_max_net_usage = 0; vector tx_permission; @@ -172,8 +172,8 @@ void add_standard_transaction_options(CLI::App* cmd, string default_permission = msg += " (defaults to '" + default_permission + "')"; cmd->add_option("-p,--permission", tx_permission, localized(msg.c_str())); - cmd->add_option("--cf-cpu-usage", tx_cf_cpu_usage, localized("set the cpu usage budget, in instructions-retired, for the execution of all context free actions, defaults to an estimated value based on the transaction")); - cmd->add_option("--net-usage", tx_net_usage, localized("set the net usage budget, in bytes, for the storage of the transaction (compressed), signatures and any context-free data on the block chain")); + cmd->add_option("--max-cpu-usage", tx_max_cpu_usage, localized("set an upper limit on the cpu usage budget, in instructions-retired, for the execution of the transaction (defaults to 0 which means no limit)")); + cmd->add_option("--max-net-usage", tx_max_net_usage, localized("set an upper limit on the net usage budget, in bytes, for the transaction (defaults to 0 which means no limit)")); } string generate_nonce_value() { @@ -229,32 +229,6 @@ void sign_transaction(signed_transaction& trx, fc::variant& required_keys) { trx = signed_trx.as(); } -static uint32_t estimate_transaction_context_free_kilo_cpu_usage( const signed_transaction& trx, int32_t extra_kcpu = 1000 ) { - if (tx_cf_cpu_usage != 0) { - return (uint32_t)(tx_cf_cpu_usage + 1023UL) / (uint32_t)1024UL; - } - - const uint32_t estimated_per_action_usage = config::default_base_per_action_cpu_usage * 10; - return extra_kcpu + (uint32_t)(trx.context_free_actions.size() * estimated_per_action_usage + 1023) / (uint32_t)1024; -} - -static uint32_t estimate_transaction_net_usage_words( const signed_transaction& trx, packed_transaction::compression_type compression, size_t num_keys ) { - if (tx_net_usage != 0) { - return tx_net_usage / (uint32_t)8UL; - } - - uint32_t sigs = (uint32_t)5 + // the maximum encoded size of the unsigned_int for the size of the signature block - (uint32_t)(num_keys * sizeof(signature_type)); - - uint32_t packed_size_drift = compression == packed_transaction::none ? - 4 : // there is 1 variably encoded ints we haven't set yet, this size it can grow by 4 bytes - 256; // allow for drift in the compression due to new data - - uint32_t estimated_packed_size = (uint32_t)packed_transaction(trx, compression).data.size() + packed_size_drift; - - return (uint32_t)(sigs + estimated_packed_size + (uint32_t)trx.context_free_data.size() + 7) / (uint32_t)8; -} - fc::variant push_transaction( signed_transaction& trx, int32_t extra_kcpu = 1000, packed_transaction::compression_type compression = packed_transaction::none ) { auto info = get_info(); trx.expiration = info.head_block_time + tx_expiration; @@ -267,8 +241,8 @@ fc::variant push_transaction( signed_transaction& trx, int32_t extra_kcpu = 1000 auto required_keys = determine_required_keys(trx); size_t num_keys = required_keys.is_array() ? required_keys.get_array().size() : 1; - trx.kcpu_usage = estimate_transaction_context_free_kilo_cpu_usage(trx, extra_kcpu ); - trx.net_usage_words = estimate_transaction_net_usage_words(trx, compression, num_keys); + trx.max_kcpu_usage = (tx_max_cpu_usage + 1023)/1024; + trx.max_net_usage_words = (tx_max_net_usage + 7)/8; if (!tx_skip_sign) { sign_transaction(trx, required_keys); @@ -292,8 +266,8 @@ void print_result( const fc::variant& result ) { const auto& processed = result["processed"]; const auto& transaction_id = processed["id"].as_string(); const auto& status = processed["status"].as_string() ; - auto net = processed["net_usage"].as_int64(); - auto cpu = processed["cpu_usage"].as_int64(); + auto net = processed["net_usage"].as_int64(); + auto cpu = processed["cpu_usage"].as_int64(); cout << status << " transaction: " << transaction_id << " " << net << " bytes " << cpu << " cycles\n"; @@ -337,7 +311,7 @@ void send_actions(std::vector&& actions, int32_t extra_kcpu = 100 void send_transaction( signed_transaction& trx, int32_t extra_kcpu, packed_transaction::compression_type compression = packed_transaction::none ) { auto result = push_transaction(trx, extra_kcpu, compression); - + if( tx_print_json ) { cout << fc::json::to_pretty_string( result ); } else { @@ -460,7 +434,7 @@ struct set_account_permission_subcommand { } auth = parsedAuthority.as(); } EOS_RETHROW_EXCEPTIONS(authority_type_exception, "Fail to parse Authority JSON") - + } name parent; @@ -846,12 +820,12 @@ int main( int argc, char** argv ) { fc::path cpath(contractPath); if( cpath.filename().generic_string() == "." ) cpath = cpath.parent_path(); - if( wastPath == string() ) + if( wastPath == string() ) { wastPath = (cpath / (cpath.filename().generic_string()+".wast")).generic_string(); } - if( abiPath == string() ) + if( abiPath == string() ) { abiPath = (cpath / (cpath.filename().generic_string()+".abi")).generic_string(); } diff --git a/tests/api_tests/api_tests.cpp b/tests/api_tests/api_tests.cpp index 4e90907501b0d41daecfb8818dd42b69a0625bc6..71c3de9a18288bbe429f38664eedd687d9b48680 100644 --- a/tests/api_tests/api_tests.cpp +++ b/tests/api_tests/api_tests.cpp @@ -155,9 +155,9 @@ transaction_trace CallAction(TESTER& test, T ac, const vector& sco } template -transaction_trace CallFunction(TESTER& test, T ac, const vector& data, const vector& scope = {N(testapi)}, uint32_t extra_cf_cpu_usage = 0) { - { - signed_transaction trx; +transaction_trace CallFunction(TESTER& test, T ac, const vector& data, const vector& scope = {N(testapi)}) { + { + signed_transaction trx; auto pl = vector{{scope[0], config::active_name}}; if (scope.size() > 1) @@ -169,14 +169,14 @@ transaction_trace CallFunction(TESTER& test, T ac, const vector& data, con act.authorization = {{N(testapi), config::active_name}}; trx.actions.push_back(act); - test.set_transaction_headers(trx, test.DEFAULT_EXPIRATION_DELTA, extra_cf_cpu_usage ); - auto sigs = trx.sign(test.get_private_key(scope[0], "active"), chain_id_type()); + test.set_transaction_headers(trx, test.DEFAULT_EXPIRATION_DELTA); + auto sigs = trx.sign(test.get_private_key(scope[0], "active"), chain_id_type()); trx.get_signature_keys(chain_id_type() ); - auto res = test.push_transaction(trx); - BOOST_CHECK_EQUAL(res.status, transaction_receipt::executed); - test.produce_block(); + auto res = test.push_transaction(trx); + BOOST_CHECK_EQUAL(res.status, transaction_receipt::executed); + test.produce_block(); return res; - } + } } #define CALL_TEST_FUNCTION(_TESTER, CLS, MTH, DATA) CallFunction(_TESTER, test_api_action{}, DATA) @@ -491,7 +491,7 @@ BOOST_FIXTURE_TEST_CASE(cf_action_tests, TESTER) { try { produce_block(); // test send context free action - auto ttrace = CallFunction( *this, test_api_action{}, {}, {N(testapi)}, 20000 ); + auto ttrace = CALL_TEST_FUNCTION( *this, "test_transaction", "send_cf_action", {} ); BOOST_CHECK_EQUAL(ttrace.action_traces.size(), 2); BOOST_CHECK_EQUAL(ttrace.action_traces[1].receiver == account_name("dummy"), true); BOOST_CHECK_EQUAL(ttrace.action_traces[1].act.account == account_name("dummy"), true); @@ -506,7 +506,7 @@ BOOST_FIXTURE_TEST_CASE(cf_action_tests, TESTER) { try { CALL_TEST_FUNCTION( *this, "test_transaction", "read_inline_action", {} ); - CallFunction( *this, test_api_action{}, {}, {N(testapi)}, 20000 ); + CALL_TEST_FUNCTION( *this, "test_transaction", "read_inline_cf_action", {} ); BOOST_REQUIRE_EQUAL( validate(), true ); } FC_LOG_AND_RETHROW() } @@ -696,13 +696,13 @@ BOOST_FIXTURE_TEST_CASE(transaction_tests, TESTER) { try { control->push_deferred_transactions( true ); // test test_transaction_size - CALL_TEST_FUNCTION(*this, "test_transaction", "test_transaction_size", fc::raw::pack(55) ); + CALL_TEST_FUNCTION(*this, "test_transaction", "test_transaction_size", fc::raw::pack(55) ); // TODO: Need a better way to test this. control->push_deferred_transactions( true ); // test test_read_transaction // this is a bit rough, but I couldn't figure out a better way to compare the hashes auto tx_trace = CALL_TEST_FUNCTION( *this, "test_transaction", "test_read_transaction", {} ); - string sha_expect = "f899d4ec365702f99607bc640ec21a21b109eee01504011769a9fd4f41a5b72c"; + string sha_expect = "f899d4ec365702f99607bc640ec21a21b109eee01504011769a9fd4f41a5b72c"; // TODO: Need a better way to test this. BOOST_CHECK_EQUAL(tx_trace.action_traces.front().console == sha_expect, true); // test test_tapos_block_num CALL_TEST_FUNCTION(*this, "test_transaction", "test_tapos_block_num", fc::raw::pack(control->head_block_num()) ); diff --git a/tests/chain_tests/block_tests.cpp b/tests/chain_tests/block_tests.cpp index 187b05aae8cd180ebbf26692de42594b342f1022..f5a00986b243420c56c8ed5fd2764f0559ae012f 100644 --- a/tests/chain_tests/block_tests.cpp +++ b/tests/chain_tests/block_tests.cpp @@ -78,7 +78,6 @@ BOOST_AUTO_TEST_CASE( push_invalid_block ) { try { trx.actions.emplace_back(std::move(on_block_act)); trx.set_reference_block(chain.control->head_block_id()); trx.expiration = chain.control->head_block_time() + fc::seconds(1); - trx.kcpu_usage = 2000; // 1 << 24; // Add properties to block header new_block.previous = chain.control->head_block_id(); @@ -223,14 +222,13 @@ BOOST_AUTO_TEST_CASE(transaction_expiration) { }); trx.ref_block_num = static_cast(chain.control->head_block_num()); trx.ref_block_prefix = static_cast(chain.control->head_block_id()._hash[1]); - trx.net_usage_words.value = 4096; trx.expiration = chain.control->head_block_time() + fc::microseconds(i * 1000000); trx.sign(chain.get_private_key(config::system_account_name, "active"), chain_id_type()); // expire in 1st time, pass in 2nd time - if (i == 0) + if (i == 0) BOOST_CHECK_THROW(chain.push_transaction(trx), expired_tx_exception); - else + else chain.push_transaction(trx); BOOST_REQUIRE_EQUAL( chain.validate(), true ); @@ -252,7 +250,6 @@ BOOST_AUTO_TEST_CASE(invalid_tapos) { }); trx.ref_block_num = static_cast(chain.control->head_block_num() + 1); trx.ref_block_prefix = static_cast(chain.control->head_block_id()._hash[1]); - trx.net_usage_words.value = 4096; trx.expiration = chain.control->head_block_time() + fc::microseconds(1000000); trx.sign(chain.get_private_key(config::system_account_name, "active"), chain_id_type()); diff --git a/tests/chain_tests/delay_tests.cpp b/tests/chain_tests/delay_tests.cpp index 72f1df1eb20283150250f4248fae5deda4727bb5..617801d2a2aaca4166d36bbe1560501f6c453b7c 100644 --- a/tests/chain_tests/delay_tests.cpp +++ b/tests/chain_tests/delay_tests.cpp @@ -123,7 +123,7 @@ BOOST_AUTO_TEST_CASE( link_delay_direct_test ) { try { ("to", "tester2") ("quantity", "3.0000 CUR") ("memo", "hi" ), - 20 + 20, 10 ); BOOST_REQUIRE_EQUAL(transaction_receipt::delayed, trace.status); BOOST_REQUIRE_EQUAL(1, trace.deferred_transaction_requests.size()); @@ -263,7 +263,7 @@ BOOST_AUTO_TEST_CASE( link_delay_direct_parent_permission_test ) { try { ("to", "tester2") ("quantity", "3.0000 CUR") ("memo", "hi" ), - 20 + 20, 15 ); BOOST_REQUIRE_EQUAL(transaction_receipt::delayed, trace.status); BOOST_REQUIRE_EQUAL(1, trace.deferred_transaction_requests.size()); @@ -409,7 +409,7 @@ BOOST_AUTO_TEST_CASE( link_delay_direct_walk_parent_permissions_test ) { try { ("to", "tester2") ("quantity", "3.0000 CUR") ("memo", "hi" ), - 30 + 30, 20 ); BOOST_REQUIRE_EQUAL(transaction_receipt::delayed, trace.status); BOOST_REQUIRE_EQUAL(1, trace.deferred_transaction_requests.size()); @@ -520,7 +520,7 @@ BOOST_AUTO_TEST_CASE( link_delay_permission_change_test ) { try { ("to", "tester2") ("quantity", "1.0000 CUR") ("memo", "hi" ), - 30 + 30, 10 ); BOOST_REQUIRE_EQUAL(transaction_receipt::delayed, trace.status); @@ -543,7 +543,7 @@ BOOST_AUTO_TEST_CASE( link_delay_permission_change_test ) { try { ("parent", "active") ("data", authority(chain.get_public_key(tester_account, "first"))) ("delay", 0), - 30); + 30, 10); BOOST_REQUIRE_EQUAL(transaction_receipt::delayed, trace.status); BOOST_REQUIRE_EQUAL(1, trace.deferred_transaction_requests.size()); BOOST_REQUIRE_EQUAL(0, trace.action_traces.size()); @@ -568,7 +568,7 @@ BOOST_AUTO_TEST_CASE( link_delay_permission_change_test ) { try { ("to", "tester2") ("quantity", "5.0000 CUR") ("memo", "hi" ), - 30 + 30, 10 ); BOOST_REQUIRE_EQUAL(transaction_receipt::delayed, trace.status); BOOST_REQUIRE_EQUAL(1, trace.deferred_transaction_requests.size()); @@ -713,7 +713,7 @@ BOOST_AUTO_TEST_CASE( link_delay_permission_change_with_delay_heirarchy_test ) { ("to", "tester2") ("quantity", "1.0000 CUR") ("memo", "hi" ), - 30 + 30, 10 ); BOOST_REQUIRE_EQUAL(transaction_receipt::delayed, trace.status); @@ -736,7 +736,8 @@ BOOST_AUTO_TEST_CASE( link_delay_permission_change_with_delay_heirarchy_test ) { ("parent", "active") ("data", authority(chain.get_public_key(tester_account, "first"))) ("delay", 0), - 30); + 30, 10 + ); BOOST_REQUIRE_EQUAL(transaction_receipt::delayed, trace.status); BOOST_REQUIRE_EQUAL(1, trace.deferred_transaction_requests.size()); BOOST_REQUIRE_EQUAL(0, trace.action_traces.size()); @@ -761,7 +762,7 @@ BOOST_AUTO_TEST_CASE( link_delay_permission_change_with_delay_heirarchy_test ) { ("to", "tester2") ("quantity", "5.0000 CUR") ("memo", "hi" ), - 30 + 30, 10 ); BOOST_REQUIRE_EQUAL(transaction_receipt::delayed, trace.status); BOOST_REQUIRE_EQUAL(1, trace.deferred_transaction_requests.size()); @@ -906,7 +907,7 @@ BOOST_AUTO_TEST_CASE( link_delay_link_change_test ) { try { ("to", "tester2") ("quantity", "1.0000 CUR") ("memo", "hi" ), - 30 + 30, 10 ); BOOST_REQUIRE_EQUAL(transaction_receipt::delayed, trace.status); @@ -928,7 +929,8 @@ BOOST_AUTO_TEST_CASE( link_delay_link_change_test ) { try { ("code", "currency") ("type", "transfer") ("requirement", "second"), - 30); + 30, 10 + ); BOOST_REQUIRE_EQUAL(transaction_receipt::delayed, trace.status); BOOST_REQUIRE_EQUAL(1, trace.deferred_transaction_requests.size()); BOOST_REQUIRE_EQUAL(0, trace.action_traces.size()); @@ -953,7 +955,7 @@ BOOST_AUTO_TEST_CASE( link_delay_link_change_test ) { try { ("to", "tester2") ("quantity", "5.0000 CUR") ("memo", "hi" ), - 30 + 30, 10 ); BOOST_REQUIRE_EQUAL(transaction_receipt::delayed, trace.status); BOOST_REQUIRE_EQUAL(1, trace.deferred_transaction_requests.size()); @@ -1104,7 +1106,7 @@ BOOST_AUTO_TEST_CASE( link_delay_link_change_heirarchy_test ) { try { ("to", "tester2") ("quantity", "1.0000 CUR") ("memo", "hi" ), - 30 + 30, 10 ); BOOST_REQUIRE_EQUAL(transaction_receipt::delayed, trace.status); @@ -1126,7 +1128,8 @@ BOOST_AUTO_TEST_CASE( link_delay_link_change_heirarchy_test ) { try { ("code", "currency") ("type", "transfer") ("requirement", "third"), - 30); + 30, 10 + ); BOOST_REQUIRE_EQUAL(transaction_receipt::delayed, trace.status); BOOST_REQUIRE_EQUAL(1, trace.deferred_transaction_requests.size()); BOOST_REQUIRE_EQUAL(0, trace.action_traces.size()); @@ -1151,7 +1154,7 @@ BOOST_AUTO_TEST_CASE( link_delay_link_change_heirarchy_test ) { try { ("to", "tester2") ("quantity", "5.0000 CUR") ("memo", "hi" ), - 30 + 30, 10 ); BOOST_REQUIRE_EQUAL(transaction_receipt::delayed, trace.status); BOOST_REQUIRE_EQUAL(1, trace.deferred_transaction_requests.size()); @@ -1220,7 +1223,7 @@ BOOST_AUTO_TEST_CASE( link_delay_link_change_heirarchy_test ) { try { } FC_LOG_AND_RETHROW() }/// schedule_test -// test mindelay action imposing delay +// test delay_sec field imposing unneeded delay BOOST_AUTO_TEST_CASE( mindelay_test ) { try { TESTER chain; @@ -1290,7 +1293,7 @@ BOOST_AUTO_TEST_CASE( mindelay_test ) { try { liquid_balance = get_currency_balance(chain, N(tester2)); BOOST_REQUIRE_EQUAL(asset::from_string("1.0000 CUR"), liquid_balance); - // send transfer and mindelay + // send transfer with delay_sec set to 10 const auto& acnt = chain.control->get_database().get(N(currency)); const auto abi = acnt.get_abi(); chain::contracts::abi_serializer abis(abi); @@ -1312,9 +1315,7 @@ BOOST_AUTO_TEST_CASE( mindelay_test ) { try { signed_transaction trx; trx.actions.push_back(act); - trx.context_free_actions.emplace_back(vector(), chain::contracts::mindelay { .delay = 10 }); - - chain.set_transaction_headers(trx, 30); + chain.set_transaction_headers(trx, 30, 10); trx.sign(chain.get_private_key(N(tester), "active"), chain_id_type()); trace = chain.push_transaction(trx); BOOST_REQUIRE_EQUAL(transaction_receipt::delayed, trace.status); @@ -1425,7 +1426,7 @@ BOOST_AUTO_TEST_CASE( canceldelay_test ) { try { ("to", "tester2") ("quantity", "1.0000 CUR") ("memo", "hi" ), - 30 + 30, 10 ); ids.push_back(trace.id); BOOST_REQUIRE_EQUAL(transaction_receipt::delayed, trace.status); @@ -1450,7 +1451,8 @@ BOOST_AUTO_TEST_CASE( canceldelay_test ) { try { ("parent", "active") ("data", authority(chain.get_public_key(tester_account, "first"))) ("delay", 0), - 30); + 30, 10 + ); ids.push_back(trace.id); BOOST_REQUIRE_EQUAL(transaction_receipt::delayed, trace.status); BOOST_REQUIRE_EQUAL(1, trace.deferred_transaction_requests.size()); @@ -1476,7 +1478,7 @@ BOOST_AUTO_TEST_CASE( canceldelay_test ) { try { ("to", "tester2") ("quantity", "5.0000 CUR") ("memo", "hi" ), - 30 + 30, 10 ); ids.push_back(trace.id); BOOST_REQUIRE_EQUAL(transaction_receipt::delayed, trace.status); diff --git a/tests/nodeos_run_test.py b/tests/nodeos_run_test.py index 6963e59105d6371d78eff0361dfbbcd201fe706c..27f8572ce5bb42d4b6f9b007c58548fc4468ba13 100755 --- a/tests/nodeos_run_test.py +++ b/tests/nodeos_run_test.py @@ -379,8 +379,8 @@ try: amountVal=None if amINoon: if not enableMongo: - typeVal= transaction["transaction"]["data"]["actions"][0]["name"] - amountVal=transaction["transaction"]["data"]["actions"][0]["data"]["quantity"] + typeVal= transaction["transaction"]["transaction"]["actions"][0]["name"] + amountVal=transaction["transaction"]["transaction"]["actions"][0]["data"]["quantity"] amountVal=int(decimal.Decimal(amountVal.split()[0])*10000) else: typeVal= transaction["name"] diff --git a/tests/testUtils.py b/tests/testUtils.py index 50531d554d2d0057771bf18f906d702544b5bf6c..828c891c2ce50b3ad1645ce7d73ba6d9dc8f72ea 100755 --- a/tests/testUtils.py +++ b/tests/testUtils.py @@ -441,7 +441,7 @@ class Node(object): blockNum=None if not self.enableMongo: - blockNum=int(trans["transaction"]["data"]["ref_block_num"]) + blockNum=int(trans["transaction"]["transaction"]["ref_block_num"]) else: blockNum=int(trans["ref_block_num"]) diff --git a/tests/tests/abi_tests.cpp b/tests/tests/abi_tests.cpp index f5a908e7b4eab1612425347c00cea14a8973d649..74e7863d489de8846b5046f8ba99b0e8fd96404c 100644 --- a/tests/tests/abi_tests.cpp +++ b/tests/tests/abi_tests.cpp @@ -2714,8 +2714,8 @@ BOOST_AUTO_TEST_CASE(packed_transaction) txn.actions.emplace_back( vector{{N(testapi4), config::active_name}}, action2{ 61, 23, (uint8_t)2}); - txn.net_usage_words = 15; - txn.kcpu_usage = 43; + txn.max_net_usage_words = 15; + txn.max_kcpu_usage = 43; // pack the transaction to verify that the var unpacking logic is correct auto packed_txn = chain::packed_transaction(txn); @@ -2795,8 +2795,8 @@ BOOST_AUTO_TEST_CASE(packed_transaction) BOOST_REQUIRE_EQUAL(txn.actions.size(), txn2.actions.size()); for (unsigned int i = 0; i < txn.actions.size(); ++i) verify_action_equal(txn.actions[i], txn2.actions[i]); - BOOST_REQUIRE_EQUAL(txn.net_usage_words.value, txn2.net_usage_words.value); - BOOST_REQUIRE_EQUAL(txn.kcpu_usage.value, txn2.kcpu_usage.value); + BOOST_REQUIRE_EQUAL(txn.max_net_usage_words.value, txn2.max_net_usage_words.value); + BOOST_REQUIRE_EQUAL(txn.max_kcpu_usage.value, txn2.max_kcpu_usage.value); } FC_LOG_AND_RETHROW() } BOOST_AUTO_TEST_CASE(abi_type_repeat)