Wire Sysio Wire Sysion 1.0.0
Loading...
Searching...
No Matches
sysio::chain_apis::account_query_db_impl Struct Reference
Collaboration diagram for sysio::chain_apis::account_query_db_impl:

Public Types

using permission_set_t = std::set<chain::permission_level>
 
using cached_trace_map_t = std::map<chain::transaction_id_type, chain::transaction_trace_ptr>
 
using onblock_trace_t = std::optional<chain::transaction_trace_ptr>
 
using time_map_t = std::map<fc::time_point, uint32_t>
 
using name_bimap_t = bimap<multiset_of<weighted<chain::permission_level>>, multiset_of<permission_info::cref>>
 
using key_bimap_t = bimap<multiset_of<weighted<chain::public_key_type>>, multiset_of<permission_info::cref>>
 

Public Member Functions

 account_query_db_impl (const chain::controller &controller)
 
void build_account_query_map ()
 
void add_to_bimaps (const permission_info &pi, const chain::permission_object &po)
 
void remove_from_bimaps (const permission_info &pi)
 
bool is_rollback_required (const chain::block_state_ptr &bsp) const
 
uint32_t last_updated_time_to_height (const fc::time_point &last_updated)
 
void rollback_to_before (const chain::block_state_ptr &bsp)
 
void cache_transaction_trace (const chain::transaction_trace_ptr &trace)
 
auto commit_block_prelock (const chain::block_state_ptr &bsp) const
 
void commit_block (const chain::block_state_ptr &bsp)
 
account_query_db::get_accounts_by_authorizers_result get_accounts_by_authorizers (const account_query_db::get_accounts_by_authorizers_params &args) const
 

Public Attributes

const chain::controllercontroller
 the controller to read data from
 
cached_trace_map_t cached_trace_map
 temporary cache of uncommitted traces
 
onblock_trace_t onblock_trace
 temporary cache of on_block trace
 
time_map_t time_to_block_num
 
permission_info_index_t permission_info_index
 multi-index that holds ephemeral indices
 
name_bimap_t name_bimap
 many:many bimap of names:permission_infos
 
key_bimap_t key_bimap
 many:many bimap of keys:permission_infos
 
std::shared_mutex rw_mutex
 mutex for read/write locking on the Multi-index and bimaps
 

Detailed Description

Implementation details of the account query DB

Definition at line 131 of file account_query_db.cpp.

Member Typedef Documentation

◆ cached_trace_map_t

◆ key_bimap_t

using sysio::chain_apis::account_query_db_impl::key_bimap_t = bimap<multiset_of<weighted<chain::public_key_type>>, multiset_of<permission_info::cref>>

Definition at line 495 of file account_query_db.cpp.

◆ name_bimap_t

using sysio::chain_apis::account_query_db_impl::name_bimap_t = bimap<multiset_of<weighted<chain::permission_level>>, multiset_of<permission_info::cref>>

Definition at line 494 of file account_query_db.cpp.

◆ onblock_trace_t

◆ permission_set_t

◆ time_map_t

Constructor & Destructor Documentation

◆ account_query_db_impl()

sysio::chain_apis::account_query_db_impl::account_query_db_impl ( const chain::controller & controller)
inline

Definition at line 132 of file account_query_db.cpp.

134 {}
const chain::controller & controller
the controller to read data from

Member Function Documentation

◆ add_to_bimaps()

void sysio::chain_apis::account_query_db_impl::add_to_bimaps ( const permission_info & pi,
const chain::permission_object & po )
inline

Add a permission to the bimaps for keys and accounts

Parameters
pi- the ephemeral permission info structure being added
po- the chain data associted with this permission

Definition at line 171 of file account_query_db.cpp.

