27 #include <graphene/chain/hardfork.hpp> 46 namespace graphene {
namespace chain {
59 const auto& trx_idx = get_index_type<transaction_index>().indices().get<by_trx_id>();
60 return trx_idx.find(
id ) != trx_idx.end();
79 if( results.size() == 1 )
80 return results[0]->data;
87 auto&
index = get_index_type<transaction_index>().indices().
get<by_trx_id>();
96 if( !((branches.first.back()->previous_id() == branches.second.back()->previous_id())) )
100 (branches.first.size())
101 (branches.second.size()) );
102 assert(branches.first.back()->previous_id() == branches.second.back()->previous_id());
104 std::vector<block_id_type> result;
105 for (
const item_ptr& fork_block : branches.second)
106 result.emplace_back(fork_block->id);
107 result.emplace_back(branches.first.back()->previous_id());
126 result = _push_block(new_block);
132 bool database::_push_block(
const signed_block& new_block)
141 GRAPHENE_ASSERT( prev_block, unlinkable_block_exception,
"block does not link to known chain" );
143 verify_signing_witness( new_block, *prev_block );
146 const shared_ptr<fork_item> new_head = _fork_db.
push_block(new_block);
154 wlog(
"Switching to fork: ${id}", (
"id",new_head->data.id()) );
165 for(
auto ritr = branches.first.rbegin(); ritr != branches.first.rend(); ++ritr )
167 ilog(
"pushing block from fork #${n} ${id}", (
"n",(*ritr)->data.block_num())(
"id",(*ritr)->id) );
172 update_witnesses( **ritr );
173 _block_id_to_block.
store( (*ritr)->id, (*ritr)->data );
179 wlog(
"exception thrown while switching forks ${e}", (
"e",except->to_detail_string() ) );
181 while( ritr != branches.first.rend() )
183 ilog(
"removing block from fork_db #${n} ${id}", (
"n",(*ritr)->data.block_num())(
"id",(*ritr)->id) );
184 _fork_db.
remove( (*ritr)->id );
187 _fork_db.
set_head( branches.second.front() );
196 ilog(
"Switching back to fork: ${id}", (
"id",branches.second.front()->data.id()) );
198 for(
auto ritr2 = branches.second.rbegin(); ritr2 != branches.second.rend(); ++ritr2 )
200 ilog(
"pushing block #${n} ${id}", (
"n",(*ritr2)->data.block_num())(
"id",(*ritr2)->id) );
203 _block_id_to_block.
store( (*ritr2)->id, (*ritr2)->data );
218 update_witnesses( *new_head );
219 _block_id_to_block.
store(new_block.
id(), new_block);
230 void database::verify_signing_witness(
const signed_block& new_block,
const fork_item& fork_entry )
const 236 FC_ASSERT( new_block.
witness == scheduled_witness.first,
"Witness produced block at wrong time",
237 (
"block witness",new_block.
witness)(
"scheduled",scheduled_witness)(
"slot_num",slot_num) );
241 void database::update_witnesses(
fork_item& fork_entry )
const 250 fork_entry.
scheduled_witnesses = std::make_shared< vector< pair< witness_id_type, public_key_type > > >();
284 if( !_pending_tx_session.valid() )
293 auto processed_trx = _apply_transaction( trx );
294 _pending_tx.push_back(processed_trx);
298 temp_session.merge();
302 return processed_trx;
308 return _apply_transaction( trx );
314 : orig_value(nesting_counter), counter(nesting_counter)
321 if( --counter != orig_value )
322 elog(
"Unexpected proposal nesting count value: ${n} != ${o}", (
"n",counter)(
"o",orig_value) );
325 const uint32_t orig_value;
336 eval_state.
_trx = &ptrx;
337 size_t old_applied_ops_size = _applied_ops.size();
347 const auto& samet_fund_idx = get_index_type<samet_fund_index>().indices().get<by_unpaid>();
348 FC_ASSERT( samet_fund_idx.empty() || samet_fund_idx.begin()->unpaid_amount == 0,
349 "Unpaid SameT Fund debt detected" );
355 for(
size_t i=old_applied_ops_size,n=_applied_ops.size(); i<n; i++ )
357 ilog(
"removing failed operation from applied_ops: ${op}", (
"op", *(_applied_ops[i])) );
358 _applied_ops[i].reset();
363 _applied_ops.resize( old_applied_ops_size );
375 witness_id_type witness_id,
383 result = _generate_block( when, witness_id, block_signing_private_key );
390 witness_id_type witness_id,
399 FC_ASSERT( scheduled_witness == witness_id );
414 _pending_tx_session.reset();
431 const size_t max_block_header_size = max_partial_block_header_size +
fc::raw::pack_size( witness_id );
433 size_t total_block_size = max_block_header_size;
439 uint64_t postponed_tx_count = 0;
445 if( new_total_size > maximum_block_size )
447 postponed_tx_count++;
464 if( new_total_size > maximum_block_size )
466 postponed_tx_count++;
470 temp_session.merge();
472 total_block_size = new_total_size;
478 wlog(
"Transaction was not processed while generating block due to ${e}", (
"e", e) );
479 wlog(
"The transaction was ${t}", (
"t", tx) );
482 if( postponed_tx_count > 0 )
484 wlog(
"Postponed ${n} transactions due to block size limit", (
"n", postponed_tx_count) );
487 _pending_tx_session.reset();
498 pending_block.
witness = witness_id;
500 if( 0 == (skip & skip_witness_signature) )
501 pending_block.
sign( block_signing_private_key );
505 return pending_block;
514 _pending_tx_session.reset();
515 auto fork_db_head = _fork_db.head();
516 FC_ASSERT( fork_db_head,
"Trying to pop() from empty fork database!?" );
518 _fork_db.pop_block();
522 FC_ASSERT( fork_db_head,
"Trying to pop() block that's not in fork database!?" );
525 _popped_tx.insert(
_popped_tx.begin(), fork_db_head->data.transactions.begin(), fork_db_head->data.transactions.end() );
530 assert( (_pending_tx.size() == 0) || _pending_tx_session.valid() );
532 _pending_tx_session.reset();
539 ++_current_virtual_op;
540 return _applied_ops.size() - 1;
544 assert( op_id < _applied_ops.size() );
545 if( _applied_ops[op_id] )
546 _applied_ops[op_id]->result = result;
549 elog(
"Could not set operation result (head_block_num=${b})", (
"b",
head_block_num()) );
563 if( !_checkpoints.empty() && _checkpoints.rbegin()->second !=
block_id_type() )
565 auto itr = _checkpoints.find( block_num );
566 if( itr != _checkpoints.end() )
567 FC_ASSERT( next_block.
id() == itr->second,
"Block did not match checkpoint", (
"checkpoint",*itr)(
"block_id",next_block.
id()) );
569 if( _checkpoints.rbegin()->first >= block_num )
575 _apply_block( next_block );
580 void database::_apply_block(
const signed_block& next_block )
582 uint32_t next_block_num = next_block.
block_num();
584 _applied_ops.clear();
595 (
"next_block",next_block)
596 (
"id",next_block.
id()) );
598 const witness_object& signing_witness = validate_block_header(skip, next_block);
600 bool maint_needed = (dynamic_global_props.next_maintenance_time <= next_block.
timestamp);
609 _current_trx_in_block = 0;
613 _issue_453_affected_assets.clear();
625 ++_current_trx_in_block;
628 _current_op_in_trx = 0;
629 _current_virtual_op = 0;
631 const uint32_t missed = update_witness_missed_blocks( next_block );
632 update_global_dynamic_data( next_block, missed );
633 update_signing_witness(signing_witness, next_block);
634 update_last_irreversible_block();
640 perform_chain_maintenance( next_block );
642 create_block_summary(next_block);
643 clear_expired_transactions();
644 clear_expired_proposals();
645 clear_expired_orders();
646 clear_expired_force_settlements();
647 clear_expired_htlcs();
648 update_expired_feeds();
649 update_core_exchange_rates();
650 update_withdraw_permissions();
651 update_credit_offers_and_deals();
658 update_maintenance_flag( maint_needed );
659 update_witness_schedule();
660 if( !_node_property_object.debug_updates.empty() )
665 _applied_ops.clear();
680 result = _apply_transaction(trx);
691 auto& trx_idx = get_mutable_index_type<transaction_index>();
695 GRAPHENE_ASSERT( trx_idx.indices().get<by_trx_id>().
find(trx.
id()) == trx_idx.indices().get<by_trx_id>().end(),
696 duplicate_transaction,
697 "Transaction '${txid}' is already in the database",
702 eval_state.
_trx = &trx;
706 bool allow_non_immediate_owner = (
head_block_time() >= HARDFORK_CORE_584_TIME );
707 auto get_active = [
this]( account_id_type id ) {
return &id(*this).active; };
708 auto get_owner = [
this]( account_id_type id ) {
return &id(*this).owner; };
713 trx.
verify_authority(chain_id, get_active, get_owner, get_custom, allow_non_immediate_owner,
724 const auto& tapos_block_summary = block_summary_id_type( trx.
ref_block_num )(*this);
738 "Transaction exceeds maximum transaction size." );
742 if( 0 == (skip & skip_transaction_dupe_check) )
754 _current_op_in_trx = 0;
757 _current_virtual_op = 0;
759 ++_current_op_in_trx;
764 const auto& samet_fund_idx = get_index_type<samet_fund_index>().indices().get<by_unpaid>();
765 FC_ASSERT( samet_fund_idx.empty() || samet_fund_idx.begin()->unpaid_amount == 0,
766 "Unpaid SameT Fund debt detected" );
774 int i_which = op.
which();
775 uint64_t u_which = uint64_t( i_which );
776 FC_ASSERT( i_which >= 0,
"Negative operation tag in operation ${op}", (
"op",op) );
777 FC_ASSERT( u_which < _operation_evaluators.size(),
"No registered evaluator for operation ${op}", (
"op",op) );
778 unique_ptr<op_evaluator>& eval = _operation_evaluators[ u_which ];
779 FC_ASSERT( eval,
"No registered evaluator for operation ${op}", (
"op",op) );
781 auto result = eval->evaluate( eval_state, op,
true );
802 FC_ASSERT( next_block.
witness == scheduled_witness,
"Witness produced block at wrong time",
803 (
"block witness",next_block.
witness)(
"scheduled",scheduled_witness)(
"slot_num",slot_num) );
809 void database::create_block_summary(
const signed_block& next_block)
811 block_summary_id_type sid(next_block.
block_num() & 0xffff );
819 for(
const auto& i : checkpts )
820 _checkpoints[i.first] = i.second;
825 return (_checkpoints.size() > 0) && (_checkpoints.rbegin()->first >=
head_block_num());
832 template<
typename Trx>
833 void database::_precompute_parallel(
const Trx* trx,
const size_t count,
const uint32_t skip )
const 835 for(
size_t i = 0; i < count; ++i, ++trx )
839 trx->get_packed_size();
849 std::vector<fc::future<void>> workers;
852 if( (skip & skip_expensive) == skip_expensive )
857 uint32_t chunk_size = ( block.
transactions.size() + chunks - 1 ) / chunks;
858 workers.reserve( chunks + 1 );
859 for(
size_t base = 0; base < block.
transactions.size(); base += chunk_size )
860 workers.push_back(
fc::do_parallel( [
this,&block,base,chunk_size,skip] () {
861 _precompute_parallel( &block.transactions[base],
862 base + chunk_size < block.transactions.size() ? chunk_size : block.transactions.size() - base,
874 if( workers.empty() )
877 auto first = workers.begin();
879 while( ++
worker != workers.end() )
virtual const transaction_id_type & id() const
bool is_known_block(const block_id_type &id) const
shared_ptr< fork_item > item_ptr
block_id_type get_block_id_for_num(uint32_t block_num) const
void modify(const T &obj, const Lambda &m)
chain_parameters parameters
push_proposal_nesting_guard(uint32_t &nesting_counter, const database &db)
optional< signed_block > fetch_by_number(uint32_t block_num) const
bool is_known_transaction(const transaction_id_type &id) const
fc::time_point_sec expiration
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
map< custom_authority_id_type, rejected_predicate > rejected_predicate_map
processed_transaction apply_transaction(const signed_transaction &trx, uint32_t skip=skip_nothing)
vector< operation > operations
public_key get_public_key() const
tracks the history of all logical operations on blockchain stateAll operations and virtual operations...
time_point_sec head_block_time() const
void notify_applied_block(const signed_block &block)
Maintains global state information (committee_member list, current fees)This is an implementation det...
tracks the blockchain state in an extensible manner
bool contains(const block_id_type &id) const
void notify_changed_objects()
uint32_t sec_since_epoch() const
uint32_t _current_block_num
shared_ptr< fork_item > head() const
const chain_id_type & get_chain_id() const
processed_transaction push_proposal(const proposal_object &proposal)
Used to generate a useful error report when an exception is thrown.At each level in the stack where t...
vector< item_ptr > fetch_block_by_number(uint32_t n) const
uint32_t maximum_transaction_size
maximum allowable size in bytes for a transaction
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...
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 >
void set_applied_operation_result(uint32_t op_id, const operation_result &r)
void with_skip_flags(database &db, uint32_t skip_flags, Lambda callback)
auto do_parallel(Functor &&f, const char *desc FC_TASK_NAME_DEFAULT_ARG) -> fc::future< decltype(f())>
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)
groups operations that should be applied atomically
void without_pending_transactions(database &db, std::vector< processed_transaction > &&pending_transactions, Lambda callback)
bool push_block(const signed_block &b, uint32_t skip=skip_nothing)
const vector< optional< operation_history_object > > & get_applied_operations() const
fc::ripemd160 block_id_type
block_id_type head_block_id() const
provides stack-based nullable value similar to boost::optional
flat_set< witness_id_type > active_witnesses
vector< operation_result > operation_results
size_t pack_size(const T &v)
void set_max_size(size_t new_max_size)
const checksum_type & calculate_merkle_root() const
void apply_block(const signed_block &next_block, uint32_t skip=skip_nothing)
virtual const object * find(object_id_type id) const =0
uint32_t push_applied_operation(const operation &op, bool is_virtual=true)
uint32_t get_slot_at_time(fc::time_point_sec when) const
const signed_transaction * _trx
void notify_on_pending_transaction(const signed_transaction &tx)
processed_transaction _push_transaction(const precomputable_transaction &trx)
uint32_t ref_block_prefix
const T * find(const object_id_type &id) const
void set_head(shared_ptr< fork_item > h)
vector< operation_result > operation_results
const object & get(object_id_type id) const
processed_transaction validate_transaction(const signed_transaction &trx)
std::vector< block_id_type > get_block_ids_on_fork(block_id_type head_of_fork) const
pair< branch_type, branch_type > fetch_branch_from(block_id_type first, block_id_type second) const
optional< signed_block > fetch_block_by_id(const block_id_type &id) const
#define FC_CAPTURE_AND_RETHROW(...)
#define FC_ASSERT(TEST,...)
Checks a condition and throws an assert_exception if the test is FALSE.
shared_ptr< fork_item > push_block(const signed_block &b)
shared_ptr< vector< pair< witness_id_type, public_key_type > > > scheduled_witnesses
adds a signature to a transaction
block_id_type fetch_block_id(uint32_t block_num) const
static uint16_t get_num_threads()
uint32_t maximum_time_until_expiration
maximum lifetime in seconds for transactions to be valid, before expiring
const node_property_object & get_node_properties() const
transaction proposed_transaction
fc::time_point_sec next_block_time
fc::time_point_sec get_slot_time(uint32_t slot_num) const
at< List, 0 > first
Get the type at the beginning of the list.
session start_undo_session(bool force_enable=false)
const witness_schedule_object & get_witness_schedule_object() const
virtual uint64_t get_packed_size() const
used while reindexing – note this skips expiration check too
const signed_transaction & get_recent_transaction(const transaction_id_type &trx_id) const
processed_transaction push_transaction(const precomputable_transaction &trx, uint32_t skip=skip_nothing)
std::string to_detail_string(log_level ll=log_level::all) const
shared_ptr< fork_item > fetch_block(const block_id_type &id) const
std::deque< precomputable_transaction > _popped_tx
bool before_last_checkpoint() const
void remove(block_id_type b)
void store(const block_id_type &id, const signed_block &b)
void apply_debug_updates()
uint32_t head_block_num() const
virtual void validate() const
public_key_type signing_key
generic_operation_result process_tickets()
tracks minimal information about past blocks to implement TaPOSWhen attempting to calculate the valid...
abstract base class for accessing objects indexed in various ways.
#define GRAPHENE_ASSERT(expr, exc_type, FORMAT,...)
~push_proposal_nesting_guard()
uint32_t sec_since_epoch() const
const dynamic_global_property_object & get_dynamic_global_properties() const
operation_result apply_operation(transaction_evaluation_state &eval_state, const operation &op, bool is_virtual=true)
optional< signed_block > fetch_optional(const block_id_type &id) const
an elliptic curve private key.
void add_checkpoints(const flat_map< uint32_t, block_id_type > &checkpts)
#define FC_LOG_AND_RETHROW()
vector< processed_transaction > transactions
captures the result of evaluating the operations contained in the transaction
vector< witness_id_type > current_shuffled_witnesses
uint32_t maximum_block_size
maximum allowable size in bytes for a block
optional< signed_block > fetch_block_by_number(uint32_t num) const
fc::future< void > precompute_parallel(const signed_block &block, const uint32_t skip=skip_nothing) const
used by non-witness nodes
bool is_known_block(const block_id_type &id) const
used when applying locally generated transactions
fc::time_point_sec _current_block_time
witness_id_type get_scheduled_witness(uint32_t slot_num) const
Get the witness scheduled for block production in a slot.
const global_property_object & get_global_properties() const
uint64_t next_block_aslot
tracks the approval of a partially approved transaction