forked from lthn/blockchain
internal stratum server
This commit is contained in:
parent
7c4a65ef2a
commit
a62abcf0b5
7 changed files with 1530 additions and 10 deletions
|
|
@ -49,6 +49,7 @@ file(GLOB_RECURSE DAEMON daemon/*)
|
|||
|
||||
file(GLOB_RECURSE P2P p2p/*)
|
||||
file(GLOB_RECURSE RPC rpc/*)
|
||||
file(GLOB_RECURSE STRATUM stratum/*)
|
||||
file(GLOB_RECURSE SIMPLEWALLET simplewallet/*)
|
||||
file(GLOB_RECURSE CONN_TOOL connectivity_tool/*)
|
||||
file(GLOB_RECURSE WALLET wallet/*)
|
||||
|
|
@ -73,6 +74,7 @@ source_group(currency_protocol FILES ${CURRENCY_PROTOCOL})
|
|||
source_group(daemon FILES ${DAEMON})
|
||||
source_group(p2p FILES ${P2P})
|
||||
source_group(rpc FILES ${RPC})
|
||||
source_group(stratum FILES ${STRATUM})
|
||||
source_group(simplewallet FILES ${SIMPLEWALLET})
|
||||
source_group(connectivity-tool FILES ${CONN_TOOL})
|
||||
source_group(wallet FILES ${WALLET})
|
||||
|
|
@ -106,6 +108,10 @@ add_library(rpc ${RPC})
|
|||
add_dependencies(rpc version ${PCH_LIB_NAME})
|
||||
ENABLE_SHARED_PCH(RPC)
|
||||
|
||||
add_library(stratum ${STRATUM})
|
||||
add_dependencies(stratum version ${PCH_LIB_NAME})
|
||||
ENABLE_SHARED_PCH(STRATUM)
|
||||
|
||||
add_library(wallet ${WALLET})
|
||||
add_dependencies(wallet version ${PCH_LIB_NAME})
|
||||
ENABLE_SHARED_PCH(WALLET)
|
||||
|
|
@ -114,7 +120,7 @@ target_link_libraries(currency_core lmdb)
|
|||
|
||||
add_executable(daemon ${DAEMON} ${P2P} ${CURRENCY_PROTOCOL})
|
||||
add_dependencies(daemon version)
|
||||
target_link_libraries(daemon rpc currency_core crypto common upnpc-static zlibstatic ethash ${CMAKE_THREAD_LIBS_INIT} ${Boost_LIBRARIES})
|
||||
target_link_libraries(daemon rpc stratum currency_core crypto common upnpc-static zlibstatic ethash ${CMAKE_THREAD_LIBS_INIT} ${Boost_LIBRARIES})
|
||||
ENABLE_SHARED_PCH(DAEMON)
|
||||
ENABLE_SHARED_PCH_EXECUTABLE(daemon)
|
||||
|
||||
|
|
@ -130,7 +136,7 @@ target_link_libraries(simplewallet wallet rpc currency_core crypto common zlibst
|
|||
ENABLE_SHARED_PCH(SIMPLEWALLET)
|
||||
ENABLE_SHARED_PCH_EXECUTABLE(simplewallet)
|
||||
|
||||
set_property(TARGET common crypto currency_core rpc wallet PROPERTY FOLDER "libs")
|
||||
set_property(TARGET common crypto currency_core rpc stratum wallet PROPERTY FOLDER "libs")
|
||||
set_property(TARGET daemon simplewallet connectivity_tool PROPERTY FOLDER "prog")
|
||||
set_property(TARGET daemon PROPERTY OUTPUT_NAME "zanod")
|
||||
|
||||
|
|
|
|||
|
|
@ -27,6 +27,7 @@
|
|||
|
||||
namespace currency
|
||||
{
|
||||
int ethash_height_to_epoch(uint64_t height);
|
||||
crypto::hash get_block_longhash(uint64_t h, const crypto::hash& block_long_ash, uint64_t nonce);
|
||||
void get_block_longhash(const block& b, crypto::hash& res);
|
||||
crypto::hash get_block_longhash(const block& b);
|
||||
|
|
|
|||
|
|
@ -114,12 +114,12 @@ namespace currency {
|
|||
return false;
|
||||
// usual slow check
|
||||
boost::multiprecision::uint512_t hashVal = 0;
|
||||
for (int i = 1; i < 4; i++)
|
||||
{ // highest word is zero
|
||||
hashVal |= swap64le(((const uint64_t *)&h)[3 - i]);
|
||||
hashVal << 64;
|
||||
for(int i = 0; i < 4; i++)
|
||||
{
|
||||
hashVal <<= 64;
|
||||
hashVal |= swap64le(((const uint64_t *) &h)[3-i]);
|
||||
}
|
||||
return (hashVal * difficulty > max256bit);
|
||||
return (hashVal * difficulty <= max256bit);
|
||||
}
|
||||
|
||||
uint64_t difficulty_to_boundary(wide_difficulty_type difficulty)
|
||||
|
|
|
|||
|
|
@ -20,6 +20,7 @@ using namespace epee;
|
|||
#include "currency_core/checkpoints_create.h"
|
||||
#include "currency_core/currency_core.h"
|
||||
#include "rpc/core_rpc_server.h"
|
||||
#include "stratum/stratum_server.h"
|
||||
#include "currency_protocol/currency_protocol_handler.h"
|
||||
#include "daemon_commands_handler.h"
|
||||
#include "common/miniupnp_helper.h"
|
||||
|
|
@ -85,6 +86,7 @@ int main(int argc, char* argv[])
|
|||
nodetool::node_server<currency::t_currency_protocol_handler<currency::core> >::init_options(desc_cmd_sett);
|
||||
currency::miner::init_options(desc_cmd_sett);
|
||||
bc_services::bc_offers_service::init_options(desc_cmd_sett);
|
||||
currency::stratum_server::init_options(desc_cmd_sett);
|
||||
|
||||
|
||||
po::options_description desc_options("Allowed options");
|
||||
|
|
@ -146,8 +148,8 @@ int main(int argc, char* argv[])
|
|||
}
|
||||
|
||||
|
||||
|
||||
|
||||
// stratum server is enabled if any of its options present
|
||||
bool stratum_enabled = currency::stratum_server::should_start(vm);
|
||||
LOG_PRINT("Module folder: " << argv[0], LOG_LEVEL_0);
|
||||
|
||||
//create objects and link them
|
||||
|
|
@ -162,6 +164,9 @@ int main(int argc, char* argv[])
|
|||
daemon_cmmands_handler dch(p2psrv, rpc_server);
|
||||
tools::miniupnp_helper upnp_helper;
|
||||
//ccore.get_blockchain_storage().get_attachment_services_manager().add_service(&offers_service);
|
||||
std::shared_ptr<currency::stratum_server> stratum_server_ptr;
|
||||
if (stratum_enabled)
|
||||
stratum_server_ptr = std::make_shared<currency::stratum_server>(&ccore);
|
||||
|
||||
if (command_line::get_arg(vm, command_line::arg_show_rpc_autodoc))
|
||||
{
|
||||
|
|
@ -201,6 +206,13 @@ int main(int argc, char* argv[])
|
|||
CHECK_AND_ASSERT_MES(res, 1, "Failed to initialize core rpc server.");
|
||||
LOG_PRINT_GREEN("Core rpc server initialized OK on port: " << rpc_server.get_binded_port(), LOG_LEVEL_0);
|
||||
|
||||
if (stratum_enabled)
|
||||
{
|
||||
LOG_PRINT_L0("Initializing stratum server...");
|
||||
res = stratum_server_ptr->init(vm);
|
||||
CHECK_AND_ASSERT_MES(res, 1, "Failed to initialize stratum server.");
|
||||
}
|
||||
|
||||
//initialize core here
|
||||
LOG_PRINT_L0("Initializing core...");
|
||||
res = ccore.init(vm);
|
||||
|
|
@ -231,16 +243,34 @@ int main(int argc, char* argv[])
|
|||
CHECK_AND_ASSERT_MES(res, 1, "Failed to initialize core rpc server.");
|
||||
LOG_PRINT_L0("Core rpc server started ok");
|
||||
|
||||
if (stratum_enabled)
|
||||
{
|
||||
LOG_PRINT_L0("Starting stratum server...");
|
||||
res = stratum_server_ptr->run(false);
|
||||
CHECK_AND_ASSERT_MES(res, 1, "Failed to start stratum server.");
|
||||
LOG_PRINT_L0("Stratum server started ok");
|
||||
}
|
||||
|
||||
tools::signal_handler::install([&dch, &p2psrv] {
|
||||
tools::signal_handler::install([&dch, &p2psrv, &stratum_server_ptr] {
|
||||
dch.stop_handling();
|
||||
p2psrv.send_stop_signal();
|
||||
if (stratum_server_ptr)
|
||||
stratum_server_ptr->send_stop_signal();
|
||||
});
|
||||
|
||||
LOG_PRINT_L0("Starting p2p net loop...");
|
||||
p2psrv.run();
|
||||
LOG_PRINT_L0("p2p net loop stopped");
|
||||
|
||||
//stop components
|
||||
if (stratum_enabled)
|
||||
{
|
||||
LOG_PRINT_L0("Stopping stratum server...");
|
||||
stratum_server_ptr->send_stop_signal();
|
||||
stratum_server_ptr->timed_wait_server_stop(1000);
|
||||
LOG_PRINT_L0("Stratum server stopped");
|
||||
}
|
||||
|
||||
LOG_PRINT_L0("Stopping core rpc server...");
|
||||
rpc_server.send_stop_signal();
|
||||
rpc_server.timed_wait_server_stop(5000);
|
||||
|
|
@ -253,6 +283,9 @@ int main(int argc, char* argv[])
|
|||
LOG_PRINT_L0("Deinitializing market...");
|
||||
(static_cast<currency::i_bc_service&>(offers_service)).deinit();
|
||||
|
||||
LOG_PRINT_L0("Deinitializing stratum server ...");
|
||||
stratum_server_ptr.reset();
|
||||
|
||||
LOG_PRINT_L0("Deinitializing rpc server ...");
|
||||
rpc_server.deinit();
|
||||
LOG_PRINT_L0("Deinitializing currency_protocol...");
|
||||
|
|
|
|||
248
src/stratum/stratum_helpers.h
Normal file
248
src/stratum/stratum_helpers.h
Normal file
|
|
@ -0,0 +1,248 @@
|
|||
// Copyright (c) 2018-2019 Zano Project
|
||||
// Copyright (c) 2014-2018 The Louisdor Project
|
||||
// Distributed under the MIT/X11 software license, see the accompanying
|
||||
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
|
||||
|
||||
#pragma once
|
||||
#include <string>
|
||||
#include "epee/include/misc_language.h"
|
||||
#include "epee/include/storages/parserse_base_utils.h"
|
||||
#include "epee/include/storages/portable_storage.h"
|
||||
#include "ethereum/libethash/ethash/ethash.h"
|
||||
#include "ethereum/libethash/ethash/keccak.h"
|
||||
#include "currency_core/currency_format_utils.h"
|
||||
|
||||
namespace stratum
|
||||
{
|
||||
//------------------------------------------------------------------------------------------------------------------------------
|
||||
|
||||
// Small helper for extracting separate JSON-RPC requests from input buffer.
|
||||
// TODO: currently it does not handle curly brackets within strings to make things simplier
|
||||
struct json_helper
|
||||
{
|
||||
void feed(const std::string& s)
|
||||
{
|
||||
feed(s.c_str(), s.size());
|
||||
}
|
||||
|
||||
void feed(const char* str, size_t size)
|
||||
{
|
||||
m_buffer.append(str, size);
|
||||
|
||||
int b_count = 0;
|
||||
for(size_t i = 0; i < m_buffer.size(); )
|
||||
{
|
||||
char c = m_buffer[i];
|
||||
if (c == '{')
|
||||
++b_count;
|
||||
else if (c == '}')
|
||||
{
|
||||
if (--b_count == 0)
|
||||
{
|
||||
m_objects.push_back(m_buffer.substr(0, i + 1));
|
||||
m_buffer.erase(0, i + 1);
|
||||
i = 0;
|
||||
continue;
|
||||
}
|
||||
}
|
||||
++i;
|
||||
}
|
||||
}
|
||||
|
||||
bool has_objects() const
|
||||
{
|
||||
return !m_objects.empty();
|
||||
}
|
||||
|
||||
bool pop_object(std::string &destination)
|
||||
{
|
||||
if (m_objects.empty())
|
||||
return false;
|
||||
|
||||
destination = m_objects.front();
|
||||
m_objects.pop_front();
|
||||
return true;
|
||||
}
|
||||
|
||||
std::string m_buffer;
|
||||
std::list<std::string> m_objects;
|
||||
};
|
||||
|
||||
template<class t_value>
|
||||
bool ps_get_value_noexcept(epee::serialization::portable_storage& ps, const std::string& value_name, t_value& val, epee::serialization::portable_storage::hsection hparent_section)
|
||||
{
|
||||
try
|
||||
{
|
||||
return ps.get_value(value_name, val, hparent_section);
|
||||
}
|
||||
catch (...)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
std::string trim_0x(const std::string& s)
|
||||
{
|
||||
if (s.length() >= 2 && s[0] == '0' && s[1] == 'x')
|
||||
return s.substr(2);
|
||||
return s;
|
||||
}
|
||||
|
||||
constexpr char hexmap[] = {'0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'a', 'b', 'c', 'd', 'e', 'f'};
|
||||
constexpr char hexmap_backward[] =
|
||||
{ //0 1 2 3 4 5 6 7 8 9 A B C D E F
|
||||
20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, // 0
|
||||
20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, // 1
|
||||
20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, // 2
|
||||
0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 20, 20, 20, 20, 20, 20, // 3
|
||||
20, 10, 11, 12, 13, 14, 15, 20, 20, 20, 20, 20, 20, 20, 20, 20, // 4
|
||||
20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, // 5
|
||||
20, 10, 11, 12, 13, 14, 15, 20, 20, 20, 20, 20, 20, 20, 20, 20, // 6
|
||||
20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, // 7
|
||||
20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, // 8
|
||||
20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, // 9
|
||||
20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, // A
|
||||
20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, // B
|
||||
20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, // C
|
||||
20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, // D
|
||||
20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, // E
|
||||
20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20 // F
|
||||
};
|
||||
|
||||
template<class pod_t>
|
||||
std::string pod_to_net_format(const pod_t &h)
|
||||
{
|
||||
const char* data = reinterpret_cast<const char*>(&h);
|
||||
size_t len = sizeof h;
|
||||
|
||||
std::string s(len * 2, ' ');
|
||||
for (size_t i = 0; i < len; ++i) {
|
||||
s[2 * i] = hexmap[(data[i] & 0xF0) >> 4];
|
||||
s[2 * i + 1] = hexmap[(data[i] & 0x0F)];
|
||||
}
|
||||
|
||||
return "0x" + s;
|
||||
}
|
||||
|
||||
template<class pod_t>
|
||||
std::string pod_to_net_format_reverse(const pod_t &h)
|
||||
{
|
||||
const char* data = reinterpret_cast<const char*>(&h);
|
||||
size_t len = sizeof h;
|
||||
|
||||
std::string s(len * 2, ' ');
|
||||
for (size_t i = 0; i < len; ++i) {
|
||||
s[2 * i] = hexmap[(data[len - i - 1] & 0xF0) >> 4]; // reverse bytes order in data
|
||||
s[2 * i + 1] = hexmap[(data[len - i - 1] & 0x0F)];
|
||||
}
|
||||
|
||||
return "0x" + s;
|
||||
}
|
||||
template<class pod_t>
|
||||
bool pod_from_net_format(const std::string& str, pod_t& result, bool assume_following_zeroes = false)
|
||||
{
|
||||
std::string s = trim_0x(str);
|
||||
if (s.size() != sizeof(pod_t) * 2)
|
||||
{
|
||||
if (!assume_following_zeroes || s.size() > sizeof(pod_t) * 2)
|
||||
return false; // invalid string length
|
||||
s.insert(s.size() - 1, sizeof(pod_t) * 2 - s.size(), '0'); // add zeroes at the end
|
||||
}
|
||||
|
||||
const unsigned char* hex_str = reinterpret_cast<const unsigned char*>(s.c_str());
|
||||
char* pod_data = reinterpret_cast<char*>(&result);
|
||||
|
||||
for (size_t i = 0; i < sizeof(pod_t); ++i)
|
||||
{
|
||||
char a = hexmap_backward[hex_str[2 * i + 1]];
|
||||
char b = hexmap_backward[hex_str[2 * i + 0]];
|
||||
if (a > 15 || b > 15)
|
||||
return false; // invalid character
|
||||
pod_data[i] = a | (b << 4);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
template<class pod_t>
|
||||
bool pod_from_net_format_reverse(const std::string& str, pod_t& result, bool assume_leading_zeroes = false)
|
||||
{
|
||||
std::string s = trim_0x(str);
|
||||
if (s.size() != sizeof(pod_t) * 2)
|
||||
{
|
||||
if (!assume_leading_zeroes || s.size() > sizeof(pod_t) * 2)
|
||||
return false; // invalid string length
|
||||
s.insert(0, sizeof(pod_t) * 2 - s.size(), '0'); // add zeroes at the beginning
|
||||
}
|
||||
|
||||
const unsigned char* hex_str = reinterpret_cast<const unsigned char*>(s.c_str());
|
||||
char* pod_data = reinterpret_cast<char*>(&result);
|
||||
|
||||
for (size_t i = 0; i < sizeof(pod_t); ++i)
|
||||
{
|
||||
char a = hexmap_backward[hex_str[2 * i + 1]];
|
||||
char b = hexmap_backward[hex_str[2 * i + 0]];
|
||||
if (a > 15 || b > 15)
|
||||
return false; // invalid character
|
||||
pod_data[sizeof(pod_t) - i - 1] = a | (b << 4); // reverse byte order
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
uint64_t epoch_by_seedhash(const ethash_hash256& seed_hash)
|
||||
{
|
||||
ethash_hash256 epoch_seed = {};
|
||||
for (uint32_t i = 0; i < 2016; ++i) // 2016 epoches will be enough until 2038
|
||||
{
|
||||
if (memcmp(&seed_hash, &epoch_seed, sizeof seed_hash) == 0)
|
||||
return i;
|
||||
epoch_seed = ethash_keccak256_32(epoch_seed.bytes);
|
||||
}
|
||||
return UINT64_MAX;
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------------------------------------------------------
|
||||
|
||||
// http://www.jsonrpc.org/specification
|
||||
// 'id' -- an identifier established by the Client that MUST contain a String, Number, or NULL value if included.
|
||||
// The Server MUST reply with the same value in the Response object if included.
|
||||
struct jsonrpc_id_null_t {};
|
||||
typedef boost::variant<int64_t, std::string, jsonrpc_id_null_t> jsonrpc_id_t;
|
||||
|
||||
std::string jsonrpc_id_to_value_str(const jsonrpc_id_t& id)
|
||||
{
|
||||
if (id.type() == typeid(int64_t))
|
||||
return boost::to_string(boost::get<int64_t>(id));
|
||||
if (id.type() == typeid(std::string))
|
||||
return '"' + boost::to_string(boost::get<std::string>(id)) + '"';
|
||||
return "null";
|
||||
}
|
||||
|
||||
namespace details
|
||||
{
|
||||
struct jsonrpc_id_visitor : public boost::static_visitor<>
|
||||
{
|
||||
explicit jsonrpc_id_visitor(jsonrpc_id_t &value) : m_value(value) {}
|
||||
void operator()(const uint64_t id) { m_value = id; }
|
||||
void operator()(const int64_t id) { m_value = id; }
|
||||
void operator()(const std::string& id) { m_value = id; }
|
||||
template<typename T>
|
||||
void operator()(const T&) { /* nothing */ }
|
||||
|
||||
jsonrpc_id_t &m_value;
|
||||
};
|
||||
}
|
||||
|
||||
bool read_jsonrpc_id(epee::serialization::portable_storage& ps, jsonrpc_id_t& result)
|
||||
{
|
||||
epee::serialization::storage_entry se;
|
||||
if (!ps.get_value("id", se, nullptr))
|
||||
return false;
|
||||
|
||||
details::jsonrpc_id_visitor vis(result);
|
||||
boost::apply_visitor(vis, se);
|
||||
return true;
|
||||
}
|
||||
|
||||
} // namespace stratum
|
||||
|
||||
inline std::ostream &operator <<(std::ostream &o, const ethash_hash256 &v) { return print256(o, v); }
|
||||
1190
src/stratum/stratum_server.cpp
Normal file
1190
src/stratum/stratum_server.cpp
Normal file
File diff suppressed because it is too large
Load diff
42
src/stratum/stratum_server.h
Normal file
42
src/stratum/stratum_server.h
Normal file
|
|
@ -0,0 +1,42 @@
|
|||
// Copyright (c) 2018-2019 Zano Project
|
||||
// Copyright (c) 2014-2018 The Louisdor Project
|
||||
// Distributed under the MIT/X11 software license, see the accompanying
|
||||
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <boost/program_options/options_description.hpp>
|
||||
#include <boost/program_options/variables_map.hpp>
|
||||
|
||||
#undef LOG_DEFAULT_CHANNEL
|
||||
#define LOG_DEFAULT_CHANNEL "stratum"
|
||||
|
||||
namespace currency
|
||||
{
|
||||
class core;
|
||||
struct stratum_server_impl;
|
||||
|
||||
class stratum_server
|
||||
{
|
||||
public:
|
||||
static void init_options(boost::program_options::options_description& desc);
|
||||
static bool should_start(const boost::program_options::variables_map& vm);
|
||||
|
||||
stratum_server(core* c);
|
||||
~stratum_server();
|
||||
bool init(const boost::program_options::variables_map& vm);
|
||||
bool run(bool wait = true);
|
||||
bool deinit();
|
||||
bool timed_wait_server_stop(uint64_t ms);
|
||||
bool send_stop_signal();
|
||||
|
||||
private:
|
||||
size_t m_threads_count;
|
||||
|
||||
stratum_server_impl* m_impl;
|
||||
core* m_p_core;
|
||||
};
|
||||
}
|
||||
|
||||
#undef LOG_DEFAULT_CHANNEL
|
||||
#define LOG_DEFAULT_CHANNEL NULL
|
||||
Loading…
Add table
Reference in a new issue