171 {
172 // For each account, add this permission info's non-owning reference to the bimap for accounts
173 for (const auto& a : po.auth.accounts) {
174 name_bimap.insert(name_bimap_t::value_type {{a.permission, a.weight}, pi});
175 }
176
177 // for each key, add this permission info's non-owning reference to the bimap for keys
178 for (const auto& k: po.auth.keys) {
179 chain::public_key_type key = k.key;
180 key_bimap.insert(key_bimap_t::value_type {{std::move(key), k.weight}, pi});
181 }
182 }
fc::crypto::public_key public_key_type
Definition types.hpp:76
const GenericPointer< typename T::ValueType > T2 T::AllocatorType & a
Definition pointer.h:1181
name_bimap_t name_bimap
many:many bimap of names:permission_infos
key_bimap_t key_bimap
many:many bimap of keys:permission_infos
Here is the caller graph for this function:

◆ build_account_query_map()

void sysio::chain_apis::account_query_db_impl::build_account_query_map ( )
inline

Build the initial database from the chain controller by extracting the information contained in the blockchain state at the current HEAD

Definition at line 140 of file account_query_db.cpp.

140 {
141 std::unique_lock write_lock(rw_mutex);
142
143 ilog("Building account query DB");
144 auto start = fc::time_point::now();
145 const auto& index = controller.db().get_index<chain::permission_index>().indices().get<by_id>();
146
147 // build a initial time to block number map
148 const auto lib_num = controller.last_irreversible_block_num();
149 const auto head_num = controller.head_block_num();
150
151 for (uint32_t block_num = lib_num + 1; block_num <= head_num; block_num++) {
152 const auto block_p = controller.fetch_block_by_number(block_num);
153 SYS_ASSERT(block_p, chain::plugin_exception, "cannot fetch reversible block ${block_num}, required for account_db initialization", ("block_num", block_num));
154 time_to_block_num.emplace(block_p->timestamp.to_time_point(), block_num);
155 }
156
157 for (const auto& po : index ) {
158 uint32_t last_updated_height = last_updated_time_to_height(po.last_updated);
159 const auto& pi = permission_info_index.emplace( permission_info{ po.owner, po.name, last_updated_height, po.auth.threshold } ).first;
160 add_to_bimaps(*pi, po);
161 }
162 auto duration = fc::time_point::now() - start;
163 ilog("Finished building account query DB in ${sec}", ("sec", (duration.count() / 1'000'000.0 )));
164 }
#define SYS_ASSERT(expr, exc_type, FORMAT,...)
Definition exceptions.hpp:7
const generic_index< MultiIndexType > & get_index() const
static time_point now()
Definition time.cpp:14
const chainbase::database & db() const
signed_block_ptr fetch_block_by_number(uint32_t block_num) const
uint32_t head_block_num() const
uint32_t last_irreversible_block_num() const
#define ilog(FORMAT,...)
Definition logger.hpp:118
chainbase::shared_multi_index_container< permission_object, indexed_by< ordered_unique< tag< by_id >, member< permission_object, permission_object::id_type, &permission_object::id > >, ordered_unique< tag< by_parent >, composite_key< permission_object, member< permission_object, permission_object::id_type, &permission_object::parent >, member< permission_object, permission_object::id_type, &permission_object::id > > >, ordered_unique< tag< by_owner >, composite_key< permission_object, member< permission_object, account_name, &permission_object::owner >, member< permission_object, permission_name, &permission_object::name > > >, ordered_unique< tag< by_name >, composite_key< permission_object, member< permission_object, permission_name, &permission_object::name >, member< permission_object, permission_object::id_type, &permission_object::id > > > > > permission_index
unsigned int uint32_t
Definition stdint.h:126
uint32_t last_updated_time_to_height(const fc::time_point &last_updated)
void add_to_bimaps(const permission_info &pi, const chain::permission_object &po)
permission_info_index_t permission_info_index
multi-index that holds ephemeral indices
std::shared_mutex rw_mutex
mutex for read/write locking on the Multi-index and bimaps
Here is the call graph for this function:

