Merge remote-tracking branch 'origin/develop' into feature/cli-activate-deregistered-son

This commit is contained in:
moss9001 2021-12-02 02:07:42 +02:00
commit f7c8ac8528
12 changed files with 1279 additions and 180 deletions

View file

@ -76,6 +76,10 @@ void block_database::flush()
void block_database::store( const block_id_type& _id, const signed_block& b )
{
if (true == replay_mode){
return;
}
block_id_type id = _id;
if( id == block_id_type() )
{
@ -271,4 +275,9 @@ optional<block_id_type> block_database::last_id()const
return optional<block_id_type>();
}
void block_database::set_replay_mode(bool mode)
{
replay_mode = mode;
}
} }

View file

@ -232,7 +232,12 @@ void database::open(
FC_ASSERT( *last_block >= head_block_id(),
"last block ID does not match current chain state",
("last_block->id", last_block)("head_block_id",head_block_num()) );
_block_id_to_block.set_replay_mode(true);
reindex( data_dir );
_block_id_to_block.set_replay_mode(false);
}
_opened = true;
}

View file

@ -47,7 +47,11 @@ namespace graphene { namespace chain {
optional<signed_block> fetch_by_number( uint32_t block_num )const;
optional<signed_block> last()const;
optional<block_id_type> last_id()const;
void set_replay_mode(bool mode);
private:
bool replay_mode = false;
optional<index_entry> last_index_entry()const;
fc::path _index_filename;
mutable std::fstream _blocks;

View file

@ -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,
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();
to = pub;
@ -49,6 +52,7 @@ void memo_data::set_message(const fc::ecc::private_key& priv, const fc::ecc::pub
}
else
{
to = public_key_type();
auto text = memo_message(0, msg).serialize();
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,
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 nonce_plus_secret = fc::sha512::hash(fc::to_string(nonce) + secret.str());

View file

@ -3,25 +3,834 @@
#include <sstream>
#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/ptree.hpp>
#include <curl/curl.h>
#include <fc/crypto/base64.hpp>
#include <fc/log/logger.hpp>
#include <fc/network/ip.hpp>
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) :
ip(_ip),
port(_port),
user(_user),
password(_password),
debug_rpc_calls(_debug_rpc_calls),
request_id(0) {
authorization.key = "Authorization";
authorization.val = "Basic " + fc::base64_encode(user + ":" + password);
constexpr auto http_port = 80;
constexpr auto https_port = 443;
template <class string>
void make_trimmed(string *str) {
boost::algorithm::trim(*str);
}
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) {
@ -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::read_json(ss, json);
if (reply.status == 200) {
if (reply.status_code == 200) {
return ss.str();
}
@ -123,63 +932,82 @@ std::string rpc_client::send_post_request(std::string method, std::string params
// return reply;
//}
static size_t write_callback(char *ptr, size_t size, size_t nmemb, rpc_reply *reply) {
size_t retval = 0;
if (reply != nullptr) {
reply->body.append(ptr, size * nmemb);
retval = size * nmemb;
}
return retval;
}
//static size_t write_callback(char *ptr, size_t size, size_t nmemb, rpc_reply *reply) {
// size_t retval = 0;
// if (reply != nullptr) {
// reply->body.append(ptr, size * nmemb);
// retval = size * nmemb;
// }
// 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;
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");
http_response rpc_client::send_post_request(const std::string &body, bool show_log) {
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());
}
http_request request(body, "application/json");
http_response response;
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);
client.exec(request, &response);
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: ${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()));
}
return reply;
return response;
}
}} // namespace graphene::peerplays_sidechain

View file

@ -3,37 +3,134 @@
#include <cstdint>
#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 {
struct rpc_reply {
uint16_t status;
std::string body;
enum class url_schema_type { unknown,
http,
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 {
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:
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 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;
uint32_t request_id;
fc::http::header authorization;
private:
//fc::http::reply send_post_request(std::string body, bool show_log);
rpc_reply send_post_request(std::string body, bool show_log);
http_call client;
http_response send_post_request(const std::string &body, bool show_log);
};
}} // namespace graphene::peerplays_sidechain

