mirror of
https://github.com/oxen-io/oxen-core.git
synced 2023-12-14 02:22:56 +01:00
Service Nodes States Endpoint (#145)
* Add get_service_node_list_state command for analytics * Update service_node_list_state to search particular pubkey * Service node list state sorts display results by longest waiting * Fix up leftover todos/unused data structures * Change get_service_node_list_state to print_sn
This commit is contained in:
parent
0891999d2b
commit
f55b9b1b82
|
@ -1106,6 +1106,12 @@ namespace cryptonote
|
|||
return true;
|
||||
}
|
||||
//-----------------------------------------------------------------------------------------------
|
||||
uint64_t core::get_uptime_proof(const crypto::public_key &key) const
|
||||
{
|
||||
uint64_t result = m_quorum_cop.get_uptime_proof(key);
|
||||
return result;
|
||||
}
|
||||
//-----------------------------------------------------------------------------------------------
|
||||
bool core::handle_uptime_proof(uint64_t timestamp, const crypto::public_key& pubkey, const crypto::signature& sig)
|
||||
{
|
||||
return m_quorum_cop.handle_uptime_proof(timestamp, pubkey, sig);
|
||||
|
@ -1673,6 +1679,12 @@ namespace cryptonote
|
|||
return result;
|
||||
}
|
||||
//-----------------------------------------------------------------------------------------------
|
||||
std::vector<service_nodes::service_node_pubkey_info> core::get_service_node_list_state(const std::vector<crypto::public_key> &service_node_pubkeys) const
|
||||
{
|
||||
std::vector<service_nodes::service_node_pubkey_info> result = m_service_node_list.get_service_node_list_state(service_node_pubkeys);
|
||||
return result;
|
||||
}
|
||||
//-----------------------------------------------------------------------------------------------
|
||||
bool core::add_deregister_vote(const loki::service_node_deregister::vote& vote, vote_verification_context &vvc)
|
||||
{
|
||||
{
|
||||
|
|
|
@ -798,6 +798,15 @@ namespace cryptonote
|
|||
*/
|
||||
const std::shared_ptr<service_nodes::quorum_state> get_quorum_state(uint64_t height) const;
|
||||
|
||||
/**
|
||||
* @brief Get a snapshot of the service node list state at the time of the call.
|
||||
*
|
||||
* @param service_node_pubkeys pubkeys to search, if empty this indicates get all the pubkeys
|
||||
*
|
||||
* @return All the service nodes that can be matched from pubkeys in param
|
||||
*/
|
||||
std::vector<service_nodes::service_node_pubkey_info> get_service_node_list_state(const std::vector<crypto::public_key>& service_node_pubkeys) const;
|
||||
|
||||
/**
|
||||
* @brief Add a vote to deregister a service node from network
|
||||
*
|
||||
|
@ -836,6 +845,15 @@ namespace cryptonote
|
|||
*/
|
||||
bool submit_uptime_proof();
|
||||
|
||||
/**
|
||||
* @brief Try find the uptime proof from the service node.
|
||||
*
|
||||
* @param key The public key of the service node
|
||||
*
|
||||
* @return 0 if no uptime proof found, otherwise the timestamp it last received in epoch time
|
||||
*/
|
||||
uint64_t get_uptime_proof(const crypto::public_key &key) const;
|
||||
|
||||
private:
|
||||
|
||||
/**
|
||||
|
|
|
@ -198,4 +198,15 @@ namespace service_nodes
|
|||
|
||||
return true;
|
||||
}
|
||||
|
||||
uint64_t quorum_cop::get_uptime_proof(const crypto::public_key &pubkey) const
|
||||
{
|
||||
const auto& it = m_uptime_proof_seen.find(pubkey);
|
||||
if (it == m_uptime_proof_seen.end())
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
return (*it).second;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -63,6 +63,8 @@ namespace service_nodes
|
|||
"Safety buffer should always be less than the vote lifetime");
|
||||
bool prune_uptime_proof();
|
||||
|
||||
uint64_t get_uptime_proof(const crypto::public_key &pubkey) const;
|
||||
|
||||
private:
|
||||
|
||||
cryptonote::core& m_core;
|
||||
|
|
|
@ -142,6 +142,41 @@ namespace service_nodes
|
|||
return result;
|
||||
}
|
||||
|
||||
std::vector<service_node_pubkey_info> service_node_list::get_service_node_list_state(const std::vector<crypto::public_key> &service_node_pubkeys) const
|
||||
{
|
||||
std::vector<service_node_pubkey_info> result;
|
||||
|
||||
if (service_node_pubkeys.empty())
|
||||
{
|
||||
result.reserve(m_service_nodes_infos.size());
|
||||
|
||||
for (const auto &it : m_service_nodes_infos)
|
||||
{
|
||||
service_node_pubkey_info entry = {};
|
||||
entry.pubkey = it.first;
|
||||
entry.info = it.second;
|
||||
result.push_back(entry);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
result.reserve(service_node_pubkeys.size());
|
||||
for (const auto &it : service_node_pubkeys)
|
||||
{
|
||||
const auto &find_it = m_service_nodes_infos.find(it);
|
||||
if (find_it == m_service_nodes_infos.end())
|
||||
continue;
|
||||
|
||||
service_node_pubkey_info entry = {};
|
||||
entry.pubkey = (*find_it).first;
|
||||
entry.info = (*find_it).second;
|
||||
result.push_back(entry);
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
bool service_node_list::is_service_node(const crypto::public_key& pubkey) const
|
||||
{
|
||||
return m_service_nodes_infos.find(pubkey) != m_service_nodes_infos.end();
|
||||
|
|
|
@ -48,6 +48,39 @@ namespace service_nodes
|
|||
std::vector<crypto::public_key> nodes_to_test;
|
||||
};
|
||||
|
||||
struct service_node_info // registration information
|
||||
{
|
||||
struct contribution
|
||||
{
|
||||
uint64_t amount;
|
||||
uint64_t reserved;
|
||||
cryptonote::account_public_address address;
|
||||
contribution(uint64_t _reserved, const cryptonote::account_public_address& _address)
|
||||
: amount(0), reserved(_reserved), address(_address) { }
|
||||
};
|
||||
|
||||
// block_height and transaction_index are to record when the service node is registered or when it last received a reward.
|
||||
uint64_t last_reward_block_height;
|
||||
uint32_t last_reward_transaction_index;
|
||||
|
||||
std::vector<contribution> contributors;
|
||||
uint64_t total_contributed;
|
||||
uint64_t total_reserved;
|
||||
uint64_t staking_requirement;
|
||||
uint32_t portions_for_operator;
|
||||
cryptonote::account_public_address operator_address;
|
||||
|
||||
bool is_fully_funded() const { return total_contributed >= staking_requirement; }
|
||||
// the minimum contribution to start a new contributor
|
||||
uint64_t get_min_contribution() const { return std::min(staking_requirement - total_reserved, staking_requirement / MAX_NUMBER_OF_CONTRIBUTORS); }
|
||||
};
|
||||
|
||||
struct service_node_pubkey_info
|
||||
{
|
||||
crypto::public_key pubkey;
|
||||
service_node_info info;
|
||||
};
|
||||
|
||||
class service_node_list
|
||||
: public cryptonote::Blockchain::BlockAddedHook,
|
||||
public cryptonote::Blockchain::BlockchainDetachedHook,
|
||||
|
@ -69,42 +102,9 @@ namespace service_nodes
|
|||
|
||||
bool is_service_node(const crypto::public_key& pubkey) const;
|
||||
const std::shared_ptr<quorum_state> get_quorum_state(uint64_t height) const;
|
||||
std::vector<service_node_pubkey_info> get_service_node_list_state(const std::vector<crypto::public_key> &service_node_pubkeys) const;
|
||||
|
||||
private:
|
||||
|
||||
struct service_node_info
|
||||
{
|
||||
struct contribution
|
||||
{
|
||||
uint64_t amount;
|
||||
uint64_t reserved;
|
||||
cryptonote::account_public_address address;
|
||||
contribution(uint64_t _reserved, const cryptonote::account_public_address& _address)
|
||||
: amount(0), reserved(_reserved), address(_address) { }
|
||||
};
|
||||
|
||||
// block_height and transaction_index are to record when the service node
|
||||
// is registered or when it last received a reward.
|
||||
//
|
||||
// set the winning service node as though it was re-registering at the
|
||||
// block height it wins on, with transaction index=-1
|
||||
// (hence transaction_index is signed)
|
||||
|
||||
uint64_t last_reward_block_height;
|
||||
uint32_t last_reward_transaction_index;
|
||||
|
||||
std::vector<contribution> contributors;
|
||||
uint64_t total_contributed;
|
||||
uint64_t total_reserved;
|
||||
uint64_t staking_requirement;
|
||||
uint32_t portions_for_operator;
|
||||
cryptonote::account_public_address operator_address;
|
||||
|
||||
bool is_fully_funded() const { return total_contributed >= staking_requirement; }
|
||||
// the minimum contribution to start a new contributor
|
||||
uint64_t get_min_contribution() const { return std::min(staking_requirement - total_reserved, staking_requirement / MAX_NUMBER_OF_CONTRIBUTORS); }
|
||||
};
|
||||
|
||||
bool is_registration_tx(const cryptonote::transaction& tx, uint64_t block_timestamp, uint64_t block_height, uint32_t index, crypto::public_key& key, service_node_info& info) const;
|
||||
bool get_contribution(const cryptonote::transaction& tx, uint64_t block_height, cryptonote::account_public_address& address, uint64_t& transferred) const;
|
||||
|
||||
|
|
|
@ -168,6 +168,12 @@ bool t_command_parser_executor::prepare_registration()
|
|||
return result;
|
||||
}
|
||||
|
||||
bool t_command_parser_executor::print_sn(const std::vector<std::string>& args)
|
||||
{
|
||||
bool result = m_executor.print_sn(args);
|
||||
return result;
|
||||
}
|
||||
|
||||
bool t_command_parser_executor::set_log_level(const std::vector<std::string>& args)
|
||||
{
|
||||
if(args.size() > 1)
|
||||
|
|
|
@ -83,6 +83,8 @@ public:
|
|||
|
||||
bool prepare_registration();
|
||||
|
||||
bool print_sn(const std::vector<std::string>& args);
|
||||
|
||||
bool set_log_level(const std::vector<std::string>& args);
|
||||
|
||||
bool set_log_categories(const std::vector<std::string>& args);
|
||||
|
|
|
@ -119,6 +119,12 @@ t_command_server::t_command_server(
|
|||
, "prepare_registration"
|
||||
, "Interactive prompt to prepare the registration. The resulting registration data is saved to disk."
|
||||
);
|
||||
m_command_lookup.set_handler(
|
||||
"print_sn"
|
||||
, std::bind(&t_command_parser_executor::print_sn, &m_parser, p::_1)
|
||||
, "print_sn [<pubkey> [...]]"
|
||||
, "Print service node registration info for the current height"
|
||||
);
|
||||
m_command_lookup.set_handler(
|
||||
"is_key_image_spent"
|
||||
, std::bind(&t_command_parser_executor::is_key_image_spent, &m_parser, p::_1)
|
||||
|
|
|
@ -1991,9 +1991,139 @@ bool t_rpc_command_executor::get_service_node_registration_cmd(const std::vector
|
|||
tools::fail_msg_writer() << make_error(fail_message, error_resp.message);
|
||||
return true;
|
||||
}
|
||||
|
||||
tools::success_msg_writer() << res.registration_cmd;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
static void print_service_node_list_state(std::vector<cryptonote::COMMAND_RPC_GET_SERVICE_NODE::response::entry *> list)
|
||||
{
|
||||
const char indent1[] = " ";
|
||||
const char indent2[] = " ";
|
||||
const char indent3[] = " ";
|
||||
|
||||
for (size_t i = 0; i < list.size(); ++i)
|
||||
{
|
||||
const cryptonote::COMMAND_RPC_GET_SERVICE_NODE::response::entry &entry = *list[i];
|
||||
|
||||
bool is_registered = entry.total_contributed >= entry.staking_requirement;
|
||||
epee::console_colors color = is_registered ? console_color_green : epee::console_color_yellow;
|
||||
|
||||
tools::msg_writer(color) << indent1 << "[" << i << "] Service Node: " << entry.service_node_pubkey;
|
||||
tools::msg_writer(color) << indent2 << "Total Contributed / Staking Requirement: " << cryptonote::print_money(entry.total_contributed) << " / " << cryptonote::print_money(entry.staking_requirement);
|
||||
|
||||
tools::msg_writer() << indent2 << "Total Reserved / Staking Requirement: " << cryptonote::print_money(entry.total_reserved) << " / " << cryptonote::print_money(entry.staking_requirement);
|
||||
|
||||
if (is_registered)
|
||||
{
|
||||
tools::msg_writer() << indent2 << "Last Reward At (Block Height/TX Index): " << entry.last_reward_block_height << " / " << entry.last_reward_transaction_index;
|
||||
}
|
||||
|
||||
tools::msg_writer() << indent2 << "Operator Cut (\% Of Reward): " << ((entry.portions_for_operator / (double)STAKING_PORTIONS) * 100.0) << "%";
|
||||
tools::msg_writer() << indent2 << "Operator Address: " << entry.operator_address;
|
||||
|
||||
epee::console_colors uptime_proof_color = (entry.last_uptime_proof == 0) ? epee::console_color_red : epee::console_color_green;
|
||||
|
||||
if (is_registered)
|
||||
{
|
||||
if (entry.last_uptime_proof == 0)
|
||||
tools::msg_writer(uptime_proof_color) << indent2 << "Last Uptime Proof Received: Not Received Yet";
|
||||
else
|
||||
tools::msg_writer(uptime_proof_color) << indent2 << "Last Uptime Proof Received: " << get_human_time_ago(entry.last_uptime_proof, time(nullptr));
|
||||
}
|
||||
|
||||
tools::msg_writer() << "";
|
||||
for (size_t j = 0; j < entry.contributors.size(); ++j)
|
||||
{
|
||||
const cryptonote::COMMAND_RPC_GET_SERVICE_NODE::response::contribution &contributor = entry.contributors[j];
|
||||
tools::msg_writer() << indent2 << "[" << j << "] Contributor: " << contributor.address;
|
||||
tools::msg_writer() << indent3 << "Amount / Reserved: " << cryptonote::print_money(contributor.amount) << " / " << cryptonote::print_money(contributor.reserved);
|
||||
}
|
||||
|
||||
tools::msg_writer() << "";
|
||||
}
|
||||
}
|
||||
|
||||
bool t_rpc_command_executor::print_sn(const std::vector<std::string> &args)
|
||||
{
|
||||
cryptonote::COMMAND_RPC_GET_SERVICE_NODE::request req = {};
|
||||
cryptonote::COMMAND_RPC_GET_SERVICE_NODE::response res = {};
|
||||
std::string fail_message = "Unsuccessful";
|
||||
epee::json_rpc::error error_resp;
|
||||
req.service_node_pubkeys = args;
|
||||
|
||||
if (m_is_rpc)
|
||||
{
|
||||
if (!m_rpc_client->json_rpc_request(req, res, "get_service_node", fail_message.c_str()))
|
||||
{
|
||||
tools::fail_msg_writer() << make_error(fail_message, res.status);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (!m_rpc_server->on_get_service_node(req, res, error_resp) || res.status != CORE_RPC_STATUS_OK)
|
||||
{
|
||||
tools::fail_msg_writer() << make_error(fail_message, error_resp.message);
|
||||
return true;
|
||||
}
|
||||
|
||||
std::vector<cryptonote::COMMAND_RPC_GET_SERVICE_NODE::response::entry *> unregistered;
|
||||
std::vector<cryptonote::COMMAND_RPC_GET_SERVICE_NODE::response::entry *> registered;
|
||||
registered.reserve (res.service_node_states.size());
|
||||
unregistered.reserve(res.service_node_states.size() * 0.5f);
|
||||
|
||||
for (auto &entry : res.service_node_states)
|
||||
{
|
||||
if (entry.total_contributed == entry.staking_requirement)
|
||||
{
|
||||
registered.push_back(&entry);
|
||||
}
|
||||
else
|
||||
{
|
||||
unregistered.push_back(&entry);
|
||||
}
|
||||
}
|
||||
|
||||
std::sort(unregistered.begin(), unregistered.end(),
|
||||
[](const cryptonote::COMMAND_RPC_GET_SERVICE_NODE::response::entry *a, const cryptonote::COMMAND_RPC_GET_SERVICE_NODE::response::entry *b) {
|
||||
uint64_t a_remaining = a->staking_requirement - a->total_reserved;
|
||||
uint64_t b_remaining = b->staking_requirement - b->total_reserved;
|
||||
|
||||
if (b_remaining == a_remaining)
|
||||
return b->portions_for_operator < a->portions_for_operator;
|
||||
|
||||
return b_remaining < a_remaining;
|
||||
});
|
||||
|
||||
std::stable_sort(registered.begin(), registered.end(),
|
||||
[](const cryptonote::COMMAND_RPC_GET_SERVICE_NODE::response::entry *a, const cryptonote::COMMAND_RPC_GET_SERVICE_NODE::response::entry *b) {
|
||||
if (a->last_reward_block_height == b->last_reward_block_height)
|
||||
return a->last_reward_transaction_index < b->last_reward_transaction_index;
|
||||
|
||||
return a->last_reward_block_height < b->last_reward_block_height;
|
||||
});
|
||||
|
||||
if (unregistered.size() > 0)
|
||||
{
|
||||
tools::msg_writer() << "Service Node Unregistered State[" << unregistered.size()<< "]";
|
||||
print_service_node_list_state(unregistered);
|
||||
}
|
||||
|
||||
if (registered.size() > 0)
|
||||
{
|
||||
tools::msg_writer() << "Service Node Registration State[" << registered.size()<< "]";
|
||||
print_service_node_list_state(registered);
|
||||
}
|
||||
|
||||
if (unregistered.size() == 0 && registered.size() == 0)
|
||||
{
|
||||
tools::msg_writer() << "No service node is currently known on the network";
|
||||
}
|
||||
}
|
||||
|
||||
tools::success_msg_writer() << res.registration_cmd;
|
||||
return true;
|
||||
}
|
||||
|
||||
|
|
|
@ -161,6 +161,8 @@ public:
|
|||
bool get_service_node_key();
|
||||
|
||||
bool prepare_registration();
|
||||
|
||||
bool print_sn(const std::vector<std::string> &args);
|
||||
};
|
||||
|
||||
} // namespace daemonize
|
||||
|
|
|
@ -2285,6 +2285,58 @@ namespace cryptonote
|
|||
return true;
|
||||
}
|
||||
//------------------------------------------------------------------------------------------------------------------------------
|
||||
bool core_rpc_server::on_get_service_node(const COMMAND_RPC_GET_SERVICE_NODE::request& req, COMMAND_RPC_GET_SERVICE_NODE::response& res, epee::json_rpc::error& error_resp)
|
||||
{
|
||||
PERF_TIMER(on_get_sn);
|
||||
|
||||
std::vector<crypto::public_key> pubkeys(req.service_node_pubkeys.size());
|
||||
for (size_t i = 0; i < req.service_node_pubkeys.size(); i++)
|
||||
{
|
||||
if (!string_tools::hex_to_pod(req.service_node_pubkeys[i], pubkeys[i]))
|
||||
{
|
||||
error_resp.code = CORE_RPC_ERROR_CODE_WRONG_PARAM;
|
||||
error_resp.message = "Could not convert to a public key, arg: ";
|
||||
error_resp.message += std::to_string(i);
|
||||
error_resp.message += " which is pubkey: ";
|
||||
error_resp.message += req.service_node_pubkeys[i];
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
std::vector<service_nodes::service_node_pubkey_info> pubkey_info_list = m_core.get_service_node_list_state(pubkeys);
|
||||
|
||||
res.status = CORE_RPC_STATUS_OK;
|
||||
res.service_node_states.reserve(pubkey_info_list.size());
|
||||
for (const auto &pubkey_info : pubkey_info_list)
|
||||
{
|
||||
COMMAND_RPC_GET_SERVICE_NODE::response::entry entry = {};
|
||||
entry.service_node_pubkey = string_tools::pod_to_hex(pubkey_info.pubkey);
|
||||
entry.last_reward_block_height = pubkey_info.info.last_reward_block_height;
|
||||
entry.last_reward_transaction_index = pubkey_info.info.last_reward_transaction_index;
|
||||
entry.last_uptime_proof = m_core.get_uptime_proof(pubkey_info.pubkey);
|
||||
|
||||
entry.contributors.reserve(pubkey_info.info.contributors.size());
|
||||
for (service_nodes::service_node_info::contribution const &contributor : pubkey_info.info.contributors)
|
||||
{
|
||||
COMMAND_RPC_GET_SERVICE_NODE::response::contribution new_contributor = {};
|
||||
new_contributor.amount = contributor.amount;
|
||||
new_contributor.reserved = contributor.reserved;
|
||||
new_contributor.address = string_tools::pod_to_hex(contributor.address);
|
||||
entry.contributors.push_back(new_contributor);
|
||||
}
|
||||
|
||||
entry.total_contributed = pubkey_info.info.total_contributed;
|
||||
entry.total_reserved = pubkey_info.info.total_reserved;
|
||||
entry.staking_requirement = pubkey_info.info.staking_requirement;
|
||||
entry.portions_for_operator = pubkey_info.info.portions_for_operator;
|
||||
entry.operator_address = string_tools::pod_to_hex(pubkey_info.info.operator_address);
|
||||
|
||||
res.service_node_states.push_back(entry);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
//------------------------------------------------------------------------------------------------------------------------------
|
||||
|
||||
|
||||
const command_line::arg_descriptor<std::string, false, true, 2> core_rpc_server::arg_rpc_bind_port = {
|
||||
|
|
|
@ -158,6 +158,7 @@ namespace cryptonote
|
|||
MAP_JON_RPC_WE("get_quorum_state", on_get_quorum_state_json, COMMAND_RPC_GET_QUORUM_STATE)
|
||||
MAP_JON_RPC_WE("get_service_node_registration_cmd", on_get_service_node_registration_cmd, COMMAND_RPC_GET_SERVICE_NODE_REGISTRATION_CMD)
|
||||
MAP_JON_RPC_WE("get_service_node_key", on_get_service_node_key, COMMAND_RPC_GET_SERVICE_NODE_KEY)
|
||||
MAP_JON_RPC_WE("get_service_node", on_get_service_node, COMMAND_RPC_GET_SERVICE_NODE)
|
||||
END_JSON_RPC_MAP()
|
||||
END_URI_MAP2()
|
||||
|
||||
|
@ -224,6 +225,7 @@ namespace cryptonote
|
|||
bool on_get_quorum_state_json(const COMMAND_RPC_GET_QUORUM_STATE::request& req, COMMAND_RPC_GET_QUORUM_STATE::response& res, epee::json_rpc::error& error_resp);
|
||||
bool on_get_service_node_registration_cmd(const COMMAND_RPC_GET_SERVICE_NODE_REGISTRATION_CMD::request& req, COMMAND_RPC_GET_SERVICE_NODE_REGISTRATION_CMD::response& res, epee::json_rpc::error& error_resp);
|
||||
bool on_get_service_node_key(const COMMAND_RPC_GET_SERVICE_NODE_KEY::request& req, COMMAND_RPC_GET_SERVICE_NODE_KEY::response& res, epee::json_rpc::error &error_resp);
|
||||
bool on_get_service_node(const COMMAND_RPC_GET_SERVICE_NODE::request& req, COMMAND_RPC_GET_SERVICE_NODE::response& res, epee::json_rpc::error& error_resp);
|
||||
//-----------------------
|
||||
|
||||
private:
|
||||
|
|
|
@ -2345,4 +2345,66 @@ namespace cryptonote
|
|||
END_KV_SERIALIZE_MAP()
|
||||
};
|
||||
};
|
||||
|
||||
struct COMMAND_RPC_GET_SERVICE_NODE
|
||||
{
|
||||
struct request
|
||||
{
|
||||
std::vector<std::string> service_node_pubkeys; // pass empty vector to get all the service nodes
|
||||
BEGIN_KV_SERIALIZE_MAP()
|
||||
KV_SERIALIZE(service_node_pubkeys);
|
||||
END_KV_SERIALIZE_MAP()
|
||||
};
|
||||
|
||||
struct response
|
||||
{
|
||||
struct contribution
|
||||
{
|
||||
uint64_t amount;
|
||||
uint64_t reserved;
|
||||
std::string address;
|
||||
|
||||
BEGIN_KV_SERIALIZE_MAP()
|
||||
KV_SERIALIZE(amount)
|
||||
KV_SERIALIZE(reserved)
|
||||
KV_SERIALIZE(address)
|
||||
END_KV_SERIALIZE_MAP()
|
||||
};
|
||||
|
||||
struct entry
|
||||
{
|
||||
std::string service_node_pubkey;
|
||||
uint64_t last_reward_block_height;
|
||||
uint32_t last_reward_transaction_index;
|
||||
uint64_t last_uptime_proof;
|
||||
std::vector<contribution> contributors;
|
||||
uint64_t total_contributed;
|
||||
uint64_t total_reserved;
|
||||
uint64_t staking_requirement;
|
||||
uint32_t portions_for_operator;
|
||||
std::string operator_address;
|
||||
|
||||
BEGIN_KV_SERIALIZE_MAP()
|
||||
KV_SERIALIZE(service_node_pubkey)
|
||||
KV_SERIALIZE(last_reward_block_height)
|
||||
KV_SERIALIZE(last_reward_transaction_index)
|
||||
KV_SERIALIZE(last_uptime_proof)
|
||||
KV_SERIALIZE(contributors)
|
||||
KV_SERIALIZE(total_contributed)
|
||||
KV_SERIALIZE(total_reserved)
|
||||
KV_SERIALIZE(staking_requirement)
|
||||
KV_SERIALIZE(portions_for_operator)
|
||||
KV_SERIALIZE(operator_address)
|
||||
END_KV_SERIALIZE_MAP()
|
||||
};
|
||||
|
||||
std::vector<entry> service_node_states;
|
||||
std::string status;
|
||||
|
||||
BEGIN_KV_SERIALIZE_MAP()
|
||||
KV_SERIALIZE(service_node_states)
|
||||
KV_SERIALIZE(status)
|
||||
END_KV_SERIALIZE_MAP()
|
||||
};
|
||||
};
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue