Scorum
database.cpp
Go to the documentation of this file.
1 #include <cstdint>
2 #include <deque>
3 #include <fstream>
4 #include <functional>
5 #include <openssl/md5.h>
6 
7 #include <boost/iostreams/device/mapped_file.hpp>
8 #include <boost/core/ignore_unused.hpp>
9 
10 #include <fc/smart_ref_impl.hpp>
11 #include <fc/uint128.hpp>
12 #include <fc/container/deque.hpp>
13 #include <fc/io/fstream.hpp>
14 #include <fc/io/json.hpp>
15 
19 
21 
24 
27 #include <scorum/chain/db_with.hpp>
28 
30 
49 
63 
77 
104 
105 #include <cmath>
106 
110 
111 namespace scorum {
112 namespace chain {
113 
115 {
116 public:
117  database_impl(database& self);
118 
122 
124  {
125  return _betting_service;
126  }
127 
129  {
130  return _betting_matcher;
131  }
132 
134  {
135  return _betting_resolver;
136  }
137 
138 private:
139  betting_service _betting_service;
140  betting_matcher _betting_matcher;
141  betting_resolver _betting_resolver;
142 };
143 
145  : _self(self)
146  , _evaluator_registry(self)
147  // TODO: using boost::di to avoid these explicit calls
148  , _betting_service(_self.account_service(),
149  static_cast<database_virtual_operations_emmiter_i&>(_self),
150  _self.get_dba<betting_property_object>(),
151  _self.get_dba<matched_bet_object>(),
152  _self.get_dba<pending_bet_object>(),
153  _self.get_dba<game_object>(),
154  _self.get_dba<dynamic_global_property_object>(),
155  _self.get_dba<bet_uuid_history_object>())
156  , _betting_matcher(static_cast<database_virtual_operations_emmiter_i&>(_self),
157  _self.get_dba<pending_bet_object>(),
158  _self.get_dba<matched_bet_object>(),
159  _self.get_dba<dynamic_global_property_object>())
160  , _betting_resolver(_self.account_service(),
161  static_cast<database_virtual_operations_emmiter_i&>(_self),
162  _self.get_dba<matched_bet_object>(),
163  _self.get_dba<game_object>(),
164  _self.get_dba<dynamic_global_property_object>())
165 {
166 }
167 
168 database::database(uint32_t options)
169  : chainbase::database()
170  , dbservice_dbs_factory(*this)
171  , data_service_factory(*this)
172  , db_accessor_factory(static_cast<dba::db_index&>(*this))
173  , _my(new database_impl(*this))
174  , _options(options)
175 {
176 }
177 
179 {
180  clear_pending();
181 }
182 
183 fc::path database::block_log_path(const fc::path& data_dir)
184 {
185  return data_dir / "block_log";
186 }
187 
189 {
190  uint32_t skip_flags = database::skip_witness_signature;
193  skip_flags |= database::skip_tapos_check;
194  skip_flags |= database::skip_merkle_check;
195  skip_flags |= database::skip_authority_check;
196  skip_flags |= database::skip_validate;
198  skip_flags |= database::skip_block_log;
200  return skip_flags;
201 }
202 
203 void database::open(const fc::path& data_dir,
204  const fc::path& shared_mem_dir,
205  uint64_t shared_file_size,
206  uint32_t chainbase_flags,
207  const genesis_state_type& genesis_state)
208 {
209  try
210  {
211  chainbase::database::open(shared_mem_dir, chainbase_flags, shared_file_size);
212 
213  // must be initialized before evaluators creation
214  _my->_genesis_persistent_state = static_cast<const genesis_persistent_state_type&>(genesis_state);
215 
218 
219  set_initial_timestamp(genesis_state);
220 
221  if (chainbase_flags & chainbase::database::read_write)
222  {
223  if (!find<dynamic_global_property_object>())
224  with_write_lock([&]() { init_genesis(genesis_state); });
225 
226  if (!fc::exists(data_dir))
227  {
228  fc::create_directories(data_dir);
229  }
230 
231  _block_log.open(block_log_path(data_dir));
232 
233  auto log_head = _block_log.head();
234 
235  // Rewind all undo state. This should return us to the state at the last irreversible block.
236  with_write_lock([&]() {
237  for_each_index([&](chainbase::abstract_generic_index_i& item) { item.undo_all(); });
238 
239  for_each_index([&](chainbase::abstract_generic_index_i& item) {
240  FC_ASSERT(item.revision() == head_block_num(),
241  "Chainbase revision does not match head block num. Reindex blockchain.",
242  ("rev", item.revision())("head_block", head_block_num()));
243  });
244 
246  });
247 
248  if (head_block_num())
249  {
250  auto head_block = _block_log.read_block_by_num(head_block_num());
251  // This assertion should be caught and a reindex should occur
252  FC_ASSERT(head_block.valid() && head_block->id() == head_block_id(),
253  "Chain state does not match block log. Reindex blockchain.");
254 
255  _fork_db.start_block(*head_block);
256  }
257  }
258 
259  try
260  {
261  const auto& chain_id = get<chain_property_object>().chain_id;
262  FC_ASSERT(genesis_state.initial_chain_id == chain_id,
263  "Current chain id is not equal initial chain id = ${id}", ("id", chain_id));
264  }
265  catch (fc::exception& err)
266  {
267  throw std::logic_error(std::string("Invalid chain id: ") + err.to_detail_string());
268  }
269 
270  try
271  {
272  with_read_lock([&]() {
273  init_hardforks(genesis_state.initial_timestamp); // Writes to local state, but reads from db
274  });
275  }
276  catch (fc::exception& err)
277  {
278  throw std::logic_error(std::string("Can't initialize hardforks: ") + err.to_detail_string());
279  }
280  }
281  FC_CAPTURE_LOG_AND_RETHROW((data_dir)(shared_mem_dir)(shared_file_size))
282 }
283 
284 void database::reindex(const fc::path& data_dir,
285  const fc::path& shared_mem_dir,
286  uint64_t shared_file_size,
287  uint32_t skip_flags,
288  const genesis_state_type& genesis_state)
289 {
290  try
291  {
292  ilog("Reindexing Blockchain");
293 
294  wipe(data_dir, shared_mem_dir, false);
295  open(data_dir, shared_mem_dir, shared_file_size, chainbase::database::read_write, genesis_state);
296  _fork_db.reset(); // override effect of _fork_db.start_block() call in open()
297 
298  auto start = fc::time_point::now();
299  SCORUM_ASSERT(_block_log.head(), block_log_exception, "No blocks in block log. Cannot reindex an empty chain.");
300 
301  auto last_block_num = _block_log.head()->block_num();
302  uint log_interval_sz = std::max(last_block_num / 100u, 1000u);
303 
304  ilog("Replaying ${n} blocks...", ("n", last_block_num));
305 
306  with_write_lock([&]() {
307  auto itr = _block_log.read_block(0);
308  while (itr.first.block_num() <= last_block_num)
309  {
310  auto cur_block_num = itr.first.block_num();
311  if (cur_block_num % log_interval_sz == 0 || cur_block_num == last_block_num)
312  {
313  double percent = (cur_block_num * double(100)) / last_block_num;
314  ilog("${p}% applied. ${m}M free.",
315  ("p", (boost::format("%5.2f") % percent).str())("m", get_free_memory() / (1024 * 1024)));
316  }
317  apply_block(itr.first, skip_flags);
318  if (cur_block_num != last_block_num)
319  itr = _block_log.read_block(itr.second);
320  else
321  break;
322  }
323 
324  for_each_index([&](chainbase::abstract_generic_index_i& item) { item.set_revision(head_block_num()); });
325  });
326 
327  if (_block_log.head()->block_num())
328  {
329  _fork_db.start_block(*_block_log.head());
330  }
331 
332  auto end = fc::time_point::now();
333  ilog("Done reindexing, elapsed time: ${t} sec", ("t", double((end - start).count()) / 1000000.0));
334  }
335  FC_CAPTURE_AND_RETHROW((data_dir)(shared_mem_dir)(shared_file_size)(skip_flags)(genesis_state))
336 }
337 
338 void database::wipe(const fc::path& data_dir, const fc::path& shared_mem_dir, bool include_blocks)
339 {
340  close();
341  chainbase::database::wipe(shared_mem_dir);
342  if (include_blocks)
343  {
344  fc::path block_log_file = block_log_path(data_dir);
345  fc::remove_all(block_log_file);
346  fc::remove_all(block_log::block_log_index_path(block_log_file));
347  }
348 }
349 
350 void database::close()
351 {
352  try
353  {
354  // Since pop_block() will move tx's in the popped blocks into pending,
355  // we have to clear_pending() after we're done popping to get a clean
356  // DB state (issue #336).
357  clear_pending();
358 
359  try
360  {
361  chainbase::database::flush();
362  }
363  catch (...)
364  {
365  }
366 
367  chainbase::database::close();
368 
369  _block_log.close();
370 
371  _fork_db.reset();
372  }
373  FC_CAPTURE_AND_RETHROW()
374 }
375 
376 bool database::is_known_block(const block_id_type& id) const
377 {
378  try
379  {
380  return fetch_block_by_id(id).valid();
381  }
382  FC_CAPTURE_AND_RETHROW()
383 }
384 
390 bool database::is_known_transaction(const transaction_id_type& id) const
391 {
392  try
393  {
394  const auto& trx_idx = get_index<transaction_index>().indices().get<by_trx_id>();
395  return trx_idx.find(id) != trx_idx.end();
396  }
397  FC_CAPTURE_AND_RETHROW()
398 }
399 
400 block_id_type database::find_block_id_for_num(uint32_t block_num) const
401 {
402  try
403  {
404  if (block_num == 0)
405  {
406  return block_id_type();
407  }
408 
409  // Reversible blocks are *usually* in the TAPOS buffer. Since this
410  // is the fastest check, we do it first.
411  block_summary_id_type bsid = block_num & (uint32_t)SCORUM_BLOCKID_POOL_SIZE;
412  const block_summary_object* bs = find<block_summary_object, by_id>(bsid);
413  if (bs != nullptr)
414  {
415  if (protocol::block_header::num_from_id(bs->block_id) == block_num)
416  {
417  return bs->block_id;
418  }
419  }
420 
421  // Next we query the block log. Irreversible blocks are here.
422  auto b = _block_log.read_block_by_num(block_num);
423  if (b.valid())
424  {
425  return b->id();
426  }
427 
428  // Finally we query the fork DB.
429  std::shared_ptr<fork_item> fitem = _fork_db.fetch_block_on_main_branch_by_number(block_num);
430  if (fitem)
431  {
432  return fitem->id;
433  }
434 
435  return block_id_type();
436  }
437  FC_CAPTURE_AND_RETHROW((block_num))
438 }
439 
440 block_id_type database::get_block_id_for_num(uint32_t block_num) const
441 {
442  block_id_type bid = find_block_id_for_num(block_num);
443  FC_ASSERT(bid != block_id_type());
444  return bid;
445 }
446 
447 optional<signed_block> database::fetch_block_by_id(const block_id_type& id) const
448 {
449  try
450  {
451  auto b = _fork_db.fetch_block(id);
452  if (!b)
453  {
454  auto tmp = _block_log.read_block_by_num(protocol::block_header::num_from_id(id));
455 
456  if (tmp && tmp->id() == id)
457  {
458  return tmp;
459  }
460 
461  tmp.reset();
462  return tmp;
463  }
464 
465  return b->data;
466  }
467  FC_CAPTURE_AND_RETHROW()
468 }
469 
470 optional<signed_block> database::fetch_block_by_number(uint32_t block_num) const
471 {
472  try
473  {
474  optional<signed_block> b;
475 
476  auto results = _fork_db.fetch_block_by_number(block_num);
477  if (results.size() == 1)
478  {
479  b = results[0]->data;
480  }
481  else
482  {
483  b = _block_log.read_block_by_num(block_num);
484  }
485 
486  return b;
487  }
488  FC_LOG_AND_RETHROW()
489 }
490 
491 optional<signed_block> database::read_block_by_number(uint32_t block_num) const
492 {
493  return _block_log.read_block_by_num(block_num);
494 }
495 
496 const signed_transaction database::get_recent_transaction(const transaction_id_type& trx_id) const
497 {
498  try
499  {
500  auto& index = get_index<transaction_index>().indices().get<by_trx_id>();
501  auto itr = index.find(trx_id);
502  FC_ASSERT(itr != index.end());
503  signed_transaction trx;
504  fc::raw::unpack(itr->packed_trx, trx);
505  return trx;
506  ;
507  }
508  FC_CAPTURE_AND_RETHROW()
509 }
510 
511 std::vector<block_id_type> database::get_block_ids_on_fork(block_id_type head_of_fork) const
512 {
513  try
514  {
515  std::pair<fork_database::branch_type, fork_database::branch_type> branches
516  = _fork_db.fetch_branch_from(head_block_id(), head_of_fork);
517  if (!((branches.first.back()->previous_id() == branches.second.back()->previous_id())))
518  {
519  edump((head_of_fork)(head_block_id())(branches.first.size())(branches.second.size()));
520  assert(branches.first.back()->previous_id() == branches.second.back()->previous_id());
521  }
522  std::vector<block_id_type> result;
523  for (const item_ptr& fork_block : branches.second)
524  {
525  result.emplace_back(fork_block->id);
526  }
527  result.emplace_back(branches.first.back()->previous_id());
528  return result;
529  }
530  FC_CAPTURE_AND_RETHROW()
531 }
532 
533 chain_id_type database::get_chain_id() const
534 {
535  return get<chain_property_object>().chain_id;
536 }
537 
538 const node_property_object& database::get_node_properties() const
539 {
540  return _node_property_object;
541 }
542 
543 const time_point_sec database::calculate_discussion_payout_time(const comment_object& comment) const
544 {
545  return comment.cashout_time;
546 }
547 
548 uint32_t database::witness_participation_rate() const
549 {
550  const dynamic_global_property_object& dpo = obtain_service<dbs_dynamic_global_property>().get();
551  return uint64_t(SCORUM_100_PERCENT) * dpo.recent_slots_filled.popcount() / 128;
552 }
553 
554 void database::add_checkpoints(const flat_map<uint32_t, block_id_type>& checkpts)
555 {
556  for (const auto& i : checkpts)
557  {
558  _checkpoints[i.first] = i.second;
559  }
560 }
561 
562 bool database::before_last_checkpoint() const
563 {
564  return (_checkpoints.size() > 0) && (_checkpoints.rbegin()->first >= head_block_num());
565 }
566 
573 bool database::push_block(const signed_block& new_block, uint32_t skip)
574 {
575  // fc::time_point begin_time = fc::time_point::now();
576 
577  block_info ctx(new_block);
578 
579  debug_log(ctx, "push_block skip=${s}", ("s", skip));
580 
581  bool result;
582  detail::with_skip_flags(*this, skip, [&]() {
583  with_write_lock([&]() {
584  detail::without_pending_transactions(*this, std::move(_pending_tx), [&]() {
585  try
586  {
587  result = _push_block(new_block);
588  debug_log(ctx, "push_block resut=${r}", ("r", result));
589  }
590  FC_CAPTURE_AND_RETHROW(((std::string)ctx))
591  });
592  });
593  });
594 
595  // fc::time_point end_time = fc::time_point::now();
596  // fc::microseconds dt = end_time - begin_time;
597  // if( ( new_block.block_num() % 10000 ) == 0 )
598  // ilog( "push_block ${b} took ${t} microseconds", ("b", new_block.block_num())("t", dt.count()) );
599  return result;
600 }
601 
602 void database::_maybe_warn_multiple_production(uint32_t height) const
603 {
604  auto blocks = _fork_db.fetch_block_by_number(height);
605  if (blocks.size() > 1)
606  {
607  std::vector<std::pair<account_name_type, fc::time_point_sec>> witness_time_pairs;
608  for (const auto& b : blocks)
609  {
610  debug_log(block_info(b->data), "block_num_collision=${n}", ("n", height));
611  witness_time_pairs.push_back(std::make_pair(b->data.witness, b->data.timestamp));
612  }
613 
614  ilog("Encountered block num collision at block ${n} due to a fork, witnesses are: ${w}",
615  ("n", height)("w", witness_time_pairs));
616  }
617  return;
618 }
619 
620 bool database::_push_block(const signed_block& new_block)
621 {
622  block_info ctx(new_block);
623 
624  debug_log(ctx, "_push_block");
625 
626  try
627  {
628  uint32_t skip = get_node_properties().skip_flags;
629  // uint32_t skip_undo_db = skip & skip_undo_block;
630 
631  if (!(skip & skip_fork_db))
632  {
633  std::shared_ptr<fork_item> new_head = _fork_db.push_block(new_block);
634 
635  debug_log(ctx, "new_head_block=${b}", ("b", (std::string)block_info(new_head->data)));
636 
637  _maybe_warn_multiple_production(new_head->num);
638 
639  // If the head block from the longest chain does not build off of the current head, we need to switch forks.
640  if (new_head->data.previous != head_block_id())
641  {
642  debug_log(ctx, "current head block_id=${h_id}", ("h_id", head_block_id()));
643  debug_log(ctx, "previous head block_id=${priv_id}", ("priv_id", new_head->data.previous));
644 
645  // If the newly pushed block is the same height as head, we get head back in new_head
646  // Only switch forks if new_head is actually higher than head
647  if (new_head->data.block_num() > head_block_num())
648  {
649  debug_log(ctx, "current nead block_num=${h_num}", ("h_num", head_block_num()));
650  debug_log(ctx, "new head block number=${f_num}", ("f_num", new_head->data.block_num()));
651  debug_log(ctx, "switching to fork with block=${b}", ("b", (std::string)block_info(new_head->data)));
652 
653  auto branches = _fork_db.fetch_branch_from(new_head->data.id(), head_block_id());
654 
655  // pop blocks until we hit the forked block
656  while (head_block_id() != branches.second.back()->data.previous)
657  {
658  debug_log(ctx, "popping block_id=${id}", ("id", head_block_id()));
659  pop_block();
660  }
661 
662  // push all blocks on the new fork
663  for (auto ritr = branches.first.rbegin(); ritr != branches.first.rend(); ++ritr)
664  {
665  debug_log(ctx, "pushing blocks from fork block=${b}",
666  ("b", (std::string)block_info((*ritr)->data)));
667  optional<fc::exception> except;
668  try
669  {
670  auto session = start_undo_session();
671  apply_block((*ritr)->data, skip);
672  debug_log(ctx, "applied block=${b}", ("b", (std::string)block_info((*ritr)->data)));
673  session->push();
674  }
675  catch (const fc::exception& e)
676  {
677  except = e;
678  }
679  if (except)
680  {
681  debug_log(ctx, "failed to push fork block exception=${e}",
682  ("e", except->to_detail_string()));
683  // remove the rest of branches.first from the fork_db, those blocks are invalid
684  while (ritr != branches.first.rend())
685  {
686  debug_log(ctx, "removing_block=${b} from fork",
687  ("b", (std::string)block_info((*ritr)->data)));
688  _fork_db.remove((*ritr)->data.id());
689  ++ritr;
690  }
691  _fork_db.set_head(branches.second.front());
692 
693  // pop all blocks from the bad fork
694  while (head_block_id() != branches.second.back()->data.previous)
695  {
696  debug_log(ctx, "popping block_id=${id}", ("id", head_block_id()));
697  pop_block();
698  }
699 
700  // restore all blocks from the good fork
701  for (auto ritr = branches.second.rbegin(); ritr != branches.second.rend(); ++ritr)
702  {
703  auto session = start_undo_session();
704  apply_block((*ritr)->data, skip);
705  debug_log(ctx, "applied block=${b}", ("b", (std::string)block_info((*ritr)->data)));
706  session->push();
707  }
708  throw(*except);
709  }
710  }
711 
712  debug_log(ctx, "_push_block result=true");
713  return true;
714  }
715  else
716  {
717  debug_log(ctx, "_push_block result=false");
718  return false;
719  }
720  }
721  }
722 
723  try
724  {
725  auto session = start_undo_session();
726  apply_block(new_block, skip);
727  session->push();
728  }
729  catch (const fc::exception& e)
730  {
731  ctx_elog(ctx, "failed to push new block exception=${e}", ("e", e.to_detail_string()));
732  _fork_db.remove(new_block.id());
733  throw;
734  }
735 
736  debug_log(ctx, "_push_block result=false");
737  return false;
738  }
739  FC_CAPTURE_AND_RETHROW(((std::string)ctx))
740 }
741 
751 void database::push_transaction(const signed_transaction& trx, uint32_t skip)
752 {
753  try
754  {
755  try
756  {
757  size_t trx_size = fc::raw::pack_size(trx);
758  FC_ASSERT(
759  trx_size
760  <= (obtain_service<dbs_dynamic_global_property>().get().median_chain_props.maximum_block_size - 256));
761  set_producing(true);
762  detail::with_skip_flags(*this, skip, [&]() { with_write_lock([&]() { _push_transaction(trx); }); });
763  set_producing(false);
764  }
765  catch (...)
766  {
767  set_producing(false);
768  throw;
769  }
770  }
771  FC_CAPTURE_AND_RETHROW((trx))
772 }
773 
774 void database::_push_transaction(const signed_transaction& trx)
775 {
776  // If this is the first transaction pushed after applying a block, start a new undo session.
777  // This allows us to quickly rewind to the clean state of the head block, in case a new block arrives.
778  if (!_pending_tx_session.valid())
779  {
780  _pending_tx_session = start_undo_session();
781  }
782 
783  // Create a temporary undo session as a child of _pending_tx_session.
784  // The temporary session will be discarded by the destructor if
785  // _apply_transaction fails. If we make it to merge(), we
786  // apply the changes.
787 
788  auto temp_session = start_undo_session();
789  _apply_transaction(trx);
790  _pending_tx.push_back(trx);
791 
792  // The transaction applied successfully. Merge its changes into the pending block session.
793  for_each_index([&](chainbase::abstract_generic_index_i& item) { item.squash(); });
794  temp_session->push();
795 
796  // notify anyone listening to pending transactions
797  notify_on_pending_transaction(trx);
798 }
799 
800 signed_block database::generate_block(fc::time_point_sec when,
801  const account_name_type& witness_owner,
802  const fc::ecc::private_key& block_signing_private_key,
803  uint32_t skip /* = 0 */
804 )
805 {
806  block_info ctx(when, witness_owner);
807 
808  debug_log(ctx, "generate_block skip=${s}", ("s", skip));
809 
811  detail::with_skip_flags(*this, skip, [&]() {
812  try
813  {
814  result = _generate_block(when, witness_owner, block_signing_private_key);
815  debug_log(ctx, "generate_block result=${b}", ("b", (std::string)block_info(result)));
816  }
817  FC_CAPTURE_AND_RETHROW(((std::string)ctx))
818  });
819 
820  return result;
821 }
822 
823 signed_block database::_generate_block(fc::time_point_sec when,
824  const account_name_type& witness_owner,
825  const fc::ecc::private_key& block_signing_private_key)
826 {
827  block_info ctx(when, witness_owner);
828 
829  debug_log(ctx, "_generate_block");
830 
831  auto& witness_svc = witness_service();
832 
833  uint32_t skip = get_node_properties().skip_flags;
834  uint32_t slot_num = get_slot_at_time(when);
835  FC_ASSERT(slot_num > 0);
836  std::string scheduled_witness = get_scheduled_witness(slot_num);
837  FC_ASSERT(scheduled_witness == witness_owner);
838 
839  const auto& witness_obj = witness_svc.get(witness_owner);
840 
841  if (!(skip & skip_witness_signature))
842  {
843  FC_ASSERT(witness_obj.signing_key == block_signing_private_key.get_public_key());
844  }
845 
846  static const size_t max_block_header_size = fc::raw::pack_size(signed_block_header()) + 4;
847  auto maximum_block_size = obtain_service<dbs_dynamic_global_property>()
848  .get()
849  .median_chain_props.maximum_block_size; // SCORUM_MAX_BLOCK_SIZE;
850  size_t total_block_size = max_block_header_size;
851 
852  signed_block pending_block;
853 
854  with_write_lock([&]() {
855  //
856  // The following code throws away existing pending_tx_session and
857  // rebuilds it by re-applying pending transactions.
858  //
859  // This rebuild is necessary because pending transactions' validity
860  // and semantics may have changed since they were received, because
861  // time-based semantics are evaluated based on the current block
862  // time. These changes can only be reflected in the database when
863  // the value of the "when" variable is known, which means we need to
864  // re-apply pending transactions in this method.
865  //
866  _pending_tx_session.reset();
867  _pending_tx_session = start_undo_session();
868 
869  uint64_t postponed_tx_count = 0;
870  // pop pending state (reset to head block state)
871  for (const signed_transaction& tx : _pending_tx)
872  {
873  // Only include transactions that have not expired yet for currently generating block,
874  // this should clear problem transactions and allow block production to continue
875 
876  if (tx.expiration < when)
877  {
878  continue;
879  }
880 
881  uint64_t new_total_size = total_block_size + fc::raw::pack_size(tx);
882 
883  // postpone transaction if it would make block too big
884  if (new_total_size >= maximum_block_size)
885  {
886  postponed_tx_count++;
887  continue;
888  }
889 
890  try
891  {
892  auto temp_session = start_undo_session();
893  _apply_transaction(tx);
894  for_each_index([&](chainbase::abstract_generic_index_i& item) { item.squash(); });
895  temp_session->push();
896 
897  total_block_size += fc::raw::pack_size(tx);
898  pending_block.transactions.push_back(tx);
899  }
900  catch (const fc::exception& e)
901  {
902  // Do nothing, transaction will not be re-applied
903  // wlog( "Transaction was not processed while generating block due to ${e}", ("e", e) );
904  // wlog( "The transaction was ${t}", ("t", tx) );
905  }
906  }
907  if (postponed_tx_count > 0)
908  {
909  wlog("Postponed ${n} transactions due to block size limit", ("n", postponed_tx_count));
910  }
911 
912  _pending_tx_session.reset();
913  });
914 
915  // We have temporarily broken the invariant that
916  // _pending_tx_session is the result of applying _pending_tx, as
917  // _pending_tx now consists of the set of postponed transactions.
918  // However, the push_block() call below will re-create the
919  // _pending_tx_session.
920 
921  pending_block.previous = head_block_id();
922  pending_block.timestamp = when;
923  pending_block.transaction_merkle_root = pending_block.calculate_merkle_root();
924  pending_block.witness = witness_owner;
925 
926  const auto& witness = witness_svc.get(witness_owner);
927 
928  if (witness.running_version != SCORUM_BLOCKCHAIN_VERSION)
929  {
930  pending_block.extensions.insert(block_header_extensions(SCORUM_BLOCKCHAIN_VERSION));
931  }
932 
933  const auto& hfp = obtain_service<dbs_hardfork_property>().get();
934 
935  if (hfp.current_hardfork_version
936  < SCORUM_BLOCKCHAIN_HARDFORK_VERSION // Binary is newer hardfork than has been applied
937  && (witness.hardfork_version_vote != _hardfork_versions[hfp.last_hardfork + 1]
938  || witness.hardfork_time_vote
939  != _hardfork_times[hfp.last_hardfork + 1])) // Witness vote does not match binary configuration
940  {
941  // Make vote match binary configuration
942  pending_block.extensions.insert(block_header_extensions(
943  hardfork_version_vote(_hardfork_versions[hfp.last_hardfork + 1], _hardfork_times[hfp.last_hardfork + 1])));
944  }
945  else if (hfp.current_hardfork_version
946  == SCORUM_BLOCKCHAIN_HARDFORK_VERSION // Binary does not know of a new hardfork
947  && witness.hardfork_version_vote
948  > SCORUM_BLOCKCHAIN_HARDFORK_VERSION) // Voting for hardfork in the future, that we do not know of...
949  {
950  // Make vote match binary configuration. This is vote to not apply the new hardfork.
951  pending_block.extensions.insert(block_header_extensions(
952  hardfork_version_vote(_hardfork_versions[hfp.last_hardfork], _hardfork_times[hfp.last_hardfork])));
953  }
954 
955  if (!(skip & skip_witness_signature))
956  {
957  pending_block.sign(block_signing_private_key);
958  }
959 
960  // TODO: Move this to _push_block() so session is restored.
961  if (!(skip & skip_block_size_check))
962  {
963  FC_ASSERT(fc::raw::pack_size(pending_block) <= SCORUM_MAX_BLOCK_SIZE);
964  }
965 
966  push_block(pending_block, skip);
967 
968  debug_log(ctx, "_generate_block result=${b}", ("b", (std::string)block_info(pending_block)));
969 
970  return pending_block;
971 }
972 
977 void database::pop_block()
978 {
979  block_info ctx;
980 
981  if (_fork_db.head())
982  {
983  ctx = block_info(_fork_db.head()->data);
984  }
985 
986  debug_log(ctx, "pop_block");
987 
988  try
989  {
990  _pending_tx_session.reset();
991  auto head_id = head_block_id();
992 
994  optional<signed_block> head_block = fetch_block_by_id(head_id);
995  SCORUM_ASSERT(head_block.valid(), pop_empty_chain, "there are no blocks to pop");
996 
997  _fork_db.pop_block();
998 
999  for_each_index([&](chainbase::abstract_generic_index_i& item) { item.undo(); });
1000 
1001  _popped_tx.insert(_popped_tx.begin(), head_block->transactions.begin(), head_block->transactions.end());
1002 
1003  debug_log(ctx, "pop_block result");
1004  }
1005  FC_CAPTURE_AND_RETHROW(((std::string)ctx))
1006 }
1007 
1008 void database::clear_pending()
1009 {
1010  try
1011  {
1012  assert((_pending_tx.size() == 0) || _pending_tx_session.valid());
1013  _pending_tx.clear();
1014  _pending_tx_session.reset();
1015  }
1016  FC_CAPTURE_AND_RETHROW()
1017 }
1018 
1019 void database::notify_pre_apply_operation(const operation_notification& note)
1020 {
1021  SCORUM_TRY_NOTIFY(pre_apply_operation, note);
1022 }
1023 
1024 void database::notify_post_apply_operation(const operation_notification& note)
1025 {
1026  SCORUM_TRY_NOTIFY(post_apply_operation, note);
1027 }
1028 
1029 operation_notification database::create_notification(const operation& op) const
1030 {
1031  return operation_notification(_current_trx_id, _current_block_num, _current_trx_in_block, _current_op_in_trx, op);
1032 }
1033 
1034 inline void database::push_virtual_operation(const operation& op)
1035 {
1036  if (_options & opt_notify_virtual_op_applying)
1037  {
1038  FC_ASSERT(is_virtual_operation(op));
1039 
1040  auto note = create_notification(op);
1041 
1042  operation_info ctx(op);
1043  debug_log(ctx, "virt operation pre_apply BEGIN");
1044  notify_pre_apply_operation(note);
1045  debug_log(ctx, "virt operation pre_apply END");
1046  debug_log(ctx, "virt operation post_apply BEGIN");
1047  notify_post_apply_operation(note);
1048  debug_log(ctx, "virt operation post_apply END");
1049  }
1050 }
1051 
1052 inline void database::push_hf_operation(const operation& op)
1053 {
1054  FC_ASSERT(is_virtual_operation(op));
1055 
1056  auto note = create_notification(op);
1057  notify_pre_apply_operation(note);
1058  notify_post_apply_operation(note);
1059 }
1060 
1061 void database::notify_pre_applied_block(const signed_block& block)
1062 {
1063  SCORUM_TRY_NOTIFY(pre_applied_block, block)
1064 }
1065 
1066 void database::notify_applied_block(const signed_block& block)
1067 {
1068  SCORUM_TRY_NOTIFY(applied_block, block)
1069 }
1070 
1071 void database::notify_on_pending_transaction(const signed_transaction& tx)
1072 {
1073  SCORUM_TRY_NOTIFY(on_pending_transaction, tx)
1074 }
1075 
1076 void database::notify_on_pre_apply_transaction(const signed_transaction& tx)
1077 {
1078  SCORUM_TRY_NOTIFY(on_pre_apply_transaction, tx)
1079 }
1080 
1081 void database::notify_on_applied_transaction(const signed_transaction& tx)
1082 {
1083  SCORUM_TRY_NOTIFY(on_applied_transaction, tx);
1084 }
1085 
1086 account_name_type database::get_scheduled_witness(uint32_t slot_num) const
1087 {
1088  const dynamic_global_property_object& dpo = obtain_service<dbs_dynamic_global_property>().get();
1089  const witness_schedule_object& wso = obtain_service<dbs_witness_schedule>().get();
1090 
1091  uint64_t current_aslot = dpo.current_aslot + slot_num;
1092  return wso.current_shuffled_witnesses[current_aslot % wso.num_scheduled_witnesses];
1093 }
1094 
1095 fc::time_point_sec database::get_slot_time(uint32_t slot_num) const
1096 {
1097  if (slot_num == 0)
1098  {
1099  return fc::time_point_sec();
1100  }
1101 
1102  auto interval = SCORUM_BLOCK_INTERVAL;
1103  const dynamic_global_property_object& dpo = obtain_service<dbs_dynamic_global_property>().get();
1104 
1105  if (head_block_num() == 0)
1106  {
1107  // n.b. first block is at genesis_time plus one block interval
1108  fc::time_point_sec genesis_time = dpo.time;
1109  return genesis_time + slot_num * interval;
1110  }
1111 
1112  int64_t head_block_abs_slot = head_block_time().sec_since_epoch() / interval;
1113  fc::time_point_sec head_slot_time(head_block_abs_slot * interval);
1114 
1115  // "slot 0" is head_slot_time
1116  // "slot 1" is head_slot_time,
1117  // plus maint interval if head block is a maint block
1118  // plus block interval if head block is not a maint block
1119  return head_slot_time + (slot_num * interval);
1120 }
1121 
1122 uint32_t database::get_slot_at_time(fc::time_point_sec when) const
1123 {
1124  fc::time_point_sec first_slot_time = get_slot_time(1);
1125  if (when < first_slot_time)
1126  {
1127  return 0;
1128  }
1129  return (when - first_slot_time).to_seconds() / SCORUM_BLOCK_INTERVAL + 1;
1130 }
1131 
1132 void database::account_recovery_processing()
1133 {
1134  // Clear expired recovery requests
1135  const auto& rec_req_idx = get_index<account_recovery_request_index>().indices().get<by_expiration>();
1136  auto rec_req = rec_req_idx.begin();
1137 
1138  while (rec_req != rec_req_idx.end() && rec_req->expires <= head_block_time())
1139  {
1140  remove(*rec_req);
1141  rec_req = rec_req_idx.begin();
1142  }
1143 
1144  // Clear invalid historical authorities
1145  const auto& hist_idx = get_index<owner_authority_history_index>().indices(); // by id
1146  auto hist = hist_idx.begin();
1147 
1148  while (hist != hist_idx.end()
1149  && time_point_sec(hist->last_valid_time + SCORUM_OWNER_AUTH_RECOVERY_PERIOD) < head_block_time())
1150  {
1151  remove(*hist);
1152  hist = hist_idx.begin();
1153  }
1154 
1155  // Apply effective recovery_account changes
1156  const auto& change_req_idx = get_index<change_recovery_account_request_index>().indices().get<by_effective_date>();
1157  auto change_req = change_req_idx.begin();
1158 
1159  auto& account_svc = account_service();
1160  while (change_req != change_req_idx.end() && change_req->effective_on <= head_block_time())
1161  {
1162  modify(account_svc.get_account(change_req->account_to_recover),
1163  [&](account_object& a) { a.recovery_account = change_req->recovery_account; });
1164 
1165  remove(*change_req);
1166  change_req = change_req_idx.begin();
1167  }
1168 }
1169 
1170 void database::expire_escrow_ratification()
1171 {
1172  const auto& escrow_idx = get_index<escrow_index>().indices().get<by_ratification_deadline>();
1173  auto escrow_itr = escrow_idx.lower_bound(false);
1174 
1175  auto& account_svc = account_service();
1176 
1177  while (escrow_itr != escrow_idx.end() && !escrow_itr->is_approved()
1178  && escrow_itr->ratification_deadline <= head_block_time())
1179  {
1180  const auto& old_escrow = *escrow_itr;
1181  ++escrow_itr;
1182 
1183  const auto& from_account = account_svc.get_account(old_escrow.from);
1184  account_svc.increase_balance(from_account, old_escrow.scorum_balance + old_escrow.pending_fee);
1185 
1186  remove(old_escrow);
1187  }
1188 }
1189 
1190 void database::process_decline_voting_rights()
1191 {
1192  const auto& request_idx = get_index<decline_voting_rights_request_index>().indices().get<by_effective_date>();
1193  auto itr = request_idx.begin();
1194 
1195  auto& account_svc = account_service();
1196 
1197  while (itr != request_idx.end() && itr->effective_date <= head_block_time())
1198  {
1199  const auto& account = get(itr->account);
1200 
1202  std::array<share_type, SCORUM_MAX_PROXY_RECURSION_DEPTH + 1> delta;
1203  delta[0] = -account.scorumpower.amount;
1204  for (int i = 0; i < SCORUM_MAX_PROXY_RECURSION_DEPTH; ++i)
1205  {
1206  delta[i + 1] = -account.proxied_vsf_votes[i];
1207  }
1208  account_svc.adjust_proxied_witness_votes(account, delta);
1209 
1210  account_svc.clear_witness_votes(account);
1211 
1212  modify(get(itr->account), [&](account_object& a) {
1213  a.can_vote = false;
1214  a.proxy = SCORUM_PROXY_TO_SELF_ACCOUNT;
1215  });
1216 
1217  remove(*itr);
1218  itr = request_idx.begin();
1219  }
1220 }
1221 
1222 time_point_sec database::head_block_time() const
1223 {
1224  return obtain_service<dbs_dynamic_global_property>().get().time;
1225 }
1226 
1227 uint32_t database::head_block_num() const
1228 {
1229  return obtain_service<dbs_dynamic_global_property>().get().head_block_number;
1230 }
1231 
1232 block_id_type database::head_block_id() const
1233 {
1234  return obtain_service<dbs_dynamic_global_property>().get().head_block_id;
1235 }
1236 
1237 block_info database::head_block_context() const
1238 {
1239  block_info ret;
1240  auto b = fetch_block_by_id(head_block_id());
1241  if (b.valid())
1242  {
1243  ret = block_info(*b);
1244  }
1245  else
1246  {
1247  ret = block_info(head_block_time(), obtain_service<dbs_dynamic_global_property>().get().current_witness);
1248  }
1249  return ret;
1250 }
1251 
1252 node_property_object& database::node_properties()
1253 {
1254  return _node_property_object;
1255 }
1256 
1257 uint32_t database::last_non_undoable_block_num() const
1258 {
1259  return obtain_service<dbs_dynamic_global_property>().get().last_irreversible_block_num;
1260 }
1261 
1262 void database::initialize_evaluators()
1263 {
1264  _my->_evaluator_registry.register_evaluator<account_create_evaluator>();
1265  _my->_evaluator_registry.register_evaluator<account_create_with_delegation_evaluator>();
1266  _my->_evaluator_registry.register_evaluator<account_update_evaluator>();
1267  _my->_evaluator_registry.register_evaluator<account_witness_proxy_evaluator>();
1268  _my->_evaluator_registry.register_evaluator<account_witness_vote_evaluator>();
1269  _my->_evaluator_registry.register_evaluator<atomicswap_initiate_evaluator>();
1270  _my->_evaluator_registry.register_evaluator<atomicswap_redeem_evaluator>();
1271  _my->_evaluator_registry.register_evaluator<atomicswap_refund_evaluator>();
1272  _my->_evaluator_registry.register_evaluator<change_recovery_account_evaluator>();
1273  _my->_evaluator_registry.register_evaluator<comment_evaluator>();
1274  _my->_evaluator_registry.register_evaluator<comment_options_evaluator>();
1275  _my->_evaluator_registry.register_evaluator<decline_voting_rights_evaluator>();
1276  _my->_evaluator_registry.register_evaluator<delegate_scorumpower_evaluator>();
1277  _my->_evaluator_registry.register_evaluator<delete_comment_evaluator>();
1278  _my->_evaluator_registry.register_evaluator<escrow_approve_evaluator>();
1279  _my->_evaluator_registry.register_evaluator<escrow_dispute_evaluator>();
1280  _my->_evaluator_registry.register_evaluator<escrow_release_evaluator>();
1281  _my->_evaluator_registry.register_evaluator<escrow_transfer_evaluator>();
1282  _my->_evaluator_registry.register_evaluator<prove_authority_evaluator>();
1283  _my->_evaluator_registry.register_evaluator<recover_account_evaluator>();
1284  _my->_evaluator_registry.register_evaluator<request_account_recovery_evaluator>();
1285  _my->_evaluator_registry.register_evaluator<transfer_evaluator>();
1286  _my->_evaluator_registry.register_evaluator<transfer_to_scorumpower_evaluator>();
1287  _my->_evaluator_registry.register_evaluator<vote_evaluator>();
1288  _my->_evaluator_registry.register_evaluator<witness_update_evaluator>();
1289  _my->_evaluator_registry.register_evaluator<proposal_create_evaluator>();
1290  _my->_evaluator_registry.register_evaluator<proposal_vote_evaluator>();
1291  _my->_evaluator_registry.register_evaluator<proposal_create_evaluator>();
1292  _my->_evaluator_registry.register_evaluator<set_withdraw_scorumpower_route_to_dev_pool_evaluator>();
1293  _my->_evaluator_registry.register_evaluator<set_withdraw_scorumpower_route_to_account_evaluator>();
1294  _my->_evaluator_registry.register_evaluator<withdraw_scorumpower_evaluator>();
1295  _my->_evaluator_registry.register_evaluator<registration_pool_evaluator>();
1296  _my->_evaluator_registry.register_evaluator<create_budget_evaluator>();
1297  _my->_evaluator_registry.register_evaluator<close_budget_evaluator>();
1298  _my->_evaluator_registry.register_evaluator<close_budget_by_advertising_moderator_evaluator>();
1299  _my->_evaluator_registry.register_evaluator<update_budget_evaluator>();
1300  _my->_evaluator_registry.register_evaluator(
1301  new create_game_evaluator(*this, _my->get_betting_service(), get_dba<game_uuid_history_object>()));
1302  _my->_evaluator_registry.register_evaluator(new cancel_game_evaluator(*this, _my->get_betting_service(), *this));
1303  _my->_evaluator_registry.register_evaluator(new update_game_markets_evaluator(*this, _my->get_betting_service()));
1304  _my->_evaluator_registry.register_evaluator(
1305  new update_game_start_time_evaluator(*this, _my->get_betting_service(), *this));
1306  _my->_evaluator_registry.register_evaluator(
1307  new post_game_results_evaluator(*this, _my->get_betting_service(), *this));
1308 
1309  // clang-format off
1310  _my->_evaluator_registry.register_evaluator(new post_bet_evaluator(*this,
1311  _my->get_betting_matcher(),
1312  _my->get_betting_service(),
1313  get_dba<game_object>(),
1314  get_dba<account_object>(),
1315  get_dba<bet_uuid_history_object>()));
1316  // clang-format on
1317 
1318  _my->_evaluator_registry.register_evaluator(new cancel_pending_bets_evaluator(*this, _my->get_betting_service()));
1319  _my->_evaluator_registry.register_evaluator(new delegate_sp_from_reg_pool_evaluator(
1320  *this, account_service(), get_dba<registration_pool_object>(), get_dba<registration_committee_member_object>(),
1321  get_dba<reg_pool_sp_delegation_object>()));
1322  _my->_evaluator_registry.register_evaluator(
1323  new create_nft_evaluator(*this, get_dba<account_object>(), get_dba<nft_object>()));
1324  _my->_evaluator_registry.register_evaluator(
1325  new update_nft_meta_evaluator(*this, get_dba<account_object>(), get_dba<nft_object>()));
1326  _my->_evaluator_registry.register_evaluator(
1327  new update_nft_name_evaluator(*this, get_dba<account_object>(), get_dba<nft_object>()));
1328  _my->_evaluator_registry.register_evaluator(
1329  new adjust_nft_experience_evaluator(*this, get_dba<account_object>(), get_dba<nft_object>()));
1330  _my->_evaluator_registry.register_evaluator(
1331  new create_game_round_evaluator(*this, get_dba<account_object>(), get_dba<game_round_object>()));
1332  _my->_evaluator_registry.register_evaluator(
1333  new update_game_round_result_evaluator(*this, get_dba<account_object>(), get_dba<game_round_object>()));
1334 }
1335 
1336 void database::initialize_indexes()
1337 {
1338  add_index<account_authority_index>();
1339  add_index<account_index>();
1340  add_index<account_registration_bonus_index>();
1341  add_index<account_blogging_statistic_index>();
1342  add_index<account_recovery_request_index>();
1343  add_index<block_summary_index>();
1344  add_index<fund_budget_index>();
1345  add_index<post_budget_index>();
1346  add_index<banner_budget_index>();
1347  add_index<chain_property_index>();
1348  add_index<change_recovery_account_request_index>();
1349  add_index<comment_index>();
1350  add_index<comment_statistic_scr_index>();
1351  add_index<comment_statistic_sp_index>();
1352  add_index<comment_vote_index>();
1353  add_index<decline_voting_rights_request_index>();
1354  add_index<dynamic_global_property_index>();
1355  add_index<escrow_index>();
1356  add_index<hardfork_property_index>();
1357  add_index<owner_authority_history_index>();
1358  add_index<proposal_object_index>();
1359  add_index<registration_committee_member_index>();
1360  add_index<registration_pool_index>();
1361  add_index<content_reward_fund_scr_index>();
1362  add_index<content_reward_fund_sp_index>();
1363  add_index<content_fifa_world_cup_2018_bounty_reward_fund_index>();
1364  add_index<content_reward_balancer_scr_index>();
1365  add_index<voters_reward_balancer_scr_index>();
1366  add_index<voters_reward_balancer_sp_index>();
1367  add_index<transaction_index>();
1368  add_index<scorumpower_delegation_expiration_index>();
1369  add_index<scorumpower_delegation_index>();
1370  add_index<reg_pool_sp_delegation_index>();
1371  add_index<withdraw_scorumpower_route_index>();
1372  add_index<withdraw_scorumpower_route_statistic_index>();
1373  add_index<withdraw_scorumpower_index>();
1374  add_index<witness_index>();
1375  add_index<witness_schedule_index>();
1376  add_index<witness_vote_index>();
1377  add_index<atomicswap_contract_index>();
1378 
1379  add_index<dev_committee_index>();
1380  add_index<dev_committee_member_index>();
1381 
1382  add_index<witness_reward_in_sp_migration_index>();
1383  add_index<advertising_property_index>();
1384 
1385  add_index<game_index>();
1386 
1387  add_index<betting_property_index>();
1388  add_index<pending_bet_index>();
1389  add_index<matched_bet_index>();
1390 
1391  add_index<bet_uuid_history_index>();
1392  add_index<game_uuid_history_index>();
1393  add_index<nft_index>();
1394  add_index<game_round_index>();
1395 
1396  _plugin_index_signal();
1397 }
1398 
1399 void database::validate_transaction(const signed_transaction& trx)
1400 {
1401  database::with_write_lock([&]() {
1402  auto session = start_undo_session();
1403  _apply_transaction(trx);
1404  });
1405 }
1406 
1407 void database::set_flush_interval(uint32_t flush_blocks)
1408 {
1409  _flush_blocks = flush_blocks;
1410  _next_flush_block = 0;
1411 }
1412 
1414 
1415 void database::apply_block(const signed_block& next_block, uint32_t skip)
1416 {
1417  block_info ctx(next_block);
1418 
1419  debug_log(ctx, "apply_block skip=${s}", ("s", skip));
1420 
1421  try
1422  {
1423  // fc::time_point begin_time = fc::time_point::now();
1424 
1425  auto block_num = next_block.block_num();
1426  if (_checkpoints.size() && _checkpoints.rbegin()->second != block_id_type())
1427  {
1428  auto itr = _checkpoints.find(block_num);
1429  if (itr != _checkpoints.end())
1430  FC_ASSERT(next_block.id() == itr->second, "Block did not match checkpoint",
1431  ("checkpoint", *itr)("block_id", next_block.id()));
1432 
1433  if (_checkpoints.rbegin()->first >= block_num)
1434  skip = skip_witness_signature | skip_transaction_signatures | skip_transaction_dupe_check | skip_fork_db
1435  | skip_block_size_check | skip_tapos_check
1436  | skip_authority_check
1437  /* | skip_merkle_check While blockchain is being downloaded, txs need to be validated against block
1438  headers */
1439  | skip_undo_history_check | skip_witness_schedule_check | skip_validate | skip_validate_invariants;
1440  }
1441 
1442  detail::with_skip_flags(*this, skip, [&]() { _apply_block(next_block); });
1443 
1445  if (is_producing() || !(skip & skip_validate_invariants))
1446  {
1447  try
1448  {
1449  validate_invariants();
1450  }
1451 #ifdef DEBUG
1452  FC_CAPTURE_AND_RETHROW(((std::string)ctx));
1453 #else
1454  FC_CAPTURE_AND_LOG(((std::string)ctx));
1455 #endif
1456  }
1457 
1458  // fc::time_point end_time = fc::time_point::now();
1459  // fc::microseconds dt = end_time - begin_time;
1460  if (_flush_blocks != 0)
1461  {
1462  if (_next_flush_block == 0)
1463  {
1464  uint32_t lep = block_num + 1 + _flush_blocks * 9 / 10;
1465  uint32_t rep = block_num + 1 + _flush_blocks;
1466 
1467  // use time_point::now() as RNG source to pick block randomly between lep and rep
1468  uint32_t span = rep - lep;
1469  uint32_t x = lep;
1470  if (span > 0)
1471  {
1472  uint64_t now = uint64_t(fc::time_point::now().time_since_epoch().count());
1473  x += now % span;
1474  }
1475  _next_flush_block = x;
1476  // ilog( "Next flush scheduled at block ${b}", ("b", x) );
1477  }
1478 
1479  if (_next_flush_block == block_num)
1480  {
1481  _next_flush_block = 0;
1482  // ilog( "Flushing database shared memory at block ${b}", ("b", block_num) );
1483  chainbase::database::flush();
1484  }
1485  }
1486 
1487  show_free_memory(false);
1488 
1489  debug_log(ctx, "apply_block result");
1490  }
1491  FC_CAPTURE_AND_RETHROW(((std::string)ctx))
1492 }
1493 
1494 void database::show_free_memory(bool force)
1495 {
1496  uint32_t free_gb = uint32_t(get_free_memory() / (1024 * 1024 * 1024));
1497  if (force || (free_gb < _last_free_gb_printed) || (free_gb > _last_free_gb_printed + 1))
1498  {
1499  ilog("Free memory is now ${n}G", ("n", free_gb));
1500  _last_free_gb_printed = free_gb;
1501  }
1502 
1503  if (free_gb == 0)
1504  {
1505  uint32_t free_mb = uint32_t(get_free_memory() / (1024 * 1024));
1506 
1507  if (free_mb <= SCORUM_DB_FREE_MEMORY_THRESHOLD_MB && head_block_num() % 10 == 0)
1508  {
1509  elog("Free memory is now ${n}M. Increase shared file size immediately!", ("n", free_mb));
1510  }
1511  }
1512 }
1513 
1514 void database::_apply_block(const signed_block& next_block)
1515 {
1516  block_info ctx(next_block);
1517 
1518  debug_log(ctx, "_apply_block");
1519 
1520  try
1521  {
1522  notify_pre_applied_block(next_block);
1523 
1524  uint32_t next_block_num = next_block.block_num();
1525  // block_id_type next_block_id = next_block.id();
1526 
1527  uint32_t skip = get_node_properties().skip_flags;
1528 
1529  if (!(skip & skip_merkle_check))
1530  {
1531  auto merkle_root = next_block.calculate_merkle_root();
1532 
1533  try
1534  {
1535  FC_ASSERT(next_block.transaction_merkle_root == merkle_root, "Merkle check failed",
1536  ("next_block.transaction_merkle_root", next_block.transaction_merkle_root)(
1537  "calc", merkle_root)("next_block", next_block)("id", next_block.id()));
1538  }
1539  catch (fc::assert_exception& e)
1540  {
1541  debug_log(ctx, "merkle check failed");
1542 
1543  const auto& merkle_map = get_shared_db_merkle();
1544  auto itr = merkle_map.find(next_block_num);
1545 
1546  if (itr == merkle_map.end() || itr->second != merkle_root)
1547  {
1548  debug_log(ctx, "rethrow merkle check fail");
1549 
1550  throw e;
1551  }
1552  }
1553  }
1554 
1555  const witness_object& signing_witness = validate_block_header(skip, next_block);
1556 
1557  _current_block_num = next_block_num;
1558  _current_trx_in_block = 0;
1559 
1560  const auto& gprops = obtain_service<dbs_dynamic_global_property>().get();
1561  auto block_size = fc::raw::pack_size(next_block);
1562  FC_ASSERT(block_size <= gprops.median_chain_props.maximum_block_size, "Block Size is too Big",
1563  ("next_block_num", next_block_num)("block_size",
1564  block_size)("max", gprops.median_chain_props.maximum_block_size));
1565 
1568  modify(gprops, [&](dynamic_global_property_object& dgp) { dgp.current_witness = next_block.witness; });
1569 
1571  process_header_extensions(next_block);
1572 
1573  const auto& witness = witness_service().get(next_block.witness);
1574  const auto& hardfork_state = obtain_service<dbs_hardfork_property>().get();
1575  FC_ASSERT(witness.running_version >= hardfork_state.current_hardfork_version,
1576  "Block produced by witness that is not running current hardfork",
1577  ("witness", witness)("next_block.witness", next_block.witness)("hardfork_state", hardfork_state));
1578 
1579  debug_log(ctx, "apply_transactions");
1580  for (const auto& trx : next_block.transactions)
1581  {
1582  /* We do not need to push the undo state for each transaction
1583  * because they either all apply and are valid or the
1584  * entire block fails to apply. We only need an "undo" state
1585  * for transactions when validating broadcast transactions or
1586  * when building a block.
1587  */
1588 
1589  database_ns::user_activity_context user_activity_ctx(static_cast<data_service_factory&>(*this), trx);
1590  database_ns::process_user_activity_task().apply(user_activity_ctx);
1591 
1592  apply_transaction(trx, skip);
1593  ++_current_trx_in_block;
1594  }
1595 
1596  debug_log(ctx, "update_global_dynamic_data");
1597  update_global_dynamic_data(next_block);
1598  debug_log(ctx, "update_signing_witness");
1599  update_signing_witness(signing_witness, next_block);
1600 
1601  debug_log(ctx, "update_last_irreversible_block");
1602  update_last_irreversible_block();
1603 
1604  debug_log(ctx, "create_block_summary");
1605  create_block_summary(next_block);
1606  debug_log(ctx, "clear_expired_transactions");
1607  clear_expired_transactions();
1608  debug_log(ctx, "clear_expired_delegations");
1609  clear_expired_delegations();
1610 
1611  // in dbs_database_witness_schedule.cpp
1612  update_witness_schedule();
1613 
1614  database_ns::block_task_context task_ctx(static_cast<data_service_factory&>(*this),
1615  static_cast<database_virtual_operations_emmiter_i&>(*this),
1616  _current_block_num, ctx);
1617 
1618  database_ns::process_funds(task_ctx).apply(task_ctx);
1627  database_ns::process_games_startup(_my->get_betting_service(), *this).apply(task_ctx);
1628  database_ns::process_bets_resolving(_my->get_betting_service(), _my->get_betting_resolver(), *this,
1629  get_dba<game_object>(), get_dba<dynamic_global_property_object>())
1630  .apply(task_ctx);
1631  // TODO: using boost::di to avoid these explicit calls
1632  database_ns::process_bets_auto_resolving(_my->get_betting_service(), *this, get_dba<game_object>(),
1633  get_dba<dynamic_global_property_object>())
1634  .apply(task_ctx);
1635 
1636  debug_log(ctx, "account_recovery_processing");
1637  account_recovery_processing();
1638  debug_log(ctx, "expire_escrow_ratification");
1639  expire_escrow_ratification();
1640  debug_log(ctx, "process_decline_voting_rights");
1641  process_decline_voting_rights();
1642 
1643  debug_log(ctx, "clear_expired_proposals");
1644  obtain_service<dbs_proposal>().clear_expired_proposals();
1645 
1646  debug_log(ctx, "process_hardforks");
1647  process_hardforks();
1648 
1649  // notify observers that the block has been applied
1650  notify_applied_block(next_block);
1651 
1652  debug_log(ctx, "_apply_block result");
1653  }
1654  FC_CAPTURE_LOG_AND_RETHROW(((std::string)ctx))
1655 }
1656 
1657 void database::process_header_extensions(const signed_block& next_block)
1658 {
1659  auto& witness_svc = witness_service();
1660 
1661  auto itr = next_block.extensions.begin();
1662 
1663  while (itr != next_block.extensions.end())
1664  {
1665  switch (itr->which())
1666  {
1667  case 0: // void_t
1668  break;
1669  case 1: // version
1670  {
1671  auto reported_version = itr->get<version>();
1672  const auto& signing_witness = witness_svc.get(next_block.witness);
1673  // idump( (next_block.witness)(signing_witness.running_version)(reported_version) );
1674 
1675  if (reported_version != signing_witness.running_version)
1676  {
1677  modify(signing_witness, [&](witness_object& wo) { wo.running_version = reported_version; });
1678  }
1679  break;
1680  }
1681  case 2: // hardfork_version vote
1682  {
1683  auto hfv = itr->get<hardfork_version_vote>();
1684  const auto& signing_witness = witness_svc.get(next_block.witness);
1685  // idump( (next_block.witness)(signing_witness.running_version)(hfv) );
1686 
1687  if (hfv.hf_version != signing_witness.hardfork_version_vote
1688  || hfv.hf_time != signing_witness.hardfork_time_vote)
1689  modify(signing_witness, [&](witness_object& wo) {
1690  wo.hardfork_version_vote = hfv.hf_version;
1691  wo.hardfork_time_vote = hfv.hf_time;
1692  });
1693 
1694  break;
1695  }
1696  default:
1697  FC_ASSERT(false, "Unknown extension in block header");
1698  }
1699 
1700  ++itr;
1701  }
1702 }
1703 
1704 void database::apply_transaction(const signed_transaction& trx, uint32_t skip)
1705 {
1706  detail::with_skip_flags(*this, skip, [&]() { _apply_transaction(trx); });
1707  notify_on_applied_transaction(trx);
1708 }
1709 
1710 void database::_apply_transaction(const signed_transaction& trx)
1711 {
1712  try
1713  {
1714  _current_trx_id = trx.id();
1715  uint32_t skip = get_node_properties().skip_flags;
1716 
1717  if (!(skip & skip_validate)) /* issue #505 explains why this skip_flag is disabled */
1718  {
1719  trx.validate();
1720  }
1721 
1722  auto& trx_idx = get_index<transaction_index>();
1723  auto trx_id = trx.id();
1724  // idump((trx_id)(skip&skip_transaction_dupe_check));
1725  FC_ASSERT((skip & skip_transaction_dupe_check)
1726  || trx_idx.indices().get<by_trx_id>().find(trx_id) == trx_idx.indices().get<by_trx_id>().end(),
1727  "Duplicate transaction check failed", ("trx_ix", trx_id));
1728 
1729  if (!(skip & (skip_transaction_signatures | skip_authority_check)))
1730  {
1731  auto get_active = [&](const std::string& name) {
1732  return authority(get<account_authority_object, by_account>(name).active);
1733  };
1734  auto get_owner = [&](const std::string& name) {
1735  return authority(get<account_authority_object, by_account>(name).owner);
1736  };
1737  auto get_posting = [&](const std::string& name) {
1738  return authority(get<account_authority_object, by_account>(name).posting);
1739  };
1740 
1741  try
1742  {
1743  trx.verify_authority(get_chain_id(), get_active, get_owner, get_posting, SCORUM_MAX_SIG_CHECK_DEPTH);
1744  }
1745  catch (protocol::tx_missing_active_auth& e)
1746  {
1747  if (get_shared_db_merkle().find(head_block_num() + 1) == get_shared_db_merkle().end())
1748  {
1749  throw e;
1750  }
1751  }
1752  }
1753 
1754  // Skip all manner of expiration and TaPoS checking if we're on block 1; It's impossible that the transaction is
1755  // expired, and TaPoS makes no sense as no blocks exist.
1756  if (BOOST_LIKELY(head_block_num() > 0))
1757  {
1758  if (!(skip & skip_tapos_check))
1759  {
1760  const auto& tapos_block_summary = get<block_summary_object>(trx.ref_block_num);
1761  // Verify TaPoS block summary has correct ID prefix, and that this block's time is not past the
1762  // expiration
1763  SCORUM_ASSERT(trx.ref_block_prefix == tapos_block_summary.block_id._hash[1],
1764  transaction_tapos_exception, "",
1765  ("trx.ref_block_prefix", trx.ref_block_prefix)("tapos_block_summary",
1766  tapos_block_summary.block_id._hash[1]));
1767  }
1768 
1769  fc::time_point_sec now = head_block_time();
1770 
1771  SCORUM_ASSERT(
1772  trx.expiration <= now + fc::seconds(SCORUM_MAX_TIME_UNTIL_EXPIRATION), transaction_expiration_exception,
1773  "", ("trx.expiration", trx.expiration)("now", now)("max_til_exp", SCORUM_MAX_TIME_UNTIL_EXPIRATION));
1774  // Simple solution to pending trx bug when now == trx.expiration
1775  SCORUM_ASSERT(now < trx.expiration, transaction_expiration_exception, "",
1776  ("now", now)("trx.exp", trx.expiration));
1777  }
1778 
1779  // Insert transaction into unique transactions database.
1780  if (!(skip & skip_transaction_dupe_check))
1781  {
1782  create<transaction_object>([&](transaction_object& transaction) {
1783  transaction.trx_id = trx_id;
1785  fc::raw::pack(transaction.packed_trx, trx);
1786  });
1787  }
1788 
1789  notify_on_pre_apply_transaction(trx);
1790 
1791  // Finally process the operations
1792  _current_op_in_trx = 0;
1793  for (const auto& op : trx.operations)
1794  {
1795  try
1796  {
1797  apply_operation(op);
1798  ++_current_op_in_trx;
1799  }
1800  FC_CAPTURE_AND_RETHROW((op));
1801  }
1802  _current_trx_id = transaction_id_type();
1803  }
1804  FC_CAPTURE_AND_RETHROW((trx))
1805 }
1806 
1807 void database::apply_operation(const operation& op)
1808 {
1809  auto note = create_notification(op);
1810 
1811  notify_pre_apply_operation(note);
1812  _my->_evaluator_registry.get_evaluator(op).apply(op);
1813  notify_post_apply_operation(note);
1814 }
1815 
1816 const witness_object& database::validate_block_header(uint32_t skip, const signed_block& next_block) const
1817 {
1818  try
1819  {
1820  FC_ASSERT(head_block_id() == next_block.previous, "",
1821  ("head_block_id", head_block_id())("next.prev", next_block.previous));
1822  FC_ASSERT(
1823  head_block_time() < next_block.timestamp, "",
1824  ("head_block_time", head_block_time())("next", next_block.timestamp)("blocknum", next_block.block_num()));
1825 
1826  const witness_object& witness = witness_service().get(next_block.witness);
1827 
1828  if (!(skip & skip_witness_signature))
1829  {
1830  FC_ASSERT(next_block.validate_signee(witness.signing_key));
1831  }
1832 
1833  if (!(skip & skip_witness_schedule_check))
1834  {
1835  uint32_t slot_num = get_slot_at_time(next_block.timestamp);
1836  FC_ASSERT(slot_num > 0);
1837 
1838  std::string scheduled_witness = get_scheduled_witness(slot_num);
1839 
1840  if (witness.owner != scheduled_witness)
1841  {
1842  wdump((obtain_service<dbs_dynamic_global_property>().get())(next_block.block_num())(next_block));
1843  }
1844 
1845  FC_ASSERT(witness.owner == scheduled_witness, "Witness produced block at wrong time",
1846  ("block witness", next_block.witness)("scheduled", scheduled_witness)("slot_num", slot_num));
1847  }
1848 
1849  return witness;
1850  }
1851  FC_CAPTURE_AND_RETHROW()
1852 }
1853 
1854 void database::create_block_summary(const signed_block& next_block)
1855 {
1856  try
1857  {
1858  block_summary_id_type sid(next_block.block_num() & (uint32_t)SCORUM_BLOCKID_POOL_SIZE);
1859  modify(get<block_summary_object>(sid), [&](block_summary_object& p) { p.block_id = next_block.id(); });
1860  }
1861  FC_CAPTURE_AND_RETHROW()
1862 }
1863 
1864 void database::update_global_dynamic_data(const signed_block& b)
1865 {
1866  try
1867  {
1868  const dynamic_global_property_object& _dgp = obtain_service<dbs_dynamic_global_property>().get();
1869  auto& witness_svc = witness_service();
1870 
1871  uint32_t missed_blocks = 0;
1872  if (head_block_time() != fc::time_point_sec())
1873  {
1874  missed_blocks = get_slot_at_time(b.timestamp);
1875  assert(missed_blocks != 0);
1876  missed_blocks--;
1877 
1878  if (missed_blocks > 0)
1879  {
1880  dlog("{\"missed_blocks\": ${missed_blocks}, \"last_block\": {\"last_block_num\": ${last_block_num}, "
1881  "\"info\": ${last_block}}, \"new_block\": {\"new_block_num\": ${new_block_num}, \"info\": "
1882  "${new_block}}}",
1883  ("missed_blocks", missed_blocks)("last_block_num", _dgp.head_block_number)(
1884  "last_block", fetch_block_by_id(_dgp.head_block_id))("new_block_num",
1885  b.block_num())("new_block", b));
1886  }
1887 
1888  for (uint32_t i = 0; i < missed_blocks; ++i)
1889  {
1890  const auto& witness_missed = witness_svc.get(get_scheduled_witness(i + 1));
1891  if (witness_missed.owner != b.witness)
1892  {
1893  modify(witness_missed, [&](witness_object& w) {
1894  w.total_missed++;
1895 
1896  push_virtual_operation(witness_miss_block_operation(w.owner, b.block_num()));
1897 
1899  {
1901  push_virtual_operation(shutdown_witness_operation(w.owner));
1902  }
1903  });
1904  }
1905  }
1906  }
1907 
1908  // dynamic global properties updating
1909  modify(_dgp, [&](dynamic_global_property_object& dgp) {
1910  // This is constant time assuming 100% participation. It is O(B) otherwise (B = Num blocks between update)
1911  for (uint32_t i = 0; i < missed_blocks + 1; i++)
1912  {
1913  dgp.participation_count -= dgp.recent_slots_filled.hi & 0x8000000000000000ULL ? 1 : 0;
1914  dgp.recent_slots_filled = (dgp.recent_slots_filled << 1) + (i == 0 ? 1 : 0);
1915  dgp.participation_count += (i == 0 ? 1 : 0);
1916  }
1917 
1918  dgp.head_block_number = b.block_num();
1919  dgp.head_block_id = b.id();
1920  dgp.time = b.timestamp;
1921  dgp.current_aslot += missed_blocks + 1;
1922  });
1923 
1924  if (!(get_node_properties().skip_flags & skip_undo_history_check))
1925  {
1926  SCORUM_ASSERT(
1927  _dgp.head_block_number - _dgp.last_irreversible_block_num < SCORUM_MAX_UNDO_HISTORY,
1928  undo_database_exception,
1929  "The database does not have enough undo history to support a blockchain with so many missed blocks. "
1930  "Please add a checkpoint if you would like to continue applying blocks beyond this point.",
1931  ("last_irreversible_block_num", _dgp.last_irreversible_block_num)("head", _dgp.head_block_number)(
1932  "max_undo", SCORUM_MAX_UNDO_HISTORY));
1933  }
1934  }
1935  FC_CAPTURE_AND_RETHROW()
1936 }
1937 
1938 void database::update_signing_witness(const witness_object& signing_witness, const signed_block& new_block)
1939 {
1940  try
1941  {
1942  modify(signing_witness, [&](witness_object& _wit) { _wit.last_confirmed_block_num = new_block.block_num(); });
1943  }
1944  FC_CAPTURE_AND_RETHROW()
1945 }
1946 
1947 void database::update_last_irreversible_block()
1948 {
1949  try
1950  {
1951  const dynamic_global_property_object& dpo = obtain_service<dbs_dynamic_global_property>().get();
1952 
1957  if (head_block_num() < SCORUM_START_MINER_VOTING_BLOCK)
1958  {
1959  modify(dpo, [&](dynamic_global_property_object& _dpo) {
1960  if (head_block_num() > SCORUM_MAX_WITNESSES)
1961  {
1962  _dpo.last_irreversible_block_num = head_block_num() - SCORUM_MAX_WITNESSES;
1963  }
1964  });
1965  }
1966  else
1967  {
1968  auto& witness_svc = witness_service();
1969  const witness_schedule_object& wso = obtain_service<dbs_witness_schedule>().get();
1970 
1971  std::vector<const witness_object*> wit_objs;
1972  wit_objs.reserve(wso.num_scheduled_witnesses);
1973  for (int i = 0; i < wso.num_scheduled_witnesses; i++)
1974  {
1975  wit_objs.push_back(&witness_svc.get(wso.current_shuffled_witnesses[i]));
1976  }
1977 
1978  static_assert(SCORUM_IRREVERSIBLE_THRESHOLD > 0, "irreversible threshold must be nonzero");
1979 
1980  // 1 1 1 2 2 2 2 2 2 2 -> 2 .7*10 = 7
1981  // 1 1 1 1 1 1 1 2 2 2 -> 1
1982  // 3 3 3 3 3 3 3 3 3 3 -> 3
1983 
1984  size_t offset
1985  = ((SCORUM_100_PERCENT - SCORUM_IRREVERSIBLE_THRESHOLD) * wit_objs.size() / SCORUM_100_PERCENT);
1986 
1987  std::nth_element(wit_objs.begin(), wit_objs.begin() + offset, wit_objs.end(),
1988  [](const witness_object* a, const witness_object* b) {
1989  return a->last_confirmed_block_num < b->last_confirmed_block_num;
1990  });
1991 
1992  uint32_t new_last_irreversible_block_num = wit_objs[offset]->last_confirmed_block_num;
1993 
1994  if (new_last_irreversible_block_num > dpo.last_irreversible_block_num)
1995  {
1996  modify(dpo, [&](dynamic_global_property_object& _dpo) {
1997  _dpo.last_irreversible_block_num = new_last_irreversible_block_num;
1998  });
1999  }
2000  }
2001 
2002  for_each_index(
2003  [&](chainbase::abstract_generic_index_i& item) { item.commit(dpo.last_irreversible_block_num); });
2004 
2005  if (!(get_node_properties().skip_flags & skip_block_log))
2006  {
2007  // output to block log based on new last irreversible block num
2008  const auto& tmp_head = _block_log.head();
2009  uint64_t log_head_num = 0;
2010 
2011  if (tmp_head)
2012  {
2013  log_head_num = tmp_head->block_num();
2014  }
2015 
2016  if (log_head_num < dpo.last_irreversible_block_num)
2017  {
2018  while (log_head_num < dpo.last_irreversible_block_num)
2019  {
2020  std::shared_ptr<fork_item> block = _fork_db.fetch_block_on_main_branch_by_number(log_head_num + 1);
2021  FC_ASSERT(block, "Current fork in the fork database does not contain the last_irreversible_block");
2022  _block_log.append(block->data);
2023  log_head_num++;
2024  }
2025 
2026  _block_log.flush();
2027  }
2028  }
2029 
2030  _fork_db.set_max_size(dpo.head_block_number - dpo.last_irreversible_block_num + 1);
2031  }
2032  FC_CAPTURE_AND_RETHROW()
2033 }
2034 
2035 void database::clear_expired_transactions()
2036 {
2037  // Look for expired transactions in the deduplication list, and remove them.
2038  // Transactions must have expired by at least two forking windows in order to be removed.
2039  auto& transaction_idx = get_index<transaction_index>();
2040  const auto& dedupe_index = transaction_idx.indices().get<by_expiration>();
2041  while ((!dedupe_index.empty()) && (head_block_time() > dedupe_index.begin()->expiration))
2042  {
2043  remove(*dedupe_index.begin());
2044  }
2045 }
2046 
2047 void database::clear_expired_delegations()
2048 {
2049  auto now = head_block_time();
2050  const auto& delegations_by_exp = get_index<scorumpower_delegation_expiration_index, by_expiration>();
2051  const auto& account_svc = account_service();
2052  auto itr = delegations_by_exp.begin();
2053  while (itr != delegations_by_exp.end() && itr->expiration < now)
2054  {
2055  modify(account_svc.get_account(itr->delegator),
2056  [&](account_object& a) { a.delegated_scorumpower -= itr->scorumpower; });
2057 
2058  push_virtual_operation(return_scorumpower_delegation_operation(itr->delegator, itr->scorumpower));
2059 
2060  remove(*itr);
2061  itr = delegations_by_exp.begin();
2062  }
2063 }
2064 
2065 const genesis_persistent_state_type& database::genesis_persistent_state() const
2066 {
2067  return _my->_genesis_persistent_state;
2068 }
2069 
2070 void database::init_hardforks(time_point_sec genesis_time)
2071 {
2072  _hardfork_times[0] = genesis_time;
2073  _hardfork_versions[0] = hardfork_version(0, 0);
2074 
2075  // SCORUM: structure to initialize hardofrks
2076 
2077  FC_ASSERT(SCORUM_HARDFORK_0_1 == 1, "Invalid hardfork #1 configuration");
2078  _hardfork_times[SCORUM_HARDFORK_0_1] = fc::time_point_sec(SCORUM_HARDFORK_0_1_TIME);
2079  _hardfork_versions[SCORUM_HARDFORK_0_1] = SCORUM_HARDFORK_0_1_VERSION;
2080 
2081  FC_ASSERT(SCORUM_HARDFORK_0_2 == 2, "Invalid hardfork #2 configuration");
2082  _hardfork_times[SCORUM_HARDFORK_0_2] = fc::time_point_sec(SCORUM_HARDFORK_0_2_TIME);
2083  _hardfork_versions[SCORUM_HARDFORK_0_2] = SCORUM_HARDFORK_0_2_VERSION;
2084 
2085  FC_ASSERT(SCORUM_HARDFORK_0_3 == 3, "Invalid hardfork #3 configuration");
2086  _hardfork_times[SCORUM_HARDFORK_0_3] = fc::time_point_sec(SCORUM_HARDFORK_0_3_TIME);
2087  _hardfork_versions[SCORUM_HARDFORK_0_3] = SCORUM_HARDFORK_0_3_VERSION;
2088 
2089  FC_ASSERT(SCORUM_HARDFORK_0_4 == 4, "Invalid hardfork #4 configuration");
2090  _hardfork_times[SCORUM_HARDFORK_0_4] = fc::time_point_sec(SCORUM_HARDFORK_0_4_TIME);
2091  _hardfork_versions[SCORUM_HARDFORK_0_4] = SCORUM_HARDFORK_0_4_VERSION;
2092 
2093  FC_ASSERT(SCORUM_HARDFORK_0_5 == 5, "Invalid hardfork #5 configuration");
2094  _hardfork_times[SCORUM_HARDFORK_0_5] = fc::time_point_sec(SCORUM_HARDFORK_0_5_TIME);
2095  _hardfork_versions[SCORUM_HARDFORK_0_5] = SCORUM_HARDFORK_0_5_VERSION;
2096 
2097  FC_ASSERT(SCORUM_HARDFORK_0_6 == 6, "Invalid hardfork #6 configuration");
2098  _hardfork_times[SCORUM_HARDFORK_0_6] = fc::time_point_sec(SCORUM_HARDFORK_0_6_TIME);
2099  _hardfork_versions[SCORUM_HARDFORK_0_6] = SCORUM_HARDFORK_0_6_VERSION;
2100 
2101  const auto& hardforks = obtain_service<dbs_hardfork_property>().get();
2102  FC_ASSERT(hardforks.last_hardfork <= SCORUM_NUM_HARDFORKS, "Chain knows of more hardforks than configuration",
2103  ("hardforks.last_hardfork", hardforks.last_hardfork)("SCORUM_NUM_HARDFORKS", SCORUM_NUM_HARDFORKS));
2104  FC_ASSERT(_hardfork_versions[hardforks.last_hardfork] <= SCORUM_BLOCKCHAIN_VERSION,
2105  "Blockchain version is older than last applied hardfork");
2106  FC_ASSERT(SCORUM_BLOCKCHAIN_HARDFORK_VERSION == _hardfork_versions[SCORUM_NUM_HARDFORKS]);
2107 }
2108 
2109 void database::process_hardforks()
2110 {
2111  try
2112  {
2113  // If there are upcoming hardforks and the next one is later, do nothing
2114  const auto& hardforks = obtain_service<dbs_hardfork_property>().get();
2115 
2116  while (_hardfork_versions[hardforks.last_hardfork] < hardforks.next_hardfork
2117  && hardforks.next_hardfork_time <= head_block_time())
2118  {
2119  if (hardforks.last_hardfork < SCORUM_NUM_HARDFORKS)
2120  {
2121  apply_hardfork(hardforks.last_hardfork + 1);
2122  }
2123  else
2124  {
2125  throw unknown_hardfork_exception();
2126  }
2127  }
2128  }
2129  FC_CAPTURE_AND_RETHROW()
2130 }
2131 
2132 bool database::has_hardfork(uint32_t hardfork) const
2133 {
2134  return obtain_service<dbs_hardfork_property>().get().processed_hardforks.size() > hardfork;
2135 }
2136 
2137 void database::set_hardfork(uint32_t hardfork, bool apply_now)
2138 {
2139  auto const& hardforks = obtain_service<dbs_hardfork_property>().get();
2140 
2141  for (uint32_t i = hardforks.last_hardfork + 1; i <= hardfork && i <= SCORUM_NUM_HARDFORKS; i++)
2142  {
2143  modify(hardforks, [&](hardfork_property_object& hpo) {
2144  hpo.next_hardfork = _hardfork_versions[i];
2145  hpo.next_hardfork_time = head_block_time();
2146  });
2147 
2148  if (apply_now)
2149  {
2150  apply_hardfork(i);
2151  }
2152  }
2153 }
2154 
2155 void database::apply_hardfork(uint32_t hardfork)
2156 {
2157  if (_options & opt_log_hardforks)
2158  {
2159  elog("HARDFORK ${hf} at block ${b}", ("hf", hardfork)("b", head_block_num()));
2160  }
2161 
2162  switch (hardfork)
2163  {
2164  default:
2165  break;
2166  }
2167 
2168  obtain_service<dbs_hardfork_property>().update([&](hardfork_property_object& hfp) {
2169  FC_ASSERT(hardfork == hfp.last_hardfork + 1, "Hardfork being applied out of order",
2170  ("hardfork", hardfork)("hfp.last_hardfork", hfp.last_hardfork));
2171  FC_ASSERT(hfp.processed_hardforks.size() == hardfork, "Hardfork being applied out of order");
2172  hfp.processed_hardforks.push_back(_hardfork_times[hardfork]);
2173  hfp.last_hardfork = hardfork;
2174  hfp.current_hardfork_version = _hardfork_versions[hardfork];
2175  FC_ASSERT(hfp.processed_hardforks[hfp.last_hardfork] == _hardfork_times[hfp.last_hardfork],
2176  "Hardfork processing failed sanity check...");
2177  });
2178 
2179  push_hf_operation(hardfork_operation(hardfork));
2180 }
2181 
2185 void database::validate_invariants() const
2186 {
2187  try
2188  {
2189  asset total_supply = asset(0, SCORUM_SYMBOL);
2190 
2191  const auto& account_svc = account_service();
2192  const auto& gpo = obtain_service<dbs_dynamic_global_property>().get();
2193 
2194  const auto accounts_circulating = account_svc.accounts_circulating_capital();
2195 
2196  total_supply += accounts_circulating.scr;
2197  // following two field do not represented in global properties
2198  total_supply += accounts_circulating.pending_scr;
2199  total_supply += asset(accounts_circulating.pending_sp.amount, SCORUM_SYMBOL);
2200 
2202  const auto& witness_idx = get_index<witness_index>().indices();
2203  for (auto itr = witness_idx.begin(); itr != witness_idx.end(); ++itr)
2204  {
2205  FC_ASSERT(itr->votes <= gpo.total_scorumpower.amount, "${vs} > ${tvs}",
2206  ("vs", itr->votes)("tvs", gpo.total_scorumpower.amount));
2207  }
2208 
2209  const auto& escrow_idx = get_index<escrow_index>().indices().get<by_id>();
2210  for (auto itr = escrow_idx.begin(); itr != escrow_idx.end(); ++itr)
2211  {
2212  total_supply += itr->scorum_balance;
2213  total_supply += itr->pending_fee;
2214  }
2215 
2216  total_supply += obtain_service<dbs_content_reward_fund_scr>().get().activity_reward_balance;
2217  total_supply
2218  += asset(obtain_service<dbs_content_reward_fund_sp>().get().activity_reward_balance.amount, SCORUM_SYMBOL);
2219 
2220  auto& fifa_2018_reward_service = obtain_service<dbs_content_fifa_world_cup_2018_bounty_reward_fund>();
2221  if (fifa_2018_reward_service.is_exists())
2222  {
2223  total_supply += asset(fifa_2018_reward_service.get().activity_reward_balance.amount, SCORUM_SYMBOL);
2224  }
2225 
2226  total_supply += asset(gpo.total_scorumpower.amount, SCORUM_SYMBOL);
2227  total_supply += obtain_service<dbs_content_reward_scr>().get().balance;
2228  total_supply += obtain_service<dbs_voters_reward_scr>().get().balance;
2229  total_supply += obtain_service<dbs_voters_reward_sp>().get().balance.amount;
2230 
2231  for (const post_budget_object& budget : obtain_service<dbs_post_budget>().get_budgets())
2232  {
2233  total_supply += budget.balance;
2234  total_supply += budget.owner_pending_income;
2235  total_supply += budget.budget_pending_outgo;
2236  }
2237 
2238  for (const banner_budget_object& budget : obtain_service<dbs_banner_budget>().get_budgets())
2239  {
2240  total_supply += budget.balance;
2241  total_supply += budget.owner_pending_income;
2242  total_supply += budget.budget_pending_outgo;
2243  }
2244 
2245  if (obtain_service<dbs_fund_budget>().is_exists())
2246  {
2247  total_supply += obtain_service<dbs_fund_budget>().get().balance.amount;
2248  }
2249 
2250  if (obtain_service<dbs_registration_pool>().is_exists())
2251  {
2252  auto& pool = obtain_service<dbs_registration_pool>().get();
2253  total_supply += pool.balance;
2254  total_supply += asset(pool.delegated.amount, SCORUM_SYMBOL);
2255  }
2256 
2257  total_supply += asset(obtain_service<dbs_dev_pool>().get().sp_balance.amount, SCORUM_SYMBOL);
2258  total_supply += obtain_service<dbs_dev_pool>().get().scr_balance;
2259 
2260  if (obtain_service<dbs_witness_reward_in_sp_migration>().is_exists())
2261  {
2262  total_supply += asset(obtain_service<dbs_witness_reward_in_sp_migration>().get().balance, SCORUM_SYMBOL);
2263  }
2264 
2265  const auto& atomicswap_contract_idx = get_index<atomicswap_contract_index, by_id>();
2266  for (auto itr = atomicswap_contract_idx.begin(); itr != atomicswap_contract_idx.end(); ++itr)
2267  {
2268  total_supply += itr->amount;
2269  }
2270 
2271  // clang-format off
2272  const auto& matched_bets = get_index<matched_bet_index, by_id>();
2273  for (auto itr = matched_bets.begin(); itr != matched_bets.end(); ++itr)
2274  {
2275  total_supply += itr->bet1_data.stake;
2276  total_supply += itr->bet2_data.stake;
2277  }
2278 
2279  const auto& pending_bets = get_index<pending_bet_index, by_id>();
2280  for (auto itr = pending_bets.begin(); itr != pending_bets.end(); ++itr)
2281  {
2282  total_supply += itr->data.stake;
2283  }
2284 
2285  FC_ASSERT(total_supply <= asset::maximum(SCORUM_SYMBOL), "Assets SCR overflow");
2286  FC_ASSERT(accounts_circulating.sp <= asset::maximum(SP_SYMBOL), "Assets SP overflow");
2287 
2288  FC_ASSERT(gpo.total_supply == total_supply, "",
2289  ("gpo.total_supply", gpo.total_supply)
2290  ("total_supply", total_supply));
2291 
2292  FC_ASSERT(gpo.total_scorumpower == accounts_circulating.sp, "",
2293  ("gpo.total_supply", gpo.total_supply)
2294  ("gpo.total_scorumpower", gpo.total_scorumpower)
2295  ("gpo.circulating_capital", gpo.circulating_capital)
2296  ("accounts_circulating.sp", accounts_circulating.sp)
2297  ("accounts_circulating.scr", accounts_circulating.scr));
2298 
2299  FC_ASSERT(gpo.circulating_capital.amount - gpo.total_scorumpower.amount == accounts_circulating.scr.amount, "",
2300  ("gpo.total_supply", gpo.total_supply)
2301  ("gpo.total_scorumpower", gpo.total_scorumpower)
2302  ("gpo.circulating_capital", gpo.circulating_capital)
2303  ("accounts_circulating.sp", accounts_circulating.sp)
2304  ("accounts_circulating.scr", accounts_circulating.scr));
2305 
2306  FC_ASSERT(gpo.total_scorumpower.amount == accounts_circulating.vsf_votes, "",
2307  ("total_scorumpower", gpo.total_scorumpower)
2308  ("accounts_circulating.total_vsf_votes", accounts_circulating.vsf_votes));
2309 
2310  FC_ASSERT(gpo.total_pending_scr == accounts_circulating.pending_scr, "",
2311  ("total_pending_scr", gpo.total_pending_scr)
2312  ("accounts_circulating.pending_scr", accounts_circulating.pending_scr));
2313 
2314  FC_ASSERT(gpo.total_pending_sp == accounts_circulating.pending_sp, "",
2315  ("total_pending_sp", gpo.total_pending_sp)
2316  ("accounts_circulating.pending_sp", accounts_circulating.pending_sp));
2317 
2318  // clang-format on
2319  }
2320  FC_CAPTURE_LOG_AND_RETHROW((head_block_num()));
2321 }
2322 
2323 } // namespace chain
2324 } // namespace scorum
const optional< signed_block > & head() const
Definition: block_log.cpp:285
optional< signed_block > read_block_by_num(uint32_t block_num) const
Definition: block_log.cpp:238
void open(const fc::path &file)
Definition: block_log.cpp:94
std::pair< signed_block, uint64_t > read_block(uint64_t file_pos) const
Definition: block_log.cpp:223
tracks minimal information about past blocks to implement TaPOS
evaluator_registry< operation > _evaluator_registry
Definition: database.cpp:120
betting_matcher_i & get_betting_matcher()
Definition: database.cpp:128
database_impl(database &self)
Definition: database.cpp:144
betting_resolver_i & get_betting_resolver()
Definition: database.cpp:133
betting_service_i & get_betting_service()
Definition: database.cpp:123
genesis_persistent_state_type _genesis_persistent_state
Definition: database.cpp:121
tracks the blockchain state in an extensible manner
Definition: database.hpp:52
void init_genesis(const genesis_state_type &genesis_state)
Definition: genesis.cpp:40
uint32_t get_reindex_skip_flags() const
Definition: database.cpp:188
database(uint32_t opt)
Definition: database.cpp:168
void validate_invariants() const
Definition: database.cpp:2185
void set_initial_timestamp(const genesis_state_type &genesis_state)
Definition: genesis.cpp:35
void init_hardforks(fc::time_point_sec genesis_time)
Definition: database.cpp:2070
void reindex(const fc::path &data_dir, const fc::path &shared_mem_dir, uint64_t shared_file_size, uint32_t skip_flags, const genesis_state_type &genesis_state)
Rebuild object graph from block history and open detabase.
Definition: database.cpp:284
static fc::path block_log_path(const fc::path &data_dir)
Definition: database.cpp:183
@ skip_authority_check
used while reindexing – disables any checking of authority on transactions
Definition: database.hpp:85
@ skip_validate
used prior to checkpoint, skips validate() call on transaction
Definition: database.hpp:89
@ skip_merkle_check
used while reindexing
Definition: database.hpp:86
@ skip_transaction_dupe_check
used while reindexing
Definition: database.hpp:81
@ skip_witness_schedule_check
used while reindexing
Definition: database.hpp:88
@ skip_tapos_check
used while reindexing – note this skips expiration check as well
Definition: database.hpp:84
@ skip_witness_signature
used while reindexing
Definition: database.hpp:79
@ skip_block_log
used to skip block logging on reindex
Definition: database.hpp:92
@ skip_validate_invariants
used to skip database invariant check on block application
Definition: database.hpp:90
@ skip_transaction_signatures
used by non-witness nodes
Definition: database.hpp:80
void open(const fc::path &data_dir, const fc::path &shared_mem_dir, uint64_t shared_file_size, uint32_t chainbase_flags, const genesis_state_type &genesis_state)
Open a database, creating a new one if necessary.
Definition: database.cpp:203
block_id_type head_block_id() const
Definition: database.cpp:1232
uint32_t head_block_num() const
Definition: database.cpp:1227
void apply_block(const signed_block &next_block, uint32_t skip=skip_nothing)
Definition: database.cpp:1415
void initialize_indexes()
Reset the object graph in-memory.
Definition: database.cpp:1336
void wipe(const fc::path &data_dir, const fc::path &shared_mem_dir, bool include_blocks)
wipe Delete database from disk, and potentially the raw chain as well.
Definition: database.cpp:338
uint32_t last_irreversible_block_num
last irreversible block num
uint8_t participation_count
Divide by 128 to compute participation percentage.
fc::uint128_t recent_slots_filled
used to compute witness participation.
account_name_type current_witness
Head block signed by current witness.
void start_block(signed_block b)
Contains per-node database configuration.
void apply(ContextType &ctx)
Definition: tasks_base.hpp:55
hardfork_version hardfork_version_vote
fc::array< account_name_type, SCORUM_MAX_WITNESSES_LIMIT > current_shuffled_witnesses
#define SCORUM_DB_FREE_MEMORY_THRESHOLD_MB
Definition: config.hpp:160
#define SCORUM_OWNER_AUTH_RECOVERY_PERIOD
Definition: config.hpp:138
#define SCORUM_WITNESS_MISSED_BLOCKS_THRESHOLD
Definition: config.hpp:181
#define SCORUM_BLOCKCHAIN_HARDFORK_VERSION
Definition: config.hpp:93
#define SP_SYMBOL
Definition: config.hpp:104
#define SCORUM_SYMBOL
Definition: config.hpp:102
#define SCORUM_100_PERCENT
Definition: config.hpp:200
#define SCORUM_START_MINER_VOTING_BLOCK
Definition: config.hpp:175
#define SCORUM_MAX_PROXY_RECURSION_DEPTH
Definition: config.hpp:186
#define SCORUM_BLOCKCHAIN_VERSION
Definition: config.hpp:91
#define SCORUM_MAX_WITNESSES
Definition: config.hpp:179
#define SCORUM_MAX_TIME_UNTIL_EXPIRATION
Definition: config.hpp:184
#define SCORUM_BLOCKID_POOL_SIZE
Definition: config.hpp:132
#define SCORUM_BLOCK_INTERVAL
Definition: config.hpp:171
#define SCORUM_TRY_NOTIFY(signal,...)
#define debug_log(CTX, FORMAT,...)
Definition: debug_log.hpp:3
#define SCORUM_ASSERT(expr, exc_type, FORMAT,...)
Definition: exceptions.hpp:6
void remove_all(db_index &db_idx, utils::bidir_range< const TObject > items)
Definition: db_accessor.hpp:62
void remove(db_index &db_idx, const TObject &o)
Definition: db_accessor.hpp:57
chainbase::database_index< chainbase::segment_manager > db_index
Definition: dba.hpp:12
void without_pending_transactions(database &db, std::vector< signed_transaction > &&pending_transactions, Lambda callback)
Definition: db_with.hpp:133
void with_skip_flags(database &db, uint32_t skip_flags, Lambda callback)
Definition: db_with.hpp:117
std::shared_ptr< fork_item > item_ptr
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
fc::fixed_string_16 account_name_type
Definition: types.hpp:62
fc::sha256 chain_id_type
Definition: types.hpp:61
static_variant< void_t, version, hardfork_version_vote > block_header_extensions
Definition: base.hpp:78
fc::ripemd160 block_id_type
Definition: types.hpp:63
bool is_virtual_operation(const operation &op)
Definition: operations.cpp:41
Definition: asset.cpp:15
share_type amount
Definition: asset.hpp:31
static uint32_t num_from_id(const block_id_type &id)
Definition: block.cpp:14
block_header_extensions_type extensions
fc::time_point_sec timestamp
bool validate_signee(const fc::ecc::public_key &expected_signee) const
Definition: block.cpp:40
block_id_type id() const
Definition: block.cpp:19
std::vector< signed_transaction > transactions
Definition: block.hpp:13
checksum_type calculate_merkle_root() const
Definition: block.cpp:45
void verify_authority(const chain_id_type &chain_id, const authority_getter &get_active, const authority_getter &get_owner, const authority_getter &get_posting, uint32_t max_recursion=SCORUM_MAX_SIG_CHECK_DEPTH) const
transaction_id_type id() const
Definition: transaction.cpp:43
std::vector< operation > operations
Definition: transaction.hpp:18
fc::time_point_sec expiration
Definition: transaction.hpp:16