Merge remote-tracking branch 'origin/develop' into feature/cli-activate-deregistered-son
This commit is contained in:
commit
f7c8ac8528
12 changed files with 1279 additions and 180 deletions
|
|
@ -76,6 +76,10 @@ void block_database::flush()
|
||||||
|
|
||||||
void block_database::store( const block_id_type& _id, const signed_block& b )
|
void block_database::store( const block_id_type& _id, const signed_block& b )
|
||||||
{
|
{
|
||||||
|
if (true == replay_mode){
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
block_id_type id = _id;
|
block_id_type id = _id;
|
||||||
if( id == block_id_type() )
|
if( id == block_id_type() )
|
||||||
{
|
{
|
||||||
|
|
@ -271,4 +275,9 @@ optional<block_id_type> block_database::last_id()const
|
||||||
return optional<block_id_type>();
|
return optional<block_id_type>();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void block_database::set_replay_mode(bool mode)
|
||||||
|
{
|
||||||
|
replay_mode = mode;
|
||||||
|
}
|
||||||
|
|
||||||
} }
|
} }
|
||||||
|
|
|
||||||
|
|
@ -232,7 +232,12 @@ void database::open(
|
||||||
FC_ASSERT( *last_block >= head_block_id(),
|
FC_ASSERT( *last_block >= head_block_id(),
|
||||||
"last block ID does not match current chain state",
|
"last block ID does not match current chain state",
|
||||||
("last_block->id", last_block)("head_block_id",head_block_num()) );
|
("last_block->id", last_block)("head_block_id",head_block_num()) );
|
||||||
|
|
||||||
|
_block_id_to_block.set_replay_mode(true);
|
||||||
|
|
||||||
reindex( data_dir );
|
reindex( data_dir );
|
||||||
|
|
||||||
|
_block_id_to_block.set_replay_mode(false);
|
||||||
}
|
}
|
||||||
_opened = true;
|
_opened = true;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -47,7 +47,11 @@ namespace graphene { namespace chain {
|
||||||
optional<signed_block> fetch_by_number( uint32_t block_num )const;
|
optional<signed_block> fetch_by_number( uint32_t block_num )const;
|
||||||
optional<signed_block> last()const;
|
optional<signed_block> last()const;
|
||||||
optional<block_id_type> last_id()const;
|
optional<block_id_type> last_id()const;
|
||||||
|
|
||||||
|
void set_replay_mode(bool mode);
|
||||||
private:
|
private:
|
||||||
|
bool replay_mode = false;
|
||||||
|
|
||||||
optional<index_entry> last_index_entry()const;
|
optional<index_entry> last_index_entry()const;
|
||||||
fc::path _index_filename;
|
fc::path _index_filename;
|
||||||
mutable std::fstream _blocks;
|
mutable std::fstream _blocks;
|
||||||
|
|
|
||||||
|
|
@ -30,7 +30,10 @@ namespace graphene { namespace chain {
|
||||||
void memo_data::set_message(const fc::ecc::private_key& priv, const fc::ecc::public_key& pub,
|
void memo_data::set_message(const fc::ecc::private_key& priv, const fc::ecc::public_key& pub,
|
||||||
const string& msg, uint64_t custom_nonce)
|
const string& msg, uint64_t custom_nonce)
|
||||||
{
|
{
|
||||||
if( priv != fc::ecc::private_key() && pub.valid() )
|
bool should_encrypt = (priv != fc::ecc::private_key() && pub.valid());
|
||||||
|
should_encrypt = (should_encrypt) && (msg.size()) && (msg.find("#") == 0);
|
||||||
|
|
||||||
|
if( should_encrypt )
|
||||||
{
|
{
|
||||||
from = priv.get_public_key();
|
from = priv.get_public_key();
|
||||||
to = pub;
|
to = pub;
|
||||||
|
|
@ -49,6 +52,7 @@ void memo_data::set_message(const fc::ecc::private_key& priv, const fc::ecc::pub
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
to = public_key_type();
|
||||||
auto text = memo_message(0, msg).serialize();
|
auto text = memo_message(0, msg).serialize();
|
||||||
message = vector<char>(text.begin(), text.end());
|
message = vector<char>(text.begin(), text.end());
|
||||||
}
|
}
|
||||||
|
|
@ -57,7 +61,7 @@ void memo_data::set_message(const fc::ecc::private_key& priv, const fc::ecc::pub
|
||||||
string memo_data::get_message(const fc::ecc::private_key& priv,
|
string memo_data::get_message(const fc::ecc::private_key& priv,
|
||||||
const fc::ecc::public_key& pub)const
|
const fc::ecc::public_key& pub)const
|
||||||
{
|
{
|
||||||
if( from != public_key_type() && pub.valid() )
|
if( from != public_key_type() && to != public_key_type() && pub.valid() )
|
||||||
{
|
{
|
||||||
auto secret = priv.get_shared_secret(pub);
|
auto secret = priv.get_shared_secret(pub);
|
||||||
auto nonce_plus_secret = fc::sha512::hash(fc::to_string(nonce) + secret.str());
|
auto nonce_plus_secret = fc::sha512::hash(fc::to_string(nonce) + secret.str());
|
||||||
|
|
|
||||||
|
|
@ -3,25 +3,834 @@
|
||||||
#include <sstream>
|
#include <sstream>
|
||||||
#include <string>
|
#include <string>
|
||||||
|
|
||||||
|
//#include <curl/curl.h>
|
||||||
|
|
||||||
|
#include <boost/algorithm/string/case_conv.hpp>
|
||||||
|
#include <boost/algorithm/string/trim.hpp>
|
||||||
|
#include <boost/asio/buffer.hpp>
|
||||||
#include <boost/property_tree/json_parser.hpp>
|
#include <boost/property_tree/json_parser.hpp>
|
||||||
#include <boost/property_tree/ptree.hpp>
|
#include <boost/property_tree/ptree.hpp>
|
||||||
|
|
||||||
#include <curl/curl.h>
|
|
||||||
|
|
||||||
#include <fc/crypto/base64.hpp>
|
#include <fc/crypto/base64.hpp>
|
||||||
#include <fc/log/logger.hpp>
|
#include <fc/log/logger.hpp>
|
||||||
|
#include <fc/network/ip.hpp>
|
||||||
|
|
||||||
namespace graphene { namespace peerplays_sidechain {
|
namespace graphene { namespace peerplays_sidechain {
|
||||||
|
|
||||||
rpc_client::rpc_client(std::string _ip, uint32_t _port, std::string _user, std::string _password, bool _debug_rpc_calls) :
|
constexpr auto http_port = 80;
|
||||||
ip(_ip),
|
constexpr auto https_port = 443;
|
||||||
port(_port),
|
|
||||||
user(_user),
|
template <class string>
|
||||||
password(_password),
|
void make_trimmed(string *str) {
|
||||||
debug_rpc_calls(_debug_rpc_calls),
|
boost::algorithm::trim(*str);
|
||||||
request_id(0) {
|
}
|
||||||
authorization.key = "Authorization";
|
|
||||||
authorization.val = "Basic " + fc::base64_encode(user + ":" + password);
|
template <class string>
|
||||||
|
void make_lower(string *str) {
|
||||||
|
boost::algorithm::to_lower(*str);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool convert_hex_to_num_helper1(const std::string &str, uint32_t *value) {
|
||||||
|
try {
|
||||||
|
size_t idx;
|
||||||
|
auto v = stol(str, &idx, 16);
|
||||||
|
if (idx != str.size())
|
||||||
|
return false;
|
||||||
|
if (value)
|
||||||
|
*value = v;
|
||||||
|
return true;
|
||||||
|
} catch (...) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
bool convert_dec_to_num_helper1(const std::string &str, uint32_t *value) {
|
||||||
|
try {
|
||||||
|
size_t idx;
|
||||||
|
auto v = stol(str, &idx, 10);
|
||||||
|
if (idx != str.size())
|
||||||
|
return false;
|
||||||
|
if (value)
|
||||||
|
*value = v;
|
||||||
|
return true;
|
||||||
|
} catch (...) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
bool convert_dec_to_num_helper1(const std::string &str, uint16_t *value) {
|
||||||
|
try {
|
||||||
|
size_t idx;
|
||||||
|
auto v = stol(str, &idx, 10);
|
||||||
|
if (idx != str.size())
|
||||||
|
return false;
|
||||||
|
if (v > std::numeric_limits<uint16_t>::max())
|
||||||
|
return false;
|
||||||
|
if (value)
|
||||||
|
*value = v;
|
||||||
|
return true;
|
||||||
|
} catch (...) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename V, typename D>
|
||||||
|
constexpr V ceilDiv(V value, D divider) {
|
||||||
|
return (value + divider - 1) / divider;
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename V, typename A>
|
||||||
|
constexpr V aligned(V value, A align) {
|
||||||
|
return ceilDiv(value, align) * align;
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename Container>
|
||||||
|
void reserve(
|
||||||
|
Container *container,
|
||||||
|
typename Container::size_type freeSpaceRequired,
|
||||||
|
typename Container::size_type firstAlloc,
|
||||||
|
typename Container::size_type nextAlloc) {
|
||||||
|
//TSL_ASSERT(container);
|
||||||
|
auto &c = *container;
|
||||||
|
auto required = c.size() + freeSpaceRequired;
|
||||||
|
if (c.capacity() >= required)
|
||||||
|
return;
|
||||||
|
c.reserve((firstAlloc >= required) ? firstAlloc
|
||||||
|
: firstAlloc + aligned(required - firstAlloc, nextAlloc));
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename Container>
|
||||||
|
void reserve(
|
||||||
|
Container *container,
|
||||||
|
typename Container::size_type freeSpaceRequired,
|
||||||
|
typename Container::size_type alloc) {
|
||||||
|
//TSL_ASSERT(container);
|
||||||
|
auto &c = *container;
|
||||||
|
auto required = c.size() + freeSpaceRequired;
|
||||||
|
if (c.capacity() >= required)
|
||||||
|
return;
|
||||||
|
c.reserve(aligned(required, alloc));
|
||||||
|
}
|
||||||
|
|
||||||
|
bool is_valid(const boost::asio::ip::tcp::endpoint &ep) {
|
||||||
|
|
||||||
|
if (ep.port() == 0)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
if (ep.address().is_unspecified())
|
||||||
|
return false;
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
// utl
|
||||||
|
|
||||||
|
url_schema_type identify_url_schema_type(const std::string &schema_name) {
|
||||||
|
// rework
|
||||||
|
auto temp = schema_name;
|
||||||
|
make_lower(&temp);
|
||||||
|
if (temp == "http")
|
||||||
|
return url_schema_type::http;
|
||||||
|
if (temp == "https")
|
||||||
|
return url_schema_type::https;
|
||||||
|
return url_schema_type::unknown;
|
||||||
|
}
|
||||||
|
|
||||||
|
// url_data
|
||||||
|
|
||||||
|
url_data::url_data(const std::string &url) {
|
||||||
|
if (!parse(url))
|
||||||
|
FC_THROW("URL parse failed");
|
||||||
|
}
|
||||||
|
|
||||||
|
void url_data::clear() {
|
||||||
|
schema_type = url_schema_type::unknown;
|
||||||
|
schema = decltype(schema)();
|
||||||
|
host = decltype(host)();
|
||||||
|
port = 0;
|
||||||
|
path = decltype(path)();
|
||||||
|
}
|
||||||
|
|
||||||
|
bool url_data::parse(const std::string &url) {
|
||||||
|
|
||||||
|
typedef std::string::size_type size_t;
|
||||||
|
constexpr auto npos = std::string::npos;
|
||||||
|
|
||||||
|
size_t schema_end = url.find("://");
|
||||||
|
size_t host_begin;
|
||||||
|
std::string temp_schema;
|
||||||
|
|
||||||
|
if (schema_end == npos)
|
||||||
|
host_begin = 0; // no schema
|
||||||
|
else {
|
||||||
|
if (schema_end < 3) { // schema too short: less than 3 chars
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
if (schema_end > 5) { // schema too long: more than 5 chars
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
host_begin = schema_end + 3;
|
||||||
|
temp_schema = url.substr(0, schema_end);
|
||||||
|
}
|
||||||
|
|
||||||
|
// ASSERT(url.size() >= host_begin);
|
||||||
|
|
||||||
|
if (url.size() == host_begin) // host is empty
|
||||||
|
return false;
|
||||||
|
|
||||||
|
size_t port_sep = url.find(':', host_begin);
|
||||||
|
|
||||||
|
if (port_sep == host_begin)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
size_t path_sep = url.find('/', host_begin);
|
||||||
|
|
||||||
|
if (path_sep == host_begin)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
if ((port_sep != npos) && (path_sep != npos) && (port_sep > path_sep))
|
||||||
|
port_sep = npos;
|
||||||
|
|
||||||
|
std::string temp_port;
|
||||||
|
|
||||||
|
if (port_sep != npos) {
|
||||||
|
auto port_index = port_sep + 1;
|
||||||
|
if (path_sep == npos)
|
||||||
|
temp_port = url.substr(port_index);
|
||||||
|
else
|
||||||
|
temp_port = url.substr(port_index, path_sep - port_index);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (temp_port.empty())
|
||||||
|
port = 0;
|
||||||
|
else {
|
||||||
|
if (!convert_dec_to_num_helper1(temp_port, &port))
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string temp_path;
|
||||||
|
|
||||||
|
if (path_sep != npos)
|
||||||
|
temp_path = url.substr(path_sep);
|
||||||
|
|
||||||
|
std::string temp_host;
|
||||||
|
|
||||||
|
if (port_sep != npos) {
|
||||||
|
temp_host = url.substr(host_begin, port_sep - host_begin);
|
||||||
|
} else {
|
||||||
|
if (path_sep != npos)
|
||||||
|
temp_host = url.substr(host_begin, path_sep - host_begin);
|
||||||
|
else
|
||||||
|
temp_host = url.substr(host_begin);
|
||||||
|
}
|
||||||
|
|
||||||
|
schema = temp_schema;
|
||||||
|
host = temp_host;
|
||||||
|
path = temp_path;
|
||||||
|
schema_type = identify_url_schema_type(schema);
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
}} // namespace graphene::peerplays_sidechain
|
||||||
|
|
||||||
|
namespace graphene { namespace peerplays_sidechain {
|
||||||
|
|
||||||
|
using namespace boost::asio;
|
||||||
|
using error_code = boost::system::error_code;
|
||||||
|
using endpoint = ip::tcp::endpoint;
|
||||||
|
|
||||||
|
namespace detail {
|
||||||
|
|
||||||
|
// http_call_impl
|
||||||
|
|
||||||
|
struct tcp_socket {
|
||||||
|
|
||||||
|
typedef ip::tcp::socket underlying_type;
|
||||||
|
|
||||||
|
underlying_type underlying;
|
||||||
|
|
||||||
|
tcp_socket(http_call &call) :
|
||||||
|
underlying(call.m_service) {
|
||||||
|
}
|
||||||
|
|
||||||
|
underlying_type &operator()() {
|
||||||
|
return underlying;
|
||||||
|
}
|
||||||
|
|
||||||
|
void connect(const http_call &call, const endpoint &ep, error_code *ec) {
|
||||||
|
// TCP connect
|
||||||
|
underlying.connect(ep, *ec);
|
||||||
|
}
|
||||||
|
|
||||||
|
void shutdown() {
|
||||||
|
error_code ec;
|
||||||
|
underlying.close(ec);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
struct ssl_socket {
|
||||||
|
|
||||||
|
typedef ssl::stream<ip::tcp::socket> underlying_type;
|
||||||
|
|
||||||
|
underlying_type underlying;
|
||||||
|
|
||||||
|
ssl_socket(http_call &call) :
|
||||||
|
underlying(call.m_service, *call.m_context) {
|
||||||
|
}
|
||||||
|
|
||||||
|
underlying_type &operator()() {
|
||||||
|
return underlying;
|
||||||
|
}
|
||||||
|
|
||||||
|
void connect(const http_call &call, const endpoint &ep, error_code *ec) {
|
||||||
|
|
||||||
|
auto &u = underlying;
|
||||||
|
|
||||||
|
// TCP connect
|
||||||
|
u.lowest_layer().connect(ep, *ec);
|
||||||
|
|
||||||
|
// SSL connect
|
||||||
|
if (!SSL_set_tlsext_host_name(u.native_handle(), call.m_host.c_str()))
|
||||||
|
FC_THROW("SSL_set_tlsext_host_name failed");
|
||||||
|
|
||||||
|
u.set_verify_mode(ssl::verify_peer, *ec);
|
||||||
|
u.handshake(ssl::stream_base::client, *ec);
|
||||||
|
}
|
||||||
|
|
||||||
|
void shutdown() {
|
||||||
|
auto &u = underlying;
|
||||||
|
error_code ec;
|
||||||
|
u.shutdown(ec);
|
||||||
|
u.lowest_layer().close(ec);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
template <class socket_type>
|
||||||
|
class http_call_impl {
|
||||||
|
public:
|
||||||
|
http_call_impl(http_call &call, const void *body_data, size_t body_size, const std::string &content_type_, http_response &response);
|
||||||
|
void exec();
|
||||||
|
|
||||||
|
private:
|
||||||
|
http_call &call;
|
||||||
|
const void *body_data;
|
||||||
|
size_t body_size;
|
||||||
|
std::string content_type;
|
||||||
|
http_response &response;
|
||||||
|
|
||||||
|
socket_type socket;
|
||||||
|
streambuf response_buf;
|
||||||
|
|
||||||
|
int32_t content_length;
|
||||||
|
bool transfer_encoding_chunked;
|
||||||
|
|
||||||
|
private:
|
||||||
|
void connect();
|
||||||
|
void shutdown();
|
||||||
|
void send_request();
|
||||||
|
void on_header(std::string &name, std::string &value);
|
||||||
|
void on_header();
|
||||||
|
void process_headers();
|
||||||
|
void append_entity_body(std::istream *stream, size_t size);
|
||||||
|
void append_entity_body_2(std::istream *strm);
|
||||||
|
bool read_next_chunk(std::istream *strm);
|
||||||
|
void skip_footer();
|
||||||
|
void read_body_chunked();
|
||||||
|
void read_body_until_eof();
|
||||||
|
void read_body_exact();
|
||||||
|
void process_response();
|
||||||
|
};
|
||||||
|
|
||||||
|
static const char cr = 0x0D;
|
||||||
|
static const char lf = 0x0A;
|
||||||
|
static const char *crlf = "\x0D\x0A";
|
||||||
|
static const char *crlfcrlf = "\x0D\x0A\x0D\x0A";
|
||||||
|
static const auto crlf_uint = (((uint16_t)lf) << 8) + cr;
|
||||||
|
|
||||||
|
template <class s>
|
||||||
|
http_call_impl<s>::http_call_impl(http_call &call_, const void *body_data_, size_t body_size_, const std::string &content_type_, http_response &response_) :
|
||||||
|
call(call_),
|
||||||
|
body_data(body_data_),
|
||||||
|
body_size(body_size_),
|
||||||
|
content_type(content_type_),
|
||||||
|
response(response_),
|
||||||
|
socket(call),
|
||||||
|
response_buf(http_call::response_size_limit_bytes) {
|
||||||
|
}
|
||||||
|
|
||||||
|
template <class s>
|
||||||
|
void http_call_impl<s>::exec() {
|
||||||
|
try {
|
||||||
|
connect();
|
||||||
|
send_request();
|
||||||
|
process_response();
|
||||||
|
shutdown();
|
||||||
|
} catch (...) {
|
||||||
|
shutdown();
|
||||||
|
throw;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
template <class s>
|
||||||
|
void http_call_impl<s>::connect() {
|
||||||
|
|
||||||
|
{
|
||||||
|
error_code ec;
|
||||||
|
auto &ep = call.m_endpoint;
|
||||||
|
if (is_valid(ep)) {
|
||||||
|
socket.connect(call, ep, &ec);
|
||||||
|
if (!ec)
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
ip::tcp::resolver resolver(call.m_service);
|
||||||
|
|
||||||
|
auto rng = resolver.resolve(call.m_host, std::string());
|
||||||
|
|
||||||
|
//ASSERT(rng.begin() != rng.end());
|
||||||
|
|
||||||
|
error_code ec;
|
||||||
|
|
||||||
|
for (endpoint ep : rng) {
|
||||||
|
ep.port(call.m_port);
|
||||||
|
socket.connect(call, ep, &ec);
|
||||||
|
if (!ec) {
|
||||||
|
call.m_endpoint = ep;
|
||||||
|
return; // comment to test1
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// if (!ec) return; // uncomment to test1
|
||||||
|
|
||||||
|
//ASSERT(ec);
|
||||||
|
throw boost::system::system_error(ec);
|
||||||
|
}
|
||||||
|
|
||||||
|
template <class s>
|
||||||
|
void http_call_impl<s>::shutdown() {
|
||||||
|
socket.shutdown();
|
||||||
|
}
|
||||||
|
|
||||||
|
template <class s>
|
||||||
|
void http_call_impl<s>::send_request() {
|
||||||
|
|
||||||
|
streambuf request;
|
||||||
|
std::ostream stream(&request);
|
||||||
|
|
||||||
|
// start string: <method> <path> HTTP/1.0
|
||||||
|
|
||||||
|
//ASSERT(!call.m_path.empty());
|
||||||
|
|
||||||
|
stream << call.m_method << " " << call.m_path << " HTTP/1.1" << crlf;
|
||||||
|
|
||||||
|
// host
|
||||||
|
|
||||||
|
stream << "Host: " << call.m_host << ":" << call.m_endpoint.port() << crlf;
|
||||||
|
|
||||||
|
// content
|
||||||
|
|
||||||
|
if (body_size) {
|
||||||
|
stream << "Content-Type: " << content_type << crlf;
|
||||||
|
stream << "Content-Length: " << body_size << crlf;
|
||||||
|
}
|
||||||
|
|
||||||
|
// additional headers
|
||||||
|
|
||||||
|
const auto &h = call.m_headers;
|
||||||
|
|
||||||
|
if (!h.empty()) {
|
||||||
|
if (h.size() < 2)
|
||||||
|
FC_THROW("invalid headers data");
|
||||||
|
stream << h;
|
||||||
|
// ensure headers finished correctly
|
||||||
|
if ((h.substr(h.size() - 2) != crlf))
|
||||||
|
stream << crlf;
|
||||||
|
}
|
||||||
|
|
||||||
|
// other
|
||||||
|
|
||||||
|
// stream << "Accept: *\x2F*" << crlf;
|
||||||
|
stream << "Accept: text/html, application/json" << crlf;
|
||||||
|
stream << "Connection: close" << crlf;
|
||||||
|
|
||||||
|
// end
|
||||||
|
|
||||||
|
stream << crlf;
|
||||||
|
|
||||||
|
// send headers
|
||||||
|
|
||||||
|
write(socket(), request);
|
||||||
|
|
||||||
|
// send body
|
||||||
|
|
||||||
|
if (body_size)
|
||||||
|
write(socket(), buffer(body_data, body_size));
|
||||||
|
}
|
||||||
|
|
||||||
|
template <class s>
|
||||||
|
void http_call_impl<s>::on_header(std::string &name, std::string &value) {
|
||||||
|
|
||||||
|
if (name == "content-length") {
|
||||||
|
uint32_t u;
|
||||||
|
if (!convert_dec_to_num_helper1(value, &u))
|
||||||
|
FC_THROW("invalid content-length header data");
|
||||||
|
content_length = u;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (name == "transfer-encoding") {
|
||||||
|
boost::algorithm::to_lower(value);
|
||||||
|
if (value == "chunked")
|
||||||
|
transfer_encoding_chunked = true;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
template <class s>
|
||||||
|
void http_call_impl<s>::process_headers() {
|
||||||
|
|
||||||
|
std::istream stream(&response_buf);
|
||||||
|
|
||||||
|
std::string http_version;
|
||||||
|
stream >> http_version;
|
||||||
|
stream >> response.status_code;
|
||||||
|
|
||||||
|
make_trimmed(&http_version);
|
||||||
|
make_lower(&http_version);
|
||||||
|
|
||||||
|
if (!stream || http_version.substr(0, 6) != "http/1")
|
||||||
|
FC_THROW("invalid response data");
|
||||||
|
|
||||||
|
// read/skip headers
|
||||||
|
|
||||||
|
content_length = -1;
|
||||||
|
transfer_encoding_chunked = false;
|
||||||
|
|
||||||
|
for (;;) {
|
||||||
|
std::string header;
|
||||||
|
if (!std::getline(stream, header, lf) || (header.size() == 1 && header[0] == cr))
|
||||||
|
break;
|
||||||
|
auto pos = header.find(':');
|
||||||
|
if (pos == std::string::npos)
|
||||||
|
continue;
|
||||||
|
auto name = header.substr(0, pos);
|
||||||
|
make_trimmed(&name);
|
||||||
|
boost::algorithm::to_lower(name);
|
||||||
|
auto value = header.substr(pos + 1);
|
||||||
|
make_trimmed(&value);
|
||||||
|
on_header(name, value);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
template <class s>
|
||||||
|
void http_call_impl<s>::append_entity_body(std::istream *strm, size_t size) {
|
||||||
|
if (size == 0)
|
||||||
|
return;
|
||||||
|
auto &body = response.body;
|
||||||
|
reserve(&body, size, http_call::response_first_alloc_bytes, http_call::response_next_alloc_bytes);
|
||||||
|
auto cur = body.size();
|
||||||
|
body.resize(cur + size);
|
||||||
|
auto p = &body[cur];
|
||||||
|
if (!strm->read(p, size))
|
||||||
|
FC_THROW("stream read failed");
|
||||||
|
}
|
||||||
|
|
||||||
|
template <class s>
|
||||||
|
void http_call_impl<s>::append_entity_body_2(std::istream *strm) {
|
||||||
|
auto avail = response_buf.size();
|
||||||
|
if (response.body.size() + avail > http_call::response_size_limit_bytes)
|
||||||
|
FC_THROW("response body size limit exceeded");
|
||||||
|
append_entity_body(strm, avail);
|
||||||
|
}
|
||||||
|
|
||||||
|
template <class s>
|
||||||
|
bool http_call_impl<s>::read_next_chunk(std::istream *strm) {
|
||||||
|
|
||||||
|
// content length info is used as pre-alloc hint only
|
||||||
|
// it is not used inside the reading logic
|
||||||
|
|
||||||
|
auto &buf = response_buf;
|
||||||
|
auto &stream = *strm;
|
||||||
|
auto &body = response.body;
|
||||||
|
|
||||||
|
read_until(socket(), buf, crlf);
|
||||||
|
|
||||||
|
std::string chunk_header;
|
||||||
|
|
||||||
|
if (!std::getline(stream, chunk_header, lf))
|
||||||
|
FC_THROW("failed to read chunk size");
|
||||||
|
|
||||||
|
auto ext_index = chunk_header.find(':');
|
||||||
|
|
||||||
|
if (ext_index != std::string::npos)
|
||||||
|
chunk_header.resize(ext_index);
|
||||||
|
|
||||||
|
make_trimmed(&chunk_header);
|
||||||
|
|
||||||
|
uint32_t chink_size;
|
||||||
|
|
||||||
|
if (!convert_hex_to_num_helper1(chunk_header, &chink_size))
|
||||||
|
FC_THROW("invalid chunk size string");
|
||||||
|
|
||||||
|
if (body.size() + chink_size > http_call::response_size_limit_bytes)
|
||||||
|
FC_THROW("response body size limit exceeded");
|
||||||
|
|
||||||
|
auto avail = buf.size();
|
||||||
|
if (avail < chink_size + 2) {
|
||||||
|
auto rest = chink_size + 2 - avail;
|
||||||
|
read(socket(), buf, transfer_at_least(rest));
|
||||||
|
}
|
||||||
|
|
||||||
|
append_entity_body(&stream, chink_size);
|
||||||
|
|
||||||
|
uint16_t temp;
|
||||||
|
if (!stream.read((char *)(&temp), 2))
|
||||||
|
FC_THROW("stream read failed");
|
||||||
|
if (temp != crlf_uint)
|
||||||
|
FC_THROW("invalid chink end");
|
||||||
|
|
||||||
|
return chink_size != 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
template <class s>
|
||||||
|
void http_call_impl<s>::skip_footer() {
|
||||||
|
// to be implemeted
|
||||||
|
}
|
||||||
|
|
||||||
|
template <class s>
|
||||||
|
void http_call_impl<s>::read_body_chunked() {
|
||||||
|
|
||||||
|
std::istream stream(&response_buf);
|
||||||
|
|
||||||
|
for (;;) {
|
||||||
|
if (!read_next_chunk(&stream))
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
skip_footer();
|
||||||
|
}
|
||||||
|
|
||||||
|
template <class s>
|
||||||
|
void http_call_impl<s>::read_body_until_eof() {
|
||||||
|
|
||||||
|
auto &buf = response_buf;
|
||||||
|
std::istream stream(&buf);
|
||||||
|
|
||||||
|
append_entity_body_2(&stream);
|
||||||
|
|
||||||
|
error_code ec;
|
||||||
|
|
||||||
|
for (;;) {
|
||||||
|
auto readed = read(socket(), buf, transfer_at_least(1), ec);
|
||||||
|
append_entity_body_2(&stream);
|
||||||
|
if (ec)
|
||||||
|
break;
|
||||||
|
if (!readed) {
|
||||||
|
//ASSERT(buf.size() == 0);
|
||||||
|
FC_THROW("logic error: read failed but no error conditon");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if ((ec != error::eof) &&
|
||||||
|
(ec != ssl::error::stream_truncated))
|
||||||
|
throw boost::system::system_error(ec);
|
||||||
|
}
|
||||||
|
|
||||||
|
template <class s>
|
||||||
|
void http_call_impl<s>::read_body_exact() {
|
||||||
|
|
||||||
|
auto &buf = response_buf;
|
||||||
|
auto &body = response.body;
|
||||||
|
|
||||||
|
auto avail = buf.size();
|
||||||
|
|
||||||
|
if (avail > content_length)
|
||||||
|
FC_THROW("invalid response body (content length mismatch)");
|
||||||
|
|
||||||
|
body.resize(content_length);
|
||||||
|
|
||||||
|
if (avail) {
|
||||||
|
if (avail != buf.sgetn(&body[0], avail))
|
||||||
|
FC_THROW("stream read failed");
|
||||||
|
}
|
||||||
|
|
||||||
|
auto rest = content_length - avail;
|
||||||
|
|
||||||
|
if (rest > 0) {
|
||||||
|
auto readed = read(socket(), buffer(&body[avail], rest), transfer_exactly(rest));
|
||||||
|
//ASSERT(readed <= rest);
|
||||||
|
if (readed < rest)
|
||||||
|
FC_THROW("logic error: read failed but no error conditon");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
template <class s>
|
||||||
|
void http_call_impl<s>::process_response() {
|
||||||
|
|
||||||
|
auto &buf = response_buf;
|
||||||
|
auto &body = response.body;
|
||||||
|
|
||||||
|
read_until(socket(), buf, crlfcrlf);
|
||||||
|
|
||||||
|
process_headers();
|
||||||
|
|
||||||
|
// check content length
|
||||||
|
|
||||||
|
if (content_length >= 0) {
|
||||||
|
if (content_length < 2) { // minimum content is "{}"
|
||||||
|
FC_THROW("invalid response body (too short)");
|
||||||
|
}
|
||||||
|
if (content_length > http_call::response_size_limit_bytes)
|
||||||
|
FC_THROW("response body size limit exceeded");
|
||||||
|
body.reserve(content_length);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (transfer_encoding_chunked) {
|
||||||
|
read_body_chunked();
|
||||||
|
} else {
|
||||||
|
if (content_length < 0)
|
||||||
|
read_body_until_eof();
|
||||||
|
else {
|
||||||
|
if (content_length > 0)
|
||||||
|
read_body_exact();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace detail
|
||||||
|
|
||||||
|
// https_call
|
||||||
|
|
||||||
|
http_call::http_call(const url_data &url, const std::string &method, const std::string &headers) :
|
||||||
|
m_host(url.host),
|
||||||
|
m_method(method),
|
||||||
|
m_headers(headers) {
|
||||||
|
|
||||||
|
if (url.schema_type == url_schema_type::https) {
|
||||||
|
m_context = new boost::asio::ssl::context(ssl::context::tlsv12_client);
|
||||||
|
} else {
|
||||||
|
m_context = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (url.port)
|
||||||
|
m_port_default = url.port;
|
||||||
|
else {
|
||||||
|
if (url.schema_type == url_schema_type::https)
|
||||||
|
m_port_default = https_port;
|
||||||
|
else
|
||||||
|
m_port_default = http_port;
|
||||||
|
}
|
||||||
|
|
||||||
|
m_port = m_port_default;
|
||||||
|
|
||||||
|
set_path(url.path);
|
||||||
|
|
||||||
|
try {
|
||||||
|
ctor_priv();
|
||||||
|
} catch (...) {
|
||||||
|
if (m_context)
|
||||||
|
delete m_context;
|
||||||
|
throw;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
http_call::~http_call() {
|
||||||
|
if (m_context)
|
||||||
|
delete m_context;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool http_call::is_ssl() const {
|
||||||
|
return m_context != 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
const std::string &http_call::path() const {
|
||||||
|
return m_path;
|
||||||
|
}
|
||||||
|
|
||||||
|
void http_call::set_path(const std::string &path) {
|
||||||
|
if (path.empty())
|
||||||
|
m_path = "/";
|
||||||
|
else
|
||||||
|
m_path = path;
|
||||||
|
}
|
||||||
|
|
||||||
|
void http_call::set_method(const std::string &method) {
|
||||||
|
m_method = method;
|
||||||
|
}
|
||||||
|
|
||||||
|
void http_call::set_headers(const std::string &headers) {
|
||||||
|
m_headers = headers;
|
||||||
|
}
|
||||||
|
|
||||||
|
const std::string &http_call::host() const {
|
||||||
|
return m_host;
|
||||||
|
}
|
||||||
|
|
||||||
|
void http_call::set_host(const std::string &host) {
|
||||||
|
m_host = host;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint16_t http_call::port() const {
|
||||||
|
return m_port;
|
||||||
|
}
|
||||||
|
|
||||||
|
void http_call::set_port(uint16_t port) {
|
||||||
|
if (port)
|
||||||
|
m_port = port;
|
||||||
|
else
|
||||||
|
m_port = m_port_default;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool http_call::exec(const http_request &request, http_response *response) {
|
||||||
|
|
||||||
|
//ASSERT(response);
|
||||||
|
auto &resp = *response;
|
||||||
|
m_error_what = decltype(m_error_what)();
|
||||||
|
resp.clear();
|
||||||
|
|
||||||
|
try {
|
||||||
|
try {
|
||||||
|
using namespace detail;
|
||||||
|
if (!m_context)
|
||||||
|
http_call_impl<tcp_socket>(*this, request.body.data(), request.body.size(), request.content_type, resp).exec();
|
||||||
|
else
|
||||||
|
http_call_impl<ssl_socket>(*this, request.body.data(), request.body.size(), request.content_type, resp).exec();
|
||||||
|
return true;
|
||||||
|
} catch (const std::exception &e) {
|
||||||
|
m_error_what = e.what();
|
||||||
|
}
|
||||||
|
} catch (...) {
|
||||||
|
m_error_what = "unknown exception";
|
||||||
|
}
|
||||||
|
|
||||||
|
resp.clear();
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
const std::string &http_call::error_what() const {
|
||||||
|
return m_error_what;
|
||||||
|
}
|
||||||
|
|
||||||
|
void http_call::ctor_priv() {
|
||||||
|
if (m_context) {
|
||||||
|
m_context->set_default_verify_paths();
|
||||||
|
m_context->set_options(ssl::context::default_workarounds);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}} // namespace graphene::peerplays_sidechain
|
||||||
|
|
||||||
|
namespace graphene { namespace peerplays_sidechain {
|
||||||
|
|
||||||
|
rpc_client::rpc_client(const std::string &url, const std::string &user_name, const std::string &password, bool debug) :
|
||||||
|
debug_rpc_calls(debug),
|
||||||
|
request_id(0),
|
||||||
|
client(url)
|
||||||
|
|
||||||
|
{
|
||||||
|
|
||||||
|
client.set_method("POST");
|
||||||
|
client.set_headers("Authorization : Basic" + fc::base64_encode(user_name + ":" + password));
|
||||||
}
|
}
|
||||||
|
|
||||||
std::string rpc_client::retrieve_array_value_from_reply(std::string reply_str, std::string array_path, uint32_t idx) {
|
std::string rpc_client::retrieve_array_value_from_reply(std::string reply_str, std::string array_path, uint32_t idx) {
|
||||||
|
|
@ -91,7 +900,7 @@ std::string rpc_client::send_post_request(std::string method, std::string params
|
||||||
boost::property_tree::ptree json;
|
boost::property_tree::ptree json;
|
||||||
boost::property_tree::read_json(ss, json);
|
boost::property_tree::read_json(ss, json);
|
||||||
|
|
||||||
if (reply.status == 200) {
|
if (reply.status_code == 200) {
|
||||||
return ss.str();
|
return ss.str();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -123,63 +932,82 @@ std::string rpc_client::send_post_request(std::string method, std::string params
|
||||||
// return reply;
|
// return reply;
|
||||||
//}
|
//}
|
||||||
|
|
||||||
static size_t write_callback(char *ptr, size_t size, size_t nmemb, rpc_reply *reply) {
|
//static size_t write_callback(char *ptr, size_t size, size_t nmemb, rpc_reply *reply) {
|
||||||
size_t retval = 0;
|
// size_t retval = 0;
|
||||||
if (reply != nullptr) {
|
// if (reply != nullptr) {
|
||||||
reply->body.append(ptr, size * nmemb);
|
// reply->body.append(ptr, size * nmemb);
|
||||||
retval = size * nmemb;
|
// retval = size * nmemb;
|
||||||
}
|
// }
|
||||||
return retval;
|
// return retval;
|
||||||
}
|
//}
|
||||||
|
|
||||||
rpc_reply rpc_client::send_post_request(std::string body, bool show_log) {
|
//rpc_reply rpc_client::send_post_request(std::string body, bool show_log) {
|
||||||
|
//
|
||||||
|
// struct curl_slist *headers = nullptr;
|
||||||
|
// headers = curl_slist_append(headers, "Accept: application/json");
|
||||||
|
// headers = curl_slist_append(headers, "Content-Type: application/json");
|
||||||
|
// headers = curl_slist_append(headers, "charset: utf-8");
|
||||||
|
//
|
||||||
|
// CURL *curl = curl_easy_init();
|
||||||
|
// if (ip.find("https://", 0) != 0) {
|
||||||
|
// curl_easy_setopt(curl, CURLOPT_URL, ip.c_str());
|
||||||
|
// curl_easy_setopt(curl, CURLOPT_PORT, port);
|
||||||
|
// } else {
|
||||||
|
// std::string full_address = ip + ":" + std::to_string(port);
|
||||||
|
// curl_easy_setopt(curl, CURLOPT_URL, full_address.c_str());
|
||||||
|
// curl_easy_setopt(curl, CURLOPT_SSL_VERIFYPEER, false);
|
||||||
|
// curl_easy_setopt(curl, CURLOPT_SSL_VERIFYHOST, false);
|
||||||
|
// }
|
||||||
|
// if (!user.empty()) {
|
||||||
|
// curl_easy_setopt(curl, CURLOPT_USERNAME, user.c_str());
|
||||||
|
// curl_easy_setopt(curl, CURLOPT_PASSWORD, password.c_str());
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// curl_easy_setopt(curl, CURLOPT_HTTPHEADER, headers);
|
||||||
|
// curl_easy_setopt(curl, CURLOPT_POSTFIELDS, body.c_str());
|
||||||
|
//
|
||||||
|
// //curl_easy_setopt(curl, CURLOPT_VERBOSE, true);
|
||||||
|
//
|
||||||
|
// rpc_reply reply;
|
||||||
|
//
|
||||||
|
// curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, write_callback);
|
||||||
|
// curl_easy_setopt(curl, CURLOPT_WRITEDATA, &reply);
|
||||||
|
//
|
||||||
|
// curl_easy_perform(curl);
|
||||||
|
//
|
||||||
|
// curl_easy_getinfo(curl, CURLINFO_RESPONSE_CODE, &reply.status);
|
||||||
|
//
|
||||||
|
// curl_easy_cleanup(curl);
|
||||||
|
// curl_slist_free_all(headers);
|
||||||
|
//
|
||||||
|
// if (show_log) {
|
||||||
|
// std::string url = ip + ":" + std::to_string(port);
|
||||||
|
// ilog("### Request URL: ${url}", ("url", url));
|
||||||
|
// ilog("### Request: ${body}", ("body", body));
|
||||||
|
// std::stringstream ss(std::string(reply.body.begin(), reply.body.end()));
|
||||||
|
// ilog("### Response: ${ss}", ("ss", ss.str()));
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// return reply;
|
||||||
|
//}
|
||||||
|
|
||||||
struct curl_slist *headers = nullptr;
|
http_response rpc_client::send_post_request(const std::string &body, bool show_log) {
|
||||||
headers = curl_slist_append(headers, "Accept: application/json");
|
|
||||||
headers = curl_slist_append(headers, "Content-Type: application/json");
|
|
||||||
headers = curl_slist_append(headers, "charset: utf-8");
|
|
||||||
|
|
||||||
CURL *curl = curl_easy_init();
|
http_request request(body, "application/json");
|
||||||
if (ip.find("https://", 0) != 0) {
|
http_response response;
|
||||||
curl_easy_setopt(curl, CURLOPT_URL, ip.c_str());
|
|
||||||
curl_easy_setopt(curl, CURLOPT_PORT, port);
|
|
||||||
} else {
|
|
||||||
std::string full_address = ip + ":" + std::to_string(port);
|
|
||||||
curl_easy_setopt(curl, CURLOPT_URL, full_address.c_str());
|
|
||||||
curl_easy_setopt(curl, CURLOPT_SSL_VERIFYPEER, false);
|
|
||||||
curl_easy_setopt(curl, CURLOPT_SSL_VERIFYHOST, false);
|
|
||||||
}
|
|
||||||
if (!user.empty()) {
|
|
||||||
curl_easy_setopt(curl, CURLOPT_USERNAME, user.c_str());
|
|
||||||
curl_easy_setopt(curl, CURLOPT_PASSWORD, password.c_str());
|
|
||||||
}
|
|
||||||
|
|
||||||
curl_easy_setopt(curl, CURLOPT_HTTPHEADER, headers);
|
client.exec(request, &response);
|
||||||
curl_easy_setopt(curl, CURLOPT_POSTFIELDS, body.c_str());
|
|
||||||
|
|
||||||
//curl_easy_setopt(curl, CURLOPT_VERBOSE, true);
|
|
||||||
|
|
||||||
rpc_reply reply;
|
|
||||||
|
|
||||||
curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, write_callback);
|
|
||||||
curl_easy_setopt(curl, CURLOPT_WRITEDATA, &reply);
|
|
||||||
|
|
||||||
curl_easy_perform(curl);
|
|
||||||
|
|
||||||
curl_easy_getinfo(curl, CURLINFO_RESPONSE_CODE, &reply.status);
|
|
||||||
|
|
||||||
curl_easy_cleanup(curl);
|
|
||||||
curl_slist_free_all(headers);
|
|
||||||
|
|
||||||
if (show_log) {
|
if (show_log) {
|
||||||
std::string url = ip + ":" + std::to_string(port);
|
std::string url = client.is_ssl() ? "https" : "http";
|
||||||
|
url = url + "://" + client.host() + ":" + std::to_string(client.port()) + client.path();
|
||||||
ilog("### Request URL: ${url}", ("url", url));
|
ilog("### Request URL: ${url}", ("url", url));
|
||||||
ilog("### Request: ${body}", ("body", body));
|
ilog("### Request: ${body}", ("body", body));
|
||||||
std::stringstream ss(std::string(reply.body.begin(), reply.body.end()));
|
std::stringstream ss(std::string(response.body.begin(), response.body.end()));
|
||||||
ilog("### Response: ${ss}", ("ss", ss.str()));
|
ilog("### Response: ${ss}", ("ss", ss.str()));
|
||||||
}
|
}
|
||||||
|
|
||||||
return reply;
|
return response;
|
||||||
}
|
}
|
||||||
|
|
||||||
}} // namespace graphene::peerplays_sidechain
|
}} // namespace graphene::peerplays_sidechain
|
||||||
|
|
|
||||||
|
|
@ -3,37 +3,134 @@
|
||||||
#include <cstdint>
|
#include <cstdint>
|
||||||
#include <string>
|
#include <string>
|
||||||
|
|
||||||
#include <fc/network/http/connection.hpp>
|
#include <boost/asio.hpp>
|
||||||
|
#include <boost/asio/ssl.hpp>
|
||||||
|
|
||||||
|
//#include <fc/network/http/connection.hpp>
|
||||||
|
|
||||||
namespace graphene { namespace peerplays_sidechain {
|
namespace graphene { namespace peerplays_sidechain {
|
||||||
|
|
||||||
struct rpc_reply {
|
enum class url_schema_type { unknown,
|
||||||
uint16_t status;
|
http,
|
||||||
std::string body;
|
https,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// utl
|
||||||
|
|
||||||
|
url_schema_type identify_url_schema_type(const std::string &schema_name);
|
||||||
|
|
||||||
|
struct url_data {
|
||||||
|
|
||||||
|
url_schema_type schema_type;
|
||||||
|
std::string schema;
|
||||||
|
std::string host;
|
||||||
|
uint16_t port;
|
||||||
|
std::string path;
|
||||||
|
|
||||||
|
url_data() :
|
||||||
|
schema_type(url_schema_type::unknown),
|
||||||
|
port(0) {
|
||||||
|
}
|
||||||
|
|
||||||
|
url_data(const std::string &url);
|
||||||
|
|
||||||
|
void clear();
|
||||||
|
|
||||||
|
bool parse(const std::string &url);
|
||||||
|
};
|
||||||
|
|
||||||
|
struct http_request {
|
||||||
|
|
||||||
|
std::string body;
|
||||||
|
std::string content_type;
|
||||||
|
|
||||||
|
http_request(const std::string &body_, const std::string &content_type_) :
|
||||||
|
body(body_),
|
||||||
|
content_type(content_type_) {
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
struct http_response {
|
||||||
|
|
||||||
|
uint16_t status_code;
|
||||||
|
std::string body;
|
||||||
|
|
||||||
|
void clear() {
|
||||||
|
status_code = 0;
|
||||||
|
body = decltype(body)();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
namespace detail {
|
||||||
|
template <class>
|
||||||
|
class http_call_impl;
|
||||||
|
class tcp_socket;
|
||||||
|
class ssl_socket;
|
||||||
|
} // namespace detail
|
||||||
|
|
||||||
|
class http_call {
|
||||||
|
public:
|
||||||
|
http_call(const url_data &url, const std::string &method = std::string(), const std::string &headers = std::string());
|
||||||
|
~http_call();
|
||||||
|
|
||||||
|
bool is_ssl() const;
|
||||||
|
|
||||||
|
const std::string &path() const;
|
||||||
|
void set_path(const std::string &path);
|
||||||
|
void set_method(const std::string &method);
|
||||||
|
void set_headers(const std::string &headers);
|
||||||
|
const std::string &host() const;
|
||||||
|
void set_host(const std::string &host);
|
||||||
|
|
||||||
|
uint16_t port() const;
|
||||||
|
void set_port(uint16_t port);
|
||||||
|
|
||||||
|
bool exec(const http_request &request, http_response *response);
|
||||||
|
|
||||||
|
const std::string &error_what() const;
|
||||||
|
|
||||||
|
private:
|
||||||
|
template <class>
|
||||||
|
friend class detail::http_call_impl;
|
||||||
|
friend detail::tcp_socket;
|
||||||
|
friend detail::ssl_socket;
|
||||||
|
static constexpr auto response_size_limit_bytes = 16 * 1024 * 1024;
|
||||||
|
static constexpr auto response_first_alloc_bytes = 32 * 1024;
|
||||||
|
static constexpr auto response_next_alloc_bytes = 256 * 1024;
|
||||||
|
std::string m_host;
|
||||||
|
uint16_t m_port_default;
|
||||||
|
uint16_t m_port;
|
||||||
|
std::string m_path;
|
||||||
|
std::string m_method;
|
||||||
|
std::string m_headers;
|
||||||
|
std::string m_error_what;
|
||||||
|
|
||||||
|
boost::asio::io_service m_service;
|
||||||
|
boost::asio::ssl::context *m_context;
|
||||||
|
boost::asio::ip::tcp::endpoint m_endpoint;
|
||||||
|
|
||||||
|
void ctor_priv();
|
||||||
|
};
|
||||||
|
|
||||||
|
}} // namespace graphene::peerplays_sidechain
|
||||||
|
|
||||||
|
namespace graphene { namespace peerplays_sidechain {
|
||||||
|
|
||||||
class rpc_client {
|
class rpc_client {
|
||||||
public:
|
public:
|
||||||
rpc_client(std::string _ip, uint32_t _port, std::string _user, std::string _password, bool _debug_rpc_calls);
|
rpc_client(const std::string &url, const std::string &user_name, const std::string &password, bool debug);
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
std::string retrieve_array_value_from_reply(std::string reply_str, std::string array_path, uint32_t idx);
|
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);
|
std::string retrieve_value_from_reply(std::string reply_str, std::string value_path);
|
||||||
std::string send_post_request(std::string method, std::string params, bool show_log);
|
std::string send_post_request(std::string method, std::string params, bool show_log);
|
||||||
|
|
||||||
std::string ip;
|
|
||||||
uint32_t port;
|
|
||||||
std::string user;
|
|
||||||
std::string password;
|
|
||||||
bool debug_rpc_calls;
|
bool debug_rpc_calls;
|
||||||
|
|
||||||
uint32_t request_id;
|
uint32_t request_id;
|
||||||
|
|
||||||
fc::http::header authorization;
|
|
||||||
|
|
||||||
private:
|
private:
|
||||||
//fc::http::reply send_post_request(std::string body, bool show_log);
|
http_call client;
|
||||||
rpc_reply send_post_request(std::string body, bool show_log);
|
http_response send_post_request(const std::string &body, bool show_log);
|
||||||
};
|
};
|
||||||
|
|
||||||
}} // namespace graphene::peerplays_sidechain
|
}} // namespace graphene::peerplays_sidechain
|
||||||
|
|
|
||||||
|
|
@ -7,6 +7,8 @@
|
||||||
|
|
||||||
#include <boost/signals2.hpp>
|
#include <boost/signals2.hpp>
|
||||||
|
|
||||||
|
#include <mutex>
|
||||||
|
|
||||||
#include <fc/network/http/connection.hpp>
|
#include <fc/network/http/connection.hpp>
|
||||||
#include <graphene/peerplays_sidechain/bitcoin/bitcoin_address.hpp>
|
#include <graphene/peerplays_sidechain/bitcoin/bitcoin_address.hpp>
|
||||||
|
|
||||||
|
|
@ -114,6 +116,9 @@ private:
|
||||||
fc::future<void> on_changed_objects_task;
|
fc::future<void> on_changed_objects_task;
|
||||||
bitcoin::bitcoin_address::network network_type;
|
bitcoin::bitcoin_address::network network_type;
|
||||||
|
|
||||||
|
std::mutex event_handler_mutex;
|
||||||
|
typedef std::lock_guard<decltype(event_handler_mutex)> scoped_lock;
|
||||||
|
|
||||||
std::string create_primary_wallet_address(const std::vector<son_info> &son_pubkeys);
|
std::string create_primary_wallet_address(const std::vector<son_info> &son_pubkeys);
|
||||||
|
|
||||||
std::string create_primary_wallet_transaction(const son_wallet_object &prev_swo, std::string new_sw_address);
|
std::string create_primary_wallet_transaction(const son_wallet_object &prev_swo, std::string new_sw_address);
|
||||||
|
|
|
||||||
|
|
@ -14,7 +14,7 @@ namespace graphene { namespace peerplays_sidechain {
|
||||||
|
|
||||||
class hive_node_rpc_client : public rpc_client {
|
class hive_node_rpc_client : public rpc_client {
|
||||||
public:
|
public:
|
||||||
hive_node_rpc_client(std::string _ip, uint32_t _port, std::string _user, std::string _password, bool _debug_rpc_calls);
|
hive_node_rpc_client(const std::string &url, const std::string &user_name, const std::string &password, bool debug_rpc_calls);
|
||||||
|
|
||||||
std::string account_history_api_get_transaction(std::string transaction_id);
|
std::string account_history_api_get_transaction(std::string transaction_id);
|
||||||
std::string block_api_get_block(uint32_t block_number);
|
std::string block_api_get_block(uint32_t block_number);
|
||||||
|
|
@ -48,8 +48,7 @@ public:
|
||||||
bool settle_sidechain_transaction(const sidechain_transaction_object &sto, asset &settle_amount);
|
bool settle_sidechain_transaction(const sidechain_transaction_object &sto, asset &settle_amount);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
std::string node_ip;
|
std::string node_rpc_url;
|
||||||
uint32_t node_rpc_port;
|
|
||||||
std::string node_rpc_user;
|
std::string node_rpc_user;
|
||||||
std::string node_rpc_password;
|
std::string node_rpc_password;
|
||||||
hive_node_rpc_client *node_rpc_client;
|
hive_node_rpc_client *node_rpc_client;
|
||||||
|
|
|
||||||
|
|
@ -156,8 +156,7 @@ void peerplays_sidechain_plugin_impl::plugin_set_program_options(
|
||||||
"Tuple of [Bitcoin public key, Bitcoin private key] (may specify multiple times)");
|
"Tuple of [Bitcoin public key, Bitcoin 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-sidechain-enabled", bpo::value<bool>()->default_value(false), "Hive sidechain handler enabled");
|
||||||
cli.add_options()("hive-node-ip", bpo::value<string>()->default_value("127.0.0.1"), "Hive node IP address");
|
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-port", bpo::value<uint32_t>()->default_value(28090), "Hive node RPC port");
|
|
||||||
cli.add_options()("hive-node-rpc-user", bpo::value<string>(), "Hive node RPC user");
|
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-node-rpc-password", bpo::value<string>(), "Hive node RPC password");
|
||||||
cli.add_options()("hive-private-key", bpo::value<vector<string>>()->composing()->multitoken()->DEFAULT_VALUE_VECTOR(std::make_pair("TST6LLegbAgLAy28EHrffBVuANFWcFgmqRMW13wBmTExqFE9SCkg4", "5JNHfZYKGaomSFvd4NUdQ9qMcEAC43kujbfjueTHpVapX1Kzq2n")),
|
cli.add_options()("hive-private-key", bpo::value<vector<string>>()->composing()->multitoken()->DEFAULT_VALUE_VECTOR(std::make_pair("TST6LLegbAgLAy28EHrffBVuANFWcFgmqRMW13wBmTExqFE9SCkg4", "5JNHfZYKGaomSFvd4NUdQ9qMcEAC43kujbfjueTHpVapX1Kzq2n")),
|
||||||
|
|
@ -231,8 +230,7 @@ void peerplays_sidechain_plugin_impl::plugin_initialize(const boost::program_opt
|
||||||
//}
|
//}
|
||||||
|
|
||||||
sidechain_enabled_hive = options.at("hive-sidechain-enabled").as<bool>();
|
sidechain_enabled_hive = options.at("hive-sidechain-enabled").as<bool>();
|
||||||
config_ready_hive = options.count("hive-node-ip") &&
|
config_ready_hive = options.count("hive-node-rpc-url") &&
|
||||||
options.count("hive-node-rpc-port") &&
|
|
||||||
/*options.count("hive-node-rpc-user") && options.count("hive-node-rpc-password") &&*/
|
/*options.count("hive-node-rpc-user") && options.count("hive-node-rpc-password") &&*/
|
||||||
options.count("hive-private-key");
|
options.count("hive-private-key");
|
||||||
if (!config_ready_hive) {
|
if (!config_ready_hive) {
|
||||||
|
|
|
||||||
|
|
@ -1360,37 +1360,41 @@ void sidechain_net_handler_bitcoin::process_sidechain_addresses() {
|
||||||
std::for_each(sidechain_addresses_by_sidechain_range.first, sidechain_addresses_by_sidechain_range.second,
|
std::for_each(sidechain_addresses_by_sidechain_range.first, sidechain_addresses_by_sidechain_range.second,
|
||||||
[&](const sidechain_address_object &sao) {
|
[&](const sidechain_address_object &sao) {
|
||||||
bool retval = true;
|
bool retval = true;
|
||||||
if (sao.expires == time_point_sec::maximum()) {
|
try {
|
||||||
auto usr_pubkey = fc::ecc::public_key(create_public_key_data(parse_hex(sao.deposit_public_key)));
|
if (sao.expires == time_point_sec::maximum()) {
|
||||||
|
auto usr_pubkey = fc::ecc::public_key(create_public_key_data(parse_hex(sao.deposit_public_key)));
|
||||||
|
|
||||||
btc_one_or_weighted_multisig_address addr(usr_pubkey, pubkeys, network_type);
|
btc_one_or_weighted_multisig_address addr(usr_pubkey, pubkeys, network_type);
|
||||||
std::string address_data = "{ \"redeemScript\": \"" + fc::to_hex(addr.get_redeem_script()) +
|
std::string address_data = "{ \"redeemScript\": \"" + fc::to_hex(addr.get_redeem_script()) +
|
||||||
"\", \"witnessScript\": \"" + fc::to_hex(addr.get_witness_script()) + "\" }";
|
"\", \"witnessScript\": \"" + fc::to_hex(addr.get_witness_script()) + "\" }";
|
||||||
|
|
||||||
if (addr.get_address() != sao.deposit_address) {
|
if (addr.get_address() != sao.deposit_address) {
|
||||||
sidechain_address_update_operation op;
|
sidechain_address_update_operation op;
|
||||||
op.payer = plugin.get_current_son_object().son_account;
|
op.payer = plugin.get_current_son_object().son_account;
|
||||||
op.sidechain_address_id = sao.id;
|
op.sidechain_address_id = sao.id;
|
||||||
op.sidechain_address_account = sao.sidechain_address_account;
|
op.sidechain_address_account = sao.sidechain_address_account;
|
||||||
op.sidechain = sao.sidechain;
|
op.sidechain = sao.sidechain;
|
||||||
op.deposit_public_key = sao.deposit_public_key;
|
op.deposit_public_key = sao.deposit_public_key;
|
||||||
op.deposit_address = addr.get_address();
|
op.deposit_address = addr.get_address();
|
||||||
op.deposit_address_data = address_data;
|
op.deposit_address_data = address_data;
|
||||||
op.withdraw_public_key = sao.withdraw_public_key;
|
op.withdraw_public_key = sao.withdraw_public_key;
|
||||||
op.withdraw_address = sao.withdraw_address;
|
op.withdraw_address = sao.withdraw_address;
|
||||||
|
|
||||||
signed_transaction trx = database.create_signed_transaction(plugin.get_private_key(plugin.get_current_son_id()), op);
|
signed_transaction trx = database.create_signed_transaction(plugin.get_private_key(plugin.get_current_son_id()), op);
|
||||||
try {
|
try {
|
||||||
trx.validate();
|
trx.validate();
|
||||||
database.push_transaction(trx, database::validation_steps::skip_block_size_check);
|
database.push_transaction(trx, database::validation_steps::skip_block_size_check);
|
||||||
if (plugin.app().p2p_node())
|
if (plugin.app().p2p_node())
|
||||||
plugin.app().p2p_node()->broadcast(net::trx_message(trx));
|
plugin.app().p2p_node()->broadcast(net::trx_message(trx));
|
||||||
retval = true;
|
retval = true;
|
||||||
} catch (fc::exception &e) {
|
} catch (fc::exception &e) {
|
||||||
elog("Sending transaction for sidechain address update operation failed with exception ${e}", ("e", e.what()));
|
elog("Sending transaction for sidechain address update operation failed with exception ${e}", ("e", e.what()));
|
||||||
retval = false;
|
retval = false;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
} catch (fc::exception &e) {
|
||||||
|
retval = false;
|
||||||
}
|
}
|
||||||
return retval;
|
return retval;
|
||||||
});
|
});
|
||||||
|
|
@ -1801,38 +1805,39 @@ std::string sidechain_net_handler_bitcoin::send_transaction(const sidechain_tran
|
||||||
|
|
||||||
void sidechain_net_handler_bitcoin::handle_event(const std::string &event_data) {
|
void sidechain_net_handler_bitcoin::handle_event(const std::string &event_data) {
|
||||||
std::string block = bitcoin_client->getblock(event_data);
|
std::string block = bitcoin_client->getblock(event_data);
|
||||||
if (block != "") {
|
if (block.empty())
|
||||||
const auto &vins = extract_info_from_block(block);
|
return;
|
||||||
|
|
||||||
const auto &sidechain_addresses_idx = database.get_index_type<sidechain_address_index>().indices().get<by_sidechain_and_deposit_address_and_expires>();
|
auto vins = extract_info_from_block(block);
|
||||||
|
scoped_lock interlock(event_handler_mutex);
|
||||||
|
const auto &sidechain_addresses_idx = database.get_index_type<sidechain_address_index>().indices().get<by_sidechain_and_deposit_address_and_expires>();
|
||||||
|
|
||||||
for (const auto &v : vins) {
|
for (const auto &v : vins) {
|
||||||
// !!! EXTRACT DEPOSIT ADDRESS FROM SIDECHAIN ADDRESS OBJECT
|
// !!! EXTRACT DEPOSIT ADDRESS FROM SIDECHAIN ADDRESS OBJECT
|
||||||
const auto &addr_itr = sidechain_addresses_idx.find(std::make_tuple(sidechain, v.address, time_point_sec::maximum()));
|
const auto &addr_itr = sidechain_addresses_idx.find(std::make_tuple(sidechain, v.address, time_point_sec::maximum()));
|
||||||
if (addr_itr == sidechain_addresses_idx.end())
|
if (addr_itr == sidechain_addresses_idx.end())
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
std::stringstream ss;
|
std::stringstream ss;
|
||||||
ss << "bitcoin"
|
ss << "bitcoin"
|
||||||
<< "-" << v.out.hash_tx << "-" << v.out.n_vout;
|
<< "-" << v.out.hash_tx << "-" << v.out.n_vout;
|
||||||
std::string sidechain_uid = ss.str();
|
std::string sidechain_uid = ss.str();
|
||||||
|
|
||||||
sidechain_event_data sed;
|
sidechain_event_data sed;
|
||||||
sed.timestamp = database.head_block_time();
|
sed.timestamp = database.head_block_time();
|
||||||
sed.block_num = database.head_block_num();
|
sed.block_num = database.head_block_num();
|
||||||
sed.sidechain = addr_itr->sidechain;
|
sed.sidechain = addr_itr->sidechain;
|
||||||
sed.sidechain_uid = sidechain_uid;
|
sed.sidechain_uid = sidechain_uid;
|
||||||
sed.sidechain_transaction_id = v.out.hash_tx;
|
sed.sidechain_transaction_id = v.out.hash_tx;
|
||||||
sed.sidechain_from = v.address;
|
sed.sidechain_from = v.address;
|
||||||
sed.sidechain_to = "";
|
sed.sidechain_to = "";
|
||||||
sed.sidechain_currency = "BTC";
|
sed.sidechain_currency = "BTC";
|
||||||
sed.sidechain_amount = v.out.amount;
|
sed.sidechain_amount = v.out.amount;
|
||||||
sed.peerplays_from = addr_itr->sidechain_address_account;
|
sed.peerplays_from = addr_itr->sidechain_address_account;
|
||||||
sed.peerplays_to = database.get_global_properties().parameters.son_account();
|
sed.peerplays_to = database.get_global_properties().parameters.son_account();
|
||||||
price btc_price = database.get<asset_object>(database.get_global_properties().parameters.btc_asset()).options.core_exchange_rate;
|
price btc_price = database.get<asset_object>(database.get_global_properties().parameters.btc_asset()).options.core_exchange_rate;
|
||||||
sed.peerplays_asset = asset(sed.sidechain_amount * btc_price.base.amount / btc_price.quote.amount);
|
sed.peerplays_asset = asset(sed.sidechain_amount * btc_price.base.amount / btc_price.quote.amount);
|
||||||
sidechain_event_data_received(sed);
|
sidechain_event_data_received(sed);
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -32,35 +32,8 @@
|
||||||
|
|
||||||
namespace graphene { namespace peerplays_sidechain {
|
namespace graphene { namespace peerplays_sidechain {
|
||||||
|
|
||||||
std::string resolve_host_addr(const std::string &host_name) {
|
hive_node_rpc_client::hive_node_rpc_client(const std::string &url, const std::string &user_name, const std::string &password, bool debug_rpc_calls) :
|
||||||
using namespace boost::asio;
|
rpc_client(url, user_name, password, debug_rpc_calls) {
|
||||||
io_service service;
|
|
||||||
ip::tcp::resolver resolver(service);
|
|
||||||
auto query = ip::tcp::resolver::query(host_name, std::string());
|
|
||||||
auto iter = resolver.resolve(query);
|
|
||||||
auto endpoint = *iter;
|
|
||||||
auto addr = ((ip::tcp::endpoint)endpoint).address();
|
|
||||||
return addr.to_string();
|
|
||||||
}
|
|
||||||
|
|
||||||
std::string strip_proto_name(const std::string &url, std::string *schema) {
|
|
||||||
auto index = url.find("://");
|
|
||||||
if (index == std::string::npos) {
|
|
||||||
if (schema)
|
|
||||||
schema->clear();
|
|
||||||
return url;
|
|
||||||
}
|
|
||||||
if (schema)
|
|
||||||
schema->assign(&url[0], &url[index + 3]);
|
|
||||||
return url.substr(index + 3);
|
|
||||||
}
|
|
||||||
|
|
||||||
}} // namespace graphene::peerplays_sidechain
|
|
||||||
|
|
||||||
namespace graphene { namespace peerplays_sidechain {
|
|
||||||
|
|
||||||
hive_node_rpc_client::hive_node_rpc_client(std::string _ip, uint32_t _port, std::string _user, std::string _password, bool _debug_rpc_calls) :
|
|
||||||
rpc_client(_ip, _port, _user, _password, _debug_rpc_calls) {
|
|
||||||
}
|
}
|
||||||
|
|
||||||
std::string hive_node_rpc_client::account_history_api_get_transaction(std::string transaction_id) {
|
std::string hive_node_rpc_client::account_history_api_get_transaction(std::string transaction_id) {
|
||||||
|
|
@ -149,8 +122,7 @@ sidechain_net_handler_hive::sidechain_net_handler_hive(peerplays_sidechain_plugi
|
||||||
debug_rpc_calls = options.at("debug-rpc-calls").as<bool>();
|
debug_rpc_calls = options.at("debug-rpc-calls").as<bool>();
|
||||||
}
|
}
|
||||||
|
|
||||||
node_ip = options.at("hive-node-ip").as<std::string>();
|
node_rpc_url = options.at("hive-node-rpc-url").as<std::string>();
|
||||||
node_rpc_port = options.at("hive-node-rpc-port").as<uint32_t>();
|
|
||||||
if (options.count("hive-node-rpc-user")) {
|
if (options.count("hive-node-rpc-user")) {
|
||||||
node_rpc_user = options.at("hive-node-rpc-user").as<std::string>();
|
node_rpc_user = options.at("hive-node-rpc-user").as<std::string>();
|
||||||
} else {
|
} else {
|
||||||
|
|
@ -174,11 +146,11 @@ sidechain_net_handler_hive::sidechain_net_handler_hive(peerplays_sidechain_plugi
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
node_rpc_client = new hive_node_rpc_client(node_ip, node_rpc_port, node_rpc_user, node_rpc_password, debug_rpc_calls);
|
node_rpc_client = new hive_node_rpc_client(node_rpc_url, node_rpc_user, node_rpc_password, debug_rpc_calls);
|
||||||
|
|
||||||
std::string chain_id_str = node_rpc_client->get_chain_id();
|
std::string chain_id_str = node_rpc_client->get_chain_id();
|
||||||
if (chain_id_str.empty()) {
|
if (chain_id_str.empty()) {
|
||||||
elog("No Hive node running at ${ip} or wrong rpc port: ${port}", ("ip", node_ip)("port", node_rpc_port));
|
elog("No Hive node running at ${url}", ("url", node_rpc_url));
|
||||||
FC_ASSERT(false);
|
FC_ASSERT(false);
|
||||||
}
|
}
|
||||||
chain_id = chain_id_type(chain_id_str);
|
chain_id = chain_id_type(chain_id_str);
|
||||||
|
|
|
||||||
|
|
@ -182,21 +182,194 @@ BOOST_AUTO_TEST_CASE( price_test )
|
||||||
|
|
||||||
BOOST_AUTO_TEST_CASE( memo_test )
|
BOOST_AUTO_TEST_CASE( memo_test )
|
||||||
{ try {
|
{ try {
|
||||||
memo_data m;
|
auto sender_private_key = generate_private_key("1");
|
||||||
auto sender = generate_private_key("1");
|
auto sender_public_key = sender_private_key.get_public_key();
|
||||||
auto receiver = generate_private_key("2");
|
auto receiver_private_key = generate_private_key("2");
|
||||||
m.from = sender.get_public_key();
|
auto receiver_public_key = receiver_private_key.get_public_key();
|
||||||
m.to = receiver.get_public_key();
|
|
||||||
m.set_message(sender, receiver.get_public_key(), "Hello, world!", 12345);
|
auto dummy_private_key = private_key_type();
|
||||||
|
auto dummy_public_key = public_key_type();
|
||||||
|
|
||||||
decltype(fc::digest(m)) hash("8de72a07d093a589f574460deb19023b4aff354b561eb34590d9f4629f51dbf3");
|
|
||||||
if( fc::digest(m) != hash )
|
|
||||||
{
|
{
|
||||||
// If this happens, notify the web guys that the memo serialization format changed.
|
memo_data m;
|
||||||
edump((m)(fc::digest(m)));
|
m.from = dummy_public_key;
|
||||||
BOOST_FAIL("Memo format has changed. Notify the web guys and update this test.");
|
m.to = dummy_public_key;
|
||||||
|
m.set_message(dummy_private_key, dummy_public_key, "Hello, world!", 12345);
|
||||||
|
|
||||||
|
decltype(fc::digest(m)) hash("b9ad6eb2c466678a911f2f10f29d2a0d98600335b00e4c4ffbeabccb76c77bf0");
|
||||||
|
if( fc::digest(m) != hash ) {
|
||||||
|
// If this happens, notify the web guys that the memo serialization format changed.
|
||||||
|
edump((m)(fc::digest(m)));
|
||||||
|
BOOST_FAIL("Memo format has changed. Notify the web guys and update this test.");
|
||||||
|
}
|
||||||
|
BOOST_CHECK_EQUAL(m.get_message(dummy_private_key, dummy_public_key), "Hello, world!");
|
||||||
}
|
}
|
||||||
BOOST_CHECK_EQUAL(m.get_message(receiver, sender.get_public_key()), "Hello, world!");
|
|
||||||
|
{
|
||||||
|
memo_data m;
|
||||||
|
m.from = dummy_public_key;
|
||||||
|
m.to = receiver_public_key;
|
||||||
|
m.set_message(dummy_private_key, receiver_public_key, "Hello, world!", 12345);
|
||||||
|
|
||||||
|
decltype(fc::digest(m)) hash("b9ad6eb2c466678a911f2f10f29d2a0d98600335b00e4c4ffbeabccb76c77bf0");
|
||||||
|
if( fc::digest(m) != hash ) {
|
||||||
|
// If this happens, notify the web guys that the memo serialization format changed.
|
||||||
|
edump((m)(fc::digest(m)));
|
||||||
|
BOOST_FAIL("Memo format has changed. Notify the web guys and update this test.");
|
||||||
|
}
|
||||||
|
BOOST_CHECK_EQUAL(m.get_message(receiver_private_key, dummy_public_key), "Hello, world!");
|
||||||
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
memo_data m;
|
||||||
|
m.from = sender_public_key;
|
||||||
|
m.to = dummy_public_key;
|
||||||
|
m.set_message(sender_private_key, dummy_public_key, "Hello, world!", 12345);
|
||||||
|
|
||||||
|
decltype(fc::digest(m)) hash("b756ef1b27e3bb8e61eea534a0b28e89b0fa72b73f8b7e6bc99b55a92ec3cf9b");
|
||||||
|
if( fc::digest(m) != hash ) {
|
||||||
|
// If this happens, notify the web guys that the memo serialization format changed.
|
||||||
|
edump((m)(fc::digest(m)));
|
||||||
|
BOOST_FAIL("Memo format has changed. Notify the web guys and update this test.");
|
||||||
|
}
|
||||||
|
BOOST_CHECK_EQUAL(m.get_message(dummy_private_key, sender_public_key), "Hello, world!");
|
||||||
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
memo_data m;
|
||||||
|
m.from = sender_public_key;
|
||||||
|
m.to = receiver_public_key;
|
||||||
|
m.set_message(sender_private_key, receiver_public_key, "Hello, world!", 12345);
|
||||||
|
|
||||||
|
decltype(fc::digest(m)) hash("b756ef1b27e3bb8e61eea534a0b28e89b0fa72b73f8b7e6bc99b55a92ec3cf9b");
|
||||||
|
if( fc::digest(m) != hash ) {
|
||||||
|
// If this happens, notify the web guys that the memo serialization format changed.
|
||||||
|
edump((m)(fc::digest(m)));
|
||||||
|
BOOST_FAIL("Memo format has changed. Notify the web guys and update this test.");
|
||||||
|
}
|
||||||
|
BOOST_CHECK_EQUAL(m.get_message(receiver_private_key, sender_public_key), "Hello, world!");
|
||||||
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
memo_data m;
|
||||||
|
m.from = dummy_public_key;
|
||||||
|
m.to = dummy_public_key;
|
||||||
|
m.set_message(dummy_private_key, dummy_public_key, "#Hello, world!", 12345);
|
||||||
|
|
||||||
|
decltype(fc::digest(m)) hash("8b17e79255d427b437a8b30beee5d45ca9b0bc8a04afa7a1968a0b73ab6d4b38");
|
||||||
|
if( fc::digest(m) != hash ) {
|
||||||
|
// If this happens, notify the web guys that the memo serialization format changed.
|
||||||
|
edump((m)(fc::digest(m)));
|
||||||
|
BOOST_FAIL("Memo format has changed. Notify the web guys and update this test.");
|
||||||
|
}
|
||||||
|
BOOST_CHECK_EQUAL(m.get_message(dummy_private_key, dummy_public_key), "#Hello, world!");
|
||||||
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
memo_data m;
|
||||||
|
m.from = dummy_public_key;
|
||||||
|
m.to = receiver_public_key;
|
||||||
|
m.set_message(dummy_private_key, receiver_public_key, "#Hello, world!", 12345);
|
||||||
|
|
||||||
|
decltype(fc::digest(m)) hash("8b17e79255d427b437a8b30beee5d45ca9b0bc8a04afa7a1968a0b73ab6d4b38");
|
||||||
|
if( fc::digest(m) != hash ) {
|
||||||
|
// If this happens, notify the web guys that the memo serialization format changed.
|
||||||
|
edump((m)(fc::digest(m)));
|
||||||
|
BOOST_FAIL("Memo format has changed. Notify the web guys and update this test.");
|
||||||
|
}
|
||||||
|
BOOST_CHECK_EQUAL(m.get_message(receiver_private_key, dummy_public_key), "#Hello, world!");
|
||||||
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
memo_data m;
|
||||||
|
m.from = sender_public_key;
|
||||||
|
m.to = dummy_public_key;
|
||||||
|
m.set_message(sender_private_key, dummy_public_key, "#Hello, world!", 12345);
|
||||||
|
|
||||||
|
decltype(fc::digest(m)) hash("40dbf5d26ea084d6ab61f9e93de366b7bea6a54eb1203744dd619d878a7d954a");
|
||||||
|
if( fc::digest(m) != hash ) {
|
||||||
|
// If this happens, notify the web guys that the memo serialization format changed.
|
||||||
|
edump((m)(fc::digest(m)));
|
||||||
|
BOOST_FAIL("Memo format has changed. Notify the web guys and update this test.");
|
||||||
|
}
|
||||||
|
BOOST_CHECK_EQUAL(m.get_message(dummy_private_key, sender_public_key), "#Hello, world!");
|
||||||
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
memo_data m;
|
||||||
|
m.from = sender_public_key;
|
||||||
|
m.to = receiver_public_key;
|
||||||
|
m.set_message(sender_private_key, receiver_public_key, "#Hello, world!", 12345);
|
||||||
|
|
||||||
|
decltype(fc::digest(m)) hash("2f5d44ec922f605663a3b51f1d9633641062c9b669ba4bdd5c60104ceff12c8f");
|
||||||
|
if( fc::digest(m) != hash ) {
|
||||||
|
// If this happens, notify the web guys that the memo serialization format changed.
|
||||||
|
edump((m)(fc::digest(m)));
|
||||||
|
BOOST_FAIL("Memo format has changed. Notify the web guys and update this test.");
|
||||||
|
}
|
||||||
|
BOOST_CHECK_EQUAL(m.get_message(receiver_private_key, sender_public_key), "#Hello, world!");
|
||||||
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
memo_data m;
|
||||||
|
m.from = dummy_public_key;
|
||||||
|
m.to = dummy_public_key;
|
||||||
|
m.set_message(dummy_private_key, dummy_public_key, "# Hello, world!", 12345);
|
||||||
|
|
||||||
|
decltype(fc::digest(m)) hash("93753b87b409e6532806ea3074553321b04807a675ffc0f41fb270c3141a8af2");
|
||||||
|
if( fc::digest(m) != hash ) {
|
||||||
|
// If this happens, notify the web guys that the memo serialization format changed.
|
||||||
|
edump((m)(fc::digest(m)));
|
||||||
|
BOOST_FAIL("Memo format has changed. Notify the web guys and update this test.");
|
||||||
|
}
|
||||||
|
BOOST_CHECK_EQUAL(m.get_message(dummy_private_key, dummy_public_key), "# Hello, world!");
|
||||||
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
memo_data m;
|
||||||
|
m.from = dummy_public_key;
|
||||||
|
m.to = receiver_public_key;
|
||||||
|
m.set_message(dummy_private_key, receiver_public_key, "# Hello, world!", 12345);
|
||||||
|
|
||||||
|
decltype(fc::digest(m)) hash("93753b87b409e6532806ea3074553321b04807a675ffc0f41fb270c3141a8af2");
|
||||||
|
if( fc::digest(m) != hash ) {
|
||||||
|
// If this happens, notify the web guys that the memo serialization format changed.
|
||||||
|
edump((m)(fc::digest(m)));
|
||||||
|
BOOST_FAIL("Memo format has changed. Notify the web guys and update this test.");
|
||||||
|
}
|
||||||
|
BOOST_CHECK_EQUAL(m.get_message(receiver_private_key, dummy_public_key), "# Hello, world!");
|
||||||
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
memo_data m;
|
||||||
|
m.from = sender_public_key;
|
||||||
|
m.to = dummy_public_key;
|
||||||
|
m.set_message(sender_private_key, dummy_public_key, "# Hello, world!", 12345);
|
||||||
|
|
||||||
|
decltype(fc::digest(m)) hash("5a0b4efad48090577a1296fc7221e19bdde4a8067bbbe05faa31c1c9fbdedd19");
|
||||||
|
if( fc::digest(m) != hash ) {
|
||||||
|
// If this happens, notify the web guys that the memo serialization format changed.
|
||||||
|
edump((m)(fc::digest(m)));
|
||||||
|
BOOST_FAIL("Memo format has changed. Notify the web guys and update this test.");
|
||||||
|
}
|
||||||
|
BOOST_CHECK_EQUAL(m.get_message(dummy_private_key, sender_public_key), "# Hello, world!");
|
||||||
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
memo_data m;
|
||||||
|
m.from = sender_public_key;
|
||||||
|
m.to = receiver_public_key;
|
||||||
|
m.set_message(sender_private_key, receiver_public_key, "# Hello, world!", 12345);
|
||||||
|
|
||||||
|
decltype(fc::digest(m)) hash("948b1b3219950dcaf5a376a502ba1b7631825aef85e0c692d192c06d583b2530");
|
||||||
|
if( fc::digest(m) != hash ) {
|
||||||
|
// If this happens, notify the web guys that the memo serialization format changed.
|
||||||
|
edump((m)(fc::digest(m)));
|
||||||
|
BOOST_FAIL("Memo format has changed. Notify the web guys and update this test.");
|
||||||
|
}
|
||||||
|
BOOST_CHECK_EQUAL(m.get_message(receiver_private_key, sender_public_key), "# Hello, world!");
|
||||||
|
}
|
||||||
|
|
||||||
} FC_LOG_AND_RETHROW() }
|
} FC_LOG_AND_RETHROW() }
|
||||||
|
|
||||||
BOOST_AUTO_TEST_CASE( witness_rng_test_bits )
|
BOOST_AUTO_TEST_CASE( witness_rng_test_bits )
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue