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

Addition of a Transaction Extension to Control Payment for Resources #10407

Merged
merged 35 commits into from
Jun 7, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
35 commits
Select commit Hold shift + click to select a range
1fd5cc6
Add resource_payer transaction extension
victorj8 Apr 22, 2021
a242cd6
Merge pull request #10286 from EOSIO/payer-transaction-extension
victorj8 Apr 23, 2021
c8775cc
Change Logic on Producer Plugin to change the account that is going t…
victorj8 Apr 27, 2021
8c62cd2
Transaction context changes for resource payer extension
venu-block1 Apr 27, 2021
5acc36a
Change Logic on Producer Plugin to change the account that is going t…
victorj8 Apr 27, 2021
db78e00
Change Logic on Producer Plugin to change the account that is going t…
victorj8 Apr 27, 2021
c3ee167
Merge pull request #10303 from EOSIO/producer-plugin-resource-payer-c…
victorj8 Apr 27, 2021
ce4f661
Merge branch 'resource_payer' into epe-931_transaction_context
venu-block1 Apr 28, 2021
d5dc8d4
Merge pull request #10304 from EOSIO/epe-931_transaction_context
venu-block1 Apr 29, 2021
08a467d
Merge branch 'develop' into resource_payer
victorj8 May 3, 2021
6c23e43
More transaction context changes for resource payer feature, and addi…
venu-block1 May 4, 2021
80986ca
Add protocol feature TRANSACTION_SPONSORHIP for the resource payer fe…
victorj8 May 5, 2021
0f3c753
Add protocol feature RESOURCE_PAYER for the resource payer feature - …
victorj8 May 7, 2021
adff9c8
Merge pull request #10345 from EOSIO/resource-payer-protocol-feature
victorj8 May 7, 2021
21758d6
Merge branch 'resource_payer' into epe-931_transaction_context
venu-block1 May 7, 2021
a576820
Adding protocol feature checks and other review comment changes
venu-block1 May 10, 2021
10a2d16
Merge branch 'develop' into resource_payer
venu-block1 May 11, 2021
53a40a0
Merge branch 'resource_payer' into epe-931_transaction_context
venu-block1 May 11, 2021
66b723c
submodule updates
venu-block1 May 11, 2021
b37aef7
Merge branch 'resource_payer' into epe-931_transaction_context
venu-block1 May 11, 2021
f843d20
Merge branch 'develop' into resource_payer
victorj8 May 11, 2021
8f8f8e0
submodule updates
venu-block1 May 11, 2021
7708597
Merge branch 'resource_payer' into epe-931_transaction_context
venu-block1 May 11, 2021
7e6031d
Merge pull request #10337 from EOSIO/epe-931_transaction_context
venu-block1 May 11, 2021
9040db5
changes to signature verification
May 11, 2021
2594e37
merged in resource_payer
May 11, 2021
bdd8052
add bill_to_accounts field to a transaction trace & some renaming ref…
victorj8 May 14, 2021
2d6bf3e
Merge pull request #10364 from EOSIO/resource_payer_add_bill_to_accou…
victorj8 May 14, 2021
489f45f
corrected incorrect assert
May 17, 2021
8c8bd1a
Merge branch 'resource_payer' into res_payer_sig
May 17, 2021
11b6f5e
changed method for checking auth for payer infor
May 25, 2021
354a50d
removed vestigal code
May 25, 2021
021ec24
added assertions to test case
May 26, 2021
240361b
Merge pull request #10400 from EOSIO/res_payer_sig
ndcgundlach May 26, 2021
240126c
merged in changes from develop
Jun 4, 2021
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
2 changes: 2 additions & 0 deletions libraries/chain/apply_context.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -359,6 +359,7 @@ void apply_context::execute_inline( action&& a ) {
try {
control.get_authorization_manager()
.check_authorization( {a},
{},
{},
{{receiver, config::eosio_code_name}},
control.pending_block_time() - trx_context.published,
Expand Down Expand Up @@ -525,6 +526,7 @@ void apply_context::schedule_deferred_transaction( const uint128_t& sender_id, a
try {
control.get_authorization_manager()
.check_authorization( trx.actions,
{},
{},
{{receiver, config::eosio_code_name}},
delay,
Expand Down
4 changes: 4 additions & 0 deletions libraries/chain/authorization_manager.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -483,6 +483,7 @@ namespace eosio { namespace chain {
void
authorization_manager::check_authorization( const vector<action>& actions,
const flat_set<public_key_type>& provided_keys,
std::optional<resource_payer_t> payer,
const flat_set<permission_level>& provided_permissions,
fc::microseconds provided_delay,
const std::function<void()>& _checktime,
Expand Down Expand Up @@ -552,6 +553,9 @@ namespace eosio { namespace chain {
}
}
}
if (payer) {
permissions_to_satisfy.emplace(permission_level{payer->payer, config::active_name},effective_provided_delay);
ndcgundlach marked this conversation as resolved.
Show resolved Hide resolved
}

// Now verify that all the declared authorizations are satisfied:

Expand Down
5 changes: 5 additions & 0 deletions libraries/chain/controller.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1179,6 +1179,7 @@ struct controller_impl {
{
EOS_ASSERT(deadline != fc::time_point(), transaction_exception, "deadline cannot be uninitialized");


transaction_trace_ptr trace;
try {
auto start = fc::time_point::now();
Expand Down Expand Up @@ -1216,6 +1217,7 @@ struct controller_impl {

try {
const transaction& trn = trx->packed_trx()->get_transaction();

if( trx->implicit ) {
EOS_ASSERT( !explicit_net_usage_words, transaction_exception, "NET usage cannot be explicitly set for implicit transactions" );
trx_context.init_for_implicit_trx();
Expand All @@ -1234,9 +1236,12 @@ struct controller_impl {
trx_context.delay = fc::seconds(trn.delay_sec);

if( check_auth ) {
auto payer = trn.resource_payer_info(self.is_builtin_activated(builtin_protocol_feature_t::resource_payer));

authorization.check_authorization(
trn.actions,
trx->recovered_keys(),
payer,
{},
trx_context.delay,
[&trx_context](){ trx_context.checktime(); },
Expand Down
14 changes: 14 additions & 0 deletions libraries/chain/include/eosio/chain/abi_serializer.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -566,6 +566,10 @@ namespace impl {
const auto& deferred_transaction_generation = std::get<deferred_transaction_generation_context>(exts.lower_bound(deferred_transaction_generation_context::extension_id())->second);
mvo("deferred_transaction_generation", deferred_transaction_generation);
}
if (exts.count(resource_payer::extension_id()) > 0) {
const auto& res_payer = std::get<resource_payer>(exts.lower_bound(resource_payer::extension_id())->second);
mvo("resource_payer", res_payer);
}
}

/**
Expand Down Expand Up @@ -861,6 +865,16 @@ namespace impl {
extract(vo["actions"], trx.actions, resolver, ctx);
}

if (vo.contains("resource_payer")) {
resource_payer res_payer;
from_variant(vo["resource_payer"], res_payer);
emplace_extension(
trx.transaction_extensions,
resource_payer::extension_id(),
fc::raw::pack( res_payer )
);
}

// can have "deferred_transaction_generation" (if there is a deferred transaction and the extension was "extracted" to show data),
// or "transaction_extensions" (either as empty or containing the packed deferred transaction),
// or both (when there is a deferred transaction and extension was "extracted" to show data and a redundant "transaction_extensions" was provided),
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -79,6 +79,7 @@ namespace eosio { namespace chain {
void
check_authorization( const vector<action>& actions,
const flat_set<public_key_type>& provided_keys,
std::optional<resource_payer_t> payer,
const flat_set<permission_level>& provided_permissions = flat_set<permission_level>(),
fc::microseconds provided_delay = fc::microseconds(0),
const std::function<void()>& checktime = std::function<void()>(),
Expand Down
6 changes: 6 additions & 0 deletions libraries/chain/include/eosio/chain/exceptions.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -382,6 +382,12 @@ namespace eosio { namespace chain {
3080008, "Transaction exceeded the current greylisted account CPU usage limit" )
FC_DECLARE_DERIVED_EXCEPTION( disk_usage_exceeded, resource_exhausted_exception,
3080009, "Account using more than allotted DISK usage" )
FC_DECLARE_DERIVED_EXCEPTION( resource_payer_net_exceeded, resource_exhausted_exception,
3080010, "Transaction exceeded the resource payer network usage limit" )
FC_DECLARE_DERIVED_EXCEPTION( resource_payer_cpu_exceeded, resource_exhausted_exception,
3080011, "Transaction exceeded the resource payer CPU usage limit" )
FC_DECLARE_DERIVED_EXCEPTION( resource_payer_memory_exceeded, resource_exhausted_exception,
3080012, "FOR FUTURE USE - Transaction exceeded the resource payer RAM usage limit" )

FC_DECLARE_DERIVED_EXCEPTION( leeway_deadline_exception, deadline_exception,
3081001, "Transaction reached the deadline set due to leeway on account CPU limits" )
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,8 @@ enum class builtin_protocol_feature_t : uint32_t {
kv_database,
configurable_wasm_limits,
blockchain_parameters,
security_group
security_group,
resource_payer
};

struct protocol_feature_subjective_restrictions {
Expand Down
2 changes: 1 addition & 1 deletion libraries/chain/include/eosio/chain/resource_limits.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -75,7 +75,7 @@ namespace eosio { namespace chain { namespace resource_limits {
void set_block_parameters( const elastic_limit_parameters& cpu_limit_parameters, const elastic_limit_parameters& net_limit_parameters );

void update_account_usage( const flat_set<account_name>& accounts, uint32_t ordinal );
void add_transaction_usage( const flat_set<account_name>& accounts, uint64_t cpu_usage, uint64_t net_usage, uint32_t ordinal );
void add_transaction_usage( const flat_set<account_name>& accounts, uint64_t cpu_usage, uint64_t net_usage, uint32_t ordinal, bool use_resource_payer_cpu_limit = false, bool use_resource_payer_net_limit = false );

void add_pending_ram_usage( const account_name account, int64_t ram_delta, const storage_usage_trace& trace );
void verify_account_ram_usage( const account_name accunt )const;
Expand Down
4 changes: 3 additions & 1 deletion libraries/chain/include/eosio/chain/trace.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -64,6 +64,7 @@ namespace eosio { namespace chain {
std::optional<fc::exception> except;
std::optional<uint64_t> error_code;
std::exception_ptr except_ptr;
flat_set<account_name> bill_to_accounts;
};

/**
Expand Down Expand Up @@ -124,4 +125,5 @@ FC_REFLECT( eosio::chain::action_trace,
// @ignore except_ptr
FC_REFLECT( eosio::chain::transaction_trace, (id)(block_num)(block_time)(producer_block_id)
(receipt)(elapsed)(net_usage)(scheduled)
(action_traces)(account_ram_delta)(failed_dtrx_trace)(except)(error_code) )
(action_traces)(account_ram_delta)(failed_dtrx_trace)(except)(error_code)
(bill_to_accounts) )
39 changes: 37 additions & 2 deletions libraries/chain/include/eosio/chain/transaction.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,14 @@

namespace eosio { namespace chain {

enum transaction_extension_id {
deferred_transaction_generation_context_id = 0,
resource_payer_id,
TRANSACTION_EXTENSION_ID_COUNT
};

struct deferred_transaction_generation_context : fc::reflect_init {
static constexpr uint16_t extension_id() { return 0; }
static constexpr uint16_t extension_id() { return transaction_extension_id::deferred_transaction_generation_context_id; }
static constexpr bool enforce_unique() { return true; }

deferred_transaction_generation_context() = default;
Expand All @@ -24,6 +30,30 @@ namespace eosio { namespace chain {
account_name sender;
};

struct resource_payer : fc::reflect_init {
static constexpr uint16_t extension_id() { return transaction_extension_id::resource_payer_id; }
static constexpr bool enforce_unique() { return true; }

resource_payer() = default;

resource_payer( account_name payer, uint64_t max_net_bytes, uint64_t max_cpu_us, uint64_t max_memory_bytes )
: payer(payer)
,max_net_bytes( max_net_bytes )
,max_cpu_us( max_cpu_us )
,max_memory_bytes( max_memory_bytes )
{}

void reflector_init();

account_name payer;

uint64_t max_net_bytes = 0;
uint64_t max_cpu_us = 0;
uint64_t max_memory_bytes = 0;
};

using resource_payer_t = struct resource_payer;

namespace detail {
template<typename... Ts>
struct transaction_extension_types {
Expand All @@ -33,7 +63,8 @@ namespace eosio { namespace chain {
}

using transaction_extension_types = detail::transaction_extension_types<
deferred_transaction_generation_context
deferred_transaction_generation_context,
resource_payer
>;

using transaction_extension = transaction_extension_types::transaction_extension_t;
Expand Down Expand Up @@ -98,6 +129,9 @@ namespace eosio { namespace chain {
return account_name();
}

account_name resource_payer(bool)const;
std::optional<resource_payer_t> resource_payer_info( bool is_resource_payer_pf_activated ) const;

flat_multimap<uint16_t, transaction_extension> validate_and_extract_extensions()const;
};

Expand Down Expand Up @@ -352,6 +386,7 @@ namespace eosio { namespace chain {
} } /// namespace eosio::chain

FC_REFLECT(eosio::chain::deferred_transaction_generation_context, (sender_trx_id)(sender_id)(sender) )
FC_REFLECT(eosio::chain::resource_payer, (payer)(max_net_bytes)(max_cpu_us)(max_memory_bytes) )
FC_REFLECT( eosio::chain::transaction_header, (expiration)(ref_block_num)(ref_block_prefix)
(max_net_usage_words)(max_cpu_usage_ms)(delay_sec) )
FC_REFLECT_DERIVED( eosio::chain::transaction, (eosio::chain::transaction_header), (context_free_actions)(actions)(transaction_extensions) )
Expand Down
4 changes: 2 additions & 2 deletions libraries/chain/include/eosio/chain/transaction_context.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -143,8 +143,8 @@ namespace eosio { namespace chain {
void schedule_transaction();
void record_transaction( const transaction_id_type& id, fc::time_point_sec expire );

void validate_cpu_usage_to_bill( int64_t billed_us, int64_t account_cpu_limit, bool check_minimum )const;
void validate_account_cpu_usage( int64_t billed_us, int64_t account_cpu_limit )const;
void validate_cpu_usage_to_bill( int64_t billed_us, int64_t account_cpu_limit, bool check_minimum, std::optional<resource_payer_t>& res_pyr )const;
void validate_account_cpu_usage( int64_t billed_us, int64_t account_cpu_limit, std::optional<resource_payer_t>& res_pyr )const;
void validate_account_cpu_usage_estimate( int64_t billed_us, int64_t account_cpu_limit )const;

void disallow_transaction_extensions( const char* error_msg )const;
Expand Down
11 changes: 11 additions & 0 deletions libraries/chain/protocol_feature_manager.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -238,6 +238,17 @@ Allows privileged contracts to get and set subsets of blockchain parameters.
Builtin protocol feature: SECURITY_GROUP

Allows privileged contracts to add/remove participants for mutual TLS enforcement.
*/
{}
} )
(builtin_protocol_feature_t::resource_payer, builtin_protocol_feature_spec{
"RESOURCE_PAYER",
fc::variant("3d6f070c7cfcbbdbf2c07365f54d2cc9108b98b502e07495e8cc6f6e6dbf13bc").as<digest_type>(),
// SHA256 hash of the raw message below within the comment delimiters (do not modify message below).
/*
Builtin protocol feature: RESOURCE_PAYER

Allows a 3rd party account to pay (sponsor) for the resources on the transactions of another account.
*/
{}
} )
Expand Down
48 changes: 35 additions & 13 deletions libraries/chain/resource_limits.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -169,7 +169,7 @@ void resource_limits_manager::update_account_usage(const flat_set<account_name>&
}
}

void resource_limits_manager::add_transaction_usage(const flat_set<account_name>& accounts, uint64_t cpu_usage, uint64_t net_usage, uint32_t time_slot ) {
void resource_limits_manager::add_transaction_usage(const flat_set<account_name>& accounts, uint64_t cpu_usage, uint64_t net_usage, uint32_t time_slot, bool use_resource_payer_cpu_limit, bool use_resource_payer_net_limit ) {
const auto& state = _db.get<resource_limits_state_object>();
const auto& config = _db.get<resource_limits_config_object>();

Expand Down Expand Up @@ -202,12 +202,23 @@ void resource_limits_manager::add_transaction_usage(const flat_set<account_name>

auto max_user_use_in_window = (virtual_network_capacity_in_window * user_weight) / all_user_weight;

EOS_ASSERT( cpu_used_in_window <= max_user_use_in_window,
tx_cpu_usage_exceeded,
"authorizing account '${n}' has insufficient cpu resources for this transaction",
("n", name(a))
("cpu_used_in_window",cpu_used_in_window)
("max_user_use_in_window",max_user_use_in_window) );
if ( use_resource_payer_cpu_limit ) {
EOS_ASSERT( cpu_used_in_window <= max_user_use_in_window,
resource_payer_cpu_exceeded,
"resource payer account '${n}' has insufficient cpu resources for this transaction, "
"used '${cpu_used_in_window}', max '${max_user_use_in_window}'",
("n", name(a))
("cpu_used_in_window",cpu_used_in_window)
("max_user_use_in_window",max_user_use_in_window) );
} else {
EOS_ASSERT( cpu_used_in_window <= max_user_use_in_window,
tx_cpu_usage_exceeded,
"authorizing account '${n}' has insufficient cpu resources for this transaction, "
"used '${cpu_used_in_window}', max '${max_user_use_in_window}'",
("n", name(a))
("cpu_used_in_window",cpu_used_in_window)
("max_user_use_in_window",max_user_use_in_window) );
}
}

if( net_weight >= 0 && state.total_net_weight > 0) {
Expand All @@ -221,12 +232,23 @@ void resource_limits_manager::add_transaction_usage(const flat_set<account_name>

auto max_user_use_in_window = (virtual_network_capacity_in_window * user_weight) / all_user_weight;

EOS_ASSERT( net_used_in_window <= max_user_use_in_window,
tx_net_usage_exceeded,
"authorizing account '${n}' has insufficient net resources for this transaction",
("n", name(a))
("net_used_in_window",net_used_in_window)
("max_user_use_in_window",max_user_use_in_window) );
if ( use_resource_payer_net_limit ) {
EOS_ASSERT( net_used_in_window <= max_user_use_in_window,
resource_payer_net_exceeded,
"resource payer account '${n}' has insufficient net resources for this transaction, "
"used '${net_used_in_window}', max '${max_user_use_in_window}'",
("n", name(a))
("net_used_in_window",net_used_in_window)
("max_user_use_in_window",max_user_use_in_window) );
} else {
EOS_ASSERT( net_used_in_window <= max_user_use_in_window,
tx_net_usage_exceeded,
"authorizing account '${n}' has insufficient net resources for this transaction, "
"used '${net_used_in_window}', max '${max_user_use_in_window}'",
("n", name(a))
("net_used_in_window",net_used_in_window)
("max_user_use_in_window",max_user_use_in_window) );
}

}
}
Expand Down
53 changes: 53 additions & 0 deletions libraries/chain/transaction.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,11 @@ void deferred_transaction_generation_context::reflector_init() {
);
}

void resource_payer::reflector_init() {
static_assert( fc::raw::has_feature_reflector_init_on_unpacked_reflected_types,
"resource_payer expects FC to support reflector_init" );
}

void transaction_header::set_reference_block( const block_id_type& reference_block ) {
ref_block_num = fc::endian_reverse_u32(reference_block._hash[0]);
ref_block_prefix = reference_block._hash[1];
Expand Down Expand Up @@ -77,6 +82,54 @@ fc::microseconds transaction::get_signature_keys( const vector<signature_type>&
return fc::time_point::now() - start;
} FC_CAPTURE_AND_RETHROW() }

account_name transaction::resource_payer(bool is_resource_payer_pf_activated)const {
account_name resource_payer;

bool payer_was_set = false;

if(is_resource_payer_pf_activated) {
// Check for the existence of an extension of the type resource_payer
auto extensions = validate_and_extract_extensions();


if(!extensions.empty()) {
auto itr = extensions.lower_bound(resource_payer::extension_id());
if(itr != extensions.end()) {
const auto& resource_payer_info = std::get<eosio::chain::resource_payer>(itr->second);
resource_payer = resource_payer_info.payer;
payer_was_set = true;
}
}
}

if(!payer_was_set) {
resource_payer = first_authorizer();
}

return resource_payer;
}

std::optional<resource_payer_t> transaction::resource_payer_info( bool is_resource_payer_pf_activated ) const {

// Check for the existence of an extension of the type resource_payer
bool has_res_pyr = false;
resource_payer_t res_pyr;

if( is_resource_payer_pf_activated && transaction_extensions.size() > 0 ) {
std::find_if( transaction_extensions.begin(), transaction_extensions.end(),
[&](auto& elem) {
bool ret = elem.first == transaction_extension_id::resource_payer_id;
if (ret) {
fc::raw::unpack(elem.second, res_pyr);
has_res_pyr = true;
}
return ret;
} );
}

return has_res_pyr ? std::optional<resource_payer_t>(res_pyr) : std::nullopt;
}

flat_multimap<uint16_t, transaction_extension> transaction::validate_and_extract_extensions()const {
using decompose_t = transaction_extension_types::decompose_t;

Expand Down
Loading