View file

@ -7,6 +7,8 @@
#include <boost/signals2.hpp>
#include <mutex>
#include <fc/network/http/connection.hpp>
#include <graphene/peerplays_sidechain/bitcoin/bitcoin_address.hpp>
@ -114,6 +116,9 @@ private:
fc::future<void> on_changed_objects_task;
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_transaction(const son_wallet_object &prev_swo, std::string new_sw_address);

View file

@ -14,7 +14,7 @@ namespace graphene { namespace peerplays_sidechain {
class hive_node_rpc_client : public rpc_client {
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 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);
private:
std::string node_ip;
uint32_t node_rpc_port;
std::string node_rpc_url;
std::string node_rpc_user;
std::string node_rpc_password;
hive_node_rpc_client *node_rpc_client;

View file

@ -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)");
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-port", bpo::value<uint32_t>()->default_value(28090), "Hive node RPC port");
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-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-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>();
config_ready_hive = options.count("hive-node-ip") &&
options.count("hive-node-rpc-port") &&
config_ready_hive = options.count("hive-node-rpc-url") &&
/*options.count("hive-node-rpc-user") && options.count("hive-node-rpc-password") &&*/
options.count("hive-private-key");
if (!config_ready_hive) {

View file

@ -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,
[&](const sidechain_address_object &sao) {
bool retval = true;
if (sao.expires == time_point_sec::maximum()) {
auto usr_pubkey = fc::ecc::public_key(create_public_key_data(parse_hex(sao.deposit_public_key)));
try {
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);
std::string address_data = "{ \"redeemScript\": \"" + fc::to_hex(addr.get_redeem_script()) +
"\", \"witnessScript\": \"" + fc::to_hex(addr.get_witness_script()) + "\" }";
btc_one_or_weighted_multisig_address addr(usr_pubkey, pubkeys, network_type);
std::string address_data = "{ \"redeemScript\": \"" + fc::to_hex(addr.get_redeem_script()) +
"\", \"witnessScript\": \"" + fc::to_hex(addr.get_witness_script()) + "\" }";
if (addr.get_address() != sao.deposit_address) {
sidechain_address_update_operation op;
op.payer = plugin.get_current_son_object().son_account;
op.sidechain_address_id = sao.id;
op.sidechain_address_account = sao.sidechain_address_account;
op.sidechain = sao.sidechain;
op.deposit_public_key = sao.deposit_public_key;
op.deposit_address = addr.get_address();
op.deposit_address_data = address_data;
op.withdraw_public_key = sao.withdraw_public_key;
op.withdraw_address = sao.withdraw_address;
if (addr.get_address() != sao.deposit_address) {
sidechain_address_update_operation op;
op.payer = plugin.get_current_son_object().son_account;
op.sidechain_address_id = sao.id;
op.sidechain_address_account = sao.sidechain_address_account;
op.sidechain = sao.sidechain;
op.deposit_public_key = sao.deposit_public_key;
op.deposit_address = addr.get_address();
op.deposit_address_data = address_data;
op.withdraw_public_key = sao.withdraw_public_key;
op.withdraw_address = sao.withdraw_address;
signed_transaction trx = database.create_signed_transaction(plugin.get_private_key(plugin.get_current_son_id()), op);
try {
trx.validate();
database.push_transaction(trx, database::validation_steps::skip_block_size_check);
if (plugin.app().p2p_node())
plugin.app().p2p_node()->broadcast(net::trx_message(trx));
retval = true;
} catch (fc::exception &e) {
elog("Sending transaction for sidechain address update operation failed with exception ${e}", ("e", e.what()));
retval = false;
signed_transaction trx = database.create_signed_transaction(plugin.get_private_key(plugin.get_current_son_id()), op);
try {
trx.validate();
database.push_transaction(trx, database::validation_steps::skip_block_size_check);
if (plugin.app().p2p_node())
plugin.app().p2p_node()->broadcast(net::trx_message(trx));
retval = true;
} catch (fc::exception &e) {
elog("Sending transaction for sidechain address update operation failed with exception ${e}", ("e", e.what()));
retval = false;
}
}
}
} catch (fc::exception &e) {
retval = false;
}
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) {
std::string block = bitcoin_client->getblock(event_data);
if (block != "") {
const auto &vins = extract_info_from_block(block);
if (block.empty())
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) {
// !!! 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()));
if (addr_itr == sidechain_addresses_idx.end())
continue;
for (const auto &v : vins) {
// !!! 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()));
if (addr_itr == sidechain_addresses_idx.end())
continue;
std::stringstream ss;
ss << "bitcoin"
<< "-" << v.out.hash_tx << "-" << v.out.n_vout;
std::string sidechain_uid = ss.str();
std::stringstream ss;
ss << "bitcoin"
<< "-" << v.out.hash_tx << "-" << v.out.n_vout;
std::string sidechain_uid = ss.str();
sidechain_event_data sed;
sed.timestamp = database.head_block_time();
sed.block_num = database.head_block_num();
sed.sidechain = addr_itr->sidechain;
sed.sidechain_uid = sidechain_uid;
sed.sidechain_transaction_id = v.out.hash_tx;
sed.sidechain_from = v.address;
sed.sidechain_to = "";
sed.sidechain_currency = "BTC";
sed.sidechain_amount = v.out.amount;
sed.peerplays_from = addr_itr->sidechain_address_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;
sed.peerplays_asset = asset(sed.sidechain_amount * btc_price.base.amount / btc_price.quote.amount);
sidechain_event_data_received(sed);
}
sidechain_event_data sed;
sed.timestamp = database.head_block_time();
sed.block_num = database.head_block_num();
sed.sidechain = addr_itr->sidechain;
sed.sidechain_uid = sidechain_uid;
sed.sidechain_transaction_id = v.out.hash_tx;
sed.sidechain_from = v.address;
sed.sidechain_to = "";
sed.sidechain_currency = "BTC";
sed.sidechain_amount = v.out.amount;
sed.peerplays_from = addr_itr->sidechain_address_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;
sed.peerplays_asset = asset(sed.sidechain_amount * btc_price.base.amount / btc_price.quote.amount);
sidechain_event_data_received(sed);
}
}

View file

@ -32,35 +32,8 @@
namespace graphene { namespace peerplays_sidechain {
std::string resolve_host_addr(const std::string &host_name) {
using namespace boost::asio;
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) {
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) :
rpc_client(url, user_name, password, debug_rpc_calls) {
}
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>();
}
node_ip = options.at("hive-node-ip").as<std::string>();
node_rpc_port = options.at("hive-node-rpc-port").as<uint32_t>();
node_rpc_url = options.at("hive-node-rpc-url").as<std::string>();
if (options.count("hive-node-rpc-user")) {
node_rpc_user = options.at("hive-node-rpc-user").as<std::string>();
} 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();
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);
}
chain_id = chain_id_type(chain_id_str);

View file

@ -182,21 +182,194 @@ BOOST_AUTO_TEST_CASE( price_test )
BOOST_AUTO_TEST_CASE( memo_test )
{ try {
memo_data m;
auto sender = generate_private_key("1");
auto receiver = generate_private_key("2");
m.from = sender.get_public_key();
m.to = receiver.get_public_key();
m.set_message(sender, receiver.get_public_key(), "Hello, world!", 12345);
auto sender_private_key = generate_private_key("1");
auto sender_public_key = sender_private_key.get_public_key();
auto receiver_private_key = generate_private_key("2");
auto receiver_public_key = receiver_private_key.get_public_key();
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.
edump((m)(fc::digest(m)));
BOOST_FAIL("Memo format has changed. Notify the web guys and update this test.");
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("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() }
BOOST_AUTO_TEST_CASE( witness_rng_test_bits )