Scorum
blockchain_history_api.cpp
Go to the documentation of this file.
8 
9 #include <fc/static_variant.hpp>
10 
11 #include <boost/lambda/lambda.hpp>
12 
13 namespace scorum {
14 namespace blockchain_history {
15 
16 namespace detail {
17 
19 {
20 public:
22  std::shared_ptr<chain::database> _db;
23 
24 private:
25  template <typename ObjectType> applied_operation get_filtered_operation(const ObjectType& obj) const
26  {
27  return _db->get(obj.op);
28  }
29 
31  {
32  return get_filtered_operation(obj);
33  }
34 
35  applied_operation get_operation(const filtered_virt_operations_history_object& obj) const
36  {
37  return get_filtered_operation(obj);
38  }
39 
40  applied_operation get_operation(const filtered_market_operations_history_object& obj) const
41  {
42  return get_filtered_operation(obj);
43  }
44 
45  applied_operation get_operation(const operation_object& obj) const
46  {
47  applied_operation temp;
48  temp = obj;
49  return temp;
50  }
51 
52  inline uint32_t get_head_block() const
53  {
54  return _db->obtain_service<dbs_dynamic_global_property>().get().head_block_number;
55  }
56 
57 public:
59  : _app(app)
60  , _db(_app.chain_database())
61  {
62  }
63 
64  using result_type = std::map<uint32_t, applied_operation>;
65 
66  template <typename IndexType> result_type get_ops_history(uint32_t from_op, uint32_t limit) const
67  {
68  FC_ASSERT(limit > 0, "Limit must be greater than zero");
69  FC_ASSERT(limit <= get_api_config(API_BLOCKCHAIN_HISTORY).max_blockchain_history_depth,
70  "Limit of ${l} is greater than maxmimum allowed ${2}",
71  ("l", limit)("2", get_api_config(API_BLOCKCHAIN_HISTORY).max_blockchain_history_depth));
72  FC_ASSERT(from_op >= limit, "From must be greater than limit");
73 
74  if (from_op != std::numeric_limits<decltype(from_op)>::max())
75  {
76  --from_op;
77  }
78 
80 
81  const auto& idx = _db->get_index<IndexType, by_id>();
82  if (idx.empty())
83  return result;
84 
85  // move to last operation object
86  auto itr = idx.lower_bound(from_op);
87  if (itr == idx.end())
88  --itr;
89 
90  auto start = (int64_t(itr->id._id) - limit);
91  auto end = itr->id._id;
92  auto range = idx.range(start < boost::lambda::_1, boost::lambda::_1 <= end);
93 
94  for (auto it = range.first; it != range.second; ++it)
95  {
96  auto id = it->id;
97  FC_ASSERT(id._id >= 0, "Invalid operation_object id");
98  result[(uint32_t)id._id] = get_operation(*it);
99  }
100 
101  return result;
102  }
103 
104  template <typename IndexType>
105  result_type get_ops_history_by_time(const fc::time_point_sec& from,
106  const fc::time_point_sec& to,
107  uint32_t from_op,
108  uint32_t limit) const
109  {
110  FC_ASSERT(from <= to, "'From' is greater than 'to'");
111  FC_ASSERT((to - from).to_seconds() <= get_api_config(API_BLOCKCHAIN_HISTORY).max_timestamp_range_in_s,
112  "Timestamp range can't be more then ${t} seconds",
113  ("t", get_api_config(API_BLOCKCHAIN_HISTORY).max_timestamp_range_in_s));
114  FC_ASSERT(limit > 0, "Limit must be greater than zero");
115  FC_ASSERT(limit <= get_api_config(API_BLOCKCHAIN_HISTORY).max_blockchain_history_depth,
116  "Limit of ${l} is greater than maxmimum allowed ${2}",
117  ("l", limit)("2", get_api_config(API_BLOCKCHAIN_HISTORY).max_blockchain_history_depth));
118  FC_ASSERT(from_op >= limit, "From must be greater than limit");
119 
121 
122  const auto& idx = _db->get_index<IndexType, by_timestamp>();
123  if (idx.empty())
124  return result;
125 
126  auto range = idx.range(::boost::lambda::_1 >= std::make_tuple(from, 0),
127  ::boost::lambda::_1 <= std::make_tuple(to, ALL_IDS));
128 
129  for (auto it = range.first; limit && it != range.second; ++it)
130  {
131  auto id = it->id;
132  FC_ASSERT(id._id >= 0, "Invalid operation_object id");
133  const operation_object& op = (*it);
134  if (id > from_op)
135  continue;
136 
137  --limit;
138  result[(uint32_t)id._id] = get_operation(op);
139  }
140 
141  return result;
142  }
143 
144  template <typename Filter> result_type get_ops_in_block(uint32_t block_num, Filter operation_filter) const
145  {
146  const auto& idx = _db->get_index<operation_index>().indices().get<by_location>();
147 
149 
150  auto range = idx.equal_range(block_num);
151 
152  for (auto it = range.first; it != range.second; ++it)
153  {
154  auto id = it->id;
155  applied_operation temp = *it;
156  if (operation_filter(temp.op))
157  {
158  FC_ASSERT(id._id >= 0, "Invalid operation_object id");
159  result[(uint32_t)id._id] = temp;
160  }
161  }
162 
163  return result;
164  }
165 
166  // Blocks and transactions
168  {
169 
170 #ifdef SKIP_BY_TX_ID
171  FC_ASSERT(false, "This node's operator has disabled operation indexing by transaction_id");
172 #else
173  FC_ASSERT(!_app.is_read_only(), "get_transaction is not available in read-only mode.");
174 
175  const auto& idx = _db->get_index<operation_index>().indices().get<by_transaction_id>();
176  auto itr = idx.lower_bound(id);
177  if (itr != idx.end() && itr->trx_id == id)
178  {
179  auto blk = _db->fetch_block_by_number(itr->block);
180  FC_ASSERT(blk.valid());
181  FC_ASSERT(blk->transactions.size() > itr->trx_in_block);
182  annotated_signed_transaction result = blk->transactions[itr->trx_in_block];
183  result.block_num = itr->block;
184  result.transaction_num = itr->trx_in_block;
185  return result;
186  }
187  FC_ASSERT(false, "Unknown Transaction ${t}", ("t", id));
188 #endif
189  }
190 
191  optional<signed_block> get_block(uint32_t block_num) const
192  {
193  return _db->fetch_block_by_number(block_num);
194  }
195 
196  template <typename T> std::map<uint32_t, T> get_blocks_history_by_number(uint32_t block_num, uint32_t limit) const
197  {
198  FC_ASSERT(limit <= get_api_config(API_BLOCKCHAIN_HISTORY).max_blockchain_history_depth,
199  "Limit of ${l} is greater than maxmimum allowed ${2}",
200  ("l", limit)("2", get_api_config(API_BLOCKCHAIN_HISTORY).max_blockchain_history_depth));
201  FC_ASSERT(limit > 0, "Limit must be greater than zero");
202  FC_ASSERT(block_num >= limit, "block_num must be greater than limit");
203 
204  try
205  {
206  uint32_t head_block_num = get_head_block();
207  if (block_num > head_block_num)
208  {
209  block_num = head_block_num;
210  }
211 
212  uint32_t from_block_num = (block_num > limit) ? block_num - limit : 0;
213 
214  std::map<uint32_t, T> result;
215  optional<signed_block> b;
216  while (from_block_num != block_num)
217  {
218  b = _db->fetch_block_by_number(block_num);
219  if (b.valid())
220  result[block_num] = *b; // convert from signed_block to type T
221  --block_num;
222  }
223 
224  return result;
225  }
226  FC_LOG_AND_RETHROW()
227  }
228 
229  std::vector<block_api_object> get_blocks(uint32_t block_num, uint32_t limit) const
230  {
231  FC_ASSERT(limit <= get_api_config(API_BLOCKCHAIN_HISTORY).max_blockchain_history_depth,
232  "Limit of ${l} is greater than maxmimum allowed ${2}",
233  ("l", limit)("2", get_api_config(API_BLOCKCHAIN_HISTORY).max_blockchain_history_depth));
234  FC_ASSERT(limit > 0, "Limit must be greater than zero");
235  FC_ASSERT(block_num >= limit, "block_num must be greater than limit");
236 
237  try
238  {
239  uint32_t head_block_num = get_head_block();
240  if (block_num > head_block_num)
241  {
242  block_num = head_block_num;
243  }
244 
245  uint32_t from_block_num = (block_num > limit) ? block_num - limit : 0;
246 
247  std::vector<block_api_object> result;
248  optional<signed_block> b;
249  while (from_block_num != block_num)
250  {
251  b = _db->fetch_block_by_number(block_num);
252 
253  if (b.valid())
254  {
255  block_api_object block(static_cast<signed_block_header>(*b));
256  block.block_num = block_num;
257 
258  auto operations = this->get_ops_in_block(block_num, [&](const operation&) { return true; });
259 
260  for (auto pair : operations)
261  {
262  block.operations.push_back(pair.second);
263  }
264 
265  result.push_back(block);
266  }
267  --block_num;
268  }
269 
270  return result;
271  }
272  FC_LOG_AND_RETHROW()
273  }
274 };
275 
276 } // namespace detail
277 
279  : _impl(new detail::blockchain_history_api_impl(ctx.app))
280 {
281 }
282 
284 {
285 }
286 
288 {
289 }
290 
291 std::map<uint32_t, applied_operation> blockchain_history_api::get_ops_history(
292  uint32_t from_op, uint32_t limit, applied_operation_type type_of_operation) const
293 {
294  return _impl->_app.chain_database()->with_read_lock([&]() {
295  switch (type_of_operation)
296  {
298  return _impl->get_ops_history<filtered_not_virt_operations_history_index>(from_op, limit);
300  return _impl->get_ops_history<filtered_virt_operations_history_index>(from_op, limit);
302  return _impl->get_ops_history<filtered_market_operations_history_index>(from_op, limit);
303  default:;
304  }
305 
306  return _impl->get_ops_history<operation_index>(from_op, limit);
307  });
308 }
309 
310 std::map<uint32_t, applied_operation> blockchain_history_api::get_ops_history_by_time(const fc::time_point_sec& from,
311  const fc::time_point_sec& to,
312  uint32_t from_op,
313  uint32_t limit) const
314 {
315  return _impl->_app.chain_database()->with_read_lock(
316  [&]() { return _impl->get_ops_history_by_time<operation_index>(from, to, from_op, limit); });
317 }
318 
319 std::map<uint32_t, applied_operation>
320 blockchain_history_api::get_ops_in_block(uint32_t block_num, applied_operation_type type_of_operation) const
321 {
322  return _impl->_app.chain_database()->with_read_lock([&]() {
323  switch (type_of_operation)
324  {
326  return _impl->get_ops_in_block(block_num, is_market_operation);
328  return _impl->get_ops_in_block(block_num, is_virtual_operation);
330  return _impl->get_ops_in_block(block_num, [&](const operation& op) { return !is_virtual_operation(op); });
331  default:;
332  }
333 
334  return _impl->get_ops_in_block(block_num, [&](const operation& op) { return true; });
335  });
336 }
337 
339 {
340  return _impl->_app.chain_database()->with_read_lock([&]() { return _impl->get_transaction(id); });
341 }
342 
344 // Blocks and transactions //
346 
347 optional<block_header> blockchain_history_api::get_block_header(uint32_t block_num) const
348 {
349  return _impl->_db->with_read_lock([&]() { return _impl->get_block(block_num); });
350 }
351 
352 optional<signed_block_api_obj> blockchain_history_api::get_block(uint32_t block_num) const
353 {
354  return _impl->_db->with_read_lock([&]() { return _impl->get_block(block_num); });
355 }
356 
357 std::map<uint32_t, block_header> blockchain_history_api::get_block_headers_history(uint32_t block_num,
358  uint32_t limit) const
359 {
360  FC_ASSERT(!_impl->_app.is_read_only(), "Disabled for read only mode");
361  return _impl->_db->with_read_lock(
362  [&]() { return _impl->get_blocks_history_by_number<block_header>(block_num, limit); });
363 }
364 
365 std::map<uint32_t, signed_block_api_obj> blockchain_history_api::get_blocks_history(uint32_t block_num,
366  uint32_t limit) const
367 {
368  FC_ASSERT(!_impl->_app.is_read_only(), "Disabled for read only mode");
369  return _impl->_db->with_read_lock(
370  [&]() { return _impl->get_blocks_history_by_number<signed_block_api_obj>(block_num, limit); });
371 }
372 
373 std::vector<block_api_object> blockchain_history_api::get_blocks(uint32_t from, uint32_t limit) const
374 {
375  return _impl->_db->with_read_lock([&]() { return _impl->get_blocks(from, limit); });
376 }
377 
378 } // namespace blockchain_history
379 } // namespace scorum
#define API_BLOCKCHAIN_HISTORY
blockchain_history_api(const scorum::app::api_context &ctx)
std::map< uint32_t, T > get_blocks_history_by_number(uint32_t block_num, uint32_t limit) const
result_type get_ops_history(uint32_t from_op, uint32_t limit) const
result_type get_ops_history_by_time(const fc::time_point_sec &from, const fc::time_point_sec &to, uint32_t from_op, uint32_t limit) const
std::vector< block_api_object > get_blocks(uint32_t block_num, uint32_t limit) const
result_type get_ops_in_block(uint32_t block_num, Filter operation_filter) const
optional< signed_block > get_block(uint32_t block_num) const
annotated_signed_transaction get_transaction(transaction_id_type id) const
std::map< uint32_t, applied_operation > get_ops_history_by_time(const fc::time_point_sec &from, const fc::time_point_sec &to, uint32_t from_op, uint32_t limit) const
This method returns all operations in timestamp range [from, to].
annotated_signed_transaction get_transaction(transaction_id_type trx_id) const
This method returns signed transaction by transaction id.
std::vector< block_api_object > get_blocks(uint32_t from, uint32_t limit) const
Retrieve the list of blocks from block log in range [from-limit, from].
std::map< uint32_t, block_header > get_block_headers_history(uint32_t block_num, uint32_t limit) const
Retrieve the list of block headers in range [from-limit, from].
std::map< uint32_t, applied_operation > get_ops_history(uint32_t from_op, uint32_t limit, applied_operation_type type_of_operation) const
This method returns all operations in ids range [from-limit, from].
optional< block_header > get_block_header(uint32_t block_num) const
Retrieve a block header.
std::map< uint32_t, signed_block_api_obj > get_blocks_history(uint32_t block_num, uint32_t limit) const
Retrieve the list of signed block from block log (irreversible blocks) in range [from-limit,...
std::map< uint32_t, applied_operation > get_ops_in_block(uint32_t block_num, applied_operation_type type_of_operation) const
Returns sequence of operations included/generated in a specified block.
optional< signed_block_api_obj > get_block(uint32_t block_num) const
Retrieve a full, signed block.
filtered_operation_index< filtered_market_operations_history > filtered_market_operations_history_index
filtered_operation_index< filtered_virt_operations_history > filtered_virt_operations_history_index
shared_multi_index_container< operation_object, indexed_by< ordered_unique< tag< by_id >, member< operation_object, operation_object::id_type, &operation_object::id > >, ordered_unique< tag< by_location >, composite_key< operation_object, member< operation_object, uint32_t, &operation_object::block >, member< operation_object, uint32_t, &operation_object::trx_in_block >, member< operation_object, uint16_t, &operation_object::op_in_trx >, member< operation_object, operation_object::id_type, &operation_object::id > > >, ordered_unique< tag< by_timestamp >, composite_key< operation_object, member< operation_object, fc::time_point_sec, &operation_object::timestamp >, member< operation_object, operation_object::id_type, &operation_object::id > > >, ordered_unique< tag< by_transaction_id >, composite_key< operation_object, member< operation_object, transaction_id_type, &operation_object::trx_id >, member< operation_object, operation_object::id_type, &operation_object::id > > > > > operation_index
filtered_operation_index< filtered_not_virt_operations_history > filtered_not_virt_operations_history_index
filtered_operation_object< filtered_market_operations_history > filtered_market_operations_history_object
fc::ripemd160 transaction_id_type
Definition: types.hpp:65
fc::static_variant< vote_operation, comment_operation, transfer_operation, transfer_to_scorumpower_operation, withdraw_scorumpower_operation, account_create_by_committee_operation, account_create_operation, account_create_with_delegation_operation, account_update_operation, witness_update_operation, account_witness_vote_operation, account_witness_proxy_operation, delete_comment_operation, comment_options_operation, set_withdraw_scorumpower_route_to_account_operation, set_withdraw_scorumpower_route_to_dev_pool_operation, prove_authority_operation, request_account_recovery_operation, recover_account_operation, change_recovery_account_operation, escrow_approve_operation, escrow_dispute_operation, escrow_release_operation, escrow_transfer_operation, decline_voting_rights_operation, delegate_scorumpower_operation, create_budget_operation, close_budget_operation, proposal_vote_operation, proposal_create_operation, atomicswap_initiate_operation, atomicswap_redeem_operation, atomicswap_refund_operation, close_budget_by_advertising_moderator_operation, update_budget_operation, create_game_operation, cancel_game_operation, update_game_markets_operation, update_game_start_time_operation, post_game_results_operation, post_bet_operation, cancel_pending_bets_operation, delegate_sp_from_reg_pool_operation, create_nft_operation, update_nft_meta_operation, create_game_round_operation, update_game_round_result_operation, adjust_nft_experience_operation, update_nft_name_operation, author_reward_operation, comment_benefficiary_reward_operation, comment_payout_update_operation, comment_reward_operation, curation_reward_operation, hardfork_operation, producer_reward_operation, active_sp_holders_reward_operation, return_scorumpower_delegation_operation, shutdown_witness_operation, witness_miss_block_operation, expired_contract_refund_operation, acc_finished_vesting_withdraw_operation, devpool_finished_vesting_withdraw_operation, acc_to_acc_vesting_withdraw_operation, devpool_to_acc_vesting_withdraw_operation, acc_to_devpool_vesting_withdraw_operation, devpool_to_devpool_vesting_withdraw_operation, proposal_virtual_operation, budget_outgo_operation, budget_owner_income_operation, active_sp_holders_reward_legacy_operation, budget_closing_operation, bets_matched_operation, game_status_changed_operation, bet_resolved_operation, bet_cancelled_operation, bet_restored_operation, bet_updated_operation > operation
Definition: operations.hpp:112
bool is_virtual_operation(const operation &op)
Definition: operations.cpp:41
bool is_market_operation(const operation &op)
Definition: operations.cpp:26
Definition: asset.cpp:15
config_api & get_api_config(std::string api_name)
Definition: config_api.cpp:114
#define ALL_IDS
std::vector< block_api_operation_object > operations
Definition: api_objects.hpp:58