// en.bitcoin.it/wiki/Protocol_documentation#getdata // getdata can be used to retrieve transactions, but only if they are // in the memory pool or relay set - arbitrary access to transactions // in the chain is not allowed to avoid having clients start to depend // on nodes having full transaction indexes (which modern nodes do not). void responder::send_chain_tx(const code& ec, const transaction& tx, const hash_digest& tx_hash, channel::ptr node) { if (ec == error::service_stopped) return; if (ec == error::not_found) { log::debug(LOG_RESPONDER) << "Transaction for [" << node->authority() << "] not in blockchain [" << encode_hash(tx_hash) << "]"; // It wasn't in the blockchain, so send notfound. send_tx_not_found(tx_hash, node); return; } if (ec) { log::error(LOG_RESPONDER) << "Failure fetching blockchain tx data for [" << node->authority() << "] " << ec.message(); node->stop(ec); return; } send_tx(tx, tx_hash, node); }
// We don't seem to be getting getdata requests. void responder::receive_get_data(const code& ec, const get_data& packet, channel::ptr node) { if (ec == error::channel_stopped) return; const auto peer = node->authority(); if (ec) { log::debug(LOG_RESPONDER) << "Failure in receive get data [" << peer << "] " << ec.message(); node->stop(ec); return; } // Resubscribe to serve tx and blocks. node->subscribe<message::get_data>( std::bind(&responder::receive_get_data, this, _1, _2, node)); log::debug(LOG_RESPONDER) << "Getdata BEGIN [" << peer << "] " << "txs (" << packet.count(inventory_type_id::transaction) << ") " << "blocks (" << packet.count(inventory_type_id::block) << ") " << "bloom (" << packet.count(inventory_type_id::filtered_block) << ")"; for (const auto& inventory: packet.inventories) { switch (inventory.type) { case inventory_type_id::transaction: log::debug(LOG_RESPONDER) << "Transaction getdata for [" << peer << "] " << encode_hash(inventory.hash); tx_pool_.fetch(inventory.hash, std::bind(&responder::send_pool_tx, this, _1, _2, inventory.hash, node)); break; case inventory_type_id::block: log::debug(LOG_RESPONDER) << "Block getdata for [" << peer << "] " << encode_hash(inventory.hash); block_fetcher::fetch(blockchain_, inventory.hash, std::bind(&responder::send_block, this, _1, _2, inventory.hash, node)); break; case inventory_type_id::error: case inventory_type_id::none: default: log::debug(LOG_RESPONDER) << "Ignoring invalid getdata type for [" << peer << "]"; } } log::debug(LOG_RESPONDER) << "Getdata END [" << peer << "]"; }
void responder::send_pool_tx(const code& ec, const transaction& tx, const hash_digest& tx_hash, channel::ptr node) { if (ec == error::service_stopped) return; if (ec == error::not_found) { log::debug(LOG_RESPONDER) << "Transaction for [" << node->authority() << "] not in mempool [" << encode_hash(tx_hash) << "]"; // It wasn't in the mempool, so relay the request to the blockchain. blockchain_.fetch_transaction(tx_hash, std::bind(&responder::send_chain_tx, this, _1, _2, tx_hash, node)); return; } if (ec) { log::error(LOG_RESPONDER) << "Failure fetching mempool tx data for [" << node->authority() << "] " << ec.message(); node->stop(ec); return; } send_tx(tx, tx_hash, node); }
void session::handle_start(const code& ec, channel::ptr channel, result_handler handle_started, result_handler handle_stopped) { // Must either stop or subscribe the channel for stop before returning. if (ec) channel->stop(ec); else channel->subscribe_stop(handle_stopped); // This is the end of the registration sequence. handle_started(ec); }
void protocol::handle_handshake(const code& ec, channel::ptr node) { if (ec) { log_debug(LOG_PROTOCOL) << "Failure in peer handshake [" << node->address() << "] " << ec.message(); node->stop(ec); return; } // Attach ping protocol to the new connection (until node stop event). std::make_shared<protocol_ping>(node, pool_, timeouts_.heartbeat)->start(); // Attach address protocol to the new connection (until node stop event). std::make_shared<protocol_address>(node, pool_, hosts_, self_)->start(); }
void session::handle_start(const code& ec, channel::ptr channel, result_handler handle_started, result_handler handle_stopped) { // Must either stop or subscribe the channel for stop before returning. // All closures must eventually be invoked as otherwise it is a leak. // Therefore upon start failure expect start failure and stop callbacks. if (ec) { channel->stop(ec); handle_stopped(ec); } else { channel->subscribe_stop( BIND_3(do_remove, _1, channel, handle_stopped)); } // This is the end of the registration sequence. handle_started(ec); }
// Should we look in the orphan pool first? void responder::send_block(const code& ec, const block& block, const hash_digest& block_hash, channel::ptr node) { if (ec == error::service_stopped) return; if (ec == error::not_found) { log::debug(LOG_RESPONDER) << "Block for [" << node->authority() << "] not in blockchain [" << encode_hash(block_hash) << "]"; // It wasn't in the blockchain, so send notfound. send_block_not_found(block_hash, node); } if (ec) { log::error(LOG_RESPONDER) << "Failure fetching block data for [" << node->authority() << "] " << ec.message(); node->stop(ec); return; } const auto send_handler = [block_hash, node](const code& ec) { if (ec) log::debug(LOG_RESPONDER) << "Failure sending block for [" << node->authority() << "]"; else log::debug(LOG_RESPONDER) << "Sent block for [" << node->authority() << "] " << encode_hash(block_hash); }; node->send(block, send_handler); }
void session_batch::converge(const code& ec, channel::ptr channel, atomic_counter_ptr counter, upgrade_mutex_ptr mutex, channel_handler handler) { /////////////////////////////////////////////////////////////////////////// // Critical Section mutex->lock_upgrade(); const auto initial_count = counter->load(); BITCOIN_ASSERT(initial_count <= batch_size_); // Already completed, don't call handler. if (initial_count == batch_size_) { mutex->unlock_upgrade(); //----------------------------------------------------------------- if (!ec) channel->stop(error::channel_stopped); return; } const auto count = !ec ? batch_size_ : initial_count + 1; const auto cleared = count == batch_size_; //+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ mutex->unlock_upgrade_and_lock(); counter->store(count); mutex->unlock(); /////////////////////////////////////////////////////////////////////// if (cleared) { // If the last connection attempt is an error, normalize the code. const auto result = ec ? error::operation_failed : error::success; handler(result, channel); } }