Skip to content
This repository has been archived by the owner on Aug 2, 2022. It is now read-only.

Use NET bill in transaction receipt during light validation mode #8856

Merged
merged 3 commits into from
Mar 24, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
26 changes: 19 additions & 7 deletions libraries/chain/controller.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1418,7 +1418,8 @@ struct controller_impl {
transaction_trace_ptr push_transaction( const transaction_metadata_ptr& trx,
fc::time_point deadline,
uint32_t billed_cpu_time_us,
bool explicit_billed_cpu_time )
bool explicit_billed_cpu_time,
fc::optional<uint32_t> explicit_net_usage_words )
{
EOS_ASSERT(deadline != fc::time_point(), transaction_exception, "deadline cannot be uninitialized");

Expand Down Expand Up @@ -1450,13 +1451,18 @@ struct controller_impl {
trace = trx_context.trace;
try {
if( trx->implicit ) {
EOS_ASSERT( !explicit_net_usage_words.valid(), transaction_exception, "NET usage cannot be explicitly set for implicit transactions" );
trx_context.init_for_implicit_trx();
trx_context.enforce_whiteblacklist = false;
} else {
bool skip_recording = replay_head_time && (time_point(trn.expiration) <= *replay_head_time);
trx_context.init_for_input_trx( trx->packed_trx()->get_unprunable_size(),
trx->packed_trx()->get_prunable_size(),
skip_recording);
if( explicit_net_usage_words ) {
trx_context.init_for_input_trx_with_explicit_net( *explicit_net_usage_words, skip_recording );
} else {
trx_context.init_for_input_trx( trx->packed_trx()->get_unprunable_size(),
trx->packed_trx()->get_prunable_size(),
skip_recording );
}
}

trx_context.delay = fc::seconds(trn.delay_sec);
Expand Down Expand Up @@ -1658,7 +1664,7 @@ struct controller_impl {
in_trx_requiring_checks = old_value;
});
in_trx_requiring_checks = true;
push_transaction( onbtrx, fc::time_point::maximum(), gpo.configuration.min_transaction_cpu_usage, true );
push_transaction( onbtrx, fc::time_point::maximum(), gpo.configuration.min_transaction_cpu_usage, true, {} );
} catch( const std::bad_alloc& e ) {
elog( "on block transaction failed due to a std::bad_alloc" );
throw;
Expand Down Expand Up @@ -1890,6 +1896,8 @@ struct controller_impl {

transaction_trace_ptr trace;

bool explicit_net = self.skip_trx_checks();

size_t packed_idx = 0;
const auto& trx_receipts = pending->_block_stage.get<building_block>()._pending_trx_receipts;
for( const auto& receipt : b->transactions ) {
Expand All @@ -1899,7 +1907,11 @@ struct controller_impl {
: ( !!std::get<0>( trx_metas.at( packed_idx ) ) ?
std::get<0>( trx_metas.at( packed_idx ) )
: std::get<1>( trx_metas.at( packed_idx ) ).get() ) );
trace = push_transaction( trx_meta, fc::time_point::maximum(), receipt.cpu_usage_us, true );
fc::optional<uint32_t> explicit_net_usage_words;
if( explicit_net ) {
explicit_net_usage_words = receipt.net_usage_words.value;
}
trace = push_transaction( trx_meta, fc::time_point::maximum(), receipt.cpu_usage_us, true, explicit_net_usage_words );
++packed_idx;
} else if( receipt.trx.contains<transaction_id_type>() ) {
trace = push_scheduled_transaction( receipt.trx.get<transaction_id_type>(), fc::time_point::maximum(), receipt.cpu_usage_us, true );
Expand Down Expand Up @@ -2679,7 +2691,7 @@ transaction_trace_ptr controller::push_transaction( const transaction_metadata_p
validate_db_available_size();
EOS_ASSERT( get_read_mode() != db_read_mode::IRREVERSIBLE, transaction_type_exception, "push transaction not allowed in irreversible mode" );
EOS_ASSERT( trx && !trx->implicit && !trx->scheduled, transaction_type_exception, "Implicit/Scheduled transaction not allowed" );
return my->push_transaction(trx, deadline, billed_cpu_time_us, explicit_billed_cpu_time );
return my->push_transaction(trx, deadline, billed_cpu_time_us, explicit_billed_cpu_time, {} );
}

transaction_trace_ptr controller::push_scheduled_transaction( const transaction_id_type& trxid, fc::time_point deadline,
Expand Down
22 changes: 19 additions & 3 deletions libraries/chain/include/eosio/chain/transaction_context.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,9 @@ namespace eosio { namespace chain {

class transaction_context {
private:
void init( uint64_t initial_net_usage);
void init( uint64_t initial_net_usage );

void init_for_input_trx_common( uint64_t initial_net_usage, bool skip_recording );

public:

Expand All @@ -45,7 +47,10 @@ namespace eosio { namespace chain {

void init_for_input_trx( uint64_t packed_trx_unprunable_size,
uint64_t packed_trx_prunable_size,
bool skip_recording);
bool skip_recording );

void init_for_input_trx_with_explicit_net( uint32_t explicit_net_usage_words,
bool skip_recording );

void init_for_deferred_trx( fc::time_point published );

Expand All @@ -54,7 +59,17 @@ namespace eosio { namespace chain {
void squash();
void undo();

inline void add_net_usage( uint64_t u ) { net_usage += u; check_net_usage(); }
inline void add_net_usage( uint64_t u ) {
if( explicit_net_usage ) return;
net_usage += u;
check_net_usage();
}
heifner marked this conversation as resolved.
Show resolved Hide resolved

inline void round_up_net_usage() {
if( explicit_net_usage ) return;
net_usage = ((net_usage + 7)/8)*8; // Round up to nearest multiple of word size (8 bytes)
check_net_usage();
}

void check_net_usage()const;

Expand Down Expand Up @@ -156,6 +171,7 @@ namespace eosio { namespace chain {
bool net_limit_due_to_greylist = false;
uint64_t eager_net_limit = 0;
uint64_t& net_usage; /// reference to trace->net_usage
bool explicit_net_usage = false;

bool cpu_limit_due_to_greylist = false;

Expand Down
58 changes: 37 additions & 21 deletions libraries/chain/transaction_context.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -75,7 +75,7 @@ namespace eosio { namespace chain {
}
}

void transaction_context::init(uint64_t initial_net_usage)
void transaction_context::init( uint64_t initial_net_usage )
{
EOS_ASSERT( !is_initialized, transaction_exception, "cannot initialize twice" );

Expand Down Expand Up @@ -197,7 +197,7 @@ namespace eosio { namespace chain {
}

published = control.pending_block_time();
init( initial_net_usage);
init( initial_net_usage );
}

void transaction_context::init_for_input_trx( uint64_t packed_trx_unprunable_size,
Expand Down Expand Up @@ -230,14 +230,32 @@ namespace eosio { namespace chain {
+ static_cast<uint64_t>(config::transaction_id_net_usage);
}

init_for_input_trx_common( initial_net_usage, skip_recording );
}

void transaction_context::init_for_input_trx_with_explicit_net( uint32_t explicit_net_usage_words,
bool skip_recording )
{
if( trx.transaction_extensions.size() > 0 ) {
disallow_transaction_extensions( "no transaction extensions supported yet for input transactions" );
}
heifner marked this conversation as resolved.
Show resolved Hide resolved

explicit_net_usage = true;
net_usage = (static_cast<uint64_t>(explicit_net_usage_words) * 8);

init_for_input_trx_common( 0, skip_recording );
}

void transaction_context::init_for_input_trx_common( uint64_t initial_net_usage, bool skip_recording )
{
published = control.pending_block_time();
is_input = true;
if (!control.skip_trx_checks()) {
control.validate_expiration(trx);
control.validate_tapos(trx);
validate_referenced_accounts( trx, enforce_whiteblacklist && control.is_producing_block() );
}
init( initial_net_usage);
init( initial_net_usage );
if (!skip_recording)
record_transaction( id, trx.expiration ); /// checks for dupes
}
Expand Down Expand Up @@ -323,10 +341,10 @@ namespace eosio { namespace chain {
billing_timer_exception_code = tx_cpu_usage_exceeded::code_value;
}

net_usage = ((net_usage + 7)/8)*8; // Round up to nearest multiple of word size (8 bytes)

eager_net_limit = net_limit;
check_net_usage();

round_up_net_usage(); // Round up to nearest multiple of word size (8 bytes).
check_net_usage(); // Check that NET usage satisfies limits (even when explicit_net_usage is true).

arhag marked this conversation as resolved.
Show resolved Hide resolved
auto now = fc::time_point::now();
trace->elapsed = now - start;
Expand All @@ -348,21 +366,19 @@ namespace eosio { namespace chain {
}

void transaction_context::check_net_usage()const {
if (!control.skip_trx_checks()) {
if( BOOST_UNLIKELY(net_usage > eager_net_limit) ) {
if ( net_limit_due_to_block ) {
EOS_THROW( block_net_usage_exceeded,
"not enough space left in block: ${net_usage} > ${net_limit}",
("net_usage", net_usage)("net_limit", eager_net_limit) );
} else if (net_limit_due_to_greylist) {
EOS_THROW( greylist_net_usage_exceeded,
"greylisted transaction net usage is too high: ${net_usage} > ${net_limit}",
("net_usage", net_usage)("net_limit", eager_net_limit) );
} else {
EOS_THROW( tx_net_usage_exceeded,
"transaction net usage is too high: ${net_usage} > ${net_limit}",
("net_usage", net_usage)("net_limit", eager_net_limit) );
}
if( BOOST_UNLIKELY(net_usage > eager_net_limit) ) {
if ( net_limit_due_to_block ) {
EOS_THROW( block_net_usage_exceeded,
"not enough space left in block: ${net_usage} > ${net_limit}",
("net_usage", net_usage)("net_limit", eager_net_limit) );
} else if (net_limit_due_to_greylist) {
EOS_THROW( greylist_net_usage_exceeded,
"greylisted transaction net usage is too high: ${net_usage} > ${net_limit}",
("net_usage", net_usage)("net_limit", eager_net_limit) );
} else {
EOS_THROW( tx_net_usage_exceeded,
"transaction net usage is too high: ${net_usage} > ${net_limit}",
("net_usage", net_usage)("net_limit", eager_net_limit) );
}
}
}
Expand Down
12 changes: 12 additions & 0 deletions libraries/testing/include/eosio/testing/tester.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -638,6 +638,18 @@ namespace eosio { namespace testing {
bool skip_validate = false;
};

/**
* Utility predicate to check whether an fc::exception code is equivalent to a given value
*/
struct fc_exception_code_is {
fc_exception_code_is( int64_t code )
: expected( code ) {}

bool operator()( const fc::exception& ex );

int64_t expected;
};

/**
* Utility predicate to check whether an fc::exception message is equivalent to a given string
*/
Expand Down
9 changes: 9 additions & 0 deletions libraries/testing/tester.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1153,6 +1153,15 @@ namespace eosio { namespace testing {
preactivate_protocol_features( preactivations );
}

bool fc_exception_code_is::operator()( const fc::exception& ex ) {
bool match = (ex.code() == expected);
if( !match ) {
auto message = ex.get_log().at( 0 ).get_message();
BOOST_TEST_MESSAGE( "LOG: expected code: " << expected << ", actual code: " << ex.code() << ", message: " << message );
}
return match;
}

bool fc_exception_message_is::operator()( const fc::exception& ex ) {
auto message = ex.get_log().at( 0 ).get_message();
bool match = (message == expected);
Expand Down
Loading