未验证 提交 bea08c88 编写于 作者: W wanderingbort 提交者: GitHub

Merge pull request #2084 from EOSIO/enforce-new-transaction-header-parameters

Fixes to delayed input transaction processing, and transaction header usage fields now specify upper limits on cpu and net bandwidth
......@@ -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<SystemAccount>::decrease_voting_power( del.from, del.unstake_net_quantity + del.unstake_cpu_quantity );
......
......@@ -183,7 +183,6 @@ namespace eosiosystem {
typename native<SystemAccount>::setabi,
typename native<SystemAccount>::onerror,
typename native<SystemAccount>::canceldelay,
typename native<SystemAccount>::mindelay,
nonce>( code, act) ) {
//TODO: Small hack until we refactor eosio.system like eosio.token
using undelegatebw = typename delegate_bandwidth<SystemAccount>::undelegatebw;
......
......@@ -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<key_weight> keys;
std::vector<permission_level_weight> accounts;
EOSLIB_SERIALIZE( authority, (threshold)(keys)(accounts) )
};
......@@ -52,14 +52,14 @@ namespace eosiosystem {
type_name name;
type_name base;
std::vector<field_def> 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<field_name> key_names;
std::vector<type_name> 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<struct_def> structs;
std::vector<action_def> actions;
std::vector<table_def> 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& ) {
}
};
}
......@@ -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);
......
......@@ -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<deferred_transaction>();
}
EOSLIB_SERIALIZE_DERIVED( deferred_transaction, transaction, (sender_id)(sender)(payer)(delay_until) )
EOSLIB_SERIALIZE_DERIVED( deferred_transaction, transaction, (sender_id)(sender)(payer)(execute_after) )
};
/**
......
......@@ -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);
}
}
......
......@@ -237,7 +237,8 @@ void test_transaction::send_deferred_transaction(uint64_t receiver, uint64_t, ui
auto trx = transaction();
test_action_action<N(testapi), WASM_TEST_ACTION("test_transaction", "deferred_print")> test_action;
trx.actions.emplace_back(vector<permission_level>{{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() {
......
......@@ -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<action>(), flat_set<public_key_type>(), false, {receiver});
const auto delay = controller.check_authorization({a}, flat_set<public_key_type>(), 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<action>(), flat_set<public_key_type>(), false, {receiver});
delay = controller.check_authorization(trx.actions, flat_set<public_key_type>(), 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));
......
......@@ -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<generated_transaction_multi_index, by_sender_id>();
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<transaction_id_type,size_t> 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<public_key_type>() );
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<public_key_type>() );
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<generated_transaction_object,by_trx_id>(receipt.id);
......@@ -986,7 +995,6 @@ private:
};
fc::microseconds chain_controller::check_authorization( const vector<action>& actions,
const vector<action>& context_free_actions,
const flat_set<public_key_type>& provided_keys,
bool allow_unused_signatures,
flat_set<account_name> provided_accounts )const
......@@ -1065,15 +1073,6 @@ fc::microseconds chain_controller::check_authorization( const vector<action>& 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<contracts::mindelay>();
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<public_key_type>(), true );
return check_authorization( trx.actions, flat_set<public_key_type>(), 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) ) {
......
......@@ -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 {
......
......@@ -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
......@@ -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<action>& actions,
const vector<action>& context_free_actions,
const flat_set<public_key_type>& provided_keys,
bool allow_unused_signatures = false,
flat_set<account_name> provided_accounts = flat_set<account_name>()
......@@ -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
///@{
......
......@@ -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<T>::value + billable_alignm
} } } // namespace eosio::chain::config
template<typename Number>
Number EOS_PERCENT(Number value, int percentage) {
Number EOS_PERCENT(Number value, uint32_t percentage) {
return value * percentage / eosio::chain::config::percent_100;
}
......@@ -32,7 +32,7 @@ struct abi_serializer {
typedef std::function<fc::variant(fc::datastream<const char*>&, bool, bool)> unpack_function;
typedef std::function<void(const fc::variant&, fc::datastream<char*>&, bool, bool)> pack_function;
map<type_name, pair<unpack_function, pack_function>> 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<typename Resolver>
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<bytes> 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<bytes> 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);
}
}
};
......
......@@ -8,7 +8,7 @@
#include <eosio/chain/types.hpp>
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
......@@ -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) )
......@@ -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<signature_type> signatures;
vector<bytes> 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<signature_type> signatures;
fc::enum_type<uint8_t,compression_type> compression;
bytes packed_context_free_data;
bytes packed_trx;
bytes get_raw_transaction()const;
vector<bytes> 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<bytes>& 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) )
......@@ -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))
......@@ -121,6 +121,18 @@ flat_set<public_key_type> 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<uint32_t>::max(), "packed_transaction is too big" );
return static_cast<uint32_t>(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<size_t Limit>
......@@ -139,11 +151,17 @@ struct read_limiter {
size_t _total = 0;
};
static vector<bytes> unpack_context_free_data(const bytes& data) {
if( data.size() == 0 )
return vector<bytes>();
return fc::raw::unpack< vector<bytes> >(data);
}
static transaction unpack_transaction(const bytes& data) {
return fc::raw::unpack<transaction>(data);
}
static bytes zlib_decompress(const bytes& data) {
try {
bytes out;
......@@ -162,6 +180,14 @@ static bytes zlib_decompress(const bytes& data) {
}
}
static vector<bytes> zlib_decompress_context_free_data(const bytes& data) {
if( data.size() == 0 )
return vector<bytes>();
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<bytes>& cfd ) {
if( cfd.size() == 0 )
return bytes();
return fc::raw::pack(cfd);
}
static bytes zlib_compress_context_free_data(const vector<bytes>& 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<bytes> 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<bytes>& 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");
......
......@@ -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<transaction>(*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())
......
......@@ -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<char> data, size_t data_len ) {
void send_deferred( const uint128_t& sender_id, account_name payer, array_ptr<char> 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<transaction>(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,
......
......@@ -30,7 +30,7 @@ namespace boost { namespace test_tools { namespace tt_detail {
{
::operator<<( osm, v );
}
};
};
template<>
struct print_log_value<fc::variant_object> {
......@@ -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<account_name>& 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<account_name>& 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<account_name> 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<chain_controller> 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
......@@ -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::ecc::private_key_shim>(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<account_name>{ actor }, data, expiration);
return push_action(code, acttype, vector<account_name>{ 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<account_name>& actors,
const variant_object& data,
uint32_t expiration)
uint32_t expiration,
uint32_t delay_sec)
{ try {
const auto& acnt = control->get_database().get<account_object,by_name>(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<permission_level>& auths, const vector<private_key_type>& 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<permission_level>{{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<permission_level>& 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<uint8_t> wasm ) try {
signed_transaction trx;
trx.actions.emplace_back( vector<permission_level>{{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<contracts::abi_def>();
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<char> base_tester::get_row_by_account( uint64_t code, uint64_t scope, uint64_t table, const account_name& act ) {
vector<char> data;
const auto& db = control->get_database();
......@@ -542,21 +538,21 @@ namespace eosio { namespace testing {
return data;
}
vector<uint8_t> base_tester::to_uint8_vector(const string& s) {
vector<uint8_t> v(s.size());
copy(s.begin(), s.end(), v.begin());
return v;
};
vector<uint8_t> base_tester::to_uint8_vector(uint64_t x) {
vector<uint8_t> v(sizeof(x));
*reinterpret_cast<uint64_t*>(v.data()) = x;
return v;
};
uint64_t base_tester::to_uint64(fc::variant x) {
vector<uint8_t> blob;
fc::from_variant<uint8_t>(x, blob);
......@@ -564,7 +560,7 @@ namespace eosio { namespace testing {
return *reinterpret_cast<uint64_t*>(blob.data());
}
string base_tester::to_string(fc::variant x) {
vector<uint8_t> v;
fc::from_variant<uint8_t>(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())
......
......@@ -120,9 +120,8 @@ struct txn_test_gen_plugin_impl {
trx.actions.emplace_back(vector<chain::permission_level>{{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));
}
......
......@@ -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;
}
}}}
......@@ -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<string> 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<signed_transaction>();
}
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<chain::action>&& 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<authority>();
} 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();
}
......
......@@ -155,9 +155,9 @@ transaction_trace CallAction(TESTER& test, T ac, const vector<account_name>& sco
}
template <typename T>
transaction_trace CallFunction(TESTER& test, T ac, const vector<char>& data, const vector<account_name>& scope = {N(testapi)}, uint32_t extra_cf_cpu_usage = 0) {
{
signed_transaction trx;
transaction_trace CallFunction(TESTER& test, T ac, const vector<char>& data, const vector<account_name>& scope = {N(testapi)}) {
{
signed_transaction trx;
auto pl = vector<permission_level>{{scope[0], config::active_name}};
if (scope.size() > 1)
......@@ -169,14 +169,14 @@ transaction_trace CallFunction(TESTER& test, T ac, const vector<char>& 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<TEST_METHOD(CLS, MTH)>{}, 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<TEST_METHOD("test_transaction", "send_cf_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<TEST_METHOD("test_transaction", "read_inline_cf_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()) );
......
......@@ -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<uint16_t>(chain.control->head_block_num());
trx.ref_block_prefix = static_cast<uint32_t>(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<uint16_t>(chain.control->head_block_num() + 1);
trx.ref_block_prefix = static_cast<uint32_t>(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());
......
......@@ -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<account_object,by_name>(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<permission_level>(), 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);
......
......@@ -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"]
......
......@@ -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"])
......
......@@ -2714,8 +2714,8 @@ BOOST_AUTO_TEST_CASE(packed_transaction)
txn.actions.emplace_back(
vector<permission_level>{{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<action2>(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)
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册