Compare commits

...

26 commits

Author SHA1 Message Date
timur
3402f9a726 Hotfix 2022-12-01 17:18:54 -04:00
timur
d2cb8cd846 SON conn. pool 2022-11-29 12:09:21 -04:00
timur
54a7e5b757 SON conn. pool 2022-11-29 04:17:06 -04:00
timur
75e6f9abd5 SON conn. pool 2022-11-29 04:00:00 -04:00
timur
c4f3f37075 SON conn. pool 2022-11-29 03:20:33 -04:00
timur
ac2c9e16e6 SON conn. pool 2022-11-28 15:13:37 -04:00
timur
863e8a0d91 SON conn. pool 2022-11-28 15:10:48 -04:00
timur
aab2dac1c2 SON conn. pool 2022-11-28 15:03:50 -04:00
timur
6bc8a10c67 SON conn. pool 2022-11-28 07:44:09 -04:00
timur
94092093f8 SON conn. pool 2022-11-28 07:07:35 -04:00
timur
2e35053668 SON conn. pool 2022-11-28 07:04:55 -04:00
timur
a2fab62a1a SON conn. pool 2022-11-28 07:01:05 -04:00
timur
22239bbd60 SON conn. pool 2022-11-28 07:00:05 -04:00
timur
d45b631079 SON conn. pool 2022-11-28 06:59:29 -04:00
timur
87c2f5a10f SON conn. pool 2022-11-28 06:50:57 -04:00
timur
ca32d13192 SON conn. pool 2022-11-28 06:49:54 -04:00
timur
6febed5a36 SON conn. pool 2022-11-28 06:48:29 -04:00
timur
be580e0c34 SON conn. pool 2022-11-28 06:47:43 -04:00
timur
922327f98c SON conn. pool 2022-11-28 06:38:50 -04:00
timur
94b518cb7a SON connection pool. 2022-11-23 11:36:17 -04:00
timur
4f1d1f9c34 SON connection pool. 2022-11-22 13:51:30 -04:00
timur
b3b8c926c1 SON connection pool. 2022-11-22 13:16:12 -04:00
timur
b908d7f12f SON connection pool. 2022-11-22 09:00:12 -04:00
timur
9fc3536638 SON connection pool. 2022-11-20 17:58:03 -04:00
timur
16431b3be5 SON connection pool. 2022-11-16 09:26:31 -04:00
timur
6e0064aefe SON connection pool. 2022-11-16 07:32:17 -04:00
10 changed files with 225 additions and 41 deletions

View file

