28 struct trx_cache_entry {
37 using trx_cache_index = bmi::multi_index_container<
40 bmi::hashed_unique<tag<by_id>, BOOST_MULTI_INDEX_MEMBER( trx_cache_entry,
transaction_id_type, trx_id ) >,
41 ordered_non_unique<tag<by_expiry>, BOOST_MULTI_INDEX_MEMBER( trx_cache_entry,
fc::time_point, expiry ) >
47 struct subjective_billing_info {
51 bool empty(
uint32_t time_ordinal,
uint32_t expired_accumulator_average_window) {
52 return pending_cpu_us == 0 && expired_accumulator.
value_at(time_ordinal, expired_accumulator_average_window) == 0;
56 using account_subjective_bill_cache = std::map<account_name, subjective_billing_info>;
57 using block_subjective_bill_cache = std::map<account_name, uint64_t>;
59 bool _disabled =
false;
60 trx_cache_index _trx_cache_index;
61 account_subjective_bill_cache _account_subjective_bill_cache;
62 block_subjective_bill_cache _block_subjective_bill_cache;
63 std::set<chain::account_name> _disabled_accounts;
69 SYS_ASSERT(ordinal <= std::numeric_limits<uint32_t>::max(), chain::tx_resource_exhaustion,
"overflow of quantized time in subjective billing");
73 void remove_subjective_billing(
const trx_cache_entry& entry,
uint32_t time_ordinal ) {
74 auto aitr = _account_subjective_bill_cache.find( entry.account );
75 if( aitr != _account_subjective_bill_cache.end() ) {
76 aitr->second.pending_cpu_us -= entry.subjective_cpu_bill;
77 SYS_ASSERT( aitr->second.pending_cpu_us >= 0, chain::tx_resource_exhaustion,
78 "Logic error in subjective account billing ${a}", (
"a", entry.account) );
79 if( aitr->second.empty(time_ordinal, _expired_accumulator_average_window) ) _account_subjective_bill_cache.erase( aitr );
83 void transition_to_expired(
const trx_cache_entry& entry,
uint32_t time_ordinal ) {
84 auto aitr = _account_subjective_bill_cache.find( entry.account );
85 if( aitr != _account_subjective_bill_cache.end() ) {
86 aitr->second.pending_cpu_us -= entry.subjective_cpu_bill;
87 aitr->second.expired_accumulator.add(entry.subjective_cpu_bill, time_ordinal, _expired_accumulator_average_window);
92 if( !_trx_cache_index.empty() ) {
93 for(
const auto& receipt : bsp->block->transactions ) {
94 if( std::holds_alternative<packed_transaction>(receipt.trx) ) {
95 const auto& pt = std::get<packed_transaction>(receipt.trx);
96 remove_subjective_billing( pt.id(), time_ordinal );
106 auto& idx = _trx_cache_index.get<by_id>();
107 auto itr = idx.find( trx_id );
108 if( itr != idx.end() ) {
109 remove_subjective_billing( *itr, time_ordinal );
123 if( !_disabled && !_disabled_accounts.count( first_auth ) ) {
125 auto p = _trx_cache_index.emplace(
131 _account_subjective_bill_cache[first_auth].pending_cpu_us += bill;
132 if( in_pending_block ) {
133 _block_subjective_bill_cache[first_auth] += bill;
141 if( !_disabled && !_disabled_accounts.count( first_auth ) ) {
143 const auto time_ordinal = time_ordinal_for(now);
144 _account_subjective_bill_cache[first_auth].expired_accumulator.add(bill, time_ordinal, _expired_accumulator_average_window);
149 if( _disabled || _disabled_accounts.count( first_auth ) )
return 0;
150 const auto time_ordinal = time_ordinal_for(now);
151 const subjective_billing_info* sub_bill_info =
nullptr;
152 auto aitr = _account_subjective_bill_cache.find( first_auth );
153 if( aitr != _account_subjective_bill_cache.end() ) {
154 sub_bill_info = &aitr->second;
156 uint64_t in_block_pending_cpu_us = 0;
157 auto bitr = _block_subjective_bill_cache.find( first_auth );
158 if( bitr != _block_subjective_bill_cache.end() ) {
159 in_block_pending_cpu_us = bitr->second;
163 SYS_ASSERT(sub_bill_info->pending_cpu_us >= in_block_pending_cpu_us, chain::tx_resource_exhaustion,
"Logic error subjective billing ${a}", (
"a", first_auth) );
164 int64_t sub_bill = sub_bill_info->pending_cpu_us - in_block_pending_cpu_us + sub_bill_info->expired_accumulator.
value_at(time_ordinal, _expired_accumulator_average_window );
172 _block_subjective_bill_cache.clear();
176 if( bsp ==
nullptr || _disabled )
return;
177 const auto time_ordinal = time_ordinal_for(now);
178 const auto orig_count = _account_subjective_bill_cache.size();
179 remove_subjective_billing( bsp, time_ordinal );
180 fc_dlog( log,
"Subjective billed accounts ${n} removed ${r}", (
"n", orig_count)(
"r", orig_count - _account_subjective_bill_cache.size()) );
183 template <
typename Yield>
185 bool exhausted =
false;
186 auto& idx = _trx_cache_index.get<by_expiry>();
188 const auto time_ordinal = time_ordinal_for(now);
189 const auto orig_count = _trx_cache_index.size();
192 while( !idx.empty() ) {
197 auto b = idx.begin();
198 if( b->expiry > pending_block_time )
break;
199 transition_to_expired( *b, time_ordinal );
204 fc_dlog( log,
"Processed ${n} subjective billed transactions, Expired ${expired}",
205 (
"n", orig_count)(
"expired", num_expired ) );
211 return _expired_accumulator_average_window;
215 _expired_accumulator_average_window =