mirror of https://github.com/oxen-io/oxen-core.git
Merge pull request #1432 from jagerman/ss-updates
Storage server RPC updates
This commit is contained in:
commit
eda03d1590
|
@ -6284,8 +6284,8 @@ struct service_node_proof_serialized_old
|
|||
service_node_proof_serialized_old(const service_nodes::proof_info &info)
|
||||
: timestamp{native_to_little(info.proof->timestamp)},
|
||||
ip{native_to_little(info.proof->public_ip)},
|
||||
storage_port{native_to_little(info.proof->storage_port)},
|
||||
storage_lmq_port{native_to_little(info.proof->storage_lmq_port)},
|
||||
storage_https_port{native_to_little(info.proof->storage_https_port)},
|
||||
storage_omq_port{native_to_little(info.proof->storage_omq_port)},
|
||||
quorumnet_port{native_to_little(info.proof->qnet_port)},
|
||||
version{native_to_little_container(info.proof->version)},
|
||||
pubkey_ed25519{info.proof->pubkey_ed25519}
|
||||
|
@ -6297,8 +6297,8 @@ struct service_node_proof_serialized_old
|
|||
if (info.proof->timestamp > info.effective_timestamp)
|
||||
info.effective_timestamp = info.proof->timestamp;
|
||||
info.proof->public_ip = little_to_native(ip);
|
||||
info.proof->storage_port = little_to_native(storage_port);
|
||||
info.proof->storage_lmq_port = little_to_native(storage_lmq_port);
|
||||
info.proof->storage_https_port = little_to_native(storage_https_port);
|
||||
info.proof->storage_omq_port = little_to_native(storage_omq_port);
|
||||
info.proof->qnet_port = little_to_native(quorumnet_port);
|
||||
info.proof->version = little_to_native_container(version);
|
||||
info.proof->storage_server_version = {0, 0, 0};
|
||||
|
@ -6315,10 +6315,10 @@ struct service_node_proof_serialized_old
|
|||
|
||||
uint64_t timestamp;
|
||||
uint32_t ip;
|
||||
uint16_t storage_port;
|
||||
uint16_t storage_https_port;
|
||||
uint16_t quorumnet_port;
|
||||
std::array<uint16_t, 3> version;
|
||||
uint16_t storage_lmq_port;
|
||||
uint16_t storage_omq_port;
|
||||
crypto::ed25519_public_key pubkey_ed25519;
|
||||
};
|
||||
static_assert(sizeof(service_node_proof_serialized_old) == 56, "service node serialization struct has unexpected size and/or padding");
|
||||
|
|
|
@ -182,7 +182,7 @@ namespace cryptonote
|
|||
};
|
||||
static const command_line::arg_descriptor<bool> arg_service_node = {
|
||||
"service-node"
|
||||
, "Run as a service node, options 'service-node-public-ip' and 'storage-server-port' must be set"
|
||||
, "Run as a service node, option 'service-node-public-ip' must be set"
|
||||
};
|
||||
static const command_line::arg_descriptor<std::string> arg_public_ip = {
|
||||
"service-node-public-ip"
|
||||
|
@ -192,11 +192,7 @@ namespace cryptonote
|
|||
"service node."
|
||||
};
|
||||
static const command_line::arg_descriptor<uint16_t> arg_storage_server_port = {
|
||||
"storage-server-port"
|
||||
, "The port on which this service node's storage server is accessible. A listening "
|
||||
"storage server is required for service nodes. (This option is specified "
|
||||
"automatically when using Loki Launcher.)"
|
||||
, 0};
|
||||
"storage-server-port", "Deprecated option, ignored.", 0};
|
||||
static const command_line::arg_descriptor<uint16_t, false, true, 2> arg_quorumnet_port = {
|
||||
"quorumnet-port"
|
||||
, "The port on which this service node listen for direct connections from other "
|
||||
|
@ -211,7 +207,7 @@ namespace cryptonote
|
|||
val;
|
||||
}
|
||||
};
|
||||
static const command_line::arg_descriptor<bool> arg_lmq_quorumnet_public{
|
||||
static const command_line::arg_descriptor<bool> arg_omq_quorumnet_public{
|
||||
"lmq-public-quorumnet",
|
||||
"Allow the curve-enabled quorumnet address (for a Service Node) to be used for public RPC commands as if passed to --lmq-curve-public. "
|
||||
"Note that even without this option the quorumnet port can be used for RPC commands by --lmq-admin and --lmq-user pubkeys.",
|
||||
|
@ -364,7 +360,7 @@ namespace cryptonote
|
|||
command_line::add_arg(desc, integration_test::arg_hardforks_override);
|
||||
command_line::add_arg(desc, integration_test::arg_pipe_name);
|
||||
#endif
|
||||
command_line::add_arg(desc, arg_lmq_quorumnet_public);
|
||||
command_line::add_arg(desc, arg_omq_quorumnet_public);
|
||||
|
||||
miner::init_options(desc);
|
||||
BlockchainDB::init_options(desc);
|
||||
|
@ -396,19 +392,12 @@ namespace cryptonote
|
|||
|
||||
if (m_service_node) {
|
||||
/// TODO: parse these options early, before we start p2p server etc?
|
||||
m_storage_port = command_line::get_arg(vm, arg_storage_server_port);
|
||||
|
||||
m_quorumnet_port = command_line::get_arg(vm, arg_quorumnet_port);
|
||||
|
||||
bool storage_ok = true;
|
||||
if (m_storage_port == 0 && m_nettype != DEVNET) {
|
||||
MERROR("Please specify the port on which the storage server is listening with: '--" << arg_storage_server_port.name << " <port>'");
|
||||
storage_ok = false;
|
||||
}
|
||||
|
||||
bool args_okay = true;
|
||||
if (m_quorumnet_port == 0) {
|
||||
MERROR("Quorumnet port cannot be 0; please specify a valid port to listen on with: '--" << arg_quorumnet_port.name << " <port>'");
|
||||
storage_ok = false;
|
||||
args_okay = false;
|
||||
}
|
||||
|
||||
const std::string pub_ip = command_line::get_arg(vm, arg_public_ip);
|
||||
|
@ -416,7 +405,7 @@ namespace cryptonote
|
|||
{
|
||||
if (!epee::string_tools::get_ip_int32_from_string(m_sn_public_ip, pub_ip)) {
|
||||
MERROR("Unable to parse IPv4 public address from: " << pub_ip);
|
||||
storage_ok = false;
|
||||
args_okay = false;
|
||||
}
|
||||
|
||||
if (!epee::net_utils::is_ip_public(m_sn_public_ip)) {
|
||||
|
@ -424,25 +413,21 @@ namespace cryptonote
|
|||
MWARNING("Address given for public-ip is not public; allowing it because dev-allow-local-ips was specified. This service node WILL NOT WORK ON THE PUBLIC OXEN NETWORK!");
|
||||
} else {
|
||||
MERROR("Address given for public-ip is not public: " << epee::string_tools::get_ip_string_from_int32(m_sn_public_ip));
|
||||
storage_ok = false;
|
||||
args_okay = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
MERROR("Please specify an IPv4 public address which the service node & storage server is accessible from with: '--" << arg_public_ip.name << " <ip address>'");
|
||||
storage_ok = false;
|
||||
args_okay = false;
|
||||
}
|
||||
|
||||
if (!storage_ok) {
|
||||
MERROR("IMPORTANT: All service node operators are now required to run the oxen storage "
|
||||
<< "server and provide the public ip and ports on which it can be accessed on the internet.");
|
||||
if (!args_okay) {
|
||||
MERROR("IMPORTANT: One or more required service node-related configuration settings/options were omitted or invalid; "
|
||||
<< "please fix them and restart oxend.");
|
||||
return false;
|
||||
}
|
||||
|
||||
MGINFO("Storage server endpoint is set to: "
|
||||
<< (epee::net_utils::ipv4_network_address{ m_sn_public_ip, m_storage_port }).str());
|
||||
|
||||
}
|
||||
|
||||
return true;
|
||||
|
@ -1014,9 +999,9 @@ namespace cryptonote
|
|||
}
|
||||
}
|
||||
|
||||
oxenmq::AuthLevel core::lmq_check_access(const crypto::x25519_public_key& pubkey) const {
|
||||
auto it = m_lmq_auth.find(pubkey);
|
||||
if (it != m_lmq_auth.end())
|
||||
oxenmq::AuthLevel core::omq_check_access(const crypto::x25519_public_key& pubkey) const {
|
||||
auto it = m_omq_auth.find(pubkey);
|
||||
if (it != m_omq_auth.end())
|
||||
return it->second;
|
||||
return oxenmq::AuthLevel::denied;
|
||||
}
|
||||
|
@ -1032,23 +1017,23 @@ namespace cryptonote
|
|||
// check_sn is whether we check an incoming key against known service nodes (and thus return
|
||||
// "true" for the service node access if it checks out).
|
||||
//
|
||||
oxenmq::AuthLevel core::lmq_allow(std::string_view ip, std::string_view x25519_pubkey_str, oxenmq::AuthLevel default_auth) {
|
||||
oxenmq::AuthLevel core::omq_allow(std::string_view ip, std::string_view x25519_pubkey_str, oxenmq::AuthLevel default_auth) {
|
||||
using namespace oxenmq;
|
||||
AuthLevel auth = default_auth;
|
||||
if (x25519_pubkey_str.size() == sizeof(crypto::x25519_public_key)) {
|
||||
crypto::x25519_public_key x25519_pubkey;
|
||||
std::memcpy(x25519_pubkey.data, x25519_pubkey_str.data(), x25519_pubkey_str.size());
|
||||
auto user_auth = lmq_check_access(x25519_pubkey);
|
||||
auto user_auth = omq_check_access(x25519_pubkey);
|
||||
if (user_auth >= AuthLevel::basic) {
|
||||
if (user_auth > auth)
|
||||
auth = user_auth;
|
||||
MCINFO("lmq", "Incoming " << auth << "-authenticated connection");
|
||||
MCINFO("omq", "Incoming " << auth << "-authenticated connection");
|
||||
}
|
||||
|
||||
MCINFO("lmq", "Incoming [" << auth << "] curve connection from " << ip << "/" << x25519_pubkey);
|
||||
MCINFO("omq", "Incoming [" << auth << "] curve connection from " << ip << "/" << x25519_pubkey);
|
||||
}
|
||||
else {
|
||||
MCINFO("lmq", "Incoming [" << auth << "] plain connection from " << ip);
|
||||
MCINFO("omq", "Incoming [" << auth << "] plain connection from " << ip);
|
||||
}
|
||||
return auth;
|
||||
}
|
||||
|
@ -1056,23 +1041,23 @@ namespace cryptonote
|
|||
void core::init_oxenmq(const boost::program_options::variables_map& vm) {
|
||||
using namespace oxenmq;
|
||||
MGINFO("Starting oxenmq");
|
||||
m_lmq = std::make_unique<OxenMQ>(
|
||||
m_omq = std::make_unique<OxenMQ>(
|
||||
tools::copy_guts(m_service_keys.pub_x25519),
|
||||
tools::copy_guts(m_service_keys.key_x25519),
|
||||
m_service_node,
|
||||
[this](std::string_view x25519_pk) { return m_service_node_list.remote_lookup(x25519_pk); },
|
||||
[](LogLevel level, const char *file, int line, std::string msg) {
|
||||
// What a lovely interface (<-- sarcasm)
|
||||
if (ELPP->vRegistry()->allowed(easylogging_level(level), "lmq"))
|
||||
el::base::Writer(easylogging_level(level), file, line, ELPP_FUNC, el::base::DispatchAction::NormalLog).construct("lmq") << msg;
|
||||
if (ELPP->vRegistry()->allowed(easylogging_level(level), "omq"))
|
||||
el::base::Writer(easylogging_level(level), file, line, ELPP_FUNC, el::base::DispatchAction::NormalLog).construct("omq") << msg;
|
||||
},
|
||||
oxenmq::LogLevel::trace
|
||||
);
|
||||
|
||||
// ping.ping: a simple debugging target for pinging the lmq listener
|
||||
m_lmq->add_category("ping", Access{AuthLevel::none})
|
||||
// ping.ping: a simple debugging target for pinging the omq listener
|
||||
m_omq->add_category("ping", Access{AuthLevel::none})
|
||||
.add_request_command("ping", [](Message& m) {
|
||||
MCINFO("lmq", "Received ping from " << m.conn);
|
||||
MCINFO("omq", "Received ping from " << m.conn);
|
||||
m.send_reply("pong");
|
||||
})
|
||||
;
|
||||
|
@ -1085,9 +1070,9 @@ namespace cryptonote
|
|||
listen_ip = "0.0.0.0";
|
||||
std::string qnet_listen = "tcp://" + listen_ip + ":" + std::to_string(m_quorumnet_port);
|
||||
MGINFO("- listening on " << qnet_listen << " (quorumnet)");
|
||||
m_lmq->listen_curve(qnet_listen,
|
||||
[this, public_=command_line::get_arg(vm, arg_lmq_quorumnet_public)](std::string_view ip, std::string_view pk, bool) {
|
||||
return lmq_allow(ip, pk, public_ ? AuthLevel::basic : AuthLevel::none);
|
||||
m_omq->listen_curve(qnet_listen,
|
||||
[this, public_=command_line::get_arg(vm, arg_omq_quorumnet_public)](std::string_view ip, std::string_view pk, bool) {
|
||||
return omq_allow(ip, pk, public_ ? AuthLevel::basic : AuthLevel::none);
|
||||
});
|
||||
|
||||
m_quorumnet_state = quorumnet_new(*this);
|
||||
|
@ -1097,20 +1082,20 @@ namespace cryptonote
|
|||
}
|
||||
|
||||
void core::start_oxenmq() {
|
||||
update_lmq_sns(); // Ensure we have SNs set for the current block before starting
|
||||
update_omq_sns(); // Ensure we have SNs set for the current block before starting
|
||||
|
||||
if (m_service_node)
|
||||
{
|
||||
m_pulse_thread_id = m_lmq->add_tagged_thread("pulse");
|
||||
m_lmq->add_timer([this]() { pulse::main(m_quorumnet_state, *this); },
|
||||
m_pulse_thread_id = m_omq->add_tagged_thread("pulse");
|
||||
m_omq->add_timer([this]() { pulse::main(m_quorumnet_state, *this); },
|
||||
std::chrono::milliseconds(500),
|
||||
false,
|
||||
m_pulse_thread_id);
|
||||
m_lmq->add_timer([this]() {this->check_service_node_time();},
|
||||
m_omq->add_timer([this]() {this->check_service_node_time();},
|
||||
5s,
|
||||
false);
|
||||
}
|
||||
m_lmq->start();
|
||||
m_omq->start();
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------------------------
|
||||
|
@ -1126,7 +1111,7 @@ namespace cryptonote
|
|||
#endif
|
||||
if (m_quorumnet_state)
|
||||
quorumnet_delete(m_quorumnet_state);
|
||||
m_lmq.reset();
|
||||
m_omq.reset();
|
||||
m_service_node_list.store();
|
||||
m_miner.stop();
|
||||
m_mempool.deinit();
|
||||
|
@ -1682,7 +1667,7 @@ namespace cryptonote
|
|||
});
|
||||
|
||||
if (proofversion >= MIN_TIMESTAMP_VERSION && x_pkey) {
|
||||
m_lmq->request(
|
||||
m_omq->request(
|
||||
tools::view_guts(x_pkey),
|
||||
"quorum.timestamp",
|
||||
[this, pubkey](bool success, std::vector<std::string> data) {
|
||||
|
@ -1944,10 +1929,10 @@ namespace cryptonote
|
|||
auto hf_version = get_hard_fork_version(height);
|
||||
//TODO: remove after HF18
|
||||
if (hf_version < HF_VERSION_PROOF_BTENC) {
|
||||
NOTIFY_UPTIME_PROOF::request req = m_service_node_list.generate_uptime_proof(m_sn_public_ip, m_storage_port, m_storage_lmq_port, m_quorumnet_port);
|
||||
NOTIFY_UPTIME_PROOF::request req = m_service_node_list.generate_uptime_proof(m_sn_public_ip, storage_https_port(), storage_omq_port(), m_quorumnet_port);
|
||||
relayed = get_protocol()->relay_uptime_proof(req, fake_context);
|
||||
} else {
|
||||
auto proof = m_service_node_list.generate_uptime_proof(m_sn_public_ip, m_storage_port, m_storage_lmq_port, ss_version, m_quorumnet_port, lokinet_version);
|
||||
auto proof = m_service_node_list.generate_uptime_proof(m_sn_public_ip, storage_https_port(), storage_omq_port(), ss_version, m_quorumnet_port, lokinet_version);
|
||||
NOTIFY_BTENCODED_UPTIME_PROOF::request req = proof.generate_request();
|
||||
relayed = get_protocol()->relay_btencoded_uptime_proof(req, fake_context);
|
||||
}
|
||||
|
@ -1965,7 +1950,7 @@ namespace cryptonote
|
|||
{
|
||||
oxenmq::pubkey_set added;
|
||||
added.insert(tools::copy_guts(pkey));
|
||||
m_lmq->update_active_sns(added, {} /*removed*/);
|
||||
m_omq->update_active_sns(added, {} /*removed*/);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
@ -1982,7 +1967,7 @@ namespace cryptonote
|
|||
{
|
||||
oxenmq::pubkey_set added;
|
||||
added.insert(tools::copy_guts(pkey));
|
||||
m_lmq->update_active_sns(added, {} /*removed*/);
|
||||
m_omq->update_active_sns(added, {} /*removed*/);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
@ -2245,12 +2230,12 @@ namespace cryptonote
|
|||
return true;
|
||||
}
|
||||
|
||||
void core::update_lmq_sns()
|
||||
void core::update_omq_sns()
|
||||
{
|
||||
// TODO: let callers (e.g. lokinet, ss) subscribe to callbacks when this fires
|
||||
oxenmq::pubkey_set active_sns;
|
||||
m_service_node_list.copy_active_x25519_pubkeys(std::inserter(active_sns, active_sns.end()));
|
||||
m_lmq->set_active_sns(std::move(active_sns));
|
||||
m_omq->set_active_sns(std::move(active_sns));
|
||||
}
|
||||
//-----------------------------------------------------------------------------------------------
|
||||
crypto::hash core::get_tail_id() const
|
||||
|
@ -2338,11 +2323,11 @@ namespace cryptonote
|
|||
|
||||
m_service_node_list.for_each_service_node_info_and_proof(sn_pks.begin(), sn_pks.end(), [&](auto& pk, auto& sni, auto& proof) {
|
||||
if (pk != m_service_keys.pub && proof.proof->public_ip == m_sn_public_ip &&
|
||||
(proof.proof->qnet_port == m_quorumnet_port || proof.proof->storage_port == m_storage_port || proof.proof->storage_port == m_storage_lmq_port))
|
||||
(proof.proof->qnet_port == m_quorumnet_port || proof.proof->storage_https_port == storage_https_port() || proof.proof->storage_omq_port == storage_omq_port()))
|
||||
MGINFO_RED(
|
||||
"Another service node (" << pk << ") is broadcasting the same public IP and ports as this service node (" <<
|
||||
epee::string_tools::get_ip_string_from_int32(m_sn_public_ip) << ":" << proof.proof->qnet_port << "[qnet], :" <<
|
||||
proof.proof->storage_port << "[SS-HTTP], :" << proof.proof->storage_lmq_port << "[SS-LMQ]). "
|
||||
proof.proof->storage_https_port << "[SS-HTTP], :" << proof.proof->storage_omq_port << "[SS-LMQ]). "
|
||||
"This will lead to deregistration of one or both service nodes if not corrected. "
|
||||
"(Do both service nodes have the correct IP for the service-node-public-ip setting?)");
|
||||
});
|
||||
|
|
|
@ -350,7 +350,7 @@ namespace cryptonote
|
|||
|
||||
/// Called (from service_node_quorum_cop) to tell quorumnet that it need to refresh its list of
|
||||
/// active SNs.
|
||||
void update_lmq_sns();
|
||||
void update_omq_sns();
|
||||
|
||||
/**
|
||||
* @brief get the cryptonote protocol instance
|
||||
|
@ -698,8 +698,8 @@ namespace cryptonote
|
|||
tx_memory_pool &get_pool() { return m_mempool; }
|
||||
|
||||
/// Returns a reference to the OxenMQ object. Must not be called before init(), and should not
|
||||
/// be used for any lmq communication until after start_oxenmq() has been called.
|
||||
oxenmq::OxenMQ& get_lmq() { return *m_lmq; }
|
||||
/// be used for any omq communication until after start_oxenmq() has been called.
|
||||
oxenmq::OxenMQ& get_omq() { return *m_omq; }
|
||||
|
||||
/**
|
||||
* @copydoc miner::on_synchronized
|
||||
|
@ -1024,10 +1024,11 @@ namespace cryptonote
|
|||
|
||||
/// Time point at which the storage server and lokinet last pinged us
|
||||
std::atomic<time_t> m_last_storage_server_ping, m_last_lokinet_ping;
|
||||
std::atomic<uint16_t> m_storage_lmq_port;
|
||||
std::atomic<uint16_t> m_storage_https_port, m_storage_omq_port;
|
||||
|
||||
uint32_t sn_public_ip() const { return m_sn_public_ip; }
|
||||
uint16_t storage_port() const { return m_storage_port; }
|
||||
uint16_t storage_https_port() const { return m_storage_https_port; }
|
||||
uint16_t storage_omq_port() const { return m_storage_omq_port; }
|
||||
uint16_t quorumnet_port() const { return m_quorumnet_port; }
|
||||
|
||||
/**
|
||||
|
@ -1144,7 +1145,7 @@ namespace cryptonote
|
|||
* Checks the given x25519 pubkey against the configured access lists and, if allowed, returns
|
||||
* the access level; otherwise returns `denied`.
|
||||
*/
|
||||
oxenmq::AuthLevel lmq_check_access(const crypto::x25519_public_key& pubkey) const;
|
||||
oxenmq::AuthLevel omq_check_access(const crypto::x25519_public_key& pubkey) const;
|
||||
|
||||
/**
|
||||
* @brief Initializes OxenMQ object, called during init().
|
||||
|
@ -1166,7 +1167,7 @@ namespace cryptonote
|
|||
/**
|
||||
* Returns whether to allow the connection and, if so, at what authentication level.
|
||||
*/
|
||||
oxenmq::AuthLevel lmq_allow(std::string_view ip, std::string_view x25519_pubkey, oxenmq::AuthLevel default_auth);
|
||||
oxenmq::AuthLevel omq_allow(std::string_view ip, std::string_view x25519_pubkey, oxenmq::AuthLevel default_auth);
|
||||
|
||||
/**
|
||||
* @brief Internal use only!
|
||||
|
@ -1174,7 +1175,7 @@ namespace cryptonote
|
|||
* This returns a mutable reference to the internal auth level map that OxenMQ uses, for
|
||||
* internal use only.
|
||||
*/
|
||||
std::unordered_map<crypto::x25519_public_key, oxenmq::AuthLevel>& _lmq_auth_level_map() { return m_lmq_auth; }
|
||||
std::unordered_map<crypto::x25519_public_key, oxenmq::AuthLevel>& _omq_auth_level_map() { return m_omq_auth; }
|
||||
oxenmq::TaggedThreadID const &pulse_thread_id() const { return *m_pulse_thread_id; }
|
||||
|
||||
/// Service Node's storage server and lokinet version
|
||||
|
@ -1244,13 +1245,12 @@ namespace cryptonote
|
|||
bool m_service_node; // True if running in service node mode
|
||||
service_keys m_service_keys; // Always set, even for non-SN mode -- these can be used for public oxenmq rpc
|
||||
|
||||
/// Service Node's public IP and storage server port (http and oxenmq)
|
||||
/// Service Node's public IP and qnet ports
|
||||
uint32_t m_sn_public_ip;
|
||||
uint16_t m_storage_port;
|
||||
uint16_t m_quorumnet_port;
|
||||
|
||||
/// OxenMQ main object. Gets created during init().
|
||||
std::unique_ptr<oxenmq::OxenMQ> m_lmq;
|
||||
std::unique_ptr<oxenmq::OxenMQ> m_omq;
|
||||
|
||||
// Internal opaque data object managed by cryptonote_protocol/quorumnet.cpp. void pointer to
|
||||
// avoid linking issues (protocol does not link against core).
|
||||
|
@ -1258,7 +1258,7 @@ namespace cryptonote
|
|||
|
||||
/// Stores x25519 -> access level for LMQ authentication.
|
||||
/// Not to be modified after the LMQ listener starts.
|
||||
std::unordered_map<crypto::x25519_public_key, oxenmq::AuthLevel> m_lmq_auth;
|
||||
std::unordered_map<crypto::x25519_public_key, oxenmq::AuthLevel> m_omq_auth;
|
||||
|
||||
size_t block_sync_size;
|
||||
|
||||
|
|
|
@ -2753,14 +2753,14 @@ namespace service_nodes
|
|||
size_t buf_size;
|
||||
crypto::hash result;
|
||||
|
||||
auto buf = tools::memcpy_le(proof.pubkey.data, proof.timestamp, proof.public_ip, proof.storage_port, proof.pubkey_ed25519.data, proof.qnet_port, proof.storage_lmq_port);
|
||||
auto buf = tools::memcpy_le(proof.pubkey.data, proof.timestamp, proof.public_ip, proof.storage_https_port, proof.pubkey_ed25519.data, proof.qnet_port, proof.storage_omq_port);
|
||||
buf_size = buf.size();
|
||||
crypto::cn_fast_hash(buf.data(), buf_size, result);
|
||||
return result;
|
||||
}
|
||||
|
||||
cryptonote::NOTIFY_UPTIME_PROOF::request service_node_list::generate_uptime_proof(
|
||||
uint32_t public_ip, uint16_t storage_port, uint16_t storage_lmq_port, uint16_t quorumnet_port) const
|
||||
uint32_t public_ip, uint16_t storage_https_port, uint16_t storage_omq_port, uint16_t quorumnet_port) const
|
||||
{
|
||||
assert(m_service_node_keys);
|
||||
const auto& keys = *m_service_node_keys;
|
||||
|
@ -2769,8 +2769,8 @@ namespace service_nodes
|
|||
result.timestamp = time(nullptr);
|
||||
result.pubkey = keys.pub;
|
||||
result.public_ip = public_ip;
|
||||
result.storage_port = storage_port;
|
||||
result.storage_lmq_port = storage_lmq_port;
|
||||
result.storage_https_port = storage_https_port;
|
||||
result.storage_omq_port = storage_omq_port;
|
||||
result.qnet_port = quorumnet_port;
|
||||
result.pubkey_ed25519 = keys.pub_ed25519;
|
||||
|
||||
|
@ -2780,10 +2780,10 @@ namespace service_nodes
|
|||
return result;
|
||||
}
|
||||
|
||||
uptime_proof::Proof service_node_list::generate_uptime_proof(uint32_t public_ip, uint16_t storage_port, uint16_t storage_lmq_port, std::array<uint16_t, 3> ss_version, uint16_t quorumnet_port, std::array<uint16_t, 3> lokinet_version) const
|
||||
uptime_proof::Proof service_node_list::generate_uptime_proof(uint32_t public_ip, uint16_t storage_https_port, uint16_t storage_omq_port, std::array<uint16_t, 3> ss_version, uint16_t quorumnet_port, std::array<uint16_t, 3> lokinet_version) const
|
||||
{
|
||||
const auto& keys = *m_service_node_keys;
|
||||
return uptime_proof::Proof(public_ip, storage_port, storage_lmq_port, ss_version, quorumnet_port, lokinet_version, keys);
|
||||
return uptime_proof::Proof(public_ip, storage_https_port, storage_omq_port, ss_version, quorumnet_port, lokinet_version, keys);
|
||||
}
|
||||
|
||||
#ifdef __cpp_lib_erase_if // # (C++20)
|
||||
|
@ -2853,8 +2853,8 @@ namespace service_nodes
|
|||
//TODO remove after HF18
|
||||
bool proof_info::update(uint64_t ts,
|
||||
uint32_t ip,
|
||||
uint16_t s_port,
|
||||
uint16_t s_lmq_port,
|
||||
uint16_t s_https_port,
|
||||
uint16_t s_omq_port,
|
||||
uint16_t q_port,
|
||||
std::array<uint16_t, 3> ver,
|
||||
const crypto::ed25519_public_key& pk_ed,
|
||||
|
@ -2864,8 +2864,8 @@ namespace service_nodes
|
|||
if (!proof) proof = std::unique_ptr<uptime_proof::Proof>(new uptime_proof::Proof());
|
||||
update_db |= update_val(timestamp, ts);
|
||||
update_db |= update_val(proof->public_ip, ip);
|
||||
update_db |= update_val(proof->storage_port, s_port);
|
||||
update_db |= update_val(proof->storage_lmq_port, s_lmq_port);
|
||||
update_db |= update_val(proof->storage_https_port, s_https_port);
|
||||
update_db |= update_val(proof->storage_omq_port, s_omq_port);
|
||||
update_db |= update_val(proof->qnet_port, q_port);
|
||||
update_db |= update_val(proof->version, ver);
|
||||
update_db |= update_val(proof->pubkey_ed25519, pk_ed);
|
||||
|
@ -2973,7 +2973,7 @@ namespace service_nodes
|
|||
}
|
||||
|
||||
auto old_x25519 = iproof.pubkey_x25519;
|
||||
if (iproof.update(std::chrono::system_clock::to_time_t(now), proof.public_ip, proof.storage_port, proof.storage_lmq_port, proof.qnet_port, proof.snode_version, proof.pubkey_ed25519, derived_x25519_pubkey))
|
||||
if (iproof.update(std::chrono::system_clock::to_time_t(now), proof.public_ip, proof.storage_https_port, proof.storage_omq_port, proof.qnet_port, proof.snode_version, proof.pubkey_ed25519, derived_x25519_pubkey))
|
||||
iproof.store(proof.pubkey, m_blockchain);
|
||||
|
||||
if (now - x25519_map_last_pruned >= X25519_MAP_PRUNING_INTERVAL)
|
||||
|
|
|
@ -172,7 +172,7 @@ namespace service_nodes
|
|||
// caller's responsibility).
|
||||
bool update(uint64_t ts, std::unique_ptr<uptime_proof::Proof> new_proof, const crypto::x25519_public_key &pk_x2);
|
||||
// TODO: remove after HF18
|
||||
bool update(uint64_t ts, uint32_t ip, uint16_t s_port, uint16_t s_lmq_port, uint16_t q_port, std::array<uint16_t, 3> ver, const crypto::ed25519_public_key &pk_ed, const crypto::x25519_public_key &pk_x2);
|
||||
bool update(uint64_t ts, uint32_t ip, uint16_t s_https_port, uint16_t s_omq_port, uint16_t q_port, std::array<uint16_t, 3> ver, const crypto::ed25519_public_key &pk_ed, const crypto::x25519_public_key &pk_x2);
|
||||
|
||||
// Stores this record in the database.
|
||||
void store(const crypto::public_key &pubkey, cryptonote::Blockchain &blockchain);
|
||||
|
@ -529,11 +529,11 @@ namespace service_nodes
|
|||
/// Record public ip and storage port and add them to the service node list
|
||||
//TODO: remove after HF18
|
||||
cryptonote::NOTIFY_UPTIME_PROOF::request generate_uptime_proof(uint32_t public_ip,
|
||||
uint16_t storage_port,
|
||||
uint16_t storage_lmq_port,
|
||||
uint16_t storage_https_port,
|
||||
uint16_t storage_omq_port,
|
||||
uint16_t quorumnet_port) const;
|
||||
|
||||
uptime_proof::Proof generate_uptime_proof(uint32_t public_ip, uint16_t storage_port, uint16_t storage_lmq_port, std::array<uint16_t, 3> ss_version, uint16_t quorumnet_port, std::array<uint16_t, 3> lokinet_version) const;
|
||||
uptime_proof::Proof generate_uptime_proof(uint32_t public_ip, uint16_t storage_port, uint16_t storage_omq_port, std::array<uint16_t, 3> ss_version, uint16_t quorumnet_port, std::array<uint16_t, 3> lokinet_version) const;
|
||||
|
||||
//TODO: remove after HF18
|
||||
bool handle_uptime_proof(cryptonote::NOTIFY_UPTIME_PROOF::request const &proof, bool &my_uptime_proof_confirmation, crypto::x25519_public_key &x25519_pkey);
|
||||
|
|
|
@ -532,7 +532,7 @@ namespace service_nodes
|
|||
|
||||
// These feels out of place here because the hook system sucks: TODO replace it with
|
||||
// std::function hooks instead.
|
||||
m_core.update_lmq_sns();
|
||||
m_core.update_omq_sns();
|
||||
|
||||
return true;
|
||||
}
|
||||
|
|
|
@ -211,7 +211,7 @@ namespace service_nodes {
|
|||
// blocks out of sync and sending something that it thinks is legit.
|
||||
constexpr uint64_t VOTE_OR_TX_VERIFY_HEIGHT_BUFFER = 5;
|
||||
|
||||
constexpr std::array<uint16_t, 3> MIN_STORAGE_SERVER_VERSION{{2, 0, 7}};
|
||||
constexpr std::array<uint16_t, 3> MIN_STORAGE_SERVER_VERSION{{2, 0, 9}};
|
||||
constexpr std::array<uint16_t, 3> MIN_LOKINET_VERSION{{0, 8, 0}};
|
||||
|
||||
// The minimum accepted version number, broadcasted by Service Nodes via uptime proofs for each hardfork
|
||||
|
|
|
@ -14,7 +14,23 @@ namespace uptime_proof
|
|||
{
|
||||
|
||||
//Constructor for the uptime proof, will take the service node keys as a param and sign
|
||||
Proof::Proof(uint32_t sn_public_ip, uint16_t sn_storage_port, uint16_t sn_storage_lmq_port, const std::array<uint16_t, 3> ss_version, uint16_t quorumnet_port, const std::array<uint16_t, 3> lokinet_version, const service_nodes::service_node_keys& keys) : version{OXEN_VERSION}, pubkey{keys.pub}, timestamp{static_cast<uint64_t>(time(nullptr))}, public_ip{sn_public_ip}, storage_port{sn_storage_port}, pubkey_ed25519{keys.pub_ed25519},qnet_port{quorumnet_port}, storage_lmq_port{sn_storage_lmq_port}, storage_server_version{ss_version}
|
||||
Proof::Proof(
|
||||
uint32_t sn_public_ip,
|
||||
uint16_t sn_storage_https_port,
|
||||
uint16_t sn_storage_omq_port,
|
||||
const std::array<uint16_t, 3> ss_version,
|
||||
uint16_t quorumnet_port,
|
||||
const std::array<uint16_t, 3> lokinet_version,
|
||||
const service_nodes::service_node_keys& keys) :
|
||||
version{OXEN_VERSION},
|
||||
pubkey{keys.pub},
|
||||
timestamp{static_cast<uint64_t>(time(nullptr))},
|
||||
public_ip{sn_public_ip},
|
||||
pubkey_ed25519{keys.pub_ed25519},
|
||||
qnet_port{quorumnet_port},
|
||||
storage_https_port{sn_storage_https_port},
|
||||
storage_omq_port{sn_storage_omq_port},
|
||||
storage_server_version{ss_version}
|
||||
{
|
||||
this->lokinet_version = lokinet_version;
|
||||
crypto::hash hash = this->hash_uptime_proof();
|
||||
|
@ -41,7 +57,7 @@ Proof::Proof(const std::string& serialized_proof)
|
|||
//public_ip
|
||||
bool succeeded = epee::string_tools::get_ip_int32_from_string(public_ip, var::get<std::string>(bt_proof.at("ip")));
|
||||
//storage_port
|
||||
storage_port = static_cast<uint16_t>(get_int<unsigned>(bt_proof.at("s")));
|
||||
storage_https_port = static_cast<uint16_t>(get_int<unsigned>(bt_proof.at("shp")));
|
||||
//pubkey_ed25519
|
||||
pubkey_ed25519 = tools::make_from_guts<crypto::ed25519_public_key>(var::get<std::string>(bt_proof.at("pke")));
|
||||
//pubkey
|
||||
|
@ -51,8 +67,8 @@ Proof::Proof(const std::string& serialized_proof)
|
|||
std::memcpy(pubkey.data, pubkey_ed25519.data, 32);
|
||||
//qnet_port
|
||||
qnet_port = get_int<unsigned>(bt_proof.at("q"));
|
||||
//storage_lmq_port
|
||||
storage_lmq_port = get_int<unsigned>(bt_proof.at("slp"));
|
||||
//storage_omq_port
|
||||
storage_omq_port = get_int<unsigned>(bt_proof.at("sop"));
|
||||
//storage_version
|
||||
const bt_list& bt_storage_version = var::get<bt_list>(bt_proof.at("sv"));
|
||||
k = 0;
|
||||
|
@ -92,13 +108,13 @@ oxenmq::bt_dict Proof::bt_encode_uptime_proof() const
|
|||
//public_ip
|
||||
{"ip", epee::string_tools::get_ip_string_from_int32(public_ip)},
|
||||
//storage_port
|
||||
{"s", storage_port},
|
||||
{"shp", storage_https_port},
|
||||
//pubkey_ed25519
|
||||
{"pke", tools::view_guts(pubkey_ed25519)},
|
||||
//qnet_port
|
||||
{"q", qnet_port},
|
||||
//storage_lmq_port
|
||||
{"slp", storage_lmq_port},
|
||||
//storage_omq_port
|
||||
{"sop", storage_omq_port},
|
||||
//storage_version
|
||||
{"sv", oxenmq::bt_list{{storage_server_version[0], storage_server_version[1], storage_server_version[2]}}},
|
||||
//lokinet_version
|
||||
|
@ -132,18 +148,12 @@ bool operator==(const uptime_proof::Proof& lhs, const uptime_proof::Proof& rhs)
|
|||
(lhs.pubkey_ed25519 != rhs.pubkey_ed25519) ||
|
||||
(lhs.sig_ed25519 != rhs.sig_ed25519) ||
|
||||
(lhs.public_ip != rhs.public_ip) ||
|
||||
(lhs.storage_port != rhs.storage_port) ||
|
||||
(lhs.storage_lmq_port != rhs.storage_lmq_port) ||
|
||||
(lhs.storage_https_port != rhs.storage_https_port) ||
|
||||
(lhs.storage_omq_port != rhs.storage_omq_port) ||
|
||||
(lhs.qnet_port != rhs.qnet_port) ||
|
||||
(lhs.version[0] != rhs.version[0]) ||
|
||||
(lhs.version[1] != rhs.version[1]) ||
|
||||
(lhs.version[2] != rhs.version[2]) ||
|
||||
(lhs.storage_server_version[0] != rhs.storage_server_version[0]) ||
|
||||
(lhs.storage_server_version[1] != rhs.storage_server_version[1]) ||
|
||||
(lhs.storage_server_version[2] != rhs.storage_server_version[2]) ||
|
||||
(lhs.lokinet_version[0] != rhs.lokinet_version[0]) ||
|
||||
(lhs.lokinet_version[1] != rhs.lokinet_version[1]) ||
|
||||
(lhs.lokinet_version[2] != rhs.lokinet_version[2]))
|
||||
(lhs.version != rhs.version) ||
|
||||
(lhs.storage_server_version != rhs.storage_server_version) ||
|
||||
(lhs.lokinet_version != rhs.lokinet_version))
|
||||
result = false;
|
||||
|
||||
return result;
|
||||
|
|
|
@ -21,12 +21,12 @@ public:
|
|||
crypto::ed25519_public_key pubkey_ed25519;
|
||||
crypto::ed25519_signature sig_ed25519;
|
||||
uint32_t public_ip;
|
||||
uint16_t storage_port;
|
||||
uint16_t storage_lmq_port;
|
||||
uint16_t storage_https_port;
|
||||
uint16_t storage_omq_port;
|
||||
uint16_t qnet_port;
|
||||
|
||||
Proof() = default;
|
||||
Proof(uint32_t sn_public_ip, uint16_t sn_storage_port, uint16_t sn_storage_lmq_port, std::array<uint16_t, 3> ss_version, uint16_t quorumnet_port, std::array<uint16_t, 3> lokinet_version, const service_nodes::service_node_keys& keys);
|
||||
Proof(uint32_t sn_public_ip, uint16_t sn_storage_https_port, uint16_t sn_storage_omq_port, std::array<uint16_t, 3> ss_version, uint16_t quorumnet_port, std::array<uint16_t, 3> lokinet_version, const service_nodes::service_node_keys& keys);
|
||||
|
||||
Proof(const std::string& serialized_proof);
|
||||
oxenmq::bt_dict bt_encode_uptime_proof() const;
|
||||
|
|
|
@ -110,8 +110,8 @@ KV_SERIALIZE_MAP_CODE_BEGIN(NOTIFY_UPTIME_PROOF::request)
|
|||
KV_SERIALIZE_N(snode_version[2], "snode_version_patch")
|
||||
KV_SERIALIZE(timestamp)
|
||||
KV_SERIALIZE(public_ip)
|
||||
KV_SERIALIZE(storage_port)
|
||||
KV_SERIALIZE(storage_lmq_port)
|
||||
KV_SERIALIZE_N(storage_https_port, "storage_port")
|
||||
KV_SERIALIZE_N(storage_omq_port, "storage_lmq_port")
|
||||
KV_SERIALIZE(qnet_port)
|
||||
KV_SERIALIZE_VAL_POD_AS_BLOB(pubkey)
|
||||
KV_SERIALIZE_VAL_POD_AS_BLOB(sig)
|
||||
|
|
|
@ -259,8 +259,8 @@ namespace cryptonote
|
|||
crypto::ed25519_public_key pubkey_ed25519;
|
||||
crypto::ed25519_signature sig_ed25519;
|
||||
uint32_t public_ip;
|
||||
uint16_t storage_port;
|
||||
uint16_t storage_lmq_port;
|
||||
uint16_t storage_https_port;
|
||||
uint16_t storage_omq_port;
|
||||
uint16_t qnet_port;
|
||||
|
||||
KV_MAP_SERIALIZABLE
|
||||
|
|
|
@ -71,7 +71,7 @@ using pending_signature_set = std::unordered_set<pending_signature, pending_sign
|
|||
|
||||
struct QnetState {
|
||||
cryptonote::core &core;
|
||||
OxenMQ &lmq{core.get_lmq()};
|
||||
OxenMQ &omq{core.get_omq()};
|
||||
|
||||
// Track submitted blink txes here; unlike the blinks stored in the mempool we store these ones
|
||||
// more liberally to track submitted blinks, even if unsigned/unacceptable, while the mempool
|
||||
|
@ -205,7 +205,7 @@ void peer_relay_to_prepared_destinations(cryptonote::core &core, std::vector<pre
|
|||
{
|
||||
for (auto const &[x25519_string, connect_string]: destinations) {
|
||||
MINFO("Relaying data to " << to_hex(x25519_string) << " @ " << connect_string);
|
||||
core.get_lmq().send(x25519_string, command, std::move(data), send_option::hint{connect_string});
|
||||
core.get_omq().send(x25519_string, command, std::move(data), send_option::hint{connect_string});
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -261,7 +261,7 @@ public:
|
|||
std::unordered_set<crypto::public_key> exclude = {},
|
||||
bool include_workers = false
|
||||
)
|
||||
: lmq{qnet.lmq} {
|
||||
: omq{qnet.omq} {
|
||||
|
||||
const auto& keys = qnet.core.get_service_keys();
|
||||
assert(qnet.core.service_node());
|
||||
|
@ -319,7 +319,7 @@ public:
|
|||
}
|
||||
|
||||
private:
|
||||
OxenMQ &lmq;
|
||||
OxenMQ &omq;
|
||||
|
||||
/// Looks up a pubkey in known remotes and adds it to `peers`. If strong, it is added with an
|
||||
/// address, otherwise it is added with an empty address. If the element already exists, it
|
||||
|
@ -435,9 +435,9 @@ private:
|
|||
for (auto &peer : peers) {
|
||||
MTRACE("Relaying " << cmd << " to peer " << to_hex(peer.first) << (peer.second.empty() ? " (if connected)"s : " @ " + peer.second));
|
||||
if (peer.second.empty())
|
||||
lmq.send(peer.first, cmd, relay_data[I]..., send_option::optional{});
|
||||
omq.send(peer.first, cmd, relay_data[I]..., send_option::optional{});
|
||||
else
|
||||
lmq.send(peer.first, cmd, relay_data[I]..., send_option::hint{peer.second});
|
||||
omq.send(peer.first, cmd, relay_data[I]..., send_option::hint{peer.second});
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -797,10 +797,10 @@ void process_blink_signatures(QnetState &qnet, const std::shared_ptr<blink_tx> &
|
|||
if (reply_tag && reply_conn) {
|
||||
if (became_approved) {
|
||||
MINFO("Blink tx became approved; sending result back to originating node");
|
||||
qnet.lmq.send(reply_conn, "bl.good", bt_serialize(bt_dict{{"!", reply_tag}}), send_option::optional{});
|
||||
qnet.omq.send(reply_conn, "bl.good", bt_serialize(bt_dict{{"!", reply_tag}}), send_option::optional{});
|
||||
} else if (became_rejected) {
|
||||
MINFO("Blink tx became rejected; sending result back to originating node");
|
||||
qnet.lmq.send(reply_conn, "bl.bad", bt_serialize(bt_dict{{"!", reply_tag}}), send_option::optional{});
|
||||
qnet.omq.send(reply_conn, "bl.bad", bt_serialize(bt_dict{{"!", reply_tag}}), send_option::optional{});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1602,7 +1602,7 @@ void handle_pulse_participation_bit_or_bitset(Message &m, QnetState& qnet, bool
|
|||
throw std::invalid_argument(std::string(INVALID_ARG_PREFIX) + tag + "'");
|
||||
}
|
||||
|
||||
qnet.lmq.job([&qnet, data = std::move(msg)]() { pulse::handle_message(&qnet, data); }, qnet.core.pulse_thread_id());
|
||||
qnet.omq.job([&qnet, data = std::move(msg)]() { pulse::handle_message(&qnet, data); }, qnet.core.pulse_thread_id());
|
||||
}
|
||||
|
||||
void handle_pulse_block_template(Message &m, QnetState &qnet)
|
||||
|
@ -1619,7 +1619,7 @@ void handle_pulse_block_template(Message &m, QnetState &qnet)
|
|||
else
|
||||
throw std::invalid_argument(std::string(INVALID_ARG_PREFIX) + tag + "'");
|
||||
|
||||
qnet.lmq.job([&qnet, data = std::move(msg)]() { pulse::handle_message(&qnet, data); }, qnet.core.pulse_thread_id());
|
||||
qnet.omq.job([&qnet, data = std::move(msg)]() { pulse::handle_message(&qnet, data); }, qnet.core.pulse_thread_id());
|
||||
}
|
||||
|
||||
void handle_pulse_random_value_hash(Message &m, QnetState &qnet)
|
||||
|
@ -1642,7 +1642,7 @@ void handle_pulse_random_value_hash(Message &m, QnetState &qnet)
|
|||
throw std::invalid_argument(std::string(INVALID_ARG_PREFIX) + tag + "'");
|
||||
}
|
||||
|
||||
qnet.lmq.job([&qnet, data = std::move(msg)]() { pulse::handle_message(&qnet, data); }, qnet.core.pulse_thread_id());
|
||||
qnet.omq.job([&qnet, data = std::move(msg)]() { pulse::handle_message(&qnet, data); }, qnet.core.pulse_thread_id());
|
||||
}
|
||||
|
||||
void handle_pulse_random_value(Message &m, QnetState &qnet)
|
||||
|
@ -1663,7 +1663,7 @@ void handle_pulse_random_value(Message &m, QnetState &qnet)
|
|||
throw std::invalid_argument(std::string(INVALID_ARG_PREFIX) + tag + "'");
|
||||
}
|
||||
|
||||
qnet.lmq.job([&qnet, data = std::move(msg)]() { pulse::handle_message(&qnet, data); }, qnet.core.pulse_thread_id());
|
||||
qnet.omq.job([&qnet, data = std::move(msg)]() { pulse::handle_message(&qnet, data); }, qnet.core.pulse_thread_id());
|
||||
}
|
||||
|
||||
void handle_pulse_signed_block(Message &m, QnetState &qnet)
|
||||
|
@ -1682,7 +1682,7 @@ void handle_pulse_signed_block(Message &m, QnetState &qnet)
|
|||
throw std::invalid_argument("Invalid pulse signed block: missing required field '"s + tag + "'");
|
||||
}
|
||||
|
||||
qnet.lmq.job([&qnet, data = std::move(msg)]() { pulse::handle_message(&qnet, data); }, qnet.core.pulse_thread_id());
|
||||
qnet.omq.job([&qnet, data = std::move(msg)]() { pulse::handle_message(&qnet, data); }, qnet.core.pulse_thread_id());
|
||||
}
|
||||
|
||||
} // end empty namespace
|
||||
|
@ -1701,14 +1701,14 @@ void init_core_callbacks() {
|
|||
|
||||
namespace {
|
||||
void setup_endpoints(cryptonote::core& core, void* obj) {
|
||||
auto& lmq = core.get_lmq();
|
||||
auto& omq = core.get_omq();
|
||||
|
||||
if (core.service_node()) {
|
||||
if (!obj)
|
||||
throw std::logic_error{"qnet initialization failure: quorumnet_new must be called for service node operation"};
|
||||
auto& qnet = QnetState::from(obj);
|
||||
// quorum.*: commands between quorum members, requires that both side of the connection is a SN
|
||||
lmq.add_category("quorum", Access{AuthLevel::none, true /*remote sn*/, true /*local sn*/}, 2 /*reserved threads*/)
|
||||
omq.add_category("quorum", Access{AuthLevel::none, true /*remote sn*/, true /*local sn*/}, 2 /*reserved threads*/)
|
||||
// Receives an obligation vote
|
||||
.add_command("vote_ob", [&qnet](Message& m) { handle_obligation_vote(m, qnet); })
|
||||
// Receives blink tx signatures or rejections between quorum members (either original or
|
||||
|
@ -1719,13 +1719,13 @@ void setup_endpoints(cryptonote::core& core, void* obj) {
|
|||
;
|
||||
|
||||
// blink.*: commands sent to blink quorum members from anyone (e.g. blink submission)
|
||||
lmq.add_category("blink", Access{AuthLevel::none, false /*remote sn*/, true /*local sn*/}, 1 /*reserved thread*/)
|
||||
omq.add_category("blink", Access{AuthLevel::none, false /*remote sn*/, true /*local sn*/}, 1 /*reserved thread*/)
|
||||
// Receives a new blink tx submission from an external node, or forward from other quorum
|
||||
// members who received it from an external node.
|
||||
.add_command("submit", [&qnet](Message& m) { handle_blink(m, qnet); })
|
||||
;
|
||||
|
||||
lmq.add_category(PULSE_CMD_CATEGORY, Access{AuthLevel::none, true /*remote sn*/, true /*local sn*/}, 1 /*reserved thread*/)
|
||||
omq.add_category(PULSE_CMD_CATEGORY, Access{AuthLevel::none, true /*remote sn*/, true /*local sn*/}, 1 /*reserved thread*/)
|
||||
.add_command(PULSE_CMD_VALIDATOR_BIT, [&qnet](Message& m) { handle_pulse_participation_bit_or_bitset(m, qnet, false /*bitset*/); })
|
||||
.add_command(PULSE_CMD_VALIDATOR_BITSET, [&qnet](Message& m) { handle_pulse_participation_bit_or_bitset(m, qnet, true /*bitset*/); })
|
||||
.add_command(PULSE_CMD_BLOCK_TEMPLATE, [&qnet](Message& m) { handle_pulse_block_template(m, qnet); })
|
||||
|
@ -1736,7 +1736,7 @@ void setup_endpoints(cryptonote::core& core, void* obj) {
|
|||
}
|
||||
|
||||
// bl.*: responses to blinks sent from quorum members back to the node who submitted the blink
|
||||
lmq.add_category("bl", Access{AuthLevel::none, true /*remote sn*/, false /*local sn*/})
|
||||
omq.add_category("bl", Access{AuthLevel::none, true /*remote sn*/, false /*local sn*/})
|
||||
// Message sent back to the blink initiator that the transaction was NOT relayed, either
|
||||
// because the height was invalid or the quorum checksum failed. This is only sent by the
|
||||
// entry point service nodes into the quorum to let it know the tx verification has not
|
||||
|
@ -1760,13 +1760,13 @@ void setup_endpoints(cryptonote::core& core, void* obj) {
|
|||
// 8.x.1 (i.e. the first post-hard-fork release): remove the aliases since no 7.1.x nodes will
|
||||
// be left.
|
||||
|
||||
lmq.add_command_alias("vote_ob", "quorum.vote_ob");
|
||||
lmq.add_command_alias("blink_sign", "quorum.blink_sign");
|
||||
lmq.add_command_alias("timestamp", "quorum.timestamp");
|
||||
lmq.add_command_alias("blink", "blink.submit");
|
||||
lmq.add_command_alias("bl_nostart", "bl.nostart");
|
||||
lmq.add_command_alias("bl_bad", "bl.bad");
|
||||
lmq.add_command_alias("bl_good", "bl.good");
|
||||
omq.add_command_alias("vote_ob", "quorum.vote_ob");
|
||||
omq.add_command_alias("blink_sign", "quorum.blink_sign");
|
||||
omq.add_command_alias("timestamp", "quorum.timestamp");
|
||||
omq.add_command_alias("blink", "blink.submit");
|
||||
omq.add_command_alias("bl_nostart", "bl.nostart");
|
||||
omq.add_command_alias("bl_bad", "bl.bad");
|
||||
omq.add_command_alias("bl_good", "bl.good");
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -271,7 +271,7 @@ void daemon::init_options(boost::program_options::options_description& option_sp
|
|||
node_server::init_options(option_spec);
|
||||
cryptonote::rpc::core_rpc_server::init_options(option_spec, hidden);
|
||||
cryptonote::rpc::http_server::init_options(option_spec, hidden);
|
||||
cryptonote::rpc::init_lmq_options(option_spec);
|
||||
cryptonote::rpc::init_omq_options(option_spec);
|
||||
quorumnet::init_core_callbacks();
|
||||
}
|
||||
|
||||
|
@ -308,7 +308,7 @@ bool daemon::run(bool interactive)
|
|||
throw std::runtime_error("Failed to start core");
|
||||
|
||||
MGINFO("Starting OxenMQ");
|
||||
lmq_rpc = std::make_unique<cryptonote::rpc::lmq_rpc>(*core, *rpc, vm);
|
||||
omq_rpc = std::make_unique<cryptonote::rpc::omq_rpc>(*core, *rpc, vm);
|
||||
core->start_oxenmq();
|
||||
|
||||
if (http_rpc_admin) {
|
||||
|
|
|
@ -78,7 +78,7 @@ private:
|
|||
std::unique_ptr<node_server> p2p;
|
||||
std::unique_ptr<cryptonote::rpc::core_rpc_server> rpc;
|
||||
std::optional<cryptonote::rpc::http_server> http_rpc_admin, http_rpc_public;
|
||||
std::unique_ptr<cryptonote::rpc::lmq_rpc> lmq_rpc;
|
||||
std::unique_ptr<cryptonote::rpc::omq_rpc> omq_rpc;
|
||||
};
|
||||
|
||||
} // namespace daemonize
|
||||
|
|
|
@ -1667,8 +1667,8 @@ static void append_printable_service_node_list_entry(cryptonote::network_type ne
|
|||
if (entry.public_ip == "0.0.0.0")
|
||||
stream << "(Awaiting confirmation from network)";
|
||||
else
|
||||
stream << entry.public_ip << " :" << entry.storage_port << " (storage), :" << entry.storage_lmq_port
|
||||
<< " (storage lmq), :" << entry.quorumnet_port << " (quorumnet)";
|
||||
stream << entry.public_ip << " :" << entry.storage_port << " (storage https), :" << entry.storage_lmq_port
|
||||
<< " (storage omq), :" << entry.quorumnet_port << " (quorumnet)";
|
||||
|
||||
stream << "\n";
|
||||
if (detailed_view)
|
||||
|
|
|
@ -2330,8 +2330,8 @@ namespace cryptonote { namespace rpc {
|
|||
{
|
||||
res.service_node_state.service_node_pubkey = std::move(get_service_node_key_res.service_node_pubkey);
|
||||
res.service_node_state.public_ip = epee::string_tools::get_ip_string_from_int32(m_core.sn_public_ip());
|
||||
res.service_node_state.storage_port = m_core.storage_port();
|
||||
res.service_node_state.storage_lmq_port = m_core.m_storage_lmq_port;
|
||||
res.service_node_state.storage_port = m_core.storage_https_port();
|
||||
res.service_node_state.storage_lmq_port = m_core.storage_omq_port();
|
||||
res.service_node_state.quorumnet_port = m_core.quorumnet_port();
|
||||
res.service_node_state.pubkey_ed25519 = std::move(get_service_node_key_res.service_node_ed25519_pubkey);
|
||||
res.service_node_state.pubkey_x25519 = std::move(get_service_node_key_res.service_node_x25519_pubkey);
|
||||
|
@ -3051,8 +3051,8 @@ namespace cryptonote { namespace rpc {
|
|||
entry.lokinet_version = proof.proof->lokinet_version;
|
||||
entry.storage_server_version = proof.proof->storage_server_version;
|
||||
entry.public_ip = epee::string_tools::get_ip_string_from_int32(proof.proof->public_ip);
|
||||
entry.storage_port = proof.proof->storage_port;
|
||||
entry.storage_lmq_port = proof.proof->storage_lmq_port;
|
||||
entry.storage_port = proof.proof->storage_https_port;
|
||||
entry.storage_lmq_port = proof.proof->storage_omq_port;
|
||||
entry.storage_server_reachable = proof.storage_server_reachable;
|
||||
entry.pubkey_ed25519 = proof.proof->pubkey_ed25519 ? tools::type_to_hex(proof.proof->pubkey_ed25519) : "";
|
||||
entry.pubkey_x25519 = proof.pubkey_x25519 ? tools::type_to_hex(proof.pubkey_x25519) : "";
|
||||
|
@ -3187,95 +3187,6 @@ namespace cryptonote { namespace rpc {
|
|||
|
||||
return res;
|
||||
}
|
||||
//------------------------------------------------------------------------------------------------------------------------------
|
||||
/// Start with seed and perform a series of computation arriving at the answer
|
||||
static uint64_t perform_blockchain_test_routine(const cryptonote::core& core,
|
||||
uint64_t max_height,
|
||||
uint64_t seed)
|
||||
{
|
||||
/// Should be sufficiently large to make it impractical
|
||||
/// to query remote nodes
|
||||
constexpr size_t NUM_ITERATIONS = 1000;
|
||||
|
||||
std::mt19937_64 mt(seed);
|
||||
|
||||
crypto::hash hash;
|
||||
|
||||
uint64_t height = seed;
|
||||
|
||||
for (auto i = 0u; i < NUM_ITERATIONS; ++i)
|
||||
{
|
||||
height = height % (max_height + 1);
|
||||
|
||||
hash = core.get_block_id_by_height(height);
|
||||
|
||||
using blob_t = cryptonote::blobdata;
|
||||
using block_pair_t = std::pair<blob_t, block>;
|
||||
|
||||
/// pick a random byte from the block blob
|
||||
std::vector<block_pair_t> blocks;
|
||||
std::vector<blob_t> txs;
|
||||
if (!core.get_blockchain_storage().get_blocks(height, 1, blocks, txs)) {
|
||||
MERROR("Could not query block at requested height: " << height);
|
||||
return 0;
|
||||
}
|
||||
const blob_t &blob = blocks.at(0).first;
|
||||
const uint64_t byte_idx = tools::uniform_distribution_portable(mt, blob.size());
|
||||
uint8_t byte = blob[byte_idx];
|
||||
|
||||
/// pick a random byte from a random transaction blob if found
|
||||
if (!txs.empty()) {
|
||||
const uint64_t tx_idx = tools::uniform_distribution_portable(mt, txs.size());
|
||||
const blob_t &tx_blob = txs[tx_idx];
|
||||
|
||||
/// not sure if this can be empty, so check to be safe
|
||||
if (!tx_blob.empty()) {
|
||||
const uint64_t byte_idx = tools::uniform_distribution_portable(mt, tx_blob.size());
|
||||
const uint8_t tx_byte = tx_blob[byte_idx];
|
||||
byte ^= tx_byte;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
{
|
||||
/// reduce hash down to 8 bytes
|
||||
uint64_t n[4];
|
||||
std::memcpy(n, hash.data, sizeof(n));
|
||||
for (auto &ni : n) {
|
||||
boost::endian::little_to_native_inplace(ni);
|
||||
}
|
||||
|
||||
/// Note that byte (obviously) only affects the lower byte
|
||||
/// of height, but that should be sufficient in this case
|
||||
height = n[0] ^ n[1] ^ n[2] ^ n[3] ^ byte;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
return height;
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------------------------------------------------------
|
||||
PERFORM_BLOCKCHAIN_TEST::response core_rpc_server::invoke(PERFORM_BLOCKCHAIN_TEST::request&& req, rpc_context context)
|
||||
{
|
||||
PERFORM_BLOCKCHAIN_TEST::response res{};
|
||||
|
||||
PERF_TIMER(on_perform_blockchain_test);
|
||||
|
||||
|
||||
uint64_t max_height = req.max_height;
|
||||
uint64_t seed = req.seed;
|
||||
|
||||
if (m_core.get_current_blockchain_height() <= max_height)
|
||||
throw rpc_error{ERROR_TOO_BIG_HEIGHT, "Requested block height too big."};
|
||||
|
||||
uint64_t res_height = perform_blockchain_test_routine(m_core, max_height, seed);
|
||||
|
||||
res.status = STATUS_OK;
|
||||
res.res_height = res_height;
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
namespace {
|
||||
struct version_printer { const std::array<uint16_t, 3> &v; };
|
||||
|
@ -3318,12 +3229,13 @@ namespace cryptonote { namespace rpc {
|
|||
//------------------------------------------------------------------------------------------------------------------------------
|
||||
STORAGE_SERVER_PING::response core_rpc_server::invoke(STORAGE_SERVER_PING::request&& req, rpc_context context)
|
||||
{
|
||||
m_core.ss_version = {req.version_major, req.version_minor, req.version_patch};
|
||||
m_core.ss_version = req.version;
|
||||
return handle_ping<STORAGE_SERVER_PING>(
|
||||
{req.version_major, req.version_minor, req.version_patch}, service_nodes::MIN_STORAGE_SERVER_VERSION,
|
||||
req.version, service_nodes::MIN_STORAGE_SERVER_VERSION,
|
||||
"Storage Server", m_core.m_last_storage_server_ping, m_core.get_net_config().UPTIME_PROOF_FREQUENCY,
|
||||
[this, &req](bool significant) {
|
||||
m_core.m_storage_lmq_port = req.storage_lmq_port;
|
||||
m_core.m_storage_https_port = req.https_port;
|
||||
m_core.m_storage_omq_port = req.omq_port;
|
||||
if (significant)
|
||||
m_core.reset_proof_interval();
|
||||
});
|
||||
|
|
|
@ -89,7 +89,7 @@ namespace cryptonote::rpc {
|
|||
/// Junk that epee makes us deal with to pass in a generically parsed json value
|
||||
using jsonrpc_params = std::pair<epee::serialization::portable_storage, epee::serialization::storage_entry>;
|
||||
|
||||
enum struct rpc_source : uint8_t { internal, http, lmq };
|
||||
enum struct rpc_source : uint8_t { internal, http, omq };
|
||||
|
||||
/// Contains the context of the invocation, which must be filled out by the glue code (e.g. HTTP
|
||||
/// RPC server) with requester-specific context details.
|
||||
|
@ -260,7 +260,6 @@ namespace cryptonote::rpc {
|
|||
GET_SERVICE_NODE_STATUS::response invoke(GET_SERVICE_NODE_STATUS::request&& req, rpc_context context);
|
||||
GET_SERVICE_NODES::response invoke(GET_SERVICE_NODES::request&& req, rpc_context context);
|
||||
GET_STAKING_REQUIREMENT::response invoke(GET_STAKING_REQUIREMENT::request&& req, rpc_context context);
|
||||
PERFORM_BLOCKCHAIN_TEST::response invoke(PERFORM_BLOCKCHAIN_TEST::request&& req, rpc_context context);
|
||||
STORAGE_SERVER_PING::response invoke(STORAGE_SERVER_PING::request&& req, rpc_context context);
|
||||
LOKINET_PING::response invoke(LOKINET_PING::request&& req, rpc_context context);
|
||||
GET_CHECKPOINTS::response invoke(GET_CHECKPOINTS::request&& req, rpc_context context);
|
||||
|
|
|
@ -1065,18 +1065,6 @@ KV_SERIALIZE_MAP_CODE_BEGIN(GET_SERVICE_PRIVKEYS::response)
|
|||
KV_SERIALIZE_MAP_CODE_END()
|
||||
|
||||
|
||||
KV_SERIALIZE_MAP_CODE_BEGIN(PERFORM_BLOCKCHAIN_TEST::request)
|
||||
KV_SERIALIZE(max_height)
|
||||
KV_SERIALIZE(seed)
|
||||
KV_SERIALIZE_MAP_CODE_END()
|
||||
|
||||
|
||||
KV_SERIALIZE_MAP_CODE_BEGIN(PERFORM_BLOCKCHAIN_TEST::response)
|
||||
KV_SERIALIZE(status)
|
||||
KV_SERIALIZE(res_height)
|
||||
KV_SERIALIZE_MAP_CODE_END()
|
||||
|
||||
|
||||
KV_SERIALIZE_MAP_CODE_BEGIN(service_node_contribution)
|
||||
KV_SERIALIZE(key_image)
|
||||
KV_SERIALIZE(key_image_pub_key)
|
||||
|
@ -1211,10 +1199,9 @@ KV_SERIALIZE_MAP_CODE_END()
|
|||
|
||||
|
||||
KV_SERIALIZE_MAP_CODE_BEGIN(STORAGE_SERVER_PING::request)
|
||||
KV_SERIALIZE(version_major);
|
||||
KV_SERIALIZE(version_minor);
|
||||
KV_SERIALIZE(version_patch);
|
||||
KV_SERIALIZE(storage_lmq_port);
|
||||
KV_SERIALIZE(version);
|
||||
KV_SERIALIZE(https_port);
|
||||
KV_SERIALIZE(omq_port);
|
||||
KV_SERIALIZE_MAP_CODE_END()
|
||||
|
||||
|
||||
|
|
|
@ -1988,29 +1988,6 @@ namespace rpc {
|
|||
};
|
||||
};
|
||||
|
||||
OXEN_RPC_DOC_INTROSPECT
|
||||
// TODO: Undocumented, -- unused
|
||||
struct PERFORM_BLOCKCHAIN_TEST : RPC_COMMAND
|
||||
{
|
||||
static constexpr auto names() { return NAMES("perform_blockchain_test"); }
|
||||
|
||||
struct request
|
||||
{
|
||||
uint64_t max_height;
|
||||
uint64_t seed;
|
||||
|
||||
KV_MAP_SERIALIZABLE
|
||||
};
|
||||
|
||||
struct response
|
||||
{
|
||||
std::string status;
|
||||
uint64_t res_height;
|
||||
|
||||
KV_MAP_SERIALIZABLE
|
||||
};
|
||||
};
|
||||
|
||||
OXEN_RPC_DOC_INTROSPECT
|
||||
struct service_node_contribution
|
||||
{
|
||||
|
@ -2193,10 +2170,9 @@ namespace rpc {
|
|||
|
||||
struct request
|
||||
{
|
||||
uint16_t version_major; // Storage Server Major version
|
||||
uint16_t version_minor; // Storage Server Minor version
|
||||
uint16_t version_patch; // Storage Server Patch version
|
||||
uint16_t storage_lmq_port; // Storage Server lmq port to include in uptime proofs
|
||||
std::array<uint16_t, 3> version; // Storage server version
|
||||
uint16_t https_port; // Storage server https port to include in uptime proofs
|
||||
uint16_t omq_port; // Storage Server oxenmq port to include in uptime proofs
|
||||
KV_MAP_SERIALIZABLE
|
||||
};
|
||||
|
||||
|
@ -2647,7 +2623,6 @@ namespace rpc {
|
|||
GET_SERVICE_NODE_REGISTRATION_CMD,
|
||||
GET_SERVICE_KEYS,
|
||||
GET_SERVICE_PRIVKEYS,
|
||||
PERFORM_BLOCKCHAIN_TEST,
|
||||
GET_SERVICE_NODES,
|
||||
GET_SERVICE_NODE_STATUS,
|
||||
STORAGE_SERVER_PING,
|
||||
|
|
|
@ -492,11 +492,11 @@ namespace cryptonote::rpc {
|
|||
if (!done)
|
||||
return;
|
||||
|
||||
auto& lmq = data->core_rpc.get_core().get_lmq();
|
||||
auto& omq = data->core_rpc.get_core().get_omq();
|
||||
std::string cat{data->call->is_public ? "rpc" : "admin"};
|
||||
std::string cmd{"http:" + data->uri}; // Used for LMQ job logging; prefixed with http: so we can distinguish it
|
||||
std::string remote{data->request.context.remote};
|
||||
lmq.inject_task(std::move(cat), std::move(cmd), std::move(remote), [data=std::move(data)] { invoke_rpc(std::move(data)); });
|
||||
omq.inject_task(std::move(cat), std::move(cmd), std::move(remote), [data=std::move(data)] { invoke_rpc(std::move(data)); });
|
||||
});
|
||||
}
|
||||
|
||||
|
@ -565,11 +565,11 @@ namespace cryptonote::rpc {
|
|||
if (!ps.get_value("params", st_entry, nullptr))
|
||||
data->request.body = ""sv;
|
||||
|
||||
auto& lmq = data->core_rpc.get_core().get_lmq();
|
||||
auto& omq = data->core_rpc.get_core().get_omq();
|
||||
std::string cat{data->call->is_public ? "rpc" : "admin"};
|
||||
std::string cmd{"jsonrpc:" + method}; // Used for LMQ job logging; prefixed with jsonrpc: so we can distinguish it
|
||||
std::string remote{data->request.context.remote};
|
||||
lmq.inject_task(std::move(cat), std::move(cmd), std::move(remote), [data=std::move(data)] { invoke_rpc(std::move(data)); });
|
||||
omq.inject_task(std::move(cat), std::move(cmd), std::move(remote), [data=std::move(data)] { invoke_rpc(std::move(data)); });
|
||||
});
|
||||
}
|
||||
|
||||
|
@ -588,9 +588,9 @@ namespace cryptonote::rpc {
|
|||
m_sent_startup = true;
|
||||
m_listen_socks = m_startup_success.get();
|
||||
|
||||
auto& lmq = m_server.get_core().get_lmq();
|
||||
if (timer_started.insert(&lmq).second)
|
||||
lmq.add_timer(long_poll_process_timeouts, 1s);
|
||||
auto& omq = m_server.get_core().get_omq();
|
||||
if (timer_started.insert(&omq).second)
|
||||
omq.add_timer(long_poll_process_timeouts, 1s);
|
||||
}
|
||||
|
||||
void http_server::shutdown(bool join)
|
||||
|
|
|
@ -11,29 +11,32 @@ using oxenmq::AuthLevel;
|
|||
|
||||
namespace {
|
||||
|
||||
const command_line::arg_descriptor<std::vector<std::string>> arg_lmq_public{
|
||||
// TODO: all of this --lmq-blah options really should be renamed to --omq-blah, but then we *also*
|
||||
// need some sort of backwards compatibility shim, and that is a nuissance.
|
||||
|
||||
const command_line::arg_descriptor<std::vector<std::string>> arg_omq_public{
|
||||
"lmq-public",
|
||||
"Adds a public, unencrypted OxenMQ RPC listener (with restricted capabilities) at the given "
|
||||
"address; can be specified multiple times. Examples: tcp://0.0.0.0:5555 (listen on port 5555), "
|
||||
"tcp://198.51.100.42:5555 (port 5555 on specific IPv4 address), tcp://[::]:5555, "
|
||||
"tcp://[2001:db8::abc]:5555 (IPv6), or ipc:///path/to/socket to listen on a unix domain socket"};
|
||||
const command_line::arg_descriptor<std::vector<std::string>> arg_lmq_curve_public{
|
||||
const command_line::arg_descriptor<std::vector<std::string>> arg_omq_curve_public{
|
||||
"lmq-curve-public",
|
||||
"Adds a curve-encrypted OxenMQ RPC listener at the given address that accepts (restricted) rpc "
|
||||
"commands from any client. Clients must already know this server's public x25519 key to "
|
||||
"establish an encrypted connection."};
|
||||
const command_line::arg_descriptor<std::vector<std::string>> arg_lmq_curve{
|
||||
const command_line::arg_descriptor<std::vector<std::string>> arg_omq_curve{
|
||||
"lmq-curve",
|
||||
"Adds a curve-encrypted OxenMQ RPC listener at the given address that only accepts client connections from whitelisted client x25519 pubkeys. "
|
||||
"Clients must already know this server's public x25519 key to establish an encrypted connection. When running in service node mode "
|
||||
"the quorumnet port is already listening as if specified with --lmq-curve."};
|
||||
const command_line::arg_descriptor<std::vector<std::string>> arg_lmq_admin{
|
||||
const command_line::arg_descriptor<std::vector<std::string>> arg_omq_admin{
|
||||
"lmq-admin",
|
||||
"Adds an x25519 pubkey of a client permitted to connect to the --lmq-curve, --lmq-curve-public, or quorumnet address(es) with unrestricted (admin) capabilities."};
|
||||
const command_line::arg_descriptor<std::vector<std::string>> arg_lmq_user{
|
||||
const command_line::arg_descriptor<std::vector<std::string>> arg_omq_user{
|
||||
"lmq-user",
|
||||
"Specifies an x25519 pubkey of a client permitted to connect to the --lmq-curve or quorumnet address(es) with restricted capabilities"};
|
||||
const command_line::arg_descriptor<std::vector<std::string>> arg_lmq_local_control{
|
||||
const command_line::arg_descriptor<std::vector<std::string>> arg_omq_local_control{
|
||||
"lmq-local-control",
|
||||
"Adds an unencrypted OxenMQ RPC listener with full, unrestricted capabilities and no authentication at the given address. "
|
||||
#ifndef _WIN32
|
||||
|
@ -42,18 +45,18 @@ const command_line::arg_descriptor<std::vector<std::string>> arg_lmq_local_contr
|
|||
"WARNING: Do not use this on a publicly accessible address!"};
|
||||
|
||||
#ifndef _WIN32
|
||||
const command_line::arg_descriptor<std::string> arg_lmq_umask{
|
||||
const command_line::arg_descriptor<std::string> arg_omq_umask{
|
||||
"lmq-umask",
|
||||
"Sets the umask to apply to any listening ipc:///path/to/sock LMQ sockets, in octal.",
|
||||
"0007"};
|
||||
#endif
|
||||
|
||||
|
||||
void check_lmq_listen_addr(std::string_view addr) {
|
||||
void check_omq_listen_addr(std::string_view addr) {
|
||||
// Crude check for basic validity; you can specify all sorts of invalid things, but at least
|
||||
// we can check the prefix for something that looks zmq-y.
|
||||
if (addr.size() < 7 || (addr.substr(0, 6) != "tcp://" && addr.substr(0, 6) != "ipc://"))
|
||||
throw std::runtime_error("Error: lmq listen address '" + std::string(addr) + "' is invalid: expected tcp://IP:PORT, tcp://[IPv6]:PORT or ipc:///path/to/socket");
|
||||
throw std::runtime_error("Error: omq listen address '" + std::string(addr) + "' is invalid: expected tcp://IP:PORT, tcp://[IPv6]:PORT or ipc:///path/to/socket");
|
||||
}
|
||||
|
||||
|
||||
|
@ -80,49 +83,49 @@ constexpr std::string_view
|
|||
} // end anonymous namespace
|
||||
|
||||
|
||||
void init_lmq_options(boost::program_options::options_description& desc)
|
||||
void init_omq_options(boost::program_options::options_description& desc)
|
||||
{
|
||||
command_line::add_arg(desc, arg_lmq_public);
|
||||
command_line::add_arg(desc, arg_lmq_curve_public);
|
||||
command_line::add_arg(desc, arg_lmq_curve);
|
||||
command_line::add_arg(desc, arg_lmq_admin);
|
||||
command_line::add_arg(desc, arg_lmq_user);
|
||||
command_line::add_arg(desc, arg_lmq_local_control);
|
||||
command_line::add_arg(desc, arg_omq_public);
|
||||
command_line::add_arg(desc, arg_omq_curve_public);
|
||||
command_line::add_arg(desc, arg_omq_curve);
|
||||
command_line::add_arg(desc, arg_omq_admin);
|
||||
command_line::add_arg(desc, arg_omq_user);
|
||||
command_line::add_arg(desc, arg_omq_local_control);
|
||||
#ifndef _WIN32
|
||||
command_line::add_arg(desc, arg_lmq_umask);
|
||||
command_line::add_arg(desc, arg_omq_umask);
|
||||
#endif
|
||||
}
|
||||
|
||||
lmq_rpc::lmq_rpc(cryptonote::core& core, core_rpc_server& rpc, const boost::program_options::variables_map& vm)
|
||||
omq_rpc::omq_rpc(cryptonote::core& core, core_rpc_server& rpc, const boost::program_options::variables_map& vm)
|
||||
: core_{core}, rpc_{rpc}
|
||||
{
|
||||
auto& lmq = core.get_lmq();
|
||||
auto& auth = core._lmq_auth_level_map();
|
||||
auto& omq = core.get_omq();
|
||||
auto& auth = core._omq_auth_level_map();
|
||||
|
||||
// Set up any requested listening sockets. (Note: if we are a service node, we'll already have
|
||||
// the quorumnet listener set up in cryptonote_core).
|
||||
for (const auto &addr : command_line::get_arg(vm, arg_lmq_public)) {
|
||||
check_lmq_listen_addr(addr);
|
||||
for (const auto &addr : command_line::get_arg(vm, arg_omq_public)) {
|
||||
check_omq_listen_addr(addr);
|
||||
MGINFO("LMQ listening on " << addr << " (public unencrypted)");
|
||||
lmq.listen_plain(addr,
|
||||
[&core](std::string_view ip, std::string_view pk, bool /*sn*/) { return core.lmq_allow(ip, pk, AuthLevel::basic); });
|
||||
omq.listen_plain(addr,
|
||||
[&core](std::string_view ip, std::string_view pk, bool /*sn*/) { return core.omq_allow(ip, pk, AuthLevel::basic); });
|
||||
}
|
||||
|
||||
for (const auto &addr : command_line::get_arg(vm, arg_lmq_curve_public)) {
|
||||
check_lmq_listen_addr(addr);
|
||||
for (const auto &addr : command_line::get_arg(vm, arg_omq_curve_public)) {
|
||||
check_omq_listen_addr(addr);
|
||||
MGINFO("LMQ listening on " << addr << " (public curve)");
|
||||
lmq.listen_curve(addr,
|
||||
[&core](std::string_view ip, std::string_view pk, bool /*sn*/) { return core.lmq_allow(ip, pk, AuthLevel::basic); });
|
||||
omq.listen_curve(addr,
|
||||
[&core](std::string_view ip, std::string_view pk, bool /*sn*/) { return core.omq_allow(ip, pk, AuthLevel::basic); });
|
||||
}
|
||||
|
||||
for (const auto &addr : command_line::get_arg(vm, arg_lmq_curve)) {
|
||||
check_lmq_listen_addr(addr);
|
||||
for (const auto &addr : command_line::get_arg(vm, arg_omq_curve)) {
|
||||
check_omq_listen_addr(addr);
|
||||
MGINFO("LMQ listening on " << addr << " (curve restricted)");
|
||||
lmq.listen_curve(addr,
|
||||
[&core](std::string_view ip, std::string_view pk, bool /*sn*/) { return core.lmq_allow(ip, pk, AuthLevel::denied); });
|
||||
omq.listen_curve(addr,
|
||||
[&core](std::string_view ip, std::string_view pk, bool /*sn*/) { return core.omq_allow(ip, pk, AuthLevel::denied); });
|
||||
}
|
||||
|
||||
auto locals = command_line::get_arg(vm, arg_lmq_local_control);
|
||||
auto locals = command_line::get_arg(vm, arg_omq_local_control);
|
||||
if (locals.empty()) {
|
||||
// FIXME: this requires unix sockets and so probably won't work on older Windows 10 or pre-Win10
|
||||
// windows. In theory we could do some runtime detection to see if the Windows version is new
|
||||
|
@ -138,14 +141,14 @@ lmq_rpc::lmq_rpc(cryptonote::core& core, core_rpc_server& rpc, const boost::prog
|
|||
locals.clear();
|
||||
}
|
||||
for (const auto &addr : locals) {
|
||||
check_lmq_listen_addr(addr);
|
||||
check_omq_listen_addr(addr);
|
||||
MGINFO("LMQ listening on " << addr << " (unauthenticated local admin)");
|
||||
lmq.listen_plain(addr,
|
||||
[&core](std::string_view ip, std::string_view pk, bool /*sn*/) { return core.lmq_allow(ip, pk, AuthLevel::admin); });
|
||||
omq.listen_plain(addr,
|
||||
[&core](std::string_view ip, std::string_view pk, bool /*sn*/) { return core.omq_allow(ip, pk, AuthLevel::admin); });
|
||||
}
|
||||
|
||||
#ifndef _WIN32
|
||||
auto umask_str = command_line::get_arg(vm, arg_lmq_umask);
|
||||
auto umask_str = command_line::get_arg(vm, arg_omq_umask);
|
||||
try {
|
||||
int umask = -1;
|
||||
size_t len = 0;
|
||||
|
@ -154,7 +157,7 @@ lmq_rpc::lmq_rpc(cryptonote::core& core, core_rpc_server& rpc, const boost::prog
|
|||
throw std::invalid_argument("not an octal value");
|
||||
if (umask < 0 || umask > 0777)
|
||||
throw std::invalid_argument("invalid umask value");
|
||||
lmq.STARTUP_UMASK = umask;
|
||||
omq.STARTUP_UMASK = umask;
|
||||
} catch (const std::exception& e) {
|
||||
throw std::invalid_argument("Invalid --lmq-umask value '" + umask_str + "': value must be an octal value between 0 and 0777");
|
||||
}
|
||||
|
@ -164,27 +167,27 @@ lmq_rpc::lmq_rpc(cryptonote::core& core, core_rpc_server& rpc, const boost::prog
|
|||
// Insert our own pubkey so that, e.g., console commands from localhost automatically get full access
|
||||
{
|
||||
crypto::x25519_public_key my_pubkey;
|
||||
const std::string& pk = lmq.get_pubkey();
|
||||
const std::string& pk = omq.get_pubkey();
|
||||
std::copy(pk.begin(), pk.end(), my_pubkey.data);
|
||||
auth.emplace(std::move(my_pubkey), AuthLevel::admin);
|
||||
}
|
||||
|
||||
// User-specified admin/user pubkeys
|
||||
for (auto& pk : as_x_pubkeys(command_line::get_arg(vm, arg_lmq_admin)))
|
||||
for (auto& pk : as_x_pubkeys(command_line::get_arg(vm, arg_omq_admin)))
|
||||
auth.emplace(std::move(pk), AuthLevel::admin);
|
||||
for (auto& pk : as_x_pubkeys(command_line::get_arg(vm, arg_lmq_user)))
|
||||
for (auto& pk : as_x_pubkeys(command_line::get_arg(vm, arg_omq_user)))
|
||||
auth.emplace(std::move(pk), AuthLevel::basic);
|
||||
|
||||
// basic (non-admin) rpc commands go into the "rpc." category (e.g. 'rpc.get_info')
|
||||
lmq.add_category("rpc", AuthLevel::basic, 0 /*no reserved threads*/, 1000 /*max queued requests*/);
|
||||
omq.add_category("rpc", AuthLevel::basic, 0 /*no reserved threads*/, 1000 /*max queued requests*/);
|
||||
|
||||
// Admin rpc commands go into "admin.". We also always keep one (potential) thread reserved for
|
||||
// admin RPC commands; that way even if there are loads of basic commands being processed we'll
|
||||
// still have room to invoke an admin command without waiting for the basic ones to finish.
|
||||
constexpr unsigned int admin_reserved_threads = 1;
|
||||
lmq.add_category("admin", AuthLevel::admin, admin_reserved_threads);
|
||||
omq.add_category("admin", AuthLevel::admin, admin_reserved_threads);
|
||||
for (auto& cmd : rpc_commands) {
|
||||
lmq.add_request_command(cmd.second->is_public ? "rpc" : "admin", cmd.first,
|
||||
omq.add_request_command(cmd.second->is_public ? "rpc" : "admin", cmd.first,
|
||||
[name=std::string_view{cmd.first}, &call=*cmd.second, this](oxenmq::Message& m) {
|
||||
if (m.data.size() > 1)
|
||||
m.send_reply(LMQ_BAD_REQUEST, "Bad request: RPC commands must have at most one data part "
|
||||
|
@ -192,7 +195,7 @@ lmq_rpc::lmq_rpc(cryptonote::core& core, core_rpc_server& rpc, const boost::prog
|
|||
|
||||
rpc_request request{};
|
||||
request.context.admin = m.access.auth >= AuthLevel::admin;
|
||||
request.context.source = rpc_source::lmq;
|
||||
request.context.source = rpc_source::omq;
|
||||
request.context.remote = m.remote;
|
||||
request.body = m.data.empty() ? ""sv : m.data[0];
|
||||
|
||||
|
@ -231,7 +234,7 @@ lmq_rpc::lmq_rpc(cryptonote::core& core, core_rpc_server& rpc, const boost::prog
|
|||
|
||||
// The "subscribe" category is for public subscriptions; i.e. anyone on a public RPC node, or
|
||||
// anyone on a private RPC node with public access level.
|
||||
lmq.add_category("sub", AuthLevel::basic);
|
||||
omq.add_category("sub", AuthLevel::basic);
|
||||
|
||||
// TX mempool subscriptions: [sub.mempool, blink] or [sub.mempool, all] to subscribe to new
|
||||
// approved mempool blink txes, or to all new mempool txes. You get back a reply of "OK" or
|
||||
|
@ -250,7 +253,7 @@ lmq_rpc::lmq_rpc(cryptonote::core& core, core_rpc_server& rpc, const boost::prog
|
|||
// such as txes that came from an existing block during a rollback). Note that both txhash and
|
||||
// txblob are binary: in particular, txhash is *not* hex-encoded.
|
||||
//
|
||||
lmq.add_request_command("sub", "mempool", [this](oxenmq::Message& m) {
|
||||
omq.add_request_command("sub", "mempool", [this](oxenmq::Message& m) {
|
||||
|
||||
if (m.data.size() != 1) {
|
||||
m.send_reply("Invalid subscription request: no subscription type given");
|
||||
|
@ -296,7 +299,7 @@ lmq_rpc::lmq_rpc(cryptonote::core& core, core_rpc_server& rpc, const boost::prog
|
|||
// The block notification for new blocks consists of a message [notify.block, height, blockhash]
|
||||
// containing the latest height/hash. (Note that blockhash is the hash in bytes, *not* the hex
|
||||
// encoded block hash).
|
||||
lmq.add_request_command("sub", "block", [this](oxenmq::Message& m) {
|
||||
omq.add_request_command("sub", "block", [this](oxenmq::Message& m) {
|
||||
std::unique_lock lock{subs_mutex_};
|
||||
auto expiry = std::chrono::steady_clock::now() + 30min;
|
||||
auto result = block_subs_.emplace(m.conn, block_sub{expiry});
|
||||
|
@ -352,23 +355,23 @@ static void send_notifies(Mutex& mutex, Subs& subs, const char* desc, Call call)
|
|||
}
|
||||
}
|
||||
|
||||
bool lmq_rpc::block_added(const block& block, const std::vector<transaction>& txs, const checkpoint_t *)
|
||||
bool omq_rpc::block_added(const block& block, const std::vector<transaction>& txs, const checkpoint_t *)
|
||||
{
|
||||
auto& lmq = core_.get_lmq();
|
||||
auto& omq = core_.get_omq();
|
||||
std::string height = std::to_string(get_block_height(block));
|
||||
send_notifies(subs_mutex_, block_subs_, "block", [&](auto& conn, auto& sub) {
|
||||
lmq.send(conn, "notify.block", height, std::string_view{block.hash.data, sizeof(block.hash.data)});
|
||||
omq.send(conn, "notify.block", height, std::string_view{block.hash.data, sizeof(block.hash.data)});
|
||||
});
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void lmq_rpc::send_mempool_notifications(const crypto::hash& id, const transaction& tx, const std::string& blob, const tx_pool_options& opts)
|
||||
void omq_rpc::send_mempool_notifications(const crypto::hash& id, const transaction& tx, const std::string& blob, const tx_pool_options& opts)
|
||||
{
|
||||
auto& lmq = core_.get_lmq();
|
||||
auto& omq = core_.get_omq();
|
||||
send_notifies(subs_mutex_, mempool_subs_, "mempool", [&](auto& conn, auto& sub) {
|
||||
if (sub.type == mempool_sub_type::all || opts.approved_blink)
|
||||
lmq.send(conn, "notify.mempool", std::string_view{id.data, sizeof(id.data)}, blob);
|
||||
omq.send(conn, "notify.mempool", std::string_view{id.data, sizeof(id.data)}, blob);
|
||||
});
|
||||
}
|
||||
|
||||
|
|
|
@ -37,14 +37,14 @@ namespace oxenmq { class OxenMQ; }
|
|||
|
||||
namespace cryptonote { namespace rpc {
|
||||
|
||||
void init_lmq_options(boost::program_options::options_description& desc);
|
||||
void init_omq_options(boost::program_options::options_description& desc);
|
||||
|
||||
/**
|
||||
* LMQ RPC server class. This doesn't actually hold the OxenMQ instance--that's in
|
||||
* cryptonote_core--but it works with it to add RPC endpoints, make it listen on RPC ports, and
|
||||
* handles RPC requests.
|
||||
*/
|
||||
class lmq_rpc final : public cryptonote::BlockAddedHook {
|
||||
class omq_rpc final : public cryptonote::BlockAddedHook {
|
||||
|
||||
enum class mempool_sub_type { all, blink };
|
||||
struct mempool_sub {
|
||||
|
@ -63,7 +63,7 @@ class lmq_rpc final : public cryptonote::BlockAddedHook {
|
|||
std::unordered_map<oxenmq::ConnectionID, block_sub> block_subs_;
|
||||
|
||||
public:
|
||||
lmq_rpc(cryptonote::core& core, core_rpc_server& rpc, const boost::program_options::variables_map& vm);
|
||||
omq_rpc(cryptonote::core& core, core_rpc_server& rpc, const boost::program_options::variables_map& vm);
|
||||
|
||||
bool block_added(const block& block, const std::vector<transaction>& txs, const checkpoint_t *) override;
|
||||
|
||||
|
|
Loading…
Reference in New Issue