BitShares-Core  7.0.2
BitShares blockchain node software and command-line wallet software
db_block.cpp
Go to the documentation of this file.
1 /*
2  * Copyright (c) 2015 Cryptonomex, Inc., and contributors.
3  *
4  * The MIT License
5  *
6  * Permission is hereby granted, free of charge, to any person obtaining a copy
7  * of this software and associated documentation files (the "Software"), to deal
8  * in the Software without restriction, including without limitation the rights
9  * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10  * copies of the Software, and to permit persons to whom the Software is
11  * furnished to do so, subject to the following conditions:
12  *
13  * The above copyright notice and this permission notice shall be included in
14  * all copies or substantial portions of the Software.
15  *
16  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19  * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21  * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
22  * THE SOFTWARE.
23  */
24 
27 #include <graphene/chain/hardfork.hpp>
28 
32 
40 
42 
43 #include <fc/io/raw.hpp>
44 #include <fc/thread/parallel.hpp>
45 
46 namespace graphene { namespace chain {
47 
49 {
50  return _fork_db.is_known_block(id) || _block_id_to_block.contains(id);
51 }
58 {
59  const auto& trx_idx = get_index_type<transaction_index>().indices().get<by_trx_id>();
60  return trx_idx.find( id ) != trx_idx.end();
61 }
62 
64 { try {
65  return _block_id_to_block.fetch_block_id( block_num );
66 } FC_CAPTURE_AND_RETHROW( (block_num) ) } // GCOVR_EXCL_LINE
67 
69 {
70  auto b = _fork_db.fetch_block( id );
71  if( !b )
72  return _block_id_to_block.fetch_optional(id);
73  return b->data;
74 }
75 
77 {
78  auto results = _fork_db.fetch_block_by_number(num);
79  if( results.size() == 1 )
80  return results[0]->data;
81  else
82  return _block_id_to_block.fetch_by_number(num);
83 }
84 
86 {
87  auto& index = get_index_type<transaction_index>().indices().get<by_trx_id>();
88  auto itr = index.find(trx_id);
89  FC_ASSERT(itr != index.end());
90  return itr->trx;
91 }
92 
93 std::vector<block_id_type> database::get_block_ids_on_fork(block_id_type head_of_fork) const
94 {
95  pair<fork_database::branch_type, fork_database::branch_type> branches
96  = _fork_db.fetch_branch_from(head_block_id(), head_of_fork);
97  if( !((branches.first.back()->previous_id() == branches.second.back()->previous_id())) )
98  {
99  edump( (head_of_fork)
100  (head_block_id())
101  (branches.first.size())
102  (branches.second.size()) );
103  assert(branches.first.back()->previous_id() == branches.second.back()->previous_id());
104  }
105  std::vector<block_id_type> result;
106  for (const item_ptr& fork_block : branches.second)
107  result.emplace_back(fork_block->id);
108  result.emplace_back(branches.first.back()->previous_id());
109  return result;
110 }
111 
118 bool database::push_block(const signed_block& new_block, uint32_t skip)
119 {
120 // idump((new_block.block_num())(new_block.id())(new_block.timestamp)(new_block.previous));
121  bool result;
122  detail::with_skip_flags( *this, skip, [&]()
123  {
124  detail::without_pending_transactions( *this, std::move(_pending_tx),
125  [&]()
126  {
127  result = _push_block(new_block);
128  });
129  });
130  return result;
131 }
132 
133 bool database::_push_block(const signed_block& new_block)
134 { try {
135  uint32_t skip = get_node_properties().skip_flags;
136 
137  const auto now = fc::time_point::now().sec_since_epoch();
138  if( _fork_db.head() && new_block.timestamp.sec_since_epoch() > now - 86400 )
139  {
140  // verify that the block signer is in the current set of active witnesses.
141  shared_ptr<fork_item> prev_block = _fork_db.fetch_block( new_block.previous );
142  GRAPHENE_ASSERT( prev_block, unlinkable_block_exception, "block does not link to known chain" );
143  if( prev_block->scheduled_witnesses && 0 == (skip&(skip_witness_schedule_check|skip_witness_signature)) )
144  verify_signing_witness( new_block, *prev_block );
145  }
146 
147  const shared_ptr<fork_item> new_head = _fork_db.push_block(new_block);
148  //If the head block from the longest chain does not build off of the current head, we need to switch forks.
149  if( new_head->data.previous != head_block_id() )
150  {
151  //If the newly pushed block is the same height as head, we get head back in new_head
152  //Only switch forks if new_head is actually higher than head
153  if( new_head->data.block_num() > head_block_num() )
154  {
155  wlog( "Switching to fork: ${id}", ("id",new_head->data.id()) );
156  auto branches = _fork_db.fetch_branch_from(new_head->data.id(), head_block_id());
157 
158  // pop blocks until we hit the forked block
159  while( head_block_id() != branches.second.back()->data.previous )
160  {
161  ilog( "popping block #${n} ${id}", ("n",head_block_num())("id",head_block_id()) );
162  pop_block();
163  }
164 
165  // push all blocks on the new fork
166  for( auto ritr = branches.first.rbegin(); ritr != branches.first.rend(); ++ritr )
167  {
168  ilog( "pushing block from fork #${n} ${id}", ("n",(*ritr)->data.block_num())("id",(*ritr)->id) );
169  optional<fc::exception> except;
170  try {
171  undo_database::session session = _undo_db.start_undo_session();
172  apply_block( (*ritr)->data, skip );
173  update_witnesses( **ritr );
174  _block_id_to_block.store( (*ritr)->id, (*ritr)->data );
175  session.commit();
176  }
177  catch ( const fc::exception& e ) { except = e; }
178  if( except )
179  {
180  wlog( "exception thrown while switching forks ${e}", ("e",except->to_detail_string() ) );
181  // remove the rest of branches.first from the fork_db, those blocks are invalid
182  while( ritr != branches.first.rend() )
183  {
184  ilog( "removing block from fork_db #${n} ${id}",
185  ("n",(*ritr)->data.block_num())("id",(*ritr)->id) );
186  _fork_db.remove( (*ritr)->id );
187  ++ritr;
188  }
189  _fork_db.set_head( branches.second.front() );
190 
191  // pop all blocks from the bad fork
192  while( head_block_id() != branches.second.back()->data.previous )
193  {
194  ilog( "popping block #${n} ${id}", ("n",head_block_num())("id",head_block_id()) );
195  pop_block();
196  }
197 
198  ilog( "Switching back to fork: ${id}", ("id",branches.second.front()->data.id()) );
199  // restore all blocks from the good fork
200  for( auto ritr2 = branches.second.rbegin(); ritr2 != branches.second.rend(); ++ritr2 )
201  {
202  ilog( "pushing block #${n} ${id}", ("n",(*ritr2)->data.block_num())("id",(*ritr2)->id) );
203  auto session = _undo_db.start_undo_session();
204  apply_block( (*ritr2)->data, skip );
205  _block_id_to_block.store( (*ritr2)->id, (*ritr2)->data );
206  session.commit();
207  }
208  throw *except;
209  }
210  }
211  return true;
212  }
213  else return false;
214  }
215 
216  try {
217  auto session = _undo_db.start_undo_session();
218  apply_block(new_block, skip);
219  if( new_block.timestamp.sec_since_epoch() > now - 86400 )
220  update_witnesses( *new_head );
221  _block_id_to_block.store(new_block.id(), new_block);
222  session.commit();
223  } catch ( const fc::exception& e ) {
224  elog("Failed to push new block:\n${e}", ("e", e.to_detail_string()));
225  _fork_db.remove( new_block.id() );
226  throw;
227  }
228 
229  return false;
230 } FC_CAPTURE_AND_RETHROW( (new_block) ) } // GCOVR_EXCL_LINE
231 
232 void database::verify_signing_witness( const signed_block& new_block, const fork_item& fork_entry )const
233 {
234  FC_ASSERT( new_block.timestamp >= fork_entry.next_block_time );
235  uint32_t slot_num = ( new_block.timestamp - fork_entry.next_block_time ).to_seconds() / block_interval();
236  uint64_t index = ( fork_entry.next_block_aslot + slot_num ) % fork_entry.scheduled_witnesses->size();
237  const auto& scheduled_witness = (*fork_entry.scheduled_witnesses)[index];
238  FC_ASSERT( new_block.witness == scheduled_witness.first, "Witness produced block at wrong time",
239  ("block witness",new_block.witness)("scheduled",scheduled_witness)("slot_num",slot_num) );
240  FC_ASSERT( new_block.validate_signee( scheduled_witness.second ) );
241 }
242 
243 void database::update_witnesses( fork_item& fork_entry )const
244 {
245  if( fork_entry.scheduled_witnesses ) return;
246 
247  const dynamic_global_property_object& dpo = get_dynamic_global_properties();
248  fork_entry.next_block_aslot = dpo.current_aslot + 1;
249  fork_entry.next_block_time = get_slot_time( 1 );
250 
251  const witness_schedule_object& wso = get_witness_schedule_object();
252  fork_entry.scheduled_witnesses = std::make_shared< vector< pair< witness_id_type, public_key_type > > >();
253  fork_entry.scheduled_witnesses->reserve( wso.current_shuffled_witnesses.size() );
254  for( size_t i = 0; i < wso.current_shuffled_witnesses.size(); ++i )
255  {
256  const auto& witness = wso.current_shuffled_witnesses[i](*this);
257  fork_entry.scheduled_witnesses->emplace_back( wso.current_shuffled_witnesses[i], witness.signing_key );
258  }
259 }
260 
271 { try {
272  // see https://github.com/bitshares/bitshares-core/issues/1573
273  FC_ASSERT( fc::raw::pack_size( trx ) < (1024 * 1024), "Transaction exceeds maximum transaction size." );
274  processed_transaction result;
275  detail::with_skip_flags( *this, skip, [&]()
276  {
277  result = _push_transaction( trx );
278  } );
279  return result;
280 } FC_CAPTURE_AND_RETHROW( (trx) ) } // GCOVR_EXCL_LINE
281 
283 {
284  // If this is the first transaction pushed after applying a block, start a new undo session.
285  // This allows us to quickly rewind to the clean state of the head block, in case a new block arrives.
286  if( !_pending_tx_session.valid() )
287  _pending_tx_session = _undo_db.start_undo_session();
288 
289  // Create a temporary undo session as a child of _pending_tx_session.
290  // The temporary session will be discarded by the destructor if
291  // _apply_transaction fails. If we make it to merge(), we
292  // apply the changes.
293 
294  auto temp_session = _undo_db.start_undo_session();
295  auto processed_trx = _apply_transaction( trx );
296  _pending_tx.push_back(processed_trx);
297 
298  // notify_changed_objects();
299  // The transaction applied successfully. Merge its changes into the pending block session.
300  temp_session.merge();
301 
302  // notify anyone listening to pending transactions
304  return processed_trx;
305 }
306 
308 {
309  auto session = _undo_db.start_undo_session();
310  return _apply_transaction( trx );
311 }
312 
314 public:
315  undo_session_nesting_guard( uint32_t& nesting_counter, const database& db )
316  : orig_value(nesting_counter), counter(nesting_counter)
317  {
318  FC_ASSERT( counter < db.get_global_properties().active_witnesses.size() * 2,
319  "Max undo session nesting depth exceeded!" );
320  ++counter;
321  }
323  {
324  --counter;
325  // GCOVR_EXCL_START
326  // Defensive code, should not happen
327  if( counter != orig_value )
328  elog( "Unexpected undo session nesting count value: ${n} != ${o}", ("n",counter)("o",orig_value) );
329  // GCOVR_EXCL_STOP
330  }
331 private:
332  const uint32_t orig_value;
333  uint32_t& counter;
334 };
335 
337 { try {
338  transaction_evaluation_state eval_state(this);
339  eval_state._is_proposed_trx = true;
340 
341  eval_state.operation_results.reserve(proposal.proposed_transaction.operations.size());
343  eval_state._trx = &ptrx;
344  size_t old_applied_ops_size = _applied_ops.size();
345  auto old_vop = _current_virtual_op;
346 
347  try {
348  undo_session_nesting_guard guard( _undo_session_nesting_depth, *this );
349  if( _undo_db.size() >= _undo_db.max_size() )
351  auto session = _undo_db.start_undo_session(true);
352  for( auto& op : proposal.proposed_transaction.operations )
353  eval_state.operation_results.emplace_back(apply_operation(eval_state, op)); // This is a virtual operation
354  // Make sure there is no unpaid samet fund debt
355  const auto& samet_fund_idx = get_index_type<samet_fund_index>().indices().get<by_unpaid>();
356  FC_ASSERT( samet_fund_idx.empty() || samet_fund_idx.begin()->unpaid_amount == 0,
357  "Unpaid SameT Fund debt detected" );
358  remove(proposal);
359  session.merge();
360  } catch ( const fc::exception& e ) {
361  if( head_block_time() <= HARDFORK_483_TIME )
362  {
363  for( size_t i=old_applied_ops_size,n=_applied_ops.size(); i<n; i++ )
364  {
365  ilog( "removing failed operation from applied_ops: ${op}", ("op", *(_applied_ops[i])) );
366  _applied_ops[i].reset();
367  }
368  }
369  else
370  {
371  _current_virtual_op = old_vop;
372  _applied_ops.resize( old_applied_ops_size );
373  }
374  wlog( "${e}", ("e",e.to_detail_string() ) );
375  throw;
376  }
377 
378  ptrx.operation_results = std::move(eval_state.operation_results);
379  return ptrx;
380 } FC_CAPTURE_AND_RETHROW( (proposal) ) } // GCOVR_EXCL_LINE
381 
383  fc::time_point_sec when,
384  witness_id_type witness_id,
385  const fc::ecc::private_key& block_signing_private_key,
386  uint32_t skip /* = 0 */
387  )
388 { try {
389  signed_block result;
390  detail::with_skip_flags( *this, skip, [&]()
391  {
392  result = _generate_block( when, witness_id, block_signing_private_key );
393  } );
394  return result;
395 } FC_CAPTURE_AND_RETHROW() } // GCOVR_EXCL_LINE
396 
397 signed_block database::_generate_block(
398  fc::time_point_sec when,
399  witness_id_type witness_id,
400  const fc::ecc::private_key& block_signing_private_key
401  )
402 {
403  try {
404  uint32_t skip = get_node_properties().skip_flags;
405  uint32_t slot_num = get_slot_at_time( when );
406  FC_ASSERT( slot_num > 0 );
407  witness_id_type scheduled_witness = get_scheduled_witness( slot_num );
408  FC_ASSERT( scheduled_witness == witness_id );
409 
410  //
411  // The following code throws away existing pending_tx_session and
412  // rebuilds it by re-applying pending transactions.
413  //
414  // This rebuild is necessary because pending transactions' validity
415  // and semantics may have changed since they were received, because
416  // time-based semantics are evaluated based on the current block
417  // time. These changes can only be reflected in the database when
418  // the value of the "when" variable is known, which means we need to
419  // re-apply pending transactions in this method.
420  //
421 
422  // pop pending state (reset to head block state)
423  _pending_tx_session.reset();
424 
425  // Check witness signing key
426  if( 0 == (skip & skip_witness_signature) )
427  {
428  // Note: if this check failed (which won't happen in normal situations),
429  // we would have temporarily broken the invariant that
430  // _pending_tx_session is the result of applying _pending_tx.
431  // In this case, when the node received a new block,
432  // the push_block() call will re-create the _pending_tx_session.
433  FC_ASSERT( witness_id(*this).signing_key == block_signing_private_key.get_public_key() );
434  }
435 
436  static const size_t max_partial_block_header_size = ( fc::raw::pack_size( signed_block_header() )
437  - fc::raw::pack_size( witness_id_type() ) ) // witness_id
438  + 3; // max space to store size of transactions
439  // (out of block header),
440  // +3 means 3*7=21 bits so it's practically safe
441  const size_t max_block_header_size = max_partial_block_header_size + fc::raw::pack_size( witness_id );
442  auto maximum_block_size = get_global_properties().parameters.maximum_block_size;
443  size_t total_block_size = max_block_header_size;
444 
445  signed_block pending_block;
446 
447  _pending_tx_session = _undo_db.start_undo_session();
448 
449  uint64_t postponed_tx_count = 0;
450  for( const processed_transaction& tx : _pending_tx )
451  {
452  size_t new_total_size = total_block_size + fc::raw::pack_size( tx );
453 
454  // postpone transaction if it would make block too big
455  if( new_total_size > maximum_block_size )
456  {
457  postponed_tx_count++;
458  continue;
459  }
460 
461  try
462  {
463  auto temp_session = _undo_db.start_undo_session();
464  processed_transaction ptx = _apply_transaction( tx );
465  // Clear results to save disk space and network bandwidth.
466  // This may break client applications which rely on the results.
467  ptx.operation_results.clear();
468 
469  // We have to recompute pack_size(ptx) because it may be different
470  // than pack_size(tx) (i.e. if one or more results increased
471  // their size)
472  new_total_size = total_block_size + fc::raw::pack_size( ptx );
473  // postpone transaction if it would make block too big
474  if( new_total_size > maximum_block_size )
475  {
476  postponed_tx_count++;
477  continue;
478  }
479 
480  temp_session.merge();
481 
482  total_block_size = new_total_size;
483  pending_block.transactions.push_back( ptx );
484  }
485  catch ( const fc::exception& e )
486  {
487  // Do nothing, transaction will not be re-applied
488  wlog( "Transaction was not processed while generating block due to ${e}", ("e", e) );
489  wlog( "The transaction was ${t}", ("t", tx) );
490  }
491  }
492  if( postponed_tx_count > 0 )
493  {
494  wlog( "Postponed ${n} transactions due to block size limit", ("n", postponed_tx_count) );
495  }
496 
497  _pending_tx_session.reset();
498 
499  // We have temporarily broken the invariant that
500  // _pending_tx_session is the result of applying _pending_tx, as
501  // _pending_tx now consists of the set of postponed transactions.
502  // However, the push_block() call below will re-create the
503  // _pending_tx_session.
504 
505  pending_block.previous = head_block_id();
506  pending_block.timestamp = when;
507  pending_block.transaction_merkle_root = pending_block.calculate_merkle_root();
508  pending_block.witness = witness_id;
509 
510  if( 0 == (skip & skip_witness_signature) )
511  pending_block.sign( block_signing_private_key );
512 
513  push_block( pending_block, skip | skip_transaction_signatures ); // skip authority check when pushing
514  // self-generated blocks
515 
516  return pending_block;
517 } FC_CAPTURE_AND_RETHROW( (witness_id) ) } // GCOVR_EXCL_LINE
518 
524 { try {
525  _pending_tx_session.reset();
526  auto fork_db_head = _fork_db.head();
527  FC_ASSERT( fork_db_head, "Trying to pop() from empty fork database!?" );
528  if( fork_db_head->id == head_block_id() )
529  _fork_db.pop_block();
530  else
531  {
532  fork_db_head = _fork_db.fetch_block( head_block_id() );
533  FC_ASSERT( fork_db_head, "Trying to pop() block that's not in fork database!?" );
534  }
535  pop_undo();
536  _popped_tx.insert( _popped_tx.begin(),
537  fork_db_head->data.transactions.begin(),
538  fork_db_head->data.transactions.end() );
539 } FC_CAPTURE_AND_RETHROW() } // GCOVR_EXCL_LINE
540 
542 { try {
543  assert( (_pending_tx.size() == 0) || _pending_tx_session.valid() );
544  _pending_tx.clear();
545  _pending_tx_session.reset();
546 } FC_CAPTURE_AND_RETHROW() } // GCOVR_EXCL_LINE
547 
548 uint32_t database::push_applied_operation( const operation& op, bool is_virtual /* = true */ )
549 {
550  _applied_ops.emplace_back( operation_history_object( op, _current_block_num, _current_trx_in_block,
551  _current_op_in_trx, _current_virtual_op, is_virtual, _current_block_time ) );
552  ++_current_virtual_op;
553  return _applied_ops.size() - 1;
554 }
555 void database::set_applied_operation_result( uint32_t op_id, const operation_result& result )
556 {
557  assert( op_id < _applied_ops.size() );
558  if( _applied_ops[op_id] )
559  _applied_ops[op_id]->result = result;
560  else
561  {
562  elog( "Could not set operation result (head_block_num=${b})", ("b", head_block_num()) );
563  }
564 }
565 
566 const vector<optional< operation_history_object > >& database::get_applied_operations() const
567 {
568  return _applied_ops;
569 }
570 
572 
573 void database::apply_block( const signed_block& next_block, uint32_t skip )
574 {
575  auto block_num = next_block.block_num();
576  if( !_checkpoints.empty() && _checkpoints.rbegin()->second != block_id_type() )
577  {
578  auto itr = _checkpoints.find( block_num );
579  if( itr != _checkpoints.end() )
580  FC_ASSERT( next_block.id() == itr->second, "Block did not match checkpoint", ("checkpoint",*itr)("block_id",next_block.id()) );
581 
582  if( _checkpoints.rbegin()->first >= block_num )
583  skip = ~0;// WE CAN SKIP ALMOST EVERYTHING
584  }
585 
586  detail::with_skip_flags( *this, skip, [&]()
587  {
588  _apply_block( next_block );
589  } );
590  return;
591 }
592 
593 void database::_apply_block( const signed_block& next_block )
594 { try {
595  uint32_t next_block_num = next_block.block_num();
596  uint32_t skip = get_node_properties().skip_flags;
597  _applied_ops.clear();
598 
599  if( 0 == (skip & skip_block_size_check) )
600  {
601  FC_ASSERT( fc::raw::pack_size(next_block) <= get_global_properties().parameters.maximum_block_size );
602  }
603 
604  FC_ASSERT( (skip & skip_merkle_check) || next_block.transaction_merkle_root == next_block.calculate_merkle_root(),
605  "",
606  ("next_block.transaction_merkle_root",next_block.transaction_merkle_root)
607  ("calc",next_block.calculate_merkle_root())
608  ("next_block",next_block)
609  ("id",next_block.id()) );
610 
611  const witness_object& signing_witness = validate_block_header(skip, next_block);
612  const auto& dynamic_global_props = get_dynamic_global_properties();
613  bool maint_needed = (dynamic_global_props.next_maintenance_time <= next_block.timestamp);
614 
615  // trx_in_block starts from 0.
616  // For real operations which are explicitly included in a transaction, op_in_trx starts from 0, virtual_op is 0.
617  // For virtual operations that are derived directly from a real operation,
618  // use the real operation's (block_num,trx_in_block,op_in_trx), virtual_op starts from 1.
619  // For virtual operations created after processed all transactions,
620  // trx_in_block = the_block.trsanctions.size(), op_in_trx is 0, virtual_op starts from 0.
621  _current_block_num = next_block_num;
622  _current_trx_in_block = 0;
623 
624  _current_block_time = next_block.timestamp;
625 
626  _issue_453_affected_assets.clear();
627 
628  signed_block processed_block( next_block ); // make a copy
629  for( auto& trx : processed_block.transactions )
630  {
631  /* We do not need to push the undo state for each transaction
632  * because they either all apply and are valid or the
633  * entire block fails to apply. We only need an "undo" state
634  * for transactions when validating broadcast transactions or
635  * when building a block.
636  */
637  trx.operation_results = apply_transaction( trx, skip ).operation_results;
638  ++_current_trx_in_block;
639  }
640 
641  _current_op_in_trx = 0;
642  _current_virtual_op = 0;
643 
644  const uint32_t missed = update_witness_missed_blocks( next_block );
645  update_global_dynamic_data( next_block, missed );
646  update_signing_witness(signing_witness, next_block);
647  update_last_irreversible_block();
648 
649  process_tickets();
650 
651  // Are we at the maintenance interval?
652  if( maint_needed )
653  perform_chain_maintenance( next_block );
654 
655  create_block_summary(next_block);
656  clear_expired_transactions();
657  clear_expired_proposals();
658  clear_expired_orders();
659  clear_expired_force_settlements();
660  clear_expired_htlcs();
661  update_expired_feeds(); // this will update expired feeds and some core exchange rates
662  update_core_exchange_rates(); // this will update remaining core exchange rates
663  update_withdraw_permissions();
664  update_credit_offers_and_deals();
665 
666  // n.b., update_maintenance_flag() happens this late
667  // because get_slot_time() / get_slot_at_time() is needed above
668  // TODO: figure out if we could collapse this function into
669  // update_global_dynamic_data() as perhaps these methods only need
670  // to be called for header validation?
671  update_maintenance_flag( maint_needed );
672  update_witness_schedule();
673  if( !_node_property_object.debug_updates.empty() )
675 
676  // notify observers that the block has been applied
677  notify_applied_block( processed_block ); //emit
678  _applied_ops.clear();
679 
681 } FC_CAPTURE_AND_RETHROW( (next_block.block_num()) ) } // GCOVR_EXCL_LINE
682 
689 {
690  processed_transaction result;
691  detail::with_skip_flags( *this, skip, [&]()
692  {
693  result = _apply_transaction(trx);
694  });
695  return result;
696 }
697 
698 processed_transaction database::_apply_transaction(const signed_transaction& trx)
699 { try {
700  uint32_t skip = get_node_properties().skip_flags;
701 
702  trx.validate();
703 
704  auto& trx_idx = get_mutable_index_type<transaction_index>();
705  const chain_id_type& chain_id = get_chain_id();
706  if( 0 == (skip & skip_transaction_dupe_check) )
707  {
708  GRAPHENE_ASSERT( trx_idx.indices().get<by_trx_id>().find(trx.id()) == trx_idx.indices().get<by_trx_id>().end(),
709  duplicate_transaction,
710  "Transaction '${txid}' is already in the database",
711  ("txid",trx.id()) );
712  }
713  transaction_evaluation_state eval_state(this);
714  const chain_parameters& chain_parameters = get_global_properties().parameters;
715  eval_state._trx = &trx;
716 
717  if( 0 == (skip & skip_transaction_signatures) )
718  {
719  bool allow_non_immediate_owner = ( head_block_time() >= HARDFORK_CORE_584_TIME );
720  auto get_active = [this]( account_id_type id ) { return &id(*this).active; };
721  auto get_owner = [this]( account_id_type id ) { return &id(*this).owner; };
722  auto get_custom = [this]( account_id_type id, const operation& op, rejected_predicate_map* rejects ) {
723  return get_viable_custom_authorities(id, op, rejects);
724  };
725 
726  trx.verify_authority(chain_id, get_active, get_owner, get_custom, allow_non_immediate_owner,
727  MUST_IGNORE_CUSTOM_OP_REQD_AUTHS(head_block_time()),
728  get_global_properties().parameters.max_authority_depth);
729  }
730 
731  //Skip all manner of expiration and TaPoS checking if we're on block 1; It's impossible that the transaction is
732  //expired, and TaPoS makes no sense as no blocks exist.
733  if( BOOST_LIKELY(head_block_num() > 0) )
734  {
735  if( 0 == (skip & skip_tapos_check) )
736  {
737  const auto& tapos_block_summary = block_summary_id_type( trx.ref_block_num )(*this);
738 
739  //Verify TaPoS block summary has correct ID prefix, and that this block's time is not past the expiration
740  FC_ASSERT( trx.ref_block_prefix == tapos_block_summary.block_id._hash[1].value() );
741  }
742 
744 
745  FC_ASSERT( trx.expiration <= now + chain_parameters.maximum_time_until_expiration, "",
746  ("trx.expiration",trx.expiration)("now",now)("max_til_exp",chain_parameters.maximum_time_until_expiration));
747  FC_ASSERT( now <= trx.expiration, "", ("now",now)("trx.exp",trx.expiration) );
748  if ( 0 == (skip & skip_block_size_check ) ) // don't waste time on replay
749  FC_ASSERT( head_block_time() <= HARDFORK_CORE_1573_TIME
750  || trx.get_packed_size() <= chain_parameters.maximum_transaction_size,
751  "Transaction exceeds maximum transaction size." );
752  }
753 
754  //Insert transaction into unique transactions database.
755  if( 0 == (skip & skip_transaction_dupe_check) )
756  {
757  create<transaction_history_object>([&trx](transaction_history_object& transaction) {
758  transaction.trx_id = trx.id();
759  transaction.trx = trx;
760  });
761  }
762 
763  eval_state.operation_results.reserve(trx.operations.size());
764 
765  //Finally process the operations
766  processed_transaction ptrx(trx);
767  _current_op_in_trx = 0;
768  for( const auto& op : ptrx.operations )
769  {
770  _current_virtual_op = 0;
771  eval_state.operation_results.emplace_back(apply_operation(eval_state, op, false)); // This is NOT a virtual op
772  ++_current_op_in_trx;
773  }
774  ptrx.operation_results = std::move(eval_state.operation_results);
775 
776  // Make sure there is no unpaid samet fund debt
777  const auto& samet_fund_idx = get_index_type<samet_fund_index>().indices().get<by_unpaid>();
778  FC_ASSERT( samet_fund_idx.empty() || samet_fund_idx.begin()->unpaid_amount == 0,
779  "Unpaid SameT Fund debt detected" );
780 
781  return ptrx;
782 } FC_CAPTURE_AND_RETHROW( (trx) ) } // GCOVR_EXCL_LINE
783 
785  bool is_virtual /* = true */ )
786 { try {
787  int i_which = op.which();
788  uint64_t u_which = uint64_t( i_which );
789  FC_ASSERT( i_which >= 0, "Negative operation tag in operation ${op}", ("op",op) );
790  FC_ASSERT( u_which < _operation_evaluators.size(), "No registered evaluator for operation ${op}", ("op",op) );
791  unique_ptr<op_evaluator>& eval = _operation_evaluators[ u_which ];
792  FC_ASSERT( eval, "No registered evaluator for operation ${op}", ("op",op) );
793  auto op_id = push_applied_operation( op, is_virtual );
794  auto result = eval->evaluate( eval_state, op, true );
795  set_applied_operation_result( op_id, result );
796  return result;
797 } FC_CAPTURE_AND_RETHROW( (op) ) } // GCOVR_EXCL_LINE
798 
799 operation_result database::try_push_virtual_operation( transaction_evaluation_state& eval_state, const operation& op )
800 {
801  operation_validate( op );
802 
803  // Note: these variables could be updated during the apply_operation() call
804  size_t old_applied_ops_size = _applied_ops.size();
805  auto old_vop = _current_virtual_op;
806 
807  try
808  {
809  undo_session_nesting_guard guard( _undo_session_nesting_depth, *this );
810  if( _undo_db.size() >= _undo_db.max_size() )
812  auto temp_session = _undo_db.start_undo_session(true);
813  auto result = apply_operation( eval_state, op ); // This is a virtual operation
814  temp_session.merge();
815  return result;
816  }
817  catch( const fc::exception& e )
818  {
819  wlog( "Failed to push virtual operation ${op} at block ${n}; exception was ${e}",
820  ("op", op)("n", head_block_num())("e", e.to_detail_string()) );
821  _current_virtual_op = old_vop;
822  _applied_ops.resize( old_applied_ops_size );
823  throw;
824  }
825 }
826 
827 const witness_object& database::validate_block_header( uint32_t skip, const signed_block& next_block )const
828 {
829  FC_ASSERT( head_block_id() == next_block.previous, "", ("head_block_id",head_block_id())("next.prev",next_block.previous) );
830  FC_ASSERT( head_block_time() < next_block.timestamp, "", ("head_block_time",head_block_time())("next",next_block.timestamp)("blocknum",next_block.block_num()) );
831  const witness_object& witness = next_block.witness(*this);
832 
833  if( 0 == (skip&skip_witness_signature) )
834  FC_ASSERT( next_block.validate_signee( witness.signing_key ) );
835 
836  if( 0 == (skip&skip_witness_schedule_check) )
837  {
838  uint32_t slot_num = get_slot_at_time( next_block.timestamp );
839  FC_ASSERT( slot_num > 0 );
840 
841  witness_id_type scheduled_witness = get_scheduled_witness( slot_num );
842 
843  FC_ASSERT( next_block.witness == scheduled_witness, "Witness produced block at wrong time",
844  ("block witness",next_block.witness)("scheduled",scheduled_witness)("slot_num",slot_num) );
845  }
846 
847  return witness;
848 }
849 
850 void database::create_block_summary(const signed_block& next_block)
851 {
852  block_summary_id_type sid(next_block.block_num() & 0xffff );
853  modify( sid(*this), [&](block_summary_object& p) {
854  p.block_id = next_block.id();
855  });
856 }
857 
858 void database::add_checkpoints( const flat_map<uint32_t,block_id_type>& checkpts )
859 {
860  for( const auto& i : checkpts )
861  _checkpoints[i.first] = i.second;
862 }
863 
865 {
866  return (_checkpoints.size() > 0) && (_checkpoints.rbegin()->first >= head_block_num());
867 }
868 
869 
870 static const uint32_t skip_expensive = database::skip_transaction_signatures | database::skip_witness_signature
872 
873 template<typename Trx>
874 void database::_precompute_parallel( const Trx* trx, const size_t count, const uint32_t skip )const
875 {
876  for( size_t i = 0; i < count; ++i, ++trx )
877  {
878  trx->validate(); // TODO - parallelize wrt confidential operations
879  if( 0 == (skip & skip_block_size_check) )
880  trx->get_packed_size();
881  if( 0 == (skip&skip_transaction_dupe_check) )
882  trx->id();
883  if( 0 == (skip&skip_transaction_signatures) )
884  trx->get_signature_keys( get_chain_id() );
885  }
886 }
887 
888 fc::future<void> database::precompute_parallel( const signed_block& block, const uint32_t skip )const
889 { try {
890  std::vector<fc::future<void>> workers;
891  if( !block.transactions.empty() )
892  {
893  if( (skip & skip_expensive) == skip_expensive )
894  _precompute_parallel( &block.transactions[0], block.transactions.size(), skip );
895  else
896  {
898  uint32_t chunk_size = ( block.transactions.size() + chunks - 1 ) / chunks;
899  workers.reserve( chunks + 1 );
900  for( size_t base = 0; base < block.transactions.size(); base += chunk_size )
901  workers.push_back( fc::do_parallel( [this,&block,base,chunk_size,skip] () {
902  _precompute_parallel( &block.transactions[base],
903  ( ( base + chunk_size ) < block.transactions.size() ) ? chunk_size
904  : ( block.transactions.size() - base ),
905  skip );
906  }) );
907  }
908  }
909 
910  if( 0 == (skip&skip_witness_signature) )
911  workers.push_back( fc::do_parallel( [&block] () { block.signee(); } ) );
912  if( 0 == (skip&skip_merkle_check) )
913  block.calculate_merkle_root();
914  block.id();
915 
916  if( workers.empty() )
918 
919  auto first = workers.begin();
920  auto worker = first;
921  while( ++worker != workers.end() )
922  worker->wait();
923  return *first;
924 } FC_LOG_AND_RETHROW() }
925 
927 {
928  return fc::do_parallel([this,&trx] () {
929  _precompute_parallel( &trx, 1, skip_nothing );
930  });
931 }
932 
933 } }
fc::promise
Definition: future.hpp:109
graphene::chain::database::skip_transaction_signatures
@ skip_transaction_signatures
used by non-witness nodes
Definition: database.hpp:81
graphene::protocol::transaction::operations
vector< operation > operations
Definition: transaction.hpp:89
graphene::protocol::block_header::transaction_merkle_root
checksum_type transaction_merkle_root
Definition: block.hpp:37
fc::time_point_sec::sec_since_epoch
uint32_t sec_since_epoch() const
Definition: time.hpp:90
graphene::protocol::precomputable_transaction
Definition: transaction.hpp:233
FC_CAPTURE_AND_RETHROW
#define FC_CAPTURE_AND_RETHROW(...)
Definition: exception.hpp:479
graphene::db::undo_database::size
std::size_t size() const
Definition: undo_database.hpp:120
graphene::chain::undo_session_nesting_guard::~undo_session_nesting_guard
~undo_session_nesting_guard()
Definition: db_block.cpp:322
graphene::chain::database::skip_tapos_check
@ skip_tapos_check
used while reindexing – note this skips expiration check too
Definition: database.hpp:84
transaction_history_object.hpp
graphene::chain::database::is_known_transaction
bool is_known_transaction(const transaction_id_type &id) const
Definition: db_block.cpp:57
samet_fund_object.hpp
graphene::chain::database
tracks the blockchain state in an extensible manner
Definition: database.hpp:70
wlog
#define wlog(FORMAT,...)
Definition: logger.hpp:123
graphene::chain::database::pop_undo
void pop_undo()
Definition: database.hpp:692
graphene::chain::database::get_chain_id
const chain_id_type & get_chain_id() const
Definition: db_getter.cpp:87
graphene::chain::block_database::store
void store(const block_id_type &id, const signed_block &b)
Definition: block_database.cpp:82
graphene::chain::undo_session_nesting_guard::undo_session_nesting_guard
undo_session_nesting_guard(uint32_t &nesting_counter, const database &db)
Definition: db_block.cpp:315
graphene::protocol::rejected_predicate_map
map< custom_authority_id_type, rejected_predicate > rejected_predicate_map
Definition: transaction.hpp:31
fc::exception
Used to generate a useful error report when an exception is thrown.
Definition: exception.hpp:56
graphene::chain::database::head_block_time
time_point_sec head_block_time() const
Definition: db_getter.cpp:67
graphene::protocol::transaction::id
virtual const transaction_id_type & id() const
Definition: transaction.cpp:70
graphene::chain::database::_current_block_time
fc::time_point_sec _current_block_time
Definition: database.hpp:799
fc::typelist::first
at< List, 0 > first
Get the type at the beginning of the list.
Definition: typelist.hpp:190
graphene::chain::node_property_object::debug_updates
std::map< block_id_type, std::vector< fc::variant_object > > debug_updates
Definition: node_property_object.hpp:46
database.hpp
fc::static_variant< transfer_operation, limit_order_create_operation, limit_order_cancel_operation, call_order_update_operation, fill_order_operation, account_create_operation, account_update_operation, account_whitelist_operation, account_upgrade_operation, account_transfer_operation, asset_create_operation, asset_update_operation, asset_update_bitasset_operation, asset_update_feed_producers_operation, asset_issue_operation, asset_reserve_operation, asset_fund_fee_pool_operation, asset_settle_operation, asset_global_settle_operation, asset_publish_feed_operation, witness_create_operation, witness_update_operation, proposal_create_operation, proposal_update_operation, proposal_delete_operation, withdraw_permission_create_operation, withdraw_permission_update_operation, withdraw_permission_claim_operation, withdraw_permission_delete_operation, committee_member_create_operation, committee_member_update_operation, committee_member_update_global_parameters_operation, vesting_balance_create_operation, vesting_balance_withdraw_operation, worker_create_operation, custom_operation, assert_operation, balance_claim_operation, override_transfer_operation, transfer_to_blind_operation, blind_transfer_operation, transfer_from_blind_operation, asset_settle_cancel_operation, asset_claim_fees_operation, fba_distribute_operation, bid_collateral_operation, execute_bid_operation, asset_claim_pool_operation, asset_update_issuer_operation, htlc_create_operation, htlc_redeem_operation, htlc_redeemed_operation, htlc_extend_operation, htlc_refund_operation, custom_authority_create_operation, custom_authority_update_operation, custom_authority_delete_operation, ticket_create_operation, ticket_update_operation, liquidity_pool_create_operation, liquidity_pool_delete_operation, liquidity_pool_deposit_operation, liquidity_pool_withdraw_operation, liquidity_pool_exchange_operation, samet_fund_create_operation, samet_fund_delete_operation, samet_fund_update_operation, samet_fund_borrow_operation, samet_fund_repay_operation, credit_offer_create_operation, credit_offer_delete_operation, credit_offer_update_operation, credit_offer_accept_operation, credit_deal_repay_operation, credit_deal_expired_operation, liquidity_pool_update_operation, credit_deal_update_operation, limit_order_update_operation >
graphene::chain::database::clear_pending
void clear_pending()
Definition: db_block.cpp:541
graphene::chain::detail::with_skip_flags
void with_skip_flags(database &db, uint32_t skip_flags, Lambda callback)
Definition: db_with.hpp:113
graphene::chain::database::notify_changed_objects
void notify_changed_objects()
Definition: db_notify.cpp:592
parallel.hpp
fc::time_point::sec_since_epoch
uint32_t sec_since_epoch() const
Definition: time.hpp:55
graphene::chain::detail::without_pending_transactions
void without_pending_transactions(database &db, std::vector< processed_transaction > &&pending_transactions, Lambda callback)
Definition: db_with.hpp:132
graphene::protocol::signed_block::calculate_merkle_root
const checksum_type & calculate_merkle_root() const
Definition: block.cpp:70
graphene::chain::global_property_object::parameters
chain_parameters parameters
Definition: global_property_object.hpp:44
graphene::chain::transaction_evaluation_state
Definition: transaction_evaluation_state.hpp:37
graphene::chain::fork_database::fetch_block_by_number
vector< item_ptr > fetch_block_by_number(uint32_t n) const
Definition: fork_database.cpp:133
FC_LOG_AND_RETHROW
#define FC_LOG_AND_RETHROW()
Definition: exception.hpp:395
graphene::chain::database::get_viable_custom_authorities
vector< authority > get_viable_custom_authorities(account_id_type account, const operation &op, rejected_predicate_map *rejected_authorities=nullptr) const
Get a list of custom authorities which can validate the provided operation for the provided account.
Definition: db_getter.cpp:102
graphene::chain::fork_database::pop_block
void pop_block()
Definition: fork_database.cpp:37
graphene::protocol::operation_validate
void operation_validate(const operation &op)
Definition: operations.cpp:98
fee_schedule.hpp
graphene::protocol::transaction::expiration
fc::time_point_sec expiration
Definition: transaction.hpp:87
fc::sha256
Definition: sha256.hpp:10
fc::ripemd160::data
char * data() const
Definition: ripemd160.cpp:26
graphene::chain::database::_current_block_num
uint32_t _current_block_num
Definition: database.hpp:800
graphene::chain::database::push_block
bool push_block(const signed_block &b, uint32_t skip=skip_nothing)
Definition: db_block.cpp:118
graphene::chain::database::pop_block
void pop_block()
Definition: db_block.cpp:523
graphene::chain::database::push_proposal
processed_transaction push_proposal(const proposal_object &proposal)
Definition: db_block.cpp:336
proposal_object.hpp
graphene::chain::database::get_applied_operations
const vector< optional< operation_history_object > > & get_applied_operations() const
Definition: db_block.cpp:566
graphene::chain::database::apply_block
void apply_block(const signed_block &next_block, uint32_t skip=skip_nothing)
Definition: db_block.cpp:573
graphene::chain::database::notify_on_pending_transaction
void notify_on_pending_transaction(const signed_transaction &tx)
Definition: db_notify.cpp:587
graphene::chain::database::notify_applied_block
void notify_applied_block(const signed_block &block)
Definition: db_notify.cpp:582
graphene::chain::database::set_applied_operation_result
void set_applied_operation_result(uint32_t op_id, const operation_result &r)
Definition: db_block.cpp:555
graphene::chain::proposal_object::proposed_transaction
transaction proposed_transaction
Definition: proposal_object.hpp:45
graphene::chain::database::_push_transaction
processed_transaction _push_transaction(const precomputable_transaction &trx)
Definition: db_block.cpp:282
graphene::protocol::block_header::previous
block_id_type previous
Definition: block.hpp:33
graphene::chain::fork_database::set_head
void set_head(shared_ptr< fork_item > h)
Definition: fork_database.cpp:192
graphene::chain::item_ptr
shared_ptr< fork_item > item_ptr
Definition: fork_database.hpp:57
graphene::chain::database::generate_block
signed_block generate_block(const fc::time_point_sec when, witness_id_type witness_id, const fc::ecc::private_key &block_signing_private_key, uint32_t skip)
Definition: db_block.cpp:382
graphene::db::undo_database::start_undo_session
session start_undo_session(bool force_enable=false)
Definition: undo_database.cpp:46
graphene::protocol::block_header::block_num
uint32_t block_num() const
Definition: block.hpp:34
fc::ecc::private_key
an elliptic curve private key.
Definition: elliptic.hpp:89
graphene::chain::fork_database::head
shared_ptr< fork_item > head() const
Definition: fork_database.hpp:91
graphene::protocol::processed_transaction::operation_results
vector< operation_result > operation_results
Definition: transaction.hpp:298
graphene::chain::database::fetch_block_by_id
optional< signed_block > fetch_block_by_id(const block_id_type &id) const
Definition: db_block.cpp:68
graphene::protocol::signed_transaction
adds a signature to a transaction
Definition: transaction.hpp:134
graphene::chain::database::head_block_id
block_id_type head_block_id() const
Definition: db_getter.cpp:77
fc::do_parallel
auto do_parallel(Functor &&f, const char *desc FC_TASK_NAME_DEFAULT_ARG) -> fc::future< decltype(f())>
Definition: parallel.hpp:98
graphene::chain::transaction_evaluation_state::_is_proposed_trx
bool _is_proposed_trx
Definition: transaction_evaluation_state.hpp:49
graphene::db::undo_database::max_size
size_t max_size() const
Definition: undo_database.hpp:122
fc::asio::default_io_service_scope::get_num_threads
static uint16_t get_num_threads()
Definition: asio.cpp:145
graphene::chain::block_database::fetch_by_number
optional< signed_block > fetch_by_number(uint32_t block_num) const
Definition: block_database.cpp:184
ilog
#define ilog(FORMAT,...)
Definition: logger.hpp:117
graphene::chain::undo_session_nesting_guard
Definition: db_block.cpp:313
graphene::chain::database::get_node_properties
const node_property_object & get_node_properties() const
Definition: db_getter.cpp:92
edump
#define edump(SEQ)
Definition: logger.hpp:182
graphene::db::index::get
const object & get(object_id_type id) const
Definition: index.hpp:110
evaluator.hpp
graphene::chain::transaction_evaluation_state::_trx
const signed_transaction * _trx
Definition: transaction_evaluation_state.hpp:47
graphene::chain::database::get_slot_time
fc::time_point_sec get_slot_time(uint32_t slot_num) const
Definition: db_witness_schedule.cpp:44
fc::time_point_sec
Definition: time.hpp:74
graphene::chain::database::push_applied_operation
uint32_t push_applied_operation(const operation &op, bool is_virtual=true)
Definition: db_block.cpp:548
graphene::chain::fork_database::push_block
shared_ptr< fork_item > push_block(const signed_block &b)
Definition: fork_database.cpp:56
graphene::protocol::signed_block::transactions
vector< processed_transaction > transactions
Definition: block.hpp:68
fc::ripemd160
Definition: ripemd160.hpp:11
graphene::protocol::transaction::get_packed_size
virtual uint64_t get_packed_size() const
Definition: transaction.cpp:65
graphene::chain::database::push_transaction
processed_transaction push_transaction(const precomputable_transaction &trx, uint32_t skip=skip_nothing)
Definition: db_block.cpp:270
graphene::protocol::transaction::ref_block_num
uint16_t ref_block_num
Definition: transaction.hpp:76
fc::raw::pack_size
size_t pack_size(const T &v)
Definition: raw.hpp:757
fc::exception::to_detail_string
std::string to_detail_string(log_level ll=log_level::all) const
Definition: exception.cpp:183
graphene::chain::database::before_last_checkpoint
bool before_last_checkpoint() const
Definition: db_block.cpp:864
graphene::chain::database::get_block_ids_on_fork
std::vector< block_id_type > get_block_ids_on_fork(block_id_type head_of_fork) const
Definition: db_block.cpp:93
graphene::db::index::find
virtual const object * find(object_id_type id) const =0
graphene::protocol::transaction::ref_block_prefix
uint32_t ref_block_prefix
Definition: transaction.hpp:82
graphene::protocol::block_header::timestamp
fc::time_point_sec timestamp
Definition: block.hpp:35
graphene::chain::database::head_block_num
uint32_t head_block_num() const
Definition: db_getter.cpp:72
graphene::chain::database::get_slot_at_time
uint32_t get_slot_at_time(fc::time_point_sec when) const
Definition: db_witness_schedule.cpp:74
graphene::chain::block_database::fetch_block_id
block_id_type fetch_block_id(uint32_t block_num) const
Definition: block_database.cpp:136
fc::ecc::private_key::get_public_key
public_key get_public_key() const
Definition: elliptic_impl_priv.cpp:70
graphene::chain::database::_popped_tx
std::deque< precomputable_transaction > _popped_tx
Definition: database.hpp:660
fc::time_point::now
static time_point now()
Definition: time.cpp:13
FC_ASSERT
#define FC_ASSERT(TEST,...)
Checks a condition and throws an assert_exception if the test is FALSE.
Definition: exception.hpp:345
graphene::chain::database::validate_transaction
processed_transaction validate_transaction(const signed_transaction &trx)
Definition: db_block.cpp:307
db_with.hpp
graphene::protocol::processed_transaction
captures the result of evaluating the operations contained in the transaction
Definition: transaction.hpp:292
graphene::chain::database::skip_witness_schedule_check
@ skip_witness_schedule_check
used while reindexing
Definition: database.hpp:89
graphene::chain::fork_database::fetch_branch_from
pair< branch_type, branch_type > fetch_branch_from(block_id_type first, block_id_type second) const
Definition: fork_database.cpp:149
graphene::protocol::transaction::validate
virtual void validate() const
Definition: transaction.cpp:58
graphene::chain::global_property_object::active_witnesses
flat_set< witness_id_type > active_witnesses
Definition: global_property_object.hpp:49
graphene::chain::block_database::contains
bool contains(const block_id_type &id) const
Definition: block_database.cpp:120
graphene::protocol::signed_transaction::verify_authority
void verify_authority(const chain_id_type &chain_id, const std::function< const authority *(account_id_type)> &get_active, const std::function< const authority *(account_id_type)> &get_owner, const custom_authority_lookup &get_custom, bool allow_non_immediate_owner, bool ignore_custom_operation_required_auths, uint32_t max_recursion=GRAPHENE_MAX_SIG_CHECK_DEPTH) const
Definition: transaction.cpp:464
graphene::db::undo_database::set_max_size
void set_max_size(size_t new_max_size)
Definition: undo_database.hpp:121
operation_history_object.hpp
graphene::chain::database::skip_block_size_check
@ skip_block_size_check
used when applying locally generated transactions
Definition: database.hpp:83
block_summary_object.hpp
fc::static_variant::which
tag_type which() const
Definition: static_variant.hpp:329
graphene::chain::database::skip_merkle_check
@ skip_merkle_check
used while reindexing
Definition: database.hpp:86
graphene::chain::fork_database::remove
void remove(block_id_type b)
Definition: fork_database.cpp:197
graphene::chain::fork_database::is_known_block
bool is_known_block(const block_id_type &id) const
Definition: fork_database.cpp:117
graphene::chain::database::get_witness_schedule_object
const witness_schedule_object & get_witness_schedule_object() const
Definition: db_getter.cpp:147
graphene::protocol::chain_parameters::maximum_block_size
uint32_t maximum_block_size
maximum allowable size in bytes for a block
Definition: chain_parameters.hpp:58
graphene::chain::database::apply_operation
operation_result apply_operation(transaction_evaluation_state &eval_state, const operation &op, bool is_virtual=true)
Definition: db_block.cpp:784
graphene::protocol::signed_block_header::id
const block_id_type & id() const
Definition: block.cpp:41
graphene::chain::database::apply_debug_updates
void apply_debug_updates()
Definition: db_debug.cpp:187
graphene::chain::database::process_tickets
generic_operation_result process_tickets()
Definition: db_update.cpp:652
graphene::chain::database::get_global_properties
const global_property_object & get_global_properties() const
Definition: db_getter.cpp:47
graphene::chain::node_property_object::skip_flags
uint32_t skip_flags
Definition: node_property_object.hpp:45
fc::optional
provides stack-based nullable value similar to boost::optional
Definition: optional.hpp:20
graphene::chain::database::skip_witness_signature
@ skip_witness_signature
used while reindexing
Definition: database.hpp:80
graphene::chain::database::get_recent_transaction
const signed_transaction & get_recent_transaction(const transaction_id_type &trx_id) const
Definition: db_block.cpp:85
graphene::chain::vesting_balance_type::worker
@ worker
witness_schedule_object.hpp
graphene::chain::database::get_block_id_for_num
block_id_type get_block_id_for_num(uint32_t block_num) const
Definition: db_block.cpp:63
graphene::chain::fork_database::fetch_block
shared_ptr< fork_item > fetch_block(const block_id_type &id) const
Definition: fork_database.cpp:124
graphene::chain::database::fetch_block_by_number
optional< signed_block > fetch_block_by_number(uint32_t num) const
Definition: db_block.cpp:76
graphene::protocol::signed_block
Definition: block.hpp:64
graphene::chain::database::skip_transaction_dupe_check
@ skip_transaction_dupe_check
used while reindexing
Definition: database.hpp:82
GRAPHENE_ASSERT
#define GRAPHENE_ASSERT(expr, exc_type, FORMAT,...)
Definition: exceptions.hpp:28
witness_object.hpp
graphene::chain::block_database::fetch_optional
optional< signed_block > fetch_optional(const block_id_type &id) const
Definition: block_database.cpp:152
graphene::db::object_database::remove
void remove(const object &obj)
Definition: object_database.hpp:97
graphene::chain::database::get_dynamic_global_properties
const dynamic_global_property_object & get_dynamic_global_properties() const
Definition: db_getter.cpp:57
graphene::chain::transaction_evaluation_state::operation_results
vector< operation_result > operation_results
Definition: transaction_evaluation_state.hpp:45
graphene::chain::database::get_scheduled_witness
witness_id_type get_scheduled_witness(uint32_t slot_num) const
Get the witness scheduled for block production in a slot.
Definition: db_witness_schedule.cpp:36
graphene::chain::proposal_object
tracks the approval of a partially approved transaction
Definition: proposal_object.hpp:40
graphene::chain::database::add_checkpoints
void add_checkpoints(const flat_map< uint32_t, block_id_type > &checkpts)
Definition: db_block.cpp:858
graphene::db::index
abstract base class for accessing objects indexed in various ways.
Definition: index.hpp:70
global_property_object.hpp
graphene::chain::vesting_balance_type::witness
@ witness
graphene
Definition: api.cpp:48
fc::future< void >
Definition: future.hpp:283
exceptions.hpp
graphene::chain::database::is_known_block
bool is_known_block(const block_id_type &id) const
Definition: db_block.cpp:48
graphene::chain::database::skip_nothing
@ skip_nothing
Definition: database.hpp:79
graphene::db::object_database::modify
void modify(const T &obj, const Lambda &m)
Definition: object_database.hpp:99
graphene::chain::database::precompute_parallel
fc::future< void > precompute_parallel(const signed_block &block, const uint32_t skip=skip_nothing) const
Definition: db_block.cpp:888
graphene::chain::operation_history_object
tracks the history of all logical operations on blockchain state
Definition: operation_history_object.hpp:48
graphene::db::object_database::_undo_db
undo_database _undo_db
Definition: object_database.hpp:170
graphene::chain::database::apply_transaction
processed_transaction apply_transaction(const signed_transaction &trx, uint32_t skip=skip_nothing)
Definition: db_block.cpp:688
fc::typelist::index
typename impl::zip< typename impl::make_sequence< length< List >()>::type, List >::type index
Definition: typelist.hpp:225
graphene::protocol::operation
fc::static_variant< transfer_operation, limit_order_create_operation, limit_order_cancel_operation, call_order_update_operation, fill_order_operation, account_create_operation, account_update_operation, account_whitelist_operation, account_upgrade_operation, account_transfer_operation, asset_create_operation, asset_update_operation, asset_update_bitasset_operation, asset_update_feed_producers_operation, asset_issue_operation, asset_reserve_operation, asset_fund_fee_pool_operation, asset_settle_operation, asset_global_settle_operation, asset_publish_feed_operation, witness_create_operation, witness_update_operation, proposal_create_operation, proposal_update_operation, proposal_delete_operation, withdraw_permission_create_operation, withdraw_permission_update_operation, withdraw_permission_claim_operation, withdraw_permission_delete_operation, committee_member_create_operation, committee_member_update_operation, committee_member_update_global_parameters_operation, vesting_balance_create_operation, vesting_balance_withdraw_operation, worker_create_operation, custom_operation, assert_operation, balance_claim_operation, override_transfer_operation, transfer_to_blind_operation, blind_transfer_operation, transfer_from_blind_operation, asset_settle_cancel_operation, asset_claim_fees_operation, fba_distribute_operation, bid_collateral_operation, execute_bid_operation, asset_claim_pool_operation, asset_update_issuer_operation, htlc_create_operation, htlc_redeem_operation, htlc_redeemed_operation, htlc_extend_operation, htlc_refund_operation, custom_authority_create_operation, custom_authority_update_operation, custom_authority_delete_operation, ticket_create_operation, ticket_update_operation, liquidity_pool_create_operation, liquidity_pool_delete_operation, liquidity_pool_deposit_operation, liquidity_pool_withdraw_operation, liquidity_pool_exchange_operation, samet_fund_create_operation, samet_fund_delete_operation, samet_fund_update_operation, samet_fund_borrow_operation, samet_fund_repay_operation, credit_offer_create_operation, credit_offer_delete_operation, credit_offer_update_operation, credit_offer_accept_operation, credit_deal_repay_operation, credit_deal_expired_operation, liquidity_pool_update_operation, credit_deal_update_operation, limit_order_update_operation > operation
Definition: operations.hpp:134
elog
#define elog(FORMAT,...)
Definition: logger.hpp:129
raw.hpp