@ -18,7 +18,42 @@
namespace graphene { namespace peerplays_sidechain {
rpc_client::rpc_client(std::string _url, std::string _user, std::string _password, bool _debug_rpc_calls) :
struct rpc_reply {
uint16_t status;
std::string body;
};
class rpc_connection {
public:
rpc_connection(std::string _url, std::string _user, std::string _password, bool _debug_rpc_calls);
std::string send_post_request(std::string method, std::string params, bool show_log);
std::string get_url() const;
protected:
std::string url;
std::string user;
std::string password;
bool debug_rpc_calls;
std::string protocol;
std::string host;
std::string port;
std::string target;
std::string authorization;
uint32_t request_id;
private:
rpc_reply send_post_request(std::string body, bool show_log);
boost::beast::net::io_context ioc;
boost::beast::net::ip::tcp::resolver resolver;
boost::asio::ip::basic_resolver_results<boost::asio::ip::tcp> results;
};
rpc_connection::rpc_connection(std::string _url, std::string _user, std::string _password, bool _debug_rpc_calls) :
url(_url),
user(_user),
password(_password),
@ -61,6 +96,11 @@ rpc_client::rpc_client(std::string _url, std::string _user, std::string _passwor
}
}
std::string rpc_connection::get_url() const
{
return url;
}
std::string rpc_client::retrieve_array_value_from_reply(std::string reply_str, std::string array_path, uint32_t idx) {
if (reply_str.empty()) {
wlog("RPC call ${function}, empty reply string", ("function", __FUNCTION__));
@ -125,7 +165,7 @@ std::string rpc_client::retrieve_value_from_reply(std::string reply_str, std::st
return "";
}
std::string rpc_client::send_post_request(std::string method, std::string params, bool show_log) {
std::string rpc_connection::send_post_request(std::string method, std::string params, bool show_log) {
std::stringstream body;
request_id = request_id + 1;
@ -164,7 +204,7 @@ std::string rpc_client::send_post_request(std::string method, std::string params
return "";
}
rpc_reply rpc_client::send_post_request(std::string body, bool show_log) {
rpc_reply rpc_connection::send_post_request(std::string body, bool show_log) {
// These object is used as a context for ssl connection
boost::asio::ssl::context ctx(boost::asio::ssl::context::tlsv12_client);
@ -247,4 +287,114 @@ rpc_reply rpc_client::send_post_request(std::string body, bool show_log) {
return reply;
}
rpc_client::rpc_client(const std::vector<std::string> &_urls, const std::vector<std::string> &_users, const std::vector<std::string> &_passwords, bool _debug_rpc_calls):
debug_rpc_calls(_debug_rpc_calls)
{
FC_ASSERT(_urls.size());
FC_ASSERT(_users.size() == _urls.size() && _passwords.size() == _urls.size());
for (size_t i=0; i < _urls.size(); i++)
connections.push_back(new rpc_connection(_urls[i], _users[i], _passwords[i], _debug_rpc_calls));
n_active_conn = 0;
schedule_connection_selection();
}
void rpc_client::schedule_connection_selection()
{
fc::time_point now = fc::time_point::now();
static const int64_t time_to_next_conn_selection = 2000000;
fc::time_point next_wakeup = now + fc::microseconds(time_to_next_conn_selection);
connection_selection_task = fc::schedule([this] {
select_connection();
}, next_wakeup, "SON RPC connection selection");
}
void rpc_client::select_connection()
{
//ilog("n_active_rpc_client=${n}", ("n", n_active_rpc_client));
static const int t_limit = 10*1000000, // 10 sec
quality_diff_threshold = 10000; // 10 ms
FC_ASSERT(connections.size());
int best_n = -1;
int best_quality = -1;
std::vector<uint64_t> head_block_numbers;
head_block_numbers.resize(connections.size());
std::vector<int> qualities;
qualities.resize(connections.size());
for (size_t n=0; n < connections.size(); n++) {
rpc_connection *conn = connections[n];
int quality = 0;
head_block_numbers[n] = std::numeric_limits<uint64_t>::max();
// make the ping
fc::time_point t_sent = fc::time_point::now();
uint64_t head_block_number = ping(*conn);
fc::time_point t_received = fc::time_point::now();
if (head_block_number != std::numeric_limits<uint64_t>::max()) {
int t = (t_received - t_sent).count();
t += rand() % 10;
FC_ASSERT(t != -1);
head_block_numbers[n] = head_block_number;
if (t < t_limit)
quality = t_limit - t; // the less time, the higher quality
// look for the best quality
if (quality > best_quality) {
best_n = n;
best_quality = quality;
}
}
qualities[n] = quality;
}
FC_ASSERT(best_n != -1 && best_quality != -1);
if (best_n != n_active_conn) { // if the best client is not the current one, ...
uint64_t active_head_block_number = head_block_numbers[n_active_conn];
if ((active_head_block_number == std::numeric_limits<uint64_t>::max() // ...and the current one has no known head block...
|| head_block_numbers[best_n] >= active_head_block_number) // ...or the best client's head is more recent than the current, ...
&& best_quality > qualities[n_active_conn] + quality_diff_threshold) { // ...and the new client's quality exceeds current more than by threshold
n_active_conn = best_n; // ...then select new one
ilog("!!! rpc connection reselected, now ${n}", ("n", n_active_conn));
}
}
schedule_connection_selection();
}
rpc_connection &rpc_client::get_active_connection() const
{
return *connections[n_active_conn];
}
std::string rpc_client::send_post_request(std::string method, std::string params, bool show_log)
{
return send_post_request(get_active_connection(), method, params, show_log);
}
std::string rpc_client::send_post_request(rpc_connection &conn, std::string method, std::string params, bool show_log)
{
return conn.send_post_request(method, params, show_log);
}
std::string rpc_client::get_connection_url(const rpc_connection &conn)
{
return conn.get_url();
}
rpc_client::~rpc_client()
{
try {
if (connection_selection_task.valid())
connection_selection_task.cancel_and_wait(__FUNCTION__);
} catch (fc::canceled_exception &) {
//Expected exception. Move along.
} catch (fc::exception &e) {
edump((e.to_detail_string()));
}
}
}} // namespace graphene::peerplays_sidechain

View file

@ -3,44 +3,42 @@
#include <cstdint>
#include <string>
#include <fc/thread/future.hpp>
#include <fc/thread/thread.hpp>
#include <boost/asio/ip/tcp.hpp>
#include <boost/beast/core.hpp>
namespace graphene { namespace peerplays_sidechain {
struct rpc_reply {
uint16_t status;
std::string body;
};
class rpc_connection;
class rpc_client {
public:
rpc_client(std::string _url, std::string _user, std::string _password, bool _debug_rpc_calls);
rpc_client(const std::vector<std::string> &_urls, const std::vector<std::string> &_users, const std::vector<std::string> &_passwords, bool _debug_rpc_calls);
~rpc_client();
protected:
std::string retrieve_array_value_from_reply(std::string reply_str, std::string array_path, uint32_t idx);
std::string retrieve_value_from_reply(std::string reply_str, std::string value_path);
bool debug_rpc_calls;
std::string send_post_request(std::string method, std::string params, bool show_log);
std::string url;
std::string user;
std::string password;
bool debug_rpc_calls;
static std::string send_post_request(rpc_connection &conn, std::string method, std::string params, bool show_log);
std::string protocol;
std::string host;
std::string port;
std::string target;
std::string authorization;
static std::string retrieve_array_value_from_reply(std::string reply_str, std::string array_path, uint32_t idx);
static std::string retrieve_value_from_reply(std::string reply_str, std::string value_path);
uint32_t request_id;
static std::string get_connection_url(const rpc_connection &conn);
private:
rpc_reply send_post_request(std::string body, bool show_log);
std::vector<rpc_connection*> connections;
int n_active_conn;
fc::future<void> connection_selection_task;
boost::beast::net::io_context ioc;
boost::beast::net::ip::tcp::resolver resolver;
boost::asio::ip::basic_resolver_results<boost::asio::ip::tcp> results;
rpc_connection &get_active_connection() const;
void select_connection();
void schedule_connection_selection();
virtual uint64_t ping(rpc_connection &conn) const = 0;
};
}} // namespace graphene::peerplays_sidechain

View file

@ -42,7 +42,7 @@ public:
};
public:
bitcoin_rpc_client(std::string _url, std::string _user, std::string _password, bool _debug_rpc_calls);
bitcoin_rpc_client(const std::vector<std::string> &_urls, const std::vector<std::string> &_users, const std::vector<std::string> &_passwords, bool _debug_rpc_calls);
std::string createwallet(const std::string &wallet_name);
uint64_t estimatesmartfee(uint16_t conf_target = 128);
@ -58,6 +58,8 @@ public:
std::string walletlock();
bool walletpassphrase(const std::string &passphrase, uint32_t timeout = 60);
virtual uint64_t ping(rpc_connection &conn) const override;
private:
std::string ip;
uint32_t rpc_port;

View file

@ -13,7 +13,7 @@ namespace graphene { namespace peerplays_sidechain {
class ethereum_rpc_client : public rpc_client {
public:
ethereum_rpc_client(const std::string &url, const std::string &user_name, const std::string &password, bool debug_rpc_calls);
ethereum_rpc_client(const std::vector<std::string> &urls, const std::vector<std::string> &user_names, const std::vector<std::string> &passwords, bool debug_rpc_calls);
std::string eth_blockNumber();
std::string eth_get_block_by_number(std::string block_number, bool full_block);
@ -34,6 +34,8 @@ public:
std::string eth_send_transaction(const std::string &params);
std::string eth_send_raw_transaction(const std::string &params);
std::string eth_get_transaction_receipt(const std::string &params);
virtual uint64_t ping(rpc_connection &conn) const override;
};
class sidechain_net_handler_ethereum : public sidechain_net_handler {

View file

@ -13,7 +13,7 @@ namespace graphene { namespace peerplays_sidechain {
class hive_rpc_client : public rpc_client {
public:
hive_rpc_client(const std::string &url, const std::string &user_name, const std::string &password, bool debug_rpc_calls);
hive_rpc_client(const std::vector<std::string> &urls, const std::vector<std::string> &user_names, const std::vector<std::string> &passwords, bool debug_rpc_calls);
std::string account_history_api_get_transaction(std::string transaction_id);
std::string block_api_get_block(uint32_t block_number);
@ -30,6 +30,8 @@ public:
std::string get_head_block_time();
std::string get_is_test_net();
std::string get_last_irreversible_block_num();
virtual uint64_t ping(rpc_connection &conn) const override;
};
class sidechain_net_handler_hive : public sidechain_net_handler {
@ -48,13 +50,12 @@ public:
virtual optional<asset> estimate_withdrawal_transaction_fee() const override;
private:
std::string rpc_url;
std::vector<std::string> rpc_urls;
std::string rpc_user;
std::string rpc_password;
std::string wallet_account_name;
hive_rpc_client *rpc_client;
hive::chain_id_type chain_id;
hive::network network_type;

View file

@ -196,7 +196,7 @@ void peerplays_sidechain_plugin_impl::plugin_set_program_options(
"Tuple of [Ethereum public key, Ethereum private key] (may specify multiple times)");
cli.add_options()("hive-sidechain-enabled", bpo::value<bool>()->default_value(false), "Hive sidechain handler enabled");
cli.add_options()("hive-node-rpc-url", bpo::value<string>()->default_value("127.0.0.1:28090"), "Hive node RPC URL [http[s]://]host[:port]");
cli.add_options()("hive-node-rpc-url", bpo::value<vector<string>>()->composing()->multitoken()->DEFAULT_VALUE_VECTOR("127.0.0.1:28090"), "Hive node RPC URL [http[s]://]host[:port]");
cli.add_options()("hive-node-rpc-user", bpo::value<string>(), "Hive node RPC user");
cli.add_options()("hive-node-rpc-password", bpo::value<string>(), "Hive node RPC password");
cli.add_options()("hive-wallet-account-name", bpo::value<string>(), "Hive wallet account name");

View file

@ -25,8 +25,8 @@ namespace graphene { namespace peerplays_sidechain {
// =============================================================================
bitcoin_rpc_client::bitcoin_rpc_client(std::string _url, std::string _user, std::string _password, bool _debug_rpc_calls) :
rpc_client(_url, _user, _password, _debug_rpc_calls) {
bitcoin_rpc_client::bitcoin_rpc_client(const std::vector<std::string> &_urls, const std::vector<std::string> &_users, const std::vector<std::string> &_passwords, bool _debug_rpc_calls) :
rpc_client(_urls, _users, _passwords, _debug_rpc_calls) {
}
std::string bitcoin_rpc_client::createwallet(const std::string &wallet_name) {
@ -244,6 +244,11 @@ bool bitcoin_rpc_client::walletpassphrase(const std::string &passphrase, uint32_
return true;
}
uint64_t bitcoin_rpc_client::ping(rpc_connection &conn) const {
ilog("!!!bitcoin_rpc_client::ping() ${url}", ("url", get_connection_url(conn)));
return std::numeric_limits<uint64_t>::max();
}
// =============================================================================
zmq_listener::zmq_listener(std::string _ip, uint32_t _zmq) :
@ -353,7 +358,7 @@ sidechain_net_handler_bitcoin::sidechain_net_handler_bitcoin(peerplays_sidechain
url = url + "/wallet/" + wallet_name;
}
bitcoin_client = std::unique_ptr<bitcoin_rpc_client>(new bitcoin_rpc_client(url, rpc_user, rpc_password, debug_rpc_calls));
bitcoin_client = std::unique_ptr<bitcoin_rpc_client>(new bitcoin_rpc_client({url}, {rpc_user}, {rpc_password}, debug_rpc_calls));
if (!wallet_name.empty()) {
bitcoin_client->loadwallet(wallet_name);
}

View file

@ -24,8 +24,8 @@
namespace graphene { namespace peerplays_sidechain {
ethereum_rpc_client::ethereum_rpc_client(const std::string &url, const std::string &user_name, const std::string &password, bool debug_rpc_calls) :
rpc_client(url, user_name, password, debug_rpc_calls) {
ethereum_rpc_client::ethereum_rpc_client(const std::vector<std::string> &urls, const std::vector<std::string> &user_names, const std::vector<std::string> &passwords, bool debug_rpc_calls) :
rpc_client(urls, user_names, passwords, debug_rpc_calls) {
}
std::string ethereum_rpc_client::eth_blockNumber() {
@ -121,6 +121,11 @@ std::string ethereum_rpc_client::eth_get_transaction_receipt(const std::string &
return send_post_request("eth_getTransactionReceipt", "[\"" + params + "\"]", debug_rpc_calls);
}
uint64_t ethereum_rpc_client::ping(rpc_connection &conn) const {
ilog("!!!ethereum_rpc_client::ping() ${url}", ("url", get_connection_url(conn)));
return std::numeric_limits<uint64_t>::max();
}
sidechain_net_handler_ethereum::sidechain_net_handler_ethereum(peerplays_sidechain_plugin &_plugin, const boost::program_options::variables_map &options) :
sidechain_net_handler(_plugin, options) {
sidechain = sidechain_type::ethereum;
@ -155,7 +160,7 @@ sidechain_net_handler_ethereum::sidechain_net_handler_ethereum(peerplays_sidecha
}
}
rpc_client = new ethereum_rpc_client(rpc_url, rpc_user, rpc_password, debug_rpc_calls);
rpc_client = new ethereum_rpc_client({rpc_url}, {rpc_user}, {rpc_password}, debug_rpc_calls);
const std::string chain_id_str = rpc_client->get_chain_id();
if (chain_id_str.empty()) {

View file

@ -30,8 +30,8 @@
namespace graphene { namespace peerplays_sidechain {
hive_rpc_client::hive_rpc_client(const std::string &url, const std::string &user_name, const std::string &password, bool debug_rpc_calls) :
rpc_client(url, user_name, password, debug_rpc_calls) {
hive_rpc_client::hive_rpc_client(const std::vector<std::string> &urls, const std::vector<std::string> &user_names, const std::vector<std::string> &passwords, bool debug_rpc_calls) :
rpc_client(urls, user_names, passwords, debug_rpc_calls) {
}
std::string hive_rpc_client::account_history_api_get_transaction(std::string transaction_id) {
@ -112,6 +112,20 @@ std::string hive_rpc_client::get_last_irreversible_block_num() {
return retrieve_value_from_reply(reply_str, "last_irreversible_block_num");
}
uint64_t hive_rpc_client::ping(rpc_connection &conn) const {
ilog("!!!hive_rpc_client::ping() ${url}", ("url", get_connection_url(conn)));
const std::string reply = send_post_request(conn, "database_api.get_dynamic_global_properties", "", debug_rpc_calls);
if (!reply.empty()) {
std::stringstream ss(reply);
boost::property_tree::ptree json;
boost::property_tree::read_json(ss, json);
if (json.count("result")) {
return json.get<uint64_t>("result.head_block_number");
}
}
return std::numeric_limits<uint64_t>::max();
}
sidechain_net_handler_hive::sidechain_net_handler_hive(peerplays_sidechain_plugin &_plugin, const boost::program_options::variables_map &options) :
sidechain_net_handler(_plugin, options) {
sidechain = sidechain_type::hive;
@ -120,7 +134,7 @@ sidechain_net_handler_hive::sidechain_net_handler_hive(peerplays_sidechain_plugi
debug_rpc_calls = options.at("debug-rpc-calls").as<bool>();
}
rpc_url = options.at("hive-node-rpc-url").as<std::string>();
rpc_urls = options.at("hive-node-rpc-url").as<std::vector<std::string>>();
if (options.count("hive-rpc-user")) {
rpc_user = options.at("hive-rpc-user").as<std::string>();
} else {
@ -146,11 +160,17 @@ sidechain_net_handler_hive::sidechain_net_handler_hive(peerplays_sidechain_plugi
}
}
rpc_client = new hive_rpc_client(rpc_url, rpc_user, rpc_password, debug_rpc_calls);
std::vector<std::string> rpc_users, rpc_passwords;
for (size_t i=0; i < rpc_urls.size(); i++) {
rpc_users.push_back(rpc_user);
rpc_passwords.push_back(rpc_password);
}
rpc_client = new hive_rpc_client(rpc_urls, rpc_users, rpc_passwords, debug_rpc_calls);
const std::string chain_id_str = rpc_client->get_chain_id();
if (chain_id_str.empty()) {
elog("No Hive node running at ${url}", ("url", rpc_url));
elog("No Hive node running at ${url}", ("url", rpc_urls[0]));
FC_ASSERT(false);
}
chain_id = chain_id_type(chain_id_str);

View file

@ -150,6 +150,7 @@ sub formatDocComment
for (my $i = 0; $i < @{$doc}; ++$i)
{
my $docElement = $doc->[$i];
if (ref($docElement) ne 'HASH') { continue }
if ($docElement->{params})
{