◆ cache_transaction_trace()

void sysio::chain_apis::account_query_db_impl::cache_transaction_trace ( const chain::transaction_trace_ptr & trace)
inline

Store a potentially relevant transaction trace in a short lived cache so that it can be processed if its committed to by a block

Parameters
trace

Definition at line 286 of file account_query_db.cpp.

286 {
287 if( !trace->receipt ) return;
288 // include only executed transactions; soft_fail included so that onerror (and any inlines via onerror) are included
289 if((trace->receipt->status != chain::transaction_receipt_header::executed &&
290 trace->receipt->status != chain::transaction_receipt_header::soft_fail)) {
291 return;
292 }
293 if( is_onblock( trace )) {
294 onblock_trace.emplace( trace );
295 } else if( trace->failed_dtrx_trace ) {
296 cached_trace_map[trace->failed_dtrx_trace->id] = trace;
297 } else {
298 cached_trace_map[trace->id] = trace;
299 }
300 }
bool is_onblock(const transaction_trace &tt)
Definition trace.hpp:71
@ executed
succeed, no error handler executed
Definition block.hpp:14
@ soft_fail
objectively failed (not executed), error handler executed
Definition block.hpp:15
onblock_trace_t onblock_trace
temporary cache of on_block trace
cached_trace_map_t cached_trace_map
temporary cache of uncommitted traces
Here is the call graph for this function:

◆ commit_block()

void sysio::chain_apis::account_query_db_impl::commit_block ( const chain::block_state_ptr & bsp)
inline

Commit a block of transactions to the account query DB transaction traces need to be in the cache prior to this call

Parameters
bsp

Definition at line 363 of file account_query_db.cpp.

363 {
364 permission_set_t updated;
365 permission_set_t deleted;
366 bool rollback_required = false;
367
368 std::tie(updated, deleted, rollback_required) = commit_block_prelock(bsp);
369
370 // optimistic skip of locking section if there is nothing to do
371 if (!updated.empty() || !deleted.empty() || rollback_required) {
372 std::unique_lock write_lock(rw_mutex);
373
375
376 // insert this blocks time into the time map
377 time_to_block_num.emplace(bsp->header.timestamp, bsp->block_num);
378
379 const auto bnum = bsp->block_num;
380 auto& index = permission_info_index.get<by_owner_name>();
381 const auto& permission_by_owner = controller.db().get_index<chain::permission_index>().indices().get<chain::by_owner>();
382
383 // for each updated permission, find the new values and update the account query db
384 for (const auto& up: updated) {
385 auto key = std::make_tuple(up.actor, up.permission);
386 auto source_itr = permission_by_owner.find(key);
387 SYS_ASSERT(source_itr != permission_by_owner.end(), chain::plugin_exception, "chain data is missing");
388 auto itr = index.find(key);
389 if (itr == index.end()) {
390 const auto& po = *source_itr;
391 itr = index.emplace(permission_info{ po.owner, po.name, bnum, po.auth.threshold }).first;
392 } else {
393 remove_from_bimaps(*itr);
394 index.modify(itr, [&](auto& mutable_pi){
395 mutable_pi.last_updated_height = bnum;
396 mutable_pi.threshold = source_itr->auth.threshold;
397 });
398 }
399
400 add_to_bimaps(*itr, *source_itr);
401 }
402
403 // for all deleted permissions, process their removal from the account query DB
404 for (const auto& dp: deleted) {
405 auto key = std::make_tuple(dp.actor, dp.permission);
406 auto itr = index.find(key);
407 if (itr != index.end()) {
408 remove_from_bimaps(*itr);
409 index.erase(itr);
410 }
411 }
412 }
413
414 // drop any unprocessed cached traces
415 cached_trace_map.clear();
416 onblock_trace.reset();
417 }
void rollback_to_before(const chain::block_state_ptr &bsp)
std::set< chain::permission_level > permission_set_t
void remove_from_bimaps(const permission_info &pi)
auto commit_block_prelock(const chain::block_state_ptr &bsp) const
Here is the call graph for this function:

