7#include <boost/multi_index_container.hpp>
8#include <boost/multi_index/ordered_index.hpp>
9#include <boost/multi_index/composite_key.hpp>
10#include <boost/multi_index/member.hpp>
12#include <boost/bimap.hpp>
13#include <boost/bimap/multiset_of.hpp>
14#include <boost/bimap/set_of.hpp>
16#include <shared_mutex>
20using namespace boost::multi_index;
21using namespace boost::bimaps;
28 struct permission_info {
37 using cref = std::reference_wrapper<const permission_info>;
41 struct by_last_updated_height;
46 using permission_info_index_t = multi_index_container<
51 composite_key<permission_info,
52 member<permission_info, chain::name, &permission_info::owner>,
53 member<permission_info, chain::name, &permission_info::name>
57 tag<by_last_updated_height>,
58 member<permission_info, uint32_t, &permission_info::last_updated_height>
69 if (
p->action_traces.empty())
71 const auto& act =
p->action_traces[0].act;
72 if (act.account != sysio::chain::config::system_account_name || act.name !=
"onblock"_n ||
73 act.authorization.size() != 1)
75 const auto& auth = act.authorization[0];
76 return auth.actor == sysio::chain::config::system_account_name &&
77 auth.permission == sysio::chain::config::active_name;
85 static weighted lower_bound_for(
const T& value ) {
86 return {
value, std::numeric_limits<chain::weight_type>::min()};
89 static weighted upper_bound_for(
const T& value ) {
90 return {
value, std::numeric_limits<chain::weight_type>::max()};
94 template<
typename Output,
typename Input>
95 auto make_optional_authorizer(
const Input& authorizer) -> std::optional<Output> {
96 if constexpr (std::is_same_v<Input, Output>) {
109 struct less<permission_info::cref> {
110 bool operator()(
const permission_info::cref& lhs,
const permission_info::cref& rhs )
const {
111 return std::uintptr_t(&lhs.get()) < std::uintptr_t(&rhs.get());
119 struct less<weighted<
T>> {
120 bool operator()(
const weighted<T>& lhs,
const weighted<T>& rhs )
const {
121 return std::tie(lhs.value, lhs.weight) < std::tie(rhs.value, rhs.weight);
141 std::unique_lock write_lock(
rw_mutex);
143 ilog(
"Building account query DB");
151 for (
uint32_t block_num = lib_num + 1; block_num <= head_num; 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));
157 for (
const auto& po : index ) {
159 const auto& pi =
permission_info_index.emplace( permission_info{ po.owner, po.name, last_updated_height, po.auth.threshold } ).first;
163 ilog(
"Finished building account query DB in ${sec}", (
"sec", (duration.count() / 1'000'000.0 )));
174 name_bimap.insert(name_bimap_t::value_type {{
a.permission,
a.weight}, pi});
178 for (
const auto& k: po.auth.
keys) {
180 key_bimap.insert(key_bimap_t::value_type {{std::move(key), k.weight}, pi});
190 const auto name_range =
name_bimap.right.equal_range(pi);
191 name_bimap.right.erase(name_range.first, name_range.second);
194 const auto key_range =
key_bimap.right.equal_range(pi);
195 key_bimap.right.erase(key_range.first, key_range.second);
199 std::shared_lock read_lock(
rw_mutex);
200 const auto bnum = bsp->block->block_num();
206 const auto& pi = (*index.rbegin());
207 if (pi.last_updated_height < bnum) {
219 uint32_t last_updated_height = lib_num;
220 if (last_updated > lib_time) {
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;
226 return last_updated_height;
238 const auto bnum = bsp->block->block_num();
245 time_iter =
decltype(time_iter){
time_to_block_num.erase( std::next(time_iter).base() )};
248 auto curr_iter = index.rbegin();
249 while (!index.empty()) {
250 if (curr_iter == index.rend()) {
254 const auto& pi = (*curr_iter);
255 if (pi.last_updated_height < bnum) {
262 auto itr = permission_by_owner.find(std::make_tuple(pi.owner, pi.name));
263 if (itr == permission_by_owner.end()) {
265 curr_iter =
decltype(curr_iter)( index.erase(index.iterator_to(pi)) );
267 const auto& po = *itr;
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;
287 if( !trace->receipt )
return;
295 }
else if( trace->failed_dtrx_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)) {
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);
346 id = std::get<chain::packed_transaction>(
r.trx).id();
351 process_trace( it->second );
366 bool rollback_required =
false;
371 if (!updated.empty() || !deleted.empty() || rollback_required) {
372 std::unique_lock write_lock(
rw_mutex);
379 const auto bnum = bsp->block_num;
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;
394 index.modify(itr, [&](
auto& mutable_pi){
395 mutable_pi.last_updated_height = bnum;
396 mutable_pi.threshold = source_itr->auth.threshold;
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()) {
421 std::shared_lock read_lock(
rw_mutex);
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());
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;
439 result.accounts.emplace_back(result_t::account_result{
442 make_optional_authorizer<chain::permission_level>(authorizer),
443 make_optional_authorizer<chain::public_key_type>(authorizer),
451 for (
const auto&
a: account_set) {
452 if (
a.permission.empty()) {
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);
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);
469 for (
const auto& k: key_set) {
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);
494 using name_bimap_t = bimap<multiset_of<weighted<chain::permission_level>>, multiset_of<permission_info::cref>>;
495 using key_bimap_t = bimap<multiset_of<weighted<chain::public_key_type>>, multiset_of<permission_info::cref>>;
511 _impl->build_account_query_map();
519 _impl->cache_transaction_trace(trace);
525 _impl->commit_block(block);
530 return _impl->get_accounts_by_authorizers(args);
#define SYS_ASSERT(expr, exc_type, FORMAT,...)
const generic_index< MultiIndexType > & get_index() const
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
time_point last_irreversible_block_time() const
get_accounts_by_authorizers_result get_accounts_by_authorizers(const get_accounts_by_authorizers_params &args) const
account_query_db & operator=(account_query_db &&)
account_query_db(const class sysio::chain::controller &chain)
void commit_block(const chain::block_state_ptr &block)
void cache_transaction_trace(const chain::transaction_trace_ptr &trace)
#define FC_LOG_AND_DROP(...)
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
std::shared_ptr< transaction_trace > transaction_trace_ptr
bool is_onblock(const transaction_trace &tt)
std::shared_ptr< block_state > block_state_ptr
const GenericPointer< typename T::ValueType > T2 T::AllocatorType & a
#define T(meth, val, expected)
bool operator()(const permission_info::cref &lhs, const permission_info::cref &rhs) const
bool operator()(const weighted< T > &lhs, const weighted< T > &rhs) const
static action_name get_name()
Immutable except for fc::from_variant.
static action_name get_name()
shared_vector< permission_level_weight > accounts
shared_vector< shared_key_weight > keys
static action_name get_name()
std::vector< chain::public_key_type > keys
std::vector< permission_level > accounts
const chain::controller & controller
the controller to read data from
bool is_rollback_required(const chain::block_state_ptr &bsp) const
account_query_db::get_accounts_by_authorizers_result get_accounts_by_authorizers(const account_query_db::get_accounts_by_authorizers_params &args) const
uint32_t last_updated_time_to_height(const fc::time_point &last_updated)
void rollback_to_before(const chain::block_state_ptr &bsp)
onblock_trace_t onblock_trace
temporary cache of on_block trace
name_bimap_t name_bimap
many:many bimap of names:permission_infos
account_query_db_impl(const chain::controller &controller)
std::set< chain::permission_level > permission_set_t
void add_to_bimaps(const permission_info &pi, const chain::permission_object &po)
void remove_from_bimaps(const permission_info &pi)
void build_account_query_map()
void commit_block(const chain::block_state_ptr &bsp)
auto commit_block_prelock(const chain::block_state_ptr &bsp) const
std::map< fc::time_point, uint32_t > time_map_t
permission_info_index_t permission_info_index
multi-index that holds ephemeral indices
std::optional< chain::transaction_trace_ptr > onblock_trace_t
bimap< multiset_of< weighted< chain::permission_level > >, multiset_of< permission_info::cref > > name_bimap_t
cached_trace_map_t cached_trace_map
temporary cache of uncommitted traces
std::shared_mutex rw_mutex
mutex for read/write locking on the Multi-index and bimaps
key_bimap_t key_bimap
many:many bimap of keys:permission_infos
time_map_t time_to_block_num
bimap< multiset_of< weighted< chain::public_key_type > >, multiset_of< permission_info::cref > > key_bimap_t
void cache_transaction_trace(const chain::transaction_trace_ptr &trace)
std::map< chain::transaction_id_type, chain::transaction_trace_ptr > cached_trace_map_t