int User::to_minutes(time_duration duration) { return duration.total_seconds() / 60; }
inline int total_seconds(time_duration td) { return td.total_seconds(); }
int64_t localTime() { static const ptime epoch(date(1970, 1, 1)); const time_duration diff = second_clock::local_time() - epoch; return diff.total_seconds(); }
namespace obelisk { using namespace bc; using namespace boost::posix_time; using std::placeholders::_1; using std::placeholders::_2; using std::placeholders::_3; using std::placeholders::_4; const time_duration retry_start_duration = seconds(30); void log_to_file(std::ofstream& file, log_level level, const std::string& domain, const std::string& body, bool log_requests) { if (body.empty()) return; if (!log_requests && domain == LOG_REQUEST) return; file << level_repr(level); if (!domain.empty()) file << " [" << domain << "]"; file << ": " << body << std::endl; } void log_to_both(std::ostream& device, std::ofstream& file, log_level level, const std::string& domain, const std::string& body, bool log_requests) { if (body.empty()) return; if (!log_requests && domain == LOG_REQUEST) return; std::ostringstream output; output << level_repr(level); if (!domain.empty()) output << " [" << domain << "]"; output << ": " << body; device << output.str() << std::endl; file << output.str() << std::endl; } void output_file(std::ofstream& file, log_level level, const std::string& domain, const std::string& body, bool log_requests) { log_to_file(file, level, domain, body, log_requests); } void output_both(std::ofstream& file, log_level level, const std::string& domain, const std::string& body, bool log_requests) { log_to_both(std::cout, file, level, domain, body, log_requests); } void error_file(std::ofstream& file, log_level level, const std::string& domain, const std::string& body, bool log_requests) { log_to_file(file, level, domain, body, log_requests); } void error_both(std::ofstream& file, log_level level, const std::string& domain, const std::string& body, bool log_requests) { log_to_both(std::cerr, file, level, domain, body, log_requests); } node_impl::node_impl() : network_pool_(1), disk_pool_(6), mem_pool_(1), hosts_(network_pool_), handshake_(network_pool_), network_(network_pool_), protocol_(network_pool_, hosts_, handshake_, network_), chain_(disk_pool_), poller_(mem_pool_, chain_), txpool_(mem_pool_, chain_), indexer_(mem_pool_), session_(mem_pool_, { handshake_, protocol_, chain_, poller_, txpool_}), retry_start_timer_(mem_pool_.service()) { } bool node_impl::start(config_type& config) { auto file_mode = std::ofstream::out | std::ofstream::app; outfile_.open(config.output_file, file_mode); errfile_.open(config.error_file, file_mode); log_debug().set_output_function( std::bind(output_file, std::ref(outfile_), _1, _2, _3, config.log_requests)); log_info().set_output_function( std::bind(output_both, std::ref(outfile_), _1, _2, _3, config.log_requests)); log_warning().set_output_function( std::bind(error_file, std::ref(errfile_), _1, _2, _3, config.log_requests)); log_error().set_output_function( std::bind(error_both, std::ref(errfile_), _1, _2, _3, config.log_requests)); log_fatal().set_output_function( std::bind(error_both, std::ref(errfile_), _1, _2, _3, config.log_requests)); protocol_.subscribe_channel( std::bind(&node_impl::monitor_tx, this, _1, _2)); // Start blockchain. std::promise<std::error_code> ec_chain; auto blockchain_started = [&](const std::error_code& ec) { ec_chain.set_value(ec); }; chain_.start(config.blockchain_path, blockchain_started); // Query the error_code and wait for startup completion. std::error_code ec = ec_chain.get_future().get(); if (ec) { log_error() << "Couldn't start blockchain: " << ec.message(); return false; } chain_.subscribe_reorganize( std::bind(&node_impl::reorganize, this, _1, _2, _3, _4)); // Transaction pool txpool_.start(); // Outgoing connections setting in config file before we // start p2p network subsystem. int outgoing_connections = boost::lexical_cast<int>( config.outgoing_connections); protocol_.set_max_outbound(outgoing_connections); protocol_.set_hosts_filename(config.hosts_file); if (!config.listener_enabled) protocol_.disable_listener(); for (const auto node: config.nodes) { log_info() << "Adding node: " << node.hostname << " " << node.port; protocol_.maintain_connection(node.hostname, node.port); } start_session(); return true; } void node_impl::start_session() { // Start session auto session_started = [this](const std::error_code& ec) { if (ec) wait_and_retry_start(ec); }; session_.start(session_started); } void node_impl::wait_and_retry_start(const std::error_code& ec) { BITCOIN_ASSERT(ec); log_error() << "Unable to start session: " << ec.message(); log_error() << "Retrying in " << retry_start_duration.seconds() << " seconds."; retry_start_timer_.expires_from_now(retry_start_duration); retry_start_timer_.async_wait( std::bind(&node_impl::start_session, this)); } bool node_impl::stop() { // Stop session std::promise<std::error_code> ec_session; auto session_stopped = [&](const std::error_code& ec) { ec_session.set_value(ec); }; session_.stop(session_stopped); // Query the error_code and wait for startup completion. std::error_code ec = ec_session.get_future().get(); if (ec) log_error() << "Problem stopping session: " << ec.message(); // Stop the threadpools. network_pool_.stop(); disk_pool_.stop(); mem_pool_.stop(); network_pool_.join(); disk_pool_.join(); mem_pool_.join(); chain_.stop(); return true; } void node_impl::subscribe_blocks(block_notify_callback notify_block) { notify_blocks_.push_back(notify_block); } void node_impl::subscribe_transactions(transaction_notify_callback notify_tx) { notify_txs_.push_back(notify_tx); } blockchain& node_impl::blockchain() { return chain_; } transaction_pool& node_impl::transaction_pool() { return txpool_; } transaction_indexer& node_impl::transaction_indexer() { return indexer_; } protocol& node_impl::protocol() { return protocol_; } threadpool& node_impl::memory_related_threadpool() { return mem_pool_; } void node_impl::monitor_tx(const std::error_code& ec, channel_ptr node) { if (ec) { log_warning() << "Couldn't start connection: " << ec.message(); return; } node->subscribe_transaction( std::bind(&node_impl::recv_transaction, this, _1, _2, node)); protocol_.subscribe_channel( std::bind(&node_impl::monitor_tx, this, _1, _2)); } void node_impl::recv_transaction(const std::error_code& ec, const transaction_type& tx, channel_ptr node) { if (ec) { log_error() << "recv_transaction: " << ec.message(); return; } auto handle_deindex = [](const std::error_code& ec) { if (ec) log_error() << "Deindex error: " << ec.message(); }; // Called when the transaction becomes confirmed in a block. auto handle_confirm = [this, tx, handle_deindex]( const std::error_code& ec) { log_debug() << "Confirm transaction: " << ec.message() << " " << hash_transaction(tx); // Always try to deindex tx. // The error could be error::forced_removal from txpool. indexer_.deindex(tx, handle_deindex); }; txpool_.store(tx, handle_confirm, std::bind(&node_impl::handle_mempool_store, this, _1, _2, tx, node)); node->subscribe_transaction( std::bind(&node_impl::recv_transaction, this, _1, _2, node)); } void node_impl::handle_mempool_store( const std::error_code& ec, const index_list& unconfirmed, const transaction_type& tx, channel_ptr node) { if (ec) { log_warning() << "Failed to store transaction in mempool " << hash_transaction(tx) << ": " << ec.message(); return; } auto handle_index = [](const std::error_code& ec) { if (ec) log_error() << "Index error: " << ec.message(); }; indexer_.index(tx, handle_index); log_info() << "Accepted transaction: " << hash_transaction(tx); for (auto notify: notify_txs_) notify(tx); } void node_impl::reorganize(const std::error_code& ec, size_t fork_point, const bc::blockchain::block_list& new_blocks, const bc::blockchain::block_list& replaced_blocks) { // Don't bother publishing blocks when in the initial blockchain download. if (fork_point > 235866) for (size_t i = 0; i < new_blocks.size(); ++i) { size_t height = fork_point + i + 1; const block_type& blk = *new_blocks[i]; for (auto notify: notify_blocks_) notify(height, blk); } chain_.subscribe_reorganize( std::bind(&node_impl::reorganize, this, _1, _2, _3, _4)); } } // namespace obelisk
string TimerStructs::toStringSec(time_duration & duration) { return padded2DString(duration.seconds()); }
int64_t str2time(const string& str) { static const ptime epoch(date(1970, 1, 1)); const ptime string_time = from_iso_string(str); const time_duration diff = string_time - epoch; return diff.total_seconds(); }
string TimerStructs::toStringMin(time_duration & duration) { return padded2DString(duration.minutes()); }
string TimerStructs::toStringHour(time_duration & duration) { return padded2DString(duration.hours()); }
void ParametersMap::insert( const std::string& parameterName, const time_duration& value ){ insert(parameterName, value.is_not_a_date_time() ? string() : to_simple_string(value)); }
Lightmap::Lightmap(Heightmap *orghm, int level, int shadowLevelDif, LightingInfo *li) { const ptime startTicks = microsec_clock::local_time(); tilesize.x = orghm->w-1; tilesize.y = orghm->h-1; name = "lightmap"; Heightmap *hm; int w; for(;;) { hm = orghm->GetLevel(-level); w=hm->w-1; GLint maxw; glGetIntegerv(GL_MAX_TEXTURE_SIZE, &maxw); if (w > maxw) level ++; else break; } shadowLevelDif=0; Heightmap *shadowhm = orghm->GetLevel(-(level+shadowLevelDif)); int shadowScale=1<<shadowLevelDif; int shadowW=shadowhm->w-1; assert (w/shadowW == shadowScale); //float org2c = w/float(orghm->w-1); //float c2org = (float)(orghm->w-1)/w; float *centerhm = new float[w*w]; Vector3 *shading = new Vector3[w*w]; for (int y=0;y<w;y++) for (int x=0;x<w;x++) { centerhm[y*w+x] =/* hm->scale * */ 0.25f * ( (int)hm->at(x,y)+ (int)hm->at(x+1,y)+ (int)hm->at(x,y+1) + (int)hm->at(x+1,y+1) ); //+ hm->offset; shading[y*w+x] = li->ambient; } uchar *lightMap = new uchar[shadowW*shadowW]; for (std::vector<StaticLight>::const_iterator l=li->staticLights.begin();l!=li->staticLights.end();++l) { float lightx; float lighty; if (l->directional) { lightx = l->position.x; lighty = l->position.y; } else { lightx = (int)(l->position.x / shadowhm->squareSize); lighty = (int)(l->position.z / shadowhm->squareSize); } CalculateShadows(lightMap, shadowW, lightx, lighty, l->position.y, centerhm, w, shadowScale, l->directional); for (int y=0;y<w;y++) { for (int x=0;x<w;x++) { if (!lightMap[(y*shadowW+x)/shadowScale]) continue; Vector3 wp; if (l->directional) wp = l->position; else wp = l->position - Vector3((x+0.5f)*hm->squareSize,centerhm[y*w+x],(y+0.5f)*hm->squareSize); uchar* normal = hm->GetNormal (x,y); Vector3 normv((2 * (int)normal[0] - 256)/255.0f, (2 * (int)normal[1] - 256)/255.0f, (2 * (int)normal[2] - 256)/255.0f); wp.ANormalize(); float dot = wp.dot(normv); if(dot < 0.0f) dot = 0.0f; if(dot > 1.0f) dot = 1.0f; dot *= lightMap[(y*shadowW+x)/shadowScale]*(1.0f/255.0f); shading[y*w+x] += l->color * dot; } } } delete[] lightMap; glGenTextures(1,&shadingTex); glBindTexture (GL_TEXTURE_2D, shadingTex); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR); uchar *shadingTexData=new uchar[w*w*4]; for(int y=0;y<w;y++) { for (int x=0;x<w;x++) { shadingTexData[(y*w+x)*4+0] = (uchar)(min(1.0f, shading[y*w+x].x) * 255); shadingTexData[(y*w+x)*4+1] = (uchar)(min(1.0f, shading[y*w+x].y) * 255); shadingTexData[(y*w+x)*4+2] = (uchar)(min(1.0f, shading[y*w+x].z) * 255); shadingTexData[(y*w+x)*4+3] = CReadMap::EncodeHeight(centerhm[w*y+x]); } } SaveImage ("lightmap.png", 4, IL_UNSIGNED_BYTE, w,w, shadingTexData); glBuildMipmaps(GL_TEXTURE_2D, 4, w,w, GL_RGBA, GL_UNSIGNED_BYTE, shadingTexData); delete[] shadingTexData; id = shadingTex; delete[] shading; delete[] centerhm; const time_duration numTicks = microsec_clock::local_time() - startTicks; d_trace ("Lightmap generation: %2.3f seconds\n", numTicks.total_milliseconds() * 0.001f); }
namespace server { using namespace bc::chain; using namespace bc::node; using namespace boost::posix_time; using boost::format; using std::placeholders::_1; using std::placeholders::_2; using std::placeholders::_3; using std::placeholders::_4; const time_duration retry_start_duration = seconds(30); constexpr auto append = std::ofstream::out | std::ofstream::app; server_node::server_node(settings_type& config) : outfile_(config.debug_file.string(), append), errfile_(config.error_file.string(), append), // Threadpools, the number of threads they spawn and priorities. network_pool_(1, thread_priority::normal), disk_pool_(6, thread_priority::low), mem_pool_(1, thread_priority::low), // Networking related services. hosts_(network_pool_, config.hosts_file.string(), 1000), handshake_(network_pool_), network_(network_pool_), protocol_(network_pool_, hosts_, handshake_, network_, config.out_connections), // Blockchain database service. chain_(disk_pool_, config.blockchain_path.string(), { config.history_height }, 20), // Poll new blocks, tx memory pool and tx indexer. poller_(mem_pool_, chain_), txpool_(mem_pool_, chain_, config.tx_pool_capacity), indexer_(mem_pool_), // Session manager service. session_(mem_pool_, handshake_, protocol_, chain_, poller_, txpool_), retry_start_timer_(mem_pool_.service()) { } bool server_node::start(settings_type& config) { // Set up logging for node background threads (add to config). const auto skip_log = if_else(config.log_requests, "", LOG_REQUEST); initialize_logging(outfile_, errfile_, bc::cout, bc::cerr, skip_log); // Start blockchain. if (!chain_.start()) { log_error(LOG_NODE) << "Couldn't start blockchain."; return false; } chain_.subscribe_reorganize( std::bind(&server_node::reorganize, this, _1, _2, _3, _4)); // Start transaction pool txpool_.start(); // Outgoing connections setting in config file before we // start p2p network subsystem. protocol_.set_hosts_filename(config.hosts_file.string()); if (!config.listener_enabled) protocol_.disable_listener(); for (const auto& endpoint: config.peers) { const auto host = endpoint.get_host(); const auto port = endpoint.get_port(); log_info(LOG_NODE) << "Adding node: " << host << " " << port; protocol_.maintain_connection(host, port); } start_session(); return true; } void server_node::start_session() { // Start session const auto session_started = [this](const std::error_code& ec) { if (ec) wait_and_retry_start(ec); }; session_.start(session_started); } void server_node::wait_and_retry_start(const std::error_code& ec) { BITCOIN_ASSERT(ec); log_error(LOG_NODE) << "Unable to start session: " << ec.message(); log_error(LOG_NODE) << "Retrying in " << retry_start_duration.seconds() << " seconds."; retry_start_timer_.expires_from_now(retry_start_duration); retry_start_timer_.async_wait( std::bind(&server_node::start_session, this)); } bool server_node::stop() { // Stop session std::promise<std::error_code> ec_session; const auto session_stopped = [&ec_session](const std::error_code& ec) { ec_session.set_value(ec); }; session_.stop(session_stopped); // Query the error_code and wait for startup completion. const auto ec = ec_session.get_future().get(); if (ec) log_error(LOG_NODE) << "Problem stopping session: " << ec.message(); // Safely close blockchain database. chain_.stop(); // Stop the threadpools. network_pool_.stop(); disk_pool_.stop(); mem_pool_.stop(); // Join threadpools. Wait for them to finish. network_pool_.join(); disk_pool_.join(); mem_pool_.join(); return true; } void server_node::subscribe_blocks(block_notify_callback notify_block) { notify_blocks_.push_back(notify_block); } void server_node::subscribe_transactions(transaction_notify_callback notify_tx) { notify_txs_.push_back(notify_tx); } blockchain& server_node::blockchain() { return chain_; } transaction_pool& server_node::transaction_pool() { return txpool_; } transaction_indexer& server_node::transaction_indexer() { return indexer_; } network::protocol& server_node::protocol() { return protocol_; } threadpool& server_node::memory_related_threadpool() { return mem_pool_; } void server_node::monitor_tx(const std::error_code& ec, network::channel_ptr node) { if (ec) { log_warning(LOG_NODE) << "Couldn't start connection: " << ec.message(); return; } // Subscribe to transaction messages from this node. node->subscribe_transaction( std::bind(&server_node::recv_transaction, this, _1, _2, node)); // Stay subscribed to new connections. protocol_.subscribe_channel( std::bind(&server_node::monitor_tx, this, _1, _2)); } void server_node::recv_transaction(const std::error_code& ec, const transaction_type& tx, network::channel_ptr node) { if (ec) { log_warning(LOG_NODE) << "recv_transaction: " << ec.message(); return; } const auto handle_deindex = [](const std::error_code& ec) { if (ec) log_error(LOG_NODE) << "Deindex error: " << ec.message(); }; // Called when the transaction becomes confirmed in a block. const auto handle_confirm = [this, tx, handle_deindex]( const std::error_code& ec) { log_debug(LOG_NODE) << "Confirm transaction: " << ec.message() << " " << encode_hash(hash_transaction(tx)); // Always try to deindex tx. // The error could be error::forced_removal from txpool. indexer_.deindex(tx, handle_deindex); }; // Validate the transaction from the network. // Attempt to store in the transaction pool and check the result. txpool_.store(tx, handle_confirm, std::bind(&server_node::handle_mempool_store, this, _1, _2, tx, node)); // Resubscribe to transaction messages from this node. node->subscribe_transaction( std::bind(&server_node::recv_transaction, this, _1, _2, node)); } void server_node::handle_mempool_store( const std::error_code& ec, const index_list& /* unconfirmed */, const transaction_type& tx, network::channel_ptr /* node */) { if (ec) { log_warning(LOG_NODE) << "Failed to store transaction in mempool " << encode_hash(hash_transaction(tx)) << ": " << ec.message(); return; } const auto handle_index = [](const std::error_code& ec) { if (ec) log_error(LOG_NODE) << "Index error: " << ec.message(); }; indexer_.index(tx, handle_index); log_info(LOG_NODE) << "Accepted transaction: " << encode_hash(hash_transaction(tx)); for (const auto notify: notify_txs_) notify(tx); } void server_node::reorganize(const std::error_code& /* ec */, size_t fork_point, const blockchain::block_list& new_blocks, const blockchain::block_list& /* replaced_blocks */) { // magic number (height) - how does this apply to testnet? // Don't bother publishing blocks when in the initial blockchain download. if (fork_point > 235866) for (size_t i = 0; i < new_blocks.size(); ++i) { size_t height = fork_point + i + 1; const block_type& blk = *new_blocks[i]; for (const auto notify: notify_blocks_) notify(height, blk); } chain_.subscribe_reorganize( std::bind(&server_node::reorganize, this, _1, _2, _3, _4)); } // TODO: use existing libbitcoin-node implementation. void server_node::fullnode_fetch_history(server_node& node, const incoming_message& request, queue_send_callback queue_send) { uint32_t from_height; payment_address payaddr; if (!unwrap_fetch_history_args(payaddr, from_height, request)) return; fetch_history(node.blockchain(), node.transaction_indexer(), payaddr, std::bind(send_history_result, _1, _2, request, queue_send), from_height); } } // namespace server