◆ commit_block_prelock()

auto sysio::chain_apis::account_query_db_impl::commit_block_prelock ( const chain::block_state_ptr & bsp) const
inline

Pre-Commit step with const qualifier to guarantee it does not mutate the thread-safe data set

Parameters
bsp

process traces to find updateauth and deleteauth calls maintaining a final set of permissions to either update or delete. Intra-block changes are discarded

Definition at line 308 of file account_query_db.cpp.

308 {
309 permission_set_t updated;
310 permission_set_t deleted;
311
316 auto process_trace = [&](const chain::transaction_trace_ptr& trace) {
317 for( const auto& at : trace->action_traces ) {
318 if (std::tie(at.receiver, at.act.account) != std::tie(chain::config::system_account_name,chain::config::system_account_name)) {
319 continue;
320 }
321
322 if (at.act.name == chain::updateauth::get_name()) {
323 auto data = at.act.data_as<chain::updateauth>();
324 auto itr = updated.emplace(chain::permission_level{data.account, data.permission}).first;
325 deleted.erase(*itr);
326 } else if (at.act.name == chain::deleteauth::get_name()) {
327 auto data = at.act.data_as<chain::deleteauth>();
328 auto itr = deleted.emplace(chain::permission_level{data.account, data.permission}).first;
329 updated.erase(*itr);
330 } else if (at.act.name == chain::newaccount::get_name()) {
331 auto data = at.act.data_as<chain::newaccount>();
332 updated.emplace(chain::permission_level{data.name, "owner"_n});
333 updated.emplace(chain::permission_level{data.name, "active"_n});
334 }
335 }
336 };
337
338 if( onblock_trace )
339 process_trace(*onblock_trace);
340
341 for( const auto& r : bsp->block->transactions ) {
343 if( std::holds_alternative<chain::transaction_id_type>(r.trx)) {
344 id = std::get<chain::transaction_id_type>(r.trx);
345 } else {
346 id = std::get<chain::packed_transaction>(r.trx).id();
347 }
348
349 const auto it = cached_trace_map.find( id );
350 if( it != cached_trace_map.end() ) {
351 process_trace( it->second );
352 }
353 }
354
355 return std::make_tuple(std::move(updated), std::move(deleted), is_rollback_required(bsp));
356 }
const mie::Vuint & r
Definition bn.cpp:28
uint64_t id
Definition code_cache.cpp:0
std::shared_ptr< transaction_trace > transaction_trace_ptr
Definition trace.hpp:20
checksum_type transaction_id_type
Definition types.hpp:236
static action_name get_name()
static action_name get_name()
static action_name get_name()
bool is_rollback_required(const chain::block_state_ptr &bsp) const
Here is the call graph for this function:
Here is the caller graph for this function:

◆ get_accounts_by_authorizers()

account_query_db::get_accounts_by_authorizers_result sysio::chain_apis::account_query_db_impl::get_accounts_by_authorizers ( const account_query_db::get_accounts_by_authorizers_params & args) const
inline

Add a range of results

Definition at line 420 of file account_query_db.cpp.

420 {
421 std::shared_lock read_lock(rw_mutex);
422
423 using result_t = account_query_db::get_accounts_by_authorizers_result;
424 result_t result;
425
426 // deduplicate inputs
427 auto account_set = std::set<chain::permission_level>(args.accounts.begin(), args.accounts.end());
428 const auto key_set = std::set<chain::public_key_type>(args.keys.begin(), args.keys.end());
429
433 auto push_results = [&result](const auto& begin, const auto& end) {
434 for (auto itr = begin; itr != end; ++itr) {
435 const auto& pi = itr->second.get();
436 const auto& authorizer = itr->first.value;
437 auto weight = itr->first.weight;
438
439 result.accounts.emplace_back(result_t::account_result{
440 pi.owner,
441 pi.name,
442 make_optional_authorizer<chain::permission_level>(authorizer),
443 make_optional_authorizer<chain::public_key_type>(authorizer),
444 weight,
445 pi.threshold
446 });
447 }
448 };
449
450
451 for (const auto& a: account_set) {
452 if (a.permission.empty()) {
453 // empty permission is a wildcard
454 // construct a range between the lower bound of the given account and the lower bound of the
455 // next possible account name
456 const auto begin = name_bimap.left.lower_bound(weighted<chain::permission_level>::lower_bound_for({a.actor, a.permission}));
457 const auto next_account_name = chain::name(a.actor.to_uint64_t() + 1);
458 const auto end = name_bimap.left.lower_bound(weighted<chain::permission_level>::lower_bound_for({next_account_name, a.permission}));
459 push_results(begin, end);
460 } else {
461 // construct a range of all possible weights for an account/permission pair
462 const auto p = chain::permission_level{a.actor, a.permission};
463 const auto begin = name_bimap.left.lower_bound(weighted<chain::permission_level>::lower_bound_for(p));
464 const auto end = name_bimap.left.upper_bound(weighted<chain::permission_level>::upper_bound_for(p));
465 push_results(begin, end);
466 }
467 }
468
469 for (const auto& k: key_set) {
470 // construct a range of all possible weights for a key
471 const auto begin = key_bimap.left.lower_bound(weighted<chain::public_key_type>::lower_bound_for(k));
472 const auto end = key_bimap.left.upper_bound(weighted<chain::public_key_type>::upper_bound_for(k));
473 push_results(begin, end);
474 }
475
476 return result;
477 }
const mie::Vuint & p
Definition bn.cpp:27
boost::interprocess::sharable_lock< read_write_mutex > read_lock
Definition chainbase.hpp:64

◆ is_rollback_required()

bool sysio::chain_apis::account_query_db_impl::is_rollback_required ( const chain::block_state_ptr & bsp) const
inline

Definition at line 198 of file account_query_db.cpp.

198 {
199 std::shared_lock read_lock(rw_mutex);
200 const auto bnum = bsp->block->block_num();
201 const auto& index = permission_info_index.get<by_last_updated_height>();
202
203 if (index.empty()) {
204 return false;
205 } else {
206 const auto& pi = (*index.rbegin());
207 if (pi.last_updated_height < bnum) {
208 return false;
209 }
210 }
211
212 return true;
213 }
Here is the caller graph for this function:

◆ last_updated_time_to_height()

uint32_t sysio::chain_apis::account_query_db_impl::last_updated_time_to_height ( const fc::time_point & last_updated)
inline

Definition at line 215 of file account_query_db.cpp.

215 {
216 const auto lib_num = controller.last_irreversible_block_num();
217 const auto lib_time = controller.last_irreversible_block_time();
218
219 uint32_t last_updated_height = lib_num;
220 if (last_updated > lib_time) {
221 const auto iter = time_to_block_num.find(last_updated);
222 SYS_ASSERT(iter != time_to_block_num.end(), chain::plugin_exception, "invalid block time encountered in on-chain accounts ${time}", ("time", last_updated));
223 last_updated_height = iter->second;
224 }
225
226 return last_updated_height;
227 }
time_point last_irreversible_block_time() const
Here is the call graph for this function:
Here is the caller graph for this function:

◆ remove_from_bimaps()

void sysio::chain_apis::account_query_db_impl::remove_from_bimaps ( const permission_info & pi)
inline

Remove a permission from the bimaps for keys and accounts

Parameters
pi- the ephemeral permission info structure being removed

Definition at line 188 of file account_query_db.cpp.

188 {
189 // remove all entries from the name bimap that refer to this permission_info's reference
190 const auto name_range = name_bimap.right.equal_range(pi);
191 name_bimap.right.erase(name_range.first, name_range.second);
192
193 // remove all entries from the key bimap that refer to this permission_info's reference
194 const auto key_range = key_bimap.right.equal_range(pi);
195 key_bimap.right.erase(key_range.first, key_range.second);
196 }
Here is the caller graph for this function:

◆ rollback_to_before()

void sysio::chain_apis::account_query_db_impl::rollback_to_before ( const chain::block_state_ptr & bsp)
inline

Given a block number, remove all permissions that were last updated at or after that block number this will effectively roll back the database to just before the incoming block

For each removed entry, this will create a new entry if there exists an equivalent {owner, name} permission at the HEAD state of the chain.

Parameters
bsp- the block to rollback before

Definition at line 237 of file account_query_db.cpp.

237 {
238 const auto bnum = bsp->block->block_num();
239 auto& index = permission_info_index.get<by_last_updated_height>();
240 const auto& permission_by_owner = controller.db().get_index<chain::permission_index>().indices().get<chain::by_owner>();
241
242 // roll back time-map
243 auto time_iter = time_to_block_num.rbegin();
244 while (time_iter != time_to_block_num.rend() && time_iter->second >= bnum) {
245 time_iter = decltype(time_iter){time_to_block_num.erase( std::next(time_iter).base() )};
246 }
247
248 auto curr_iter = index.rbegin();
249 while (!index.empty()) {
250 if (curr_iter == index.rend()) {
251 break;
252 }
253
254 const auto& pi = (*curr_iter);
255 if (pi.last_updated_height < bnum) {
256 break;
257 }
258
259 // remove this entry from the bimaps
261
262 auto itr = permission_by_owner.find(std::make_tuple(pi.owner, pi.name));
263 if (itr == permission_by_owner.end()) {
264 // this permission does not exist at this point in the chains history
265 curr_iter = decltype(curr_iter)( index.erase(index.iterator_to(pi)) );
266 } else {
267 const auto& po = *itr;
268
269 uint32_t last_updated_height = po.last_updated == bsp->header.timestamp ? bsp->block_num : last_updated_time_to_height(po.last_updated);
270
271 index.modify(index.iterator_to(pi), [&po, last_updated_height](auto& mutable_pi) {
272 mutable_pi.last_updated_height = last_updated_height;
273 mutable_pi.threshold = po.auth.threshold;
274 });
275 add_to_bimaps(pi, po);
276 ++curr_iter;
277 }
278 }
279 }
Here is the call graph for this function:
Here is the caller graph for this function:

Member Data Documentation

◆ cached_trace_map

cached_trace_map_t sysio::chain_apis::account_query_db_impl::cached_trace_map

Definition at line 486 of file account_query_db.cpp.

◆ controller

const chain::controller& sysio::chain_apis::account_query_db_impl::controller

Definition at line 485 of file account_query_db.cpp.

◆ key_bimap

key_bimap_t sysio::chain_apis::account_query_db_impl::key_bimap

Definition at line 503 of file account_query_db.cpp.

◆ name_bimap

name_bimap_t sysio::chain_apis::account_query_db_impl::name_bimap

Definition at line 502 of file account_query_db.cpp.

◆ onblock_trace

onblock_trace_t sysio::chain_apis::account_query_db_impl::onblock_trace

Definition at line 487 of file account_query_db.cpp.

◆ permission_info_index

permission_info_index_t sysio::chain_apis::account_query_db_impl::permission_info_index

Definition at line 501 of file account_query_db.cpp.

◆ rw_mutex

std::shared_mutex sysio::chain_apis::account_query_db_impl::rw_mutex
mutable

Definition at line 505 of file account_query_db.cpp.

◆ time_to_block_num

time_map_t sysio::chain_apis::account_query_db_impl::time_to_block_num

Definition at line 490 of file account_query_db.cpp.


The documentation for this struct was generated from the following file: