get_block_hash, get_block_template IPC + deprecated RPC

This commit is contained in:
Oran Juice 2015-06-17 19:25:07 +05:30
parent 26f7c3d5a9
commit c7d27d4979
No known key found for this signature in database
GPG Key ID: 71C5AF46CCB28124
10 changed files with 1363 additions and 124 deletions

View File

@ -57,6 +57,25 @@ namespace
} }
return check_core_busy(); return check_core_busy();
} }
//------------------------------------------------------------------------------------------------------------------------------
// equivalent of strstr, but with arbitrary bytes (ie, NULs)
// This does not differentiate between "not found" and "found at offset 0"
// (taken straight from core_rpc_server.cpp)
uint64_t slow_memmem(const void *start_buff, size_t buflen, const void *pat, size_t patlen)
{
const void *buf = start_buff;
const void *end = (const char*)buf + buflen;
if (patlen > buflen || patlen == 0) return 0;
while (buflen > 0 && (buf = memchr(buf, ((const char*)pat)[0], buflen-patlen + 1)))
{
if (memcmp(buf,pat,patlen) == 0)
return (const char*)buf - (const char*)start_buff;
buf = (const char*)buf + 1;
buflen = (const char*)end - (const char*)buf;
}
return 0;
}
} }
namespace IPC namespace IPC
@ -483,5 +502,89 @@ namespace IPC
p2p->set_save_graph(false); p2p->set_save_graph(false);
wap_proto_set_status(message, STATUS_OK); wap_proto_set_status(message, STATUS_OK);
} }
void get_block_hash(wap_proto_t *message) {
if (!check_core_busy())
{
wap_proto_set_status(message, STATUS_CORE_BUSY);
return;
}
uint64_t height = wap_proto_height(message);
if (core->get_current_blockchain_height() <= height)
{
wap_proto_set_status(message, STATUS_HEIGHT_TOO_BIG);
return;
}
std::string hash = string_tools::pod_to_hex(core->get_block_id_by_height(height));
zchunk_t *hash_chunk = zchunk_new((void*)(hash.c_str()), hash.length());
wap_proto_set_hash(message, &hash_chunk);
wap_proto_set_status(message, STATUS_OK);
}
void get_block_template(wap_proto_t *message) {
if (!check_core_ready())
{
wap_proto_set_status(message, STATUS_CORE_BUSY);
return;
}
uint64_t reserve_size = wap_proto_reserve_size(message);
if (reserve_size > 255)
{
wap_proto_set_status(message, STATUS_RESERVE_SIZE_TOO_BIG);
return;
}
cryptonote::account_public_address acc = AUTO_VAL_INIT(acc);
zchunk_t *address_chunk = wap_proto_address(message);
std::string address((char*)zchunk_data(address_chunk), zchunk_size(address_chunk));
if (!address.size() || !cryptonote::get_account_address_from_str(acc, testnet, address))
{
wap_proto_set_status(message, STATUS_WRONG_ADDRESS);
return;
}
cryptonote::block b = AUTO_VAL_INIT(b);
cryptonote::blobdata blob_reserve;
blob_reserve.resize(reserve_size, 0);
uint64_t difficulty = wap_proto_difficulty(message);
uint64_t height;
if (!core->get_block_template(b, acc, difficulty, height, blob_reserve))
{
wap_proto_set_status(message, STATUS_INTERNAL_ERROR);
return;
}
cryptonote::blobdata block_blob = t_serializable_object_to_blob(b);
crypto::public_key tx_pub_key = cryptonote::get_tx_pub_key_from_extra(b.miner_tx);
if (tx_pub_key == cryptonote::null_pkey)
{
wap_proto_set_status(message, STATUS_INTERNAL_ERROR);
return;
}
uint64_t reserved_offset = slow_memmem((void*)block_blob.data(), block_blob.size(), &tx_pub_key, sizeof(tx_pub_key));
if (!reserved_offset)
{
wap_proto_set_status(message, STATUS_INTERNAL_ERROR);
return;
}
reserved_offset += sizeof(tx_pub_key) + 3; // 3 bytes: tag for TX_EXTRA_TAG_PUBKEY(1 byte), tag for TX_EXTRA_NONCE(1 byte), counter in TX_EXTRA_NONCE(1 byte)
if (reserved_offset + reserve_size > block_blob.size())
{
wap_proto_set_status(message, STATUS_INTERNAL_ERROR);
return;
}
wap_proto_set_height(message, height);
wap_proto_set_difficulty(message, difficulty);
wap_proto_set_reserved_offset(message, reserved_offset);
std::string prev_hash = string_tools::pod_to_hex(b.prev_id);
zchunk_t *prev_hash_chunk = zchunk_new((void*)prev_hash.c_str(), prev_hash.length());
wap_proto_set_prev_hash(message, &prev_hash_chunk);
cryptonote::blobdata blocktemplate_blob = string_tools::buff_to_hex_nodelimer(block_blob);
zchunk_t *blob_chunk = zchunk_new((void*)blocktemplate_blob.c_str(), blocktemplate_blob.length());
wap_proto_set_block_template_blob(message, &blob_chunk);
wap_proto_set_status(message, STATUS_OK);
}
} }
} }

View File

@ -66,8 +66,10 @@ namespace IPC
const uint64_t STATUS_RANDOM_OUTS_FAILED = 9; const uint64_t STATUS_RANDOM_OUTS_FAILED = 9;
const uint64_t STATUS_MINING_NOT_STOPPED = 10; const uint64_t STATUS_MINING_NOT_STOPPED = 10;
const uint64_t STATUS_NOT_MINING = 11; const uint64_t STATUS_NOT_MINING = 11;
const uint64_t STATUS_INVALID_LOG_LEVEL = 11; const uint64_t STATUS_INVALID_LOG_LEVEL = 12;
const uint64_t STATUS_ERROR_STORING_BLOCKCHAIN = 11; const uint64_t STATUS_ERROR_STORING_BLOCKCHAIN = 13;
const uint64_t STATUS_HEIGHT_TOO_BIG = 13;
const uint64_t STATUS_RESERVE_SIZE_TOO_BIG = 14;
namespace Daemon namespace Daemon
{ {
void start_mining(wap_proto_t *message); void start_mining(wap_proto_t *message);
@ -85,6 +87,8 @@ namespace IPC
void set_log_level(wap_proto_t *message); void set_log_level(wap_proto_t *message);
void start_save_graph(wap_proto_t *message); void start_save_graph(wap_proto_t *message);
void stop_save_graph(wap_proto_t *message); void stop_save_graph(wap_proto_t *message);
void get_block_hash(wap_proto_t *message);
void get_block_template(wap_proto_t *message);
void init(cryptonote::core &p_core, void init(cryptonote::core &p_core,
nodetool::node_server<cryptonote::t_cryptonote_protocol_handler<cryptonote::core> > &p_p2p, nodetool::node_server<cryptonote::t_cryptonote_protocol_handler<cryptonote::core> > &p_p2p,
bool p_testnet); bool p_testnet);

View File

@ -147,6 +147,16 @@ WAP_EXPORT int
WAP_EXPORT int WAP_EXPORT int
wap_client_stop_save_graph (wap_client_t *self); wap_client_stop_save_graph (wap_client_t *self);
// Get block hash
// Returns >= 0 if successful, -1 if interrupted.
WAP_EXPORT int
wap_client_get_block_hash (wap_client_t *self, uint64_t height);
// Get block template
// Returns >= 0 if successful, -1 if interrupted.
WAP_EXPORT int
wap_client_get_block_template (wap_client_t *self, uint64_t reserve_size, zchunk_t **address_p);
// Return last received status // Return last received status
WAP_EXPORT int WAP_EXPORT int
wap_client_status (wap_client_t *self); wap_client_status (wap_client_t *self);
@ -243,6 +253,22 @@ WAP_EXPORT uint64_t
WAP_EXPORT zchunk_t * WAP_EXPORT zchunk_t *
wap_client_address (wap_client_t *self); wap_client_address (wap_client_t *self);
// Return last received hash
WAP_EXPORT zchunk_t *
wap_client_hash (wap_client_t *self);
// Return last received reserved_offset
WAP_EXPORT uint64_t
wap_client_reserved_offset (wap_client_t *self);
// Return last received prev_hash
WAP_EXPORT zchunk_t *
wap_client_prev_hash (wap_client_t *self);
// Return last received block_template_blob
WAP_EXPORT zchunk_t *
wap_client_block_template_blob (wap_client_t *self);
// Self test of this class // Self test of this class
WAP_EXPORT void WAP_EXPORT void
wap_client_test (bool verbose); wap_client_test (bool verbose);

View File

@ -40,10 +40,12 @@ typedef enum {
expect_set_log_level_ok_state = 17, expect_set_log_level_ok_state = 17,
expect_start_save_graph_ok_state = 18, expect_start_save_graph_ok_state = 18,
expect_stop_save_graph_ok_state = 19, expect_stop_save_graph_ok_state = 19,
expect_close_ok_state = 20, expect_get_block_hash_ok_state = 20,
defaults_state = 21, expect_get_block_template_ok_state = 21,
have_error_state = 22, expect_close_ok_state = 22,
reexpect_open_ok_state = 23 defaults_state = 23,
have_error_state = 24,
reexpect_open_ok_state = 25
} state_t; } state_t;
typedef enum { typedef enum {
@ -68,29 +70,33 @@ typedef enum {
set_log_level_event = 18, set_log_level_event = 18,
start_save_graph_event = 19, start_save_graph_event = 19,
stop_save_graph_event = 20, stop_save_graph_event = 20,
destructor_event = 21, get_block_hash_event = 21,
blocks_ok_event = 22, get_block_template_event = 22,
get_ok_event = 23, destructor_event = 23,
put_ok_event = 24, blocks_ok_event = 24,
save_bc_ok_event = 25, get_ok_event = 25,
start_ok_event = 26, put_ok_event = 26,
stop_ok_event = 27, save_bc_ok_event = 27,
output_indexes_ok_event = 28, start_ok_event = 28,
random_outs_ok_event = 29, stop_ok_event = 29,
get_height_ok_event = 30, output_indexes_ok_event = 30,
get_info_ok_event = 31, random_outs_ok_event = 31,
get_peer_list_ok_event = 32, get_height_ok_event = 32,
get_mining_status_ok_event = 33, get_info_ok_event = 33,
set_log_hash_rate_ok_event = 34, get_peer_list_ok_event = 34,
set_log_level_ok_event = 35, get_mining_status_ok_event = 35,
start_save_graph_ok_event = 36, set_log_hash_rate_ok_event = 36,
stop_save_graph_ok_event = 37, set_log_level_ok_event = 37,
close_ok_event = 38, start_save_graph_ok_event = 38,
ping_ok_event = 39, stop_save_graph_ok_event = 39,
error_event = 40, get_block_hash_ok_event = 40,
exception_event = 41, get_block_template_ok_event = 41,
command_invalid_event = 42, close_ok_event = 42,
other_event = 43 ping_ok_event = 43,
error_event = 44,
exception_event = 45,
command_invalid_event = 46,
other_event = 47
} event_t; } event_t;
// Names for state machine logging and error reporting // Names for state machine logging and error reporting
@ -116,6 +122,8 @@ s_state_name [] = {
"expect set log level ok", "expect set log level ok",
"expect start save graph ok", "expect start save graph ok",
"expect stop save graph ok", "expect stop save graph ok",
"expect get block hash ok",
"expect get block template ok",
"expect close ok", "expect close ok",
"defaults", "defaults",
"have error", "have error",
@ -145,6 +153,8 @@ s_event_name [] = {
"SET_LOG_LEVEL", "SET_LOG_LEVEL",
"START_SAVE_GRAPH", "START_SAVE_GRAPH",
"STOP_SAVE_GRAPH", "STOP_SAVE_GRAPH",
"GET_BLOCK_HASH",
"GET_BLOCK_TEMPLATE",
"destructor", "destructor",
"BLOCKS_OK", "BLOCKS_OK",
"GET_OK", "GET_OK",
@ -162,6 +172,8 @@ s_event_name [] = {
"SET_LOG_LEVEL_OK", "SET_LOG_LEVEL_OK",
"START_SAVE_GRAPH_OK", "START_SAVE_GRAPH_OK",
"STOP_SAVE_GRAPH_OK", "STOP_SAVE_GRAPH_OK",
"GET_BLOCK_HASH_OK",
"GET_BLOCK_TEMPLATE_OK",
"CLOSE_OK", "CLOSE_OK",
"PING_OK", "PING_OK",
"ERROR", "ERROR",
@ -191,6 +203,8 @@ struct _client_args_t {
uint64_t thread_count; uint64_t thread_count;
uint8_t visible; uint8_t visible;
uint8_t level; uint8_t level;
uint64_t height;
uint64_t reserve_size;
}; };
typedef struct { typedef struct {
@ -258,6 +272,10 @@ static void
prepare_set_log_hash_rate_command (client_t *self); prepare_set_log_hash_rate_command (client_t *self);
static void static void
prepare_set_log_level_command (client_t *self); prepare_set_log_level_command (client_t *self);
static void
prepare_get_block_hash_command (client_t *self);
static void
prepare_get_block_template_command (client_t *self);
static void static void
check_if_connection_is_dead (client_t *self); check_if_connection_is_dead (client_t *self);
static void static void
@ -292,6 +310,10 @@ static void
signal_have_start_save_graph_ok (client_t *self); signal_have_start_save_graph_ok (client_t *self);
static void static void
signal_have_stop_save_graph_ok (client_t *self); signal_have_stop_save_graph_ok (client_t *self);
static void
signal_have_get_block_hash_ok (client_t *self);
static void
signal_have_get_block_template_ok (client_t *self);
static void static void
signal_failure (client_t *self); signal_failure (client_t *self);
static void static void
@ -577,6 +599,18 @@ s_protocol_event (s_client_t *self, wap_proto_t *message)
case WAP_PROTO_STOP_SAVE_GRAPH_OK: case WAP_PROTO_STOP_SAVE_GRAPH_OK:
return stop_save_graph_ok_event; return stop_save_graph_ok_event;
break; break;
case WAP_PROTO_GET_BLOCK_HASH:
return get_block_hash_event;
break;
case WAP_PROTO_GET_BLOCK_HASH_OK:
return get_block_hash_ok_event;
break;
case WAP_PROTO_GET_BLOCK_TEMPLATE:
return get_block_template_event;
break;
case WAP_PROTO_GET_BLOCK_TEMPLATE_OK:
return get_block_template_ok_event;
break;
case WAP_PROTO_STOP: case WAP_PROTO_STOP:
return stop_event; return stop_event;
break; break;
@ -983,6 +1017,42 @@ s_client_execute (s_client_t *self, event_t event)
self->state = expect_stop_save_graph_ok_state; self->state = expect_stop_save_graph_ok_state;
} }
else else
if (self->event == get_block_hash_event) {
if (!self->exception) {
// prepare get block hash command
if (wap_client_verbose)
zsys_debug ("wap_client: $ prepare get block hash command");
prepare_get_block_hash_command (&self->client);
}
if (!self->exception) {
// send GET_BLOCK_HASH
if (wap_client_verbose)
zsys_debug ("wap_client: $ send GET_BLOCK_HASH");
wap_proto_set_id (self->message, WAP_PROTO_GET_BLOCK_HASH);
wap_proto_send (self->message, self->dealer);
}
if (!self->exception)
self->state = expect_get_block_hash_ok_state;
}
else
if (self->event == get_block_template_event) {
if (!self->exception) {
// prepare get block template command
if (wap_client_verbose)
zsys_debug ("wap_client: $ prepare get block template command");
prepare_get_block_template_command (&self->client);
}
if (!self->exception) {
// send GET_BLOCK_TEMPLATE
if (wap_client_verbose)
zsys_debug ("wap_client: $ send GET_BLOCK_TEMPLATE");
wap_proto_set_id (self->message, WAP_PROTO_GET_BLOCK_TEMPLATE);
wap_proto_send (self->message, self->dealer);
}
if (!self->exception)
self->state = expect_get_block_template_ok_state;
}
else
if (self->event == destructor_event) { if (self->event == destructor_event) {
if (!self->exception) { if (!self->exception) {
// send CLOSE // send CLOSE
@ -1764,6 +1834,96 @@ s_client_execute (s_client_t *self, event_t event)
} }
break; break;
case expect_get_block_hash_ok_state:
if (self->event == get_block_hash_ok_event) {
if (!self->exception) {
// signal have get block hash ok
if (wap_client_verbose)
zsys_debug ("wap_client: $ signal have get block hash ok");
signal_have_get_block_hash_ok (&self->client);
}
if (!self->exception)
self->state = connected_state;
}
else
if (self->event == ping_ok_event) {
if (!self->exception) {
// client is connected
if (wap_client_verbose)
zsys_debug ("wap_client: $ client is connected");
client_is_connected (&self->client);
}
}
else
if (self->event == error_event) {
if (!self->exception) {
// check status code
if (wap_client_verbose)
zsys_debug ("wap_client: $ check status code");
check_status_code (&self->client);
}
if (!self->exception)
self->state = have_error_state;
}
else
if (self->event == exception_event) {
// No action - just logging
if (wap_client_verbose)
zsys_debug ("wap_client: $ exception");
}
else {
// Handle unexpected protocol events
// No action - just logging
if (wap_client_verbose)
zsys_debug ("wap_client: $ *");
}
break;
case expect_get_block_template_ok_state:
if (self->event == get_block_template_ok_event) {
if (!self->exception) {
// signal have get block template ok
if (wap_client_verbose)
zsys_debug ("wap_client: $ signal have get block template ok");
signal_have_get_block_template_ok (&self->client);
}
if (!self->exception)
self->state = connected_state;
}
else
if (self->event == ping_ok_event) {
if (!self->exception) {
// client is connected
if (wap_client_verbose)
zsys_debug ("wap_client: $ client is connected");
client_is_connected (&self->client);
}
}
else
if (self->event == error_event) {
if (!self->exception) {
// check status code
if (wap_client_verbose)
zsys_debug ("wap_client: $ check status code");
check_status_code (&self->client);
}
if (!self->exception)
self->state = have_error_state;
}
else
if (self->event == exception_event) {
// No action - just logging
if (wap_client_verbose)
zsys_debug ("wap_client: $ exception");
}
else {
// Handle unexpected protocol events
// No action - just logging
if (wap_client_verbose)
zsys_debug ("wap_client: $ *");
}
break;
case expect_close_ok_state: case expect_close_ok_state:
if (self->event == close_ok_event) { if (self->event == close_ok_event) {
if (!self->exception) { if (!self->exception) {
@ -2093,6 +2253,17 @@ s_client_handle_cmdpipe (zloop_t *loop, zsock_t *reader, void *argument)
if (streq (method, "STOP SAVE GRAPH")) { if (streq (method, "STOP SAVE GRAPH")) {
s_client_execute (self, stop_save_graph_event); s_client_execute (self, stop_save_graph_event);
} }
else
if (streq (method, "GET BLOCK HASH")) {
zsock_recv (self->cmdpipe, "8", &self->args.height);
s_client_execute (self, get_block_hash_event);
}
else
if (streq (method, "GET BLOCK TEMPLATE")) {
zchunk_destroy (&self->args.address);
zsock_recv (self->cmdpipe, "8p", &self->args.reserve_size, &self->args.address);
s_client_execute (self, get_block_template_event);
}
// Cleanup pipe if any argument frames are still waiting to be eaten // Cleanup pipe if any argument frames are still waiting to be eaten
if (zsock_rcvmore (self->cmdpipe)) { if (zsock_rcvmore (self->cmdpipe)) {
zsys_error ("wap_client: trailing API command frames (%s)", method); zsys_error ("wap_client: trailing API command frames (%s)", method);
@ -2229,6 +2400,10 @@ struct _wap_client_t {
uint64_t speed; // Returned by actor reply uint64_t speed; // Returned by actor reply
uint64_t thread_count; // Returned by actor reply uint64_t thread_count; // Returned by actor reply
zchunk_t *address; // Returned by actor reply zchunk_t *address; // Returned by actor reply
zchunk_t *hash; // Returned by actor reply
uint64_t reserved_offset; // Returned by actor reply
zchunk_t *prev_hash; // Returned by actor reply
zchunk_t *block_template_blob; // Returned by actor reply
}; };
@ -2284,6 +2459,9 @@ wap_client_destroy (wap_client_t **self_p)
zframe_destroy (&self->white_list); zframe_destroy (&self->white_list);
zframe_destroy (&self->gray_list); zframe_destroy (&self->gray_list);
zchunk_destroy (&self->address); zchunk_destroy (&self->address);
zchunk_destroy (&self->hash);
zchunk_destroy (&self->prev_hash);
zchunk_destroy (&self->block_template_blob);
free (self); free (self);
*self_p = NULL; *self_p = NULL;
} }
@ -2432,6 +2610,17 @@ s_accept_reply (wap_client_t *self, ...)
if (streq (reply, "STOP SAVE GRAPH OK")) { if (streq (reply, "STOP SAVE GRAPH OK")) {
zsock_recv (self->actor, "8", &self->status); zsock_recv (self->actor, "8", &self->status);
} }
else
if (streq (reply, "GET BLOCK HASH OK")) {
zchunk_destroy (&self->hash);
zsock_recv (self->actor, "8p", &self->status, &self->hash);
}
else
if (streq (reply, "GET BLOCK TEMPLATE OK")) {
zchunk_destroy (&self->prev_hash);
zchunk_destroy (&self->block_template_blob);
zsock_recv (self->actor, "8888pp", &self->status, &self->reserved_offset, &self->height, &self->difficulty, &self->prev_hash, &self->block_template_blob);
}
break; break;
} }
filter = va_arg (args, char *); filter = va_arg (args, char *);
@ -2745,6 +2934,39 @@ wap_client_stop_save_graph (wap_client_t *self)
} }
// ---------------------------------------------------------------------------
// Get block hash
// Returns >= 0 if successful, -1 if interrupted.
int
wap_client_get_block_hash (wap_client_t *self, uint64_t height)
{
assert (self);
zsock_send (self->actor, "s8", "GET BLOCK HASH", height);
if (s_accept_reply (self, "GET BLOCK HASH OK", "FAILURE", NULL))
return -1; // Interrupted or timed-out
return self->status;
}
// ---------------------------------------------------------------------------
// Get block template
// Returns >= 0 if successful, -1 if interrupted.
int
wap_client_get_block_template (wap_client_t *self, uint64_t reserve_size, zchunk_t **address_p)
{
assert (self);
zsock_send (self->actor, "s8p", "GET BLOCK TEMPLATE", reserve_size, *address_p);
*address_p = NULL; // Take ownership of address
if (s_accept_reply (self, "GET BLOCK TEMPLATE OK", "FAILURE", NULL))
return -1; // Interrupted or timed-out
return self->status;
}
// --------------------------------------------------------------------------- // ---------------------------------------------------------------------------
// Return last received status // Return last received status
@ -3007,3 +3229,47 @@ wap_client_address (wap_client_t *self)
assert (self); assert (self);
return self->address; return self->address;
} }
// ---------------------------------------------------------------------------
// Return last received hash
zchunk_t *
wap_client_hash (wap_client_t *self)
{
assert (self);
return self->hash;
}
// ---------------------------------------------------------------------------
// Return last received reserved_offset
uint64_t
wap_client_reserved_offset (wap_client_t *self)
{
assert (self);
return self->reserved_offset;
}
// ---------------------------------------------------------------------------
// Return last received prev_hash
zchunk_t *
wap_client_prev_hash (wap_client_t *self)
{
assert (self);
return self->prev_hash;
}
// ---------------------------------------------------------------------------
// Return last received block_template_blob
zchunk_t *
wap_client_block_template_blob (wap_client_t *self)
{
assert (self);
return self->block_template_blob;
}

View File

@ -142,6 +142,25 @@ ERROR.
STOP_SAVE_GRAPH_OK - This is a codec for a Bitcoin Wallet Access Protocol (RFC tbd) STOP_SAVE_GRAPH_OK - This is a codec for a Bitcoin Wallet Access Protocol (RFC tbd)
status number 8 Status status number 8 Status
GET_BLOCK_HASH - get_block_hash IPC
height number 8 Height
GET_BLOCK_HASH_OK - This is a codec for a Bitcoin Wallet Access Protocol (RFC tbd)
status number 8 Status
hash chunk Hash
GET_BLOCK_TEMPLATE - get_block_template IPC
reserve_size number 8 Reserve size
address chunk Address
GET_BLOCK_TEMPLATE_OK - This is a codec for a Bitcoin Wallet Access Protocol (RFC tbd)
status number 8 Status
reserved_offset number 8 Rservered Offset
height number 8 Height
difficulty number 8 Difficulty
prev_hash chunk Previous Hash
block_template_blob chunk Block template blob
STOP - Wallet asks daemon to start mining. Daemon replies with STOP-OK, or STOP - Wallet asks daemon to start mining. Daemon replies with STOP-OK, or
ERROR. ERROR.
@ -205,13 +224,17 @@ Daemon will reply with CLOSE-OK or ERROR.
#define WAP_PROTO_START_SAVE_GRAPH_OK 30 #define WAP_PROTO_START_SAVE_GRAPH_OK 30
#define WAP_PROTO_STOP_SAVE_GRAPH 31 #define WAP_PROTO_STOP_SAVE_GRAPH 31
#define WAP_PROTO_STOP_SAVE_GRAPH_OK 32 #define WAP_PROTO_STOP_SAVE_GRAPH_OK 32
#define WAP_PROTO_STOP 33 #define WAP_PROTO_GET_BLOCK_HASH 33
#define WAP_PROTO_STOP_OK 34 #define WAP_PROTO_GET_BLOCK_HASH_OK 34
#define WAP_PROTO_CLOSE 35 #define WAP_PROTO_GET_BLOCK_TEMPLATE 35
#define WAP_PROTO_CLOSE_OK 36 #define WAP_PROTO_GET_BLOCK_TEMPLATE_OK 36
#define WAP_PROTO_PING 37 #define WAP_PROTO_STOP 37
#define WAP_PROTO_PING_OK 38 #define WAP_PROTO_STOP_OK 38
#define WAP_PROTO_ERROR 39 #define WAP_PROTO_CLOSE 39
#define WAP_PROTO_CLOSE_OK 40
#define WAP_PROTO_PING 41
#define WAP_PROTO_PING_OK 42
#define WAP_PROTO_ERROR 43
#include <czmq.h> #include <czmq.h>
@ -491,6 +514,48 @@ byte
void void
wap_proto_set_level (wap_proto_t *self, byte level); wap_proto_set_level (wap_proto_t *self, byte level);
// Get a copy of the hash field
zchunk_t *
wap_proto_hash (wap_proto_t *self);
// Get the hash field and transfer ownership to caller
zchunk_t *
wap_proto_get_hash (wap_proto_t *self);
// Set the hash field, transferring ownership from caller
void
wap_proto_set_hash (wap_proto_t *self, zchunk_t **chunk_p);
// Get/set the reserve_size field
uint64_t
wap_proto_reserve_size (wap_proto_t *self);
void
wap_proto_set_reserve_size (wap_proto_t *self, uint64_t reserve_size);
// Get/set the reserved_offset field
uint64_t
wap_proto_reserved_offset (wap_proto_t *self);
void
wap_proto_set_reserved_offset (wap_proto_t *self, uint64_t reserved_offset);
// Get a copy of the prev_hash field
zchunk_t *
wap_proto_prev_hash (wap_proto_t *self);
// Get the prev_hash field and transfer ownership to caller
zchunk_t *
wap_proto_get_prev_hash (wap_proto_t *self);
// Set the prev_hash field, transferring ownership from caller
void
wap_proto_set_prev_hash (wap_proto_t *self, zchunk_t **chunk_p);
// Get a copy of the block_template_blob field
zchunk_t *
wap_proto_block_template_blob (wap_proto_t *self);
// Get the block_template_blob field and transfer ownership to caller
zchunk_t *
wap_proto_get_block_template_blob (wap_proto_t *self);
// Set the block_template_blob field, transferring ownership from caller
void
wap_proto_set_block_template_blob (wap_proto_t *self, zchunk_t **chunk_p);
// Get/set the reason field // Get/set the reason field
const char * const char *
wap_proto_reason (wap_proto_t *self); wap_proto_reason (wap_proto_t *self);

View File

@ -47,11 +47,13 @@ typedef enum {
set_log_level_event = 16, set_log_level_event = 16,
start_save_graph_event = 17, start_save_graph_event = 17,
stop_save_graph_event = 18, stop_save_graph_event = 18,
close_event = 19, get_block_hash_event = 19,
ping_event = 20, get_block_template_event = 20,
expired_event = 21, close_event = 21,
exception_event = 22, ping_event = 22,
settled_event = 23 expired_event = 23,
exception_event = 24,
settled_event = 25
} event_t; } event_t;
// Names for state machine logging and error reporting // Names for state machine logging and error reporting
@ -85,6 +87,8 @@ s_event_name [] = {
"SET_LOG_LEVEL", "SET_LOG_LEVEL",
"START_SAVE_GRAPH", "START_SAVE_GRAPH",
"STOP_SAVE_GRAPH", "STOP_SAVE_GRAPH",
"GET_BLOCK_HASH",
"GET_BLOCK_TEMPLATE",
"CLOSE", "CLOSE",
"PING", "PING",
"expired", "expired",
@ -186,6 +190,10 @@ static void
start_save_graph (client_t *self); start_save_graph (client_t *self);
static void static void
stop_save_graph (client_t *self); stop_save_graph (client_t *self);
static void
get_block_hash (client_t *self);
static void
get_block_template (client_t *self);
static void static void
deregister_wallet (client_t *self); deregister_wallet (client_t *self);
static void static void
@ -418,6 +426,12 @@ s_protocol_event (wap_proto_t *message)
case WAP_PROTO_STOP_SAVE_GRAPH: case WAP_PROTO_STOP_SAVE_GRAPH:
return stop_save_graph_event; return stop_save_graph_event;
break; break;
case WAP_PROTO_GET_BLOCK_HASH:
return get_block_hash_event;
break;
case WAP_PROTO_GET_BLOCK_TEMPLATE:
return get_block_template_event;
break;
case WAP_PROTO_STOP: case WAP_PROTO_STOP:
return stop_event; return stop_event;
break; break;
@ -924,6 +938,42 @@ s_client_execute (s_client_t *self, event_t event)
} }
} }
else else
if (self->event == get_block_hash_event) {
if (!self->exception) {
// get block hash
if (self->server->verbose)
zsys_debug ("%s: $ get block hash", self->log_prefix);
get_block_hash (&self->client);
}
if (!self->exception) {
// send GET_BLOCK_HASH_OK
if (self->server->verbose)
zsys_debug ("%s: $ send GET_BLOCK_HASH_OK",
self->log_prefix);
wap_proto_set_id (self->server->message, WAP_PROTO_GET_BLOCK_HASH_OK);
wap_proto_set_routing_id (self->server->message, self->routing_id);
wap_proto_send (self->server->message, self->server->router);
}
}
else
if (self->event == get_block_template_event) {
if (!self->exception) {
// get block template
if (self->server->verbose)
zsys_debug ("%s: $ get block template", self->log_prefix);
get_block_template (&self->client);
}
if (!self->exception) {
// send GET_BLOCK_TEMPLATE_OK
if (self->server->verbose)
zsys_debug ("%s: $ send GET_BLOCK_TEMPLATE_OK",
self->log_prefix);
wap_proto_set_id (self->server->message, WAP_PROTO_GET_BLOCK_TEMPLATE_OK);
wap_proto_set_routing_id (self->server->message, self->routing_id);
wap_proto_send (self->server->message, self->server->router);
}
}
else
if (self->event == close_event) { if (self->event == close_event) {
if (!self->exception) { if (!self->exception) {
// send CLOSE_OK // send CLOSE_OK

View File

@ -16,9 +16,6 @@
*/ */
#include "wap_classes.h" #include "wap_classes.h"
// TODO: Change these to match your project's needs
#include "../include/wap_proto.h"
#include "../include/wap_client.h"
// Forward reference to method arguments structure // Forward reference to method arguments structure
typedef struct _client_args_t client_args_t; typedef struct _client_args_t client_args_t;
@ -98,6 +95,7 @@ use_connect_timeout (client_t *self)
engine_set_timeout (self, self->args->timeout); engine_set_timeout (self, self->args->timeout);
} }
// --------------------------------------------------------------------------- // ---------------------------------------------------------------------------
// client_is_connected // client_is_connected
// //
@ -110,6 +108,7 @@ client_is_connected (client_t *self)
engine_set_timeout (self, self->heartbeat_timer); engine_set_timeout (self, self->heartbeat_timer);
} }
// --------------------------------------------------------------------------- // ---------------------------------------------------------------------------
// check_if_connection_is_dead // check_if_connection_is_dead
// //
@ -125,17 +124,6 @@ check_if_connection_is_dead (client_t *self)
} }
} }
// ---------------------------------------------------------------------------
// use_heartbeat_timer
//
static void
use_heartbeat_timer (client_t *self)
{
engine_set_timeout (self, self->heartbeat_timer);
}
// --------------------------------------------------------------------------- // ---------------------------------------------------------------------------
// prepare_blocks_command // prepare_blocks_command
@ -148,15 +136,6 @@ prepare_blocks_command (client_t *self)
wap_proto_set_start_height (self->message, self->args->start_height); wap_proto_set_start_height (self->message, self->args->start_height);
} }
// ---------------------------------------------------------------------------
// prepare_get_output_indexes_command
//
static void
prepare_get_output_indexes_command (client_t *self)
{
wap_proto_set_tx_id (self->message, &self->args->tx_id);
}
// --------------------------------------------------------------------------- // ---------------------------------------------------------------------------
// signal_have_blocks_ok // signal_have_blocks_ok
@ -165,10 +144,13 @@ prepare_get_output_indexes_command (client_t *self)
static void static void
signal_have_blocks_ok (client_t *self) signal_have_blocks_ok (client_t *self)
{ {
zmsg_t *msg = wap_proto_get_block_data (self->message);
assert(msg != 0);
printf("%p <--\n", (void*)msg);
zsock_send (self->cmdpipe, "s888p", "BLOCKS OK", wap_proto_status(self->message), zsock_send (self->cmdpipe, "s888p", "BLOCKS OK", wap_proto_status(self->message),
wap_proto_start_height (self->message), wap_proto_start_height (self->message),
wap_proto_curr_height (self->message), wap_proto_curr_height (self->message),
wap_proto_get_block_data (self->message)); msg);
} }
@ -201,8 +183,8 @@ prepare_put_command (client_t *self)
static void static void
signal_have_put_ok (client_t *self) signal_have_put_ok (client_t *self)
{ {
zsock_send (self->cmdpipe, "s8s", "PUT OK", wap_proto_status(self->message), zsock_send (self->cmdpipe, "s8", "PUT OK",
wap_proto_tx_id (self->message)); wap_proto_status (self->message));
} }
@ -224,10 +206,21 @@ prepare_get_command (client_t *self)
static void static void
signal_have_get_ok (client_t *self) signal_have_get_ok (client_t *self)
{ {
zsock_send (self->cmdpipe, "s8p", "GET OK", 0, zsock_send (self->cmdpipe, "sip", "GET OK", 0,
wap_proto_get_tx_data (self->message)); wap_proto_get_tx_data (self->message));
} }
// ---------------------------------------------------------------------------
// signal_have_get_height_ok
//
static void
signal_have_get_height_ok (client_t *self)
{
zsock_send (self->cmdpipe, "si8", "GET HEIGHT OK", 0,
wap_proto_height (self->message));
}
// --------------------------------------------------------------------------- // ---------------------------------------------------------------------------
// signal_have_save_ok // signal_have_save_ok
@ -258,31 +251,9 @@ signal_have_start_ok (client_t *self)
static void static void
signal_have_stop_ok (client_t *self) signal_have_stop_ok (client_t *self)
{ {
zsock_send (self->cmdpipe, "s8", "STOP OK", 0); zsock_send (self->cmdpipe, "si", "STOP OK", 0);
} }
// ---------------------------------------------------------------------------
// signal_have_get_height_ok
//
static void
signal_have_get_height_ok (client_t *self)
{
zsock_send (self->cmdpipe, "si8", "GET HEIGHT OK", 0,
wap_proto_height (self->message));
}
// ---------------------------------------------------------------------------
// signal_have_output_indexes_ok
//
static void
signal_have_output_indexes_ok (client_t *self)
{
zsock_send (self->cmdpipe, "s8p", "OUTPUT INDEXES OK",
wap_proto_status (self->message),
wap_proto_get_o_indexes (self->message));
}
// --------------------------------------------------------------------------- // ---------------------------------------------------------------------------
// signal_success // signal_success
@ -352,6 +323,37 @@ signal_server_not_present (client_t *self)
zsock_send (self->cmdpipe, "sis", "FAILURE", -1, "Server is not reachable"); zsock_send (self->cmdpipe, "sis", "FAILURE", -1, "Server is not reachable");
} }
// ---------------------------------------------------------------------------
// prepare_get_output_indexes_command
//
static void
prepare_get_output_indexes_command (client_t *self)
{
wap_proto_set_tx_id (self->message, &self->args->tx_id);
}
// ---------------------------------------------------------------------------
// signal_have_output_indexes_ok
//
static void
signal_have_output_indexes_ok (client_t *self)
{
zsock_send (self->cmdpipe, "s8p", "OUTPUT INDEXES OK",
wap_proto_status (self->message),
wap_proto_get_o_indexes (self->message));
}
void wap_client_test(bool verbose) {
}
// --------------------------------------------------------------------------- // ---------------------------------------------------------------------------
// prepare_get_random_outs_command // prepare_get_random_outs_command
// //
@ -359,7 +361,6 @@ signal_server_not_present (client_t *self)
static void static void
prepare_get_random_outs_command (client_t *self) prepare_get_random_outs_command (client_t *self)
{ {
wap_proto_set_outs_count(self->message, self->args->outs_count);
wap_proto_set_amounts (self->message, &self->args->amounts); wap_proto_set_amounts (self->message, &self->args->amounts);
} }
@ -376,6 +377,8 @@ signal_have_random_outs_ok (client_t *self)
wap_proto_get_random_outputs (self->message)); wap_proto_get_random_outputs (self->message));
} }
// --------------------------------------------------------------------------- // ---------------------------------------------------------------------------
// signal_have_get_info_ok // signal_have_get_info_ok
// //
@ -397,8 +400,9 @@ signal_have_get_info_ok (client_t *self)
wap_proto_grey_peerlist_size (self->message)); wap_proto_grey_peerlist_size (self->message));
} }
// --------------------------------------------------------------------------- // ---------------------------------------------------------------------------
// signal_have_get_get_peer_list_ok // signal_have_get_peer_list_ok
// //
static void static void
@ -488,3 +492,52 @@ signal_have_stop_save_graph_ok (client_t *self)
zsock_send (self->cmdpipe, "s8", "STOP SAVE GRAPH OK", zsock_send (self->cmdpipe, "s8", "STOP SAVE GRAPH OK",
wap_proto_status (self->message)); wap_proto_status (self->message));
} }
// ---------------------------------------------------------------------------
// prepare_get_block_hash_command
//
static void
prepare_get_block_hash_command (client_t *self)
{
wap_proto_set_height (self->message, self->args->height);
}
// ---------------------------------------------------------------------------
// signal_have_get_block_hash_ok
//
static void
signal_have_get_block_hash_ok (client_t *self)
{
zsock_send (self->cmdpipe, "s8p", "GET BLOCK HASH OK",
wap_proto_status (self->message), wap_proto_get_hash (self->message));
}
// ---------------------------------------------------------------------------
// prepare_get_block_template_command
//
static void
prepare_get_block_template_command (client_t *self)
{
wap_proto_set_reserve_size (self->message, self->args->reserve_size);
wap_proto_set_address (self->message, &self->args->address);
}
// ---------------------------------------------------------------------------
// signal_have_get_block_template_ok
//
static void
signal_have_get_block_template_ok (client_t *self)
{
zsock_send (self->cmdpipe, "s8888pp", "GET BLOCK TEMPLATE OK",
wap_proto_status (self->message),
wap_proto_reserved_offset (self->message),
wap_proto_height (self->message),
wap_proto_difficulty (self->message),
wap_proto_get_prev_hash (self->message),
wap_proto_get_block_template_blob (self->message));
}

View File

@ -65,6 +65,11 @@ struct _wap_proto_t {
uint64_t speed; // Speed uint64_t speed; // Speed
byte visible; // Visible byte visible; // Visible
byte level; // Level byte level; // Level
zchunk_t *hash; // Hash
uint64_t reserve_size; // Reserve size
uint64_t reserved_offset; // Rservered Offset
zchunk_t *prev_hash; // Previous Hash
zchunk_t *block_template_blob; // Block template blob
char reason [256]; // Printable explanation char reason [256]; // Printable explanation
}; };
@ -253,6 +258,9 @@ wap_proto_destroy (wap_proto_t **self_p)
zchunk_destroy (&self->address); zchunk_destroy (&self->address);
zframe_destroy (&self->white_list); zframe_destroy (&self->white_list);
zframe_destroy (&self->gray_list); zframe_destroy (&self->gray_list);
zchunk_destroy (&self->hash);
zchunk_destroy (&self->prev_hash);
zchunk_destroy (&self->block_template_blob);
// Free object itself // Free object itself
free (self); free (self);
@ -568,6 +576,69 @@ wap_proto_recv (wap_proto_t *self, zsock_t *input)
GET_NUMBER8 (self->status); GET_NUMBER8 (self->status);
break; break;
case WAP_PROTO_GET_BLOCK_HASH:
GET_NUMBER8 (self->height);
break;
case WAP_PROTO_GET_BLOCK_HASH_OK:
GET_NUMBER8 (self->status);
{
size_t chunk_size;
GET_NUMBER4 (chunk_size);
if (self->needle + chunk_size > (self->ceiling)) {
zsys_warning ("wap_proto: hash is missing data");
goto malformed;
}
zchunk_destroy (&self->hash);
self->hash = zchunk_new (self->needle, chunk_size);
self->needle += chunk_size;
}
break;
case WAP_PROTO_GET_BLOCK_TEMPLATE:
GET_NUMBER8 (self->reserve_size);
{
size_t chunk_size;
GET_NUMBER4 (chunk_size);
if (self->needle + chunk_size > (self->ceiling)) {
zsys_warning ("wap_proto: address is missing data");
goto malformed;
}
zchunk_destroy (&self->address);
self->address = zchunk_new (self->needle, chunk_size);
self->needle += chunk_size;
}
break;
case WAP_PROTO_GET_BLOCK_TEMPLATE_OK:
GET_NUMBER8 (self->status);
GET_NUMBER8 (self->reserved_offset);
GET_NUMBER8 (self->height);
GET_NUMBER8 (self->difficulty);
{
size_t chunk_size;
GET_NUMBER4 (chunk_size);
if (self->needle + chunk_size > (self->ceiling)) {
zsys_warning ("wap_proto: prev_hash is missing data");
goto malformed;
}
zchunk_destroy (&self->prev_hash);
self->prev_hash = zchunk_new (self->needle, chunk_size);
self->needle += chunk_size;
}
{
size_t chunk_size;
GET_NUMBER4 (chunk_size);
if (self->needle + chunk_size > (self->ceiling)) {
zsys_warning ("wap_proto: block_template_blob is missing data");
goto malformed;
}
zchunk_destroy (&self->block_template_blob);
self->block_template_blob = zchunk_new (self->needle, chunk_size);
self->needle += chunk_size;
}
break;
case WAP_PROTO_STOP: case WAP_PROTO_STOP:
break; break;
@ -734,6 +805,33 @@ wap_proto_send (wap_proto_t *self, zsock_t *output)
case WAP_PROTO_STOP_SAVE_GRAPH_OK: case WAP_PROTO_STOP_SAVE_GRAPH_OK:
frame_size += 8; // status frame_size += 8; // status
break; break;
case WAP_PROTO_GET_BLOCK_HASH:
frame_size += 8; // height
break;
case WAP_PROTO_GET_BLOCK_HASH_OK:
frame_size += 8; // status
frame_size += 4; // Size is 4 octets
if (self->hash)
frame_size += zchunk_size (self->hash);
break;
case WAP_PROTO_GET_BLOCK_TEMPLATE:
frame_size += 8; // reserve_size
frame_size += 4; // Size is 4 octets
if (self->address)
frame_size += zchunk_size (self->address);
break;
case WAP_PROTO_GET_BLOCK_TEMPLATE_OK:
frame_size += 8; // status
frame_size += 8; // reserved_offset
frame_size += 8; // height
frame_size += 8; // difficulty
frame_size += 4; // Size is 4 octets
if (self->prev_hash)
frame_size += zchunk_size (self->prev_hash);
frame_size += 4; // Size is 4 octets
if (self->block_template_blob)
frame_size += zchunk_size (self->block_template_blob);
break;
case WAP_PROTO_ERROR: case WAP_PROTO_ERROR:
frame_size += 2; // status frame_size += 2; // status
frame_size += 1 + strlen (self->reason); frame_size += 1 + strlen (self->reason);
@ -930,6 +1028,61 @@ wap_proto_send (wap_proto_t *self, zsock_t *output)
PUT_NUMBER8 (self->status); PUT_NUMBER8 (self->status);
break; break;
case WAP_PROTO_GET_BLOCK_HASH:
PUT_NUMBER8 (self->height);
break;
case WAP_PROTO_GET_BLOCK_HASH_OK:
PUT_NUMBER8 (self->status);
if (self->hash) {
PUT_NUMBER4 (zchunk_size (self->hash));
memcpy (self->needle,
zchunk_data (self->hash),
zchunk_size (self->hash));
self->needle += zchunk_size (self->hash);
}
else
PUT_NUMBER4 (0); // Empty chunk
break;
case WAP_PROTO_GET_BLOCK_TEMPLATE:
PUT_NUMBER8 (self->reserve_size);
if (self->address) {
PUT_NUMBER4 (zchunk_size (self->address));
memcpy (self->needle,
zchunk_data (self->address),
zchunk_size (self->address));
self->needle += zchunk_size (self->address);
}
else
PUT_NUMBER4 (0); // Empty chunk
break;
case WAP_PROTO_GET_BLOCK_TEMPLATE_OK:
PUT_NUMBER8 (self->status);
PUT_NUMBER8 (self->reserved_offset);
PUT_NUMBER8 (self->height);
PUT_NUMBER8 (self->difficulty);
if (self->prev_hash) {
PUT_NUMBER4 (zchunk_size (self->prev_hash));
memcpy (self->needle,
zchunk_data (self->prev_hash),
zchunk_size (self->prev_hash));
self->needle += zchunk_size (self->prev_hash);
}
else
PUT_NUMBER4 (0); // Empty chunk
if (self->block_template_blob) {
PUT_NUMBER4 (zchunk_size (self->block_template_blob));
memcpy (self->needle,
zchunk_data (self->block_template_blob),
zchunk_size (self->block_template_blob));
self->needle += zchunk_size (self->block_template_blob);
}
else
PUT_NUMBER4 (0); // Empty chunk
break;
case WAP_PROTO_ERROR: case WAP_PROTO_ERROR:
PUT_NUMBER2 (self->status); PUT_NUMBER2 (self->status);
PUT_STRING (self->reason); PUT_STRING (self->reason);
@ -1210,6 +1363,33 @@ wap_proto_print (wap_proto_t *self)
zsys_debug (" status=%ld", (long) self->status); zsys_debug (" status=%ld", (long) self->status);
break; break;
case WAP_PROTO_GET_BLOCK_HASH:
zsys_debug ("WAP_PROTO_GET_BLOCK_HASH:");
zsys_debug (" height=%ld", (long) self->height);
break;
case WAP_PROTO_GET_BLOCK_HASH_OK:
zsys_debug ("WAP_PROTO_GET_BLOCK_HASH_OK:");
zsys_debug (" status=%ld", (long) self->status);
zsys_debug (" hash=[ ... ]");
break;
case WAP_PROTO_GET_BLOCK_TEMPLATE:
zsys_debug ("WAP_PROTO_GET_BLOCK_TEMPLATE:");
zsys_debug (" reserve_size=%ld", (long) self->reserve_size);
zsys_debug (" address=[ ... ]");
break;
case WAP_PROTO_GET_BLOCK_TEMPLATE_OK:
zsys_debug ("WAP_PROTO_GET_BLOCK_TEMPLATE_OK:");
zsys_debug (" status=%ld", (long) self->status);
zsys_debug (" reserved_offset=%ld", (long) self->reserved_offset);
zsys_debug (" height=%ld", (long) self->height);
zsys_debug (" difficulty=%ld", (long) self->difficulty);
zsys_debug (" prev_hash=[ ... ]");
zsys_debug (" block_template_blob=[ ... ]");
break;
case WAP_PROTO_STOP: case WAP_PROTO_STOP:
zsys_debug ("WAP_PROTO_STOP:"); zsys_debug ("WAP_PROTO_STOP:");
break; break;
@ -1383,6 +1563,18 @@ wap_proto_command (wap_proto_t *self)
case WAP_PROTO_STOP_SAVE_GRAPH_OK: case WAP_PROTO_STOP_SAVE_GRAPH_OK:
return ("STOP_SAVE_GRAPH_OK"); return ("STOP_SAVE_GRAPH_OK");
break; break;
case WAP_PROTO_GET_BLOCK_HASH:
return ("GET_BLOCK_HASH");
break;
case WAP_PROTO_GET_BLOCK_HASH_OK:
return ("GET_BLOCK_HASH_OK");
break;
case WAP_PROTO_GET_BLOCK_TEMPLATE:
return ("GET_BLOCK_TEMPLATE");
break;
case WAP_PROTO_GET_BLOCK_TEMPLATE_OK:
return ("GET_BLOCK_TEMPLATE_OK");
break;
case WAP_PROTO_STOP: case WAP_PROTO_STOP:
return ("STOP"); return ("STOP");
break; break;
@ -2137,6 +2329,141 @@ wap_proto_set_level (wap_proto_t *self, byte level)
} }
// --------------------------------------------------------------------------
// Get the hash field without transferring ownership
zchunk_t *
wap_proto_hash (wap_proto_t *self)
{
assert (self);
return self->hash;
}
// Get the hash field and transfer ownership to caller
zchunk_t *
wap_proto_get_hash (wap_proto_t *self)
{
zchunk_t *hash = self->hash;
self->hash = NULL;
return hash;
}
// Set the hash field, transferring ownership from caller
void
wap_proto_set_hash (wap_proto_t *self, zchunk_t **chunk_p)
{
assert (self);
assert (chunk_p);
zchunk_destroy (&self->hash);
self->hash = *chunk_p;
*chunk_p = NULL;
}
// --------------------------------------------------------------------------
// Get/set the reserve_size field
uint64_t
wap_proto_reserve_size (wap_proto_t *self)
{
assert (self);
return self->reserve_size;
}
void
wap_proto_set_reserve_size (wap_proto_t *self, uint64_t reserve_size)
{
assert (self);
self->reserve_size = reserve_size;
}
// --------------------------------------------------------------------------
// Get/set the reserved_offset field
uint64_t
wap_proto_reserved_offset (wap_proto_t *self)
{
assert (self);
return self->reserved_offset;
}
void
wap_proto_set_reserved_offset (wap_proto_t *self, uint64_t reserved_offset)
{
assert (self);
self->reserved_offset = reserved_offset;
}
// --------------------------------------------------------------------------
// Get the prev_hash field without transferring ownership
zchunk_t *
wap_proto_prev_hash (wap_proto_t *self)
{
assert (self);
return self->prev_hash;
}
// Get the prev_hash field and transfer ownership to caller
zchunk_t *
wap_proto_get_prev_hash (wap_proto_t *self)
{
zchunk_t *prev_hash = self->prev_hash;
self->prev_hash = NULL;
return prev_hash;
}
// Set the prev_hash field, transferring ownership from caller
void
wap_proto_set_prev_hash (wap_proto_t *self, zchunk_t **chunk_p)
{
assert (self);
assert (chunk_p);
zchunk_destroy (&self->prev_hash);
self->prev_hash = *chunk_p;
*chunk_p = NULL;
}
// --------------------------------------------------------------------------
// Get the block_template_blob field without transferring ownership
zchunk_t *
wap_proto_block_template_blob (wap_proto_t *self)
{
assert (self);
return self->block_template_blob;
}
// Get the block_template_blob field and transfer ownership to caller
zchunk_t *
wap_proto_get_block_template_blob (wap_proto_t *self)
{
zchunk_t *block_template_blob = self->block_template_blob;
self->block_template_blob = NULL;
return block_template_blob;
}
// Set the block_template_blob field, transferring ownership from caller
void
wap_proto_set_block_template_blob (wap_proto_t *self, zchunk_t **chunk_p)
{
assert (self);
assert (chunk_p);
zchunk_destroy (&self->block_template_blob);
self->block_template_blob = *chunk_p;
*chunk_p = NULL;
}
// -------------------------------------------------------------------------- // --------------------------------------------------------------------------
// Get/set the reason field // Get/set the reason field
@ -2646,6 +2973,76 @@ wap_proto_test (bool verbose)
assert (wap_proto_routing_id (self)); assert (wap_proto_routing_id (self));
assert (wap_proto_status (self) == 123); assert (wap_proto_status (self) == 123);
} }
wap_proto_set_id (self, WAP_PROTO_GET_BLOCK_HASH);
wap_proto_set_height (self, 123);
// Send twice
wap_proto_send (self, output);
wap_proto_send (self, output);
for (instance = 0; instance < 2; instance++) {
wap_proto_recv (self, input);
assert (wap_proto_routing_id (self));
assert (wap_proto_height (self) == 123);
}
wap_proto_set_id (self, WAP_PROTO_GET_BLOCK_HASH_OK);
wap_proto_set_status (self, 123);
zchunk_t *get_block_hash_ok_hash = zchunk_new ("Captcha Diem", 12);
wap_proto_set_hash (self, &get_block_hash_ok_hash);
// Send twice
wap_proto_send (self, output);
wap_proto_send (self, output);
for (instance = 0; instance < 2; instance++) {
wap_proto_recv (self, input);
assert (wap_proto_routing_id (self));
assert (wap_proto_status (self) == 123);
assert (memcmp (zchunk_data (wap_proto_hash (self)), "Captcha Diem", 12) == 0);
zchunk_destroy (&get_block_hash_ok_hash);
}
wap_proto_set_id (self, WAP_PROTO_GET_BLOCK_TEMPLATE);
wap_proto_set_reserve_size (self, 123);
zchunk_t *get_block_template_address = zchunk_new ("Captcha Diem", 12);
wap_proto_set_address (self, &get_block_template_address);
// Send twice
wap_proto_send (self, output);
wap_proto_send (self, output);
for (instance = 0; instance < 2; instance++) {
wap_proto_recv (self, input);
assert (wap_proto_routing_id (self));
assert (wap_proto_reserve_size (self) == 123);
assert (memcmp (zchunk_data (wap_proto_address (self)), "Captcha Diem", 12) == 0);
zchunk_destroy (&get_block_template_address);
}
wap_proto_set_id (self, WAP_PROTO_GET_BLOCK_TEMPLATE_OK);
wap_proto_set_status (self, 123);
wap_proto_set_reserved_offset (self, 123);
wap_proto_set_height (self, 123);
wap_proto_set_difficulty (self, 123);
zchunk_t *get_block_template_ok_prev_hash = zchunk_new ("Captcha Diem", 12);
wap_proto_set_prev_hash (self, &get_block_template_ok_prev_hash);
zchunk_t *get_block_template_ok_block_template_blob = zchunk_new ("Captcha Diem", 12);
wap_proto_set_block_template_blob (self, &get_block_template_ok_block_template_blob);
// Send twice
wap_proto_send (self, output);
wap_proto_send (self, output);
for (instance = 0; instance < 2; instance++) {
wap_proto_recv (self, input);
assert (wap_proto_routing_id (self));
assert (wap_proto_status (self) == 123);
assert (wap_proto_reserved_offset (self) == 123);
assert (wap_proto_height (self) == 123);
assert (wap_proto_difficulty (self) == 123);
assert (memcmp (zchunk_data (wap_proto_prev_hash (self)), "Captcha Diem", 12) == 0);
zchunk_destroy (&get_block_template_ok_prev_hash);
assert (memcmp (zchunk_data (wap_proto_block_template_blob (self)), "Captcha Diem", 12) == 0);
zchunk_destroy (&get_block_template_ok_block_template_blob);
}
wap_proto_set_id (self, WAP_PROTO_STOP); wap_proto_set_id (self, WAP_PROTO_STOP);
// Send twice // Send twice

View File

@ -362,3 +362,23 @@ stop_save_graph (client_t *self)
{ {
IPC::Daemon::stop_save_graph(self->message); IPC::Daemon::stop_save_graph(self->message);
} }
// ---------------------------------------------------------------------------
// get_block_hash
//
static void
get_block_hash (client_t *self)
{
IPC::Daemon::get_block_hash(self->message);
}
// ---------------------------------------------------------------------------
// get_block_template
//
static void
get_block_template (client_t *self)
{
IPC::Daemon::get_block_template(self->message);
}

View File

@ -15,6 +15,8 @@
// Trivial and error responses may be returned with ns_create_rpc_reply and ns_create_rpc_error // Trivial and error responses may be returned with ns_create_rpc_reply and ns_create_rpc_error
// respectively. // respectively.
// TODO: Add core busy checks to all methods here
#include "daemon_deprecated_rpc.h" #include "daemon_deprecated_rpc.h"
#include <stdexcept> #include <stdexcept>
@ -26,6 +28,7 @@
*/ */
namespace namespace
{ {
// TODO: put right error codes here
int daemon_connection_error = -326701; int daemon_connection_error = -326701;
int parse_error = -32700; int parse_error = -32700;
int invalid_request = -32600; int invalid_request = -32600;
@ -43,26 +46,21 @@ namespace
return ipc_client && wap_client_connected(ipc_client); return ipc_client && wap_client_connected(ipc_client);
} }
void connect_to_daemon() { bool connect_to_daemon() {
if (check_connection_to_daemon()) { if (check_connection_to_daemon()) {
return; return true;
} }
ipc_client = wap_client_new(); ipc_client = wap_client_new();
wap_client_connect(ipc_client, "ipc://@/monero", 200, "wallet identity"); wap_client_connect(ipc_client, "ipc://@/monero", 200, "wallet identity");
return check_connection_to_daemon();
} }
/*! /*!
* \brief Constructs a response string given a result JSON object. * \brief Initializes a rapidjson response object
*
* It also adds boilerplate properties like id, method.
* \param req net_skeleton request object * \param req net_skeleton request object
* \param result_json rapidjson result object * \param response_json net_skeleton request object to fill
* \param response_json "Root" rapidjson document that will eventually have the whole response
* \param response Response as a string gets written here.
*/ */
void construct_response_string(struct ns_rpc_request *req, rapidjson::Value &result_json, void init_response_object(struct ns_rpc_request *req, rapidjson::Document &response_json) {
rapidjson::Document &response_json, std::string &response)
{
response_json.SetObject(); response_json.SetObject();
response_json.AddMember("jsonrpc", "2.0" , response_json.GetAllocator()); response_json.AddMember("jsonrpc", "2.0" , response_json.GetAllocator());
rapidjson::Value string_value(rapidjson::kStringType); rapidjson::Value string_value(rapidjson::kStringType);
@ -78,6 +76,21 @@ namespace
response_json.AddMember("id", string_value, response_json.GetAllocator()); response_json.AddMember("id", string_value, response_json.GetAllocator());
string_value.SetString(req->method[0].ptr, req->method[0].len); string_value.SetString(req->method[0].ptr, req->method[0].len);
response_json.AddMember("method", string_value, response_json.GetAllocator()); response_json.AddMember("method", string_value, response_json.GetAllocator());
}
/*!
* \brief Constructs a response string given a result JSON object.
*
* It also adds boilerplate properties like id, method.
* \param req net_skeleton request object
* \param result_json rapidjson result object
* \param response_json "Root" rapidjson document that will eventually have the whole response
* \param response Response as a string gets written here.
*/
void construct_response_string(struct ns_rpc_request *req, rapidjson::Value &result_json,
rapidjson::Document &response_json, std::string &response)
{
init_response_object(req, response_json);
response_json.AddMember("result", result_json, response_json.GetAllocator()); response_json.AddMember("result", result_json, response_json.GetAllocator());
rapidjson::StringBuffer buffer; rapidjson::StringBuffer buffer;
rapidjson::Writer<rapidjson::StringBuffer> writer(buffer); rapidjson::Writer<rapidjson::StringBuffer> writer(buffer);
@ -85,6 +98,30 @@ namespace
// Write string to `response`. // Write string to `response`.
response = buffer.GetString(); response = buffer.GetString();
} }
/*!
* \brief Constructs a response string given a result string.
*
* It also adds boilerplate properties like id, method.
* \param req net_skeleton request object
* \param result rapidjson result object
* \param response_json "Root" rapidjson document that will eventually have the whole response
* \param response Response as a string gets written here.
*/
void construct_response_string(struct ns_rpc_request *req, const std::string &result,
rapidjson::Document &response_json, std::string &response)
{
init_response_object(req, response_json);
rapidjson::Value string_value(rapidjson::kStringType);
string_value.SetString(result.c_str(), result.length());
response_json.AddMember("result", string_value, response_json.GetAllocator());
rapidjson::StringBuffer buffer;
rapidjson::Writer<rapidjson::StringBuffer> writer(buffer);
response_json.Accept(writer);
// Write string to `response`.
response = buffer.GetString();
}
/*! /*!
* \brief Implementation of 'getheight' method. * \brief Implementation of 'getheight' method.
* \param buf Buffer to fill in response. * \param buf Buffer to fill in response.
@ -94,12 +131,20 @@ namespace
*/ */
int getheight(char *buf, int len, struct ns_rpc_request *req) int getheight(char *buf, int len, struct ns_rpc_request *req)
{ {
connect_to_daemon(); if (!connect_to_daemon()) {
return ns_rpc_create_error(buf, len, req, daemon_connection_error,
"Couldn't connect to daemon.", "{}");
}
int rc = wap_client_get_height(ipc_client); int rc = wap_client_get_height(ipc_client);
if (rc < 0) { if (rc < 0) {
return ns_rpc_create_error(buf, len, req, daemon_connection_error, return ns_rpc_create_error(buf, len, req, daemon_connection_error,
"Couldn't connect to daemon.", "{}"); "Couldn't connect to daemon.", "{}");
} }
uint64_t status = wap_client_status(ipc_client);
if (status == IPC::STATUS_CORE_BUSY) {
return ns_rpc_create_error(buf, len, req, internal_error,
"Core busy.", "{}");
}
uint64_t height = wap_client_height(ipc_client); uint64_t height = wap_client_height(ipc_client);
rapidjson::Document response_json; rapidjson::Document response_json;
rapidjson::Value result_json; rapidjson::Value result_json;
@ -122,7 +167,10 @@ namespace
*/ */
int startmining(char *buf, int len, struct ns_rpc_request *req) int startmining(char *buf, int len, struct ns_rpc_request *req)
{ {
connect_to_daemon(); if (!connect_to_daemon()) {
return ns_rpc_create_error(buf, len, req, daemon_connection_error,
"Couldn't connect to daemon.", "{}");
}
if (req->params == NULL) if (req->params == NULL)
{ {
return ns_rpc_create_error(buf, len, req, invalid_params, return ns_rpc_create_error(buf, len, req, invalid_params,
@ -160,7 +208,10 @@ namespace
"Couldn't connect to daemon.", "{}"); "Couldn't connect to daemon.", "{}");
} }
uint64_t status = wap_client_status(ipc_client); uint64_t status = wap_client_status(ipc_client);
if (status == IPC::STATUS_CORE_BUSY) {
return ns_rpc_create_error(buf, len, req, internal_error,
"Core busy.", "{}");
}
if (status == IPC::STATUS_WRONG_ADDRESS) if (status == IPC::STATUS_WRONG_ADDRESS)
{ {
return ns_rpc_create_error(buf, len, req, invalid_params, return ns_rpc_create_error(buf, len, req, invalid_params,
@ -183,12 +234,20 @@ namespace
*/ */
int stopmining(char *buf, int len, struct ns_rpc_request *req) int stopmining(char *buf, int len, struct ns_rpc_request *req)
{ {
connect_to_daemon(); if (!connect_to_daemon()) {
return ns_rpc_create_error(buf, len, req, daemon_connection_error,
"Couldn't connect to daemon.", "{}");
}
int rc = wap_client_stop(ipc_client); int rc = wap_client_stop(ipc_client);
if (rc < 0) { if (rc < 0) {
return ns_rpc_create_error(buf, len, req, daemon_connection_error, return ns_rpc_create_error(buf, len, req, daemon_connection_error,
"Couldn't connect to daemon.", "{}"); "Couldn't connect to daemon.", "{}");
} }
uint64_t status = wap_client_status(ipc_client);
if (status == IPC::STATUS_CORE_BUSY) {
return ns_rpc_create_error(buf, len, req, internal_error,
"Core busy.", "{}");
}
if (wap_client_status(ipc_client) != IPC::STATUS_OK) if (wap_client_status(ipc_client) != IPC::STATUS_OK)
{ {
return ns_rpc_create_error(buf, len, req, invalid_request, return ns_rpc_create_error(buf, len, req, invalid_request,
@ -206,13 +265,21 @@ namespace
*/ */
int getinfo(char *buf, int len, struct ns_rpc_request *req) int getinfo(char *buf, int len, struct ns_rpc_request *req)
{ {
connect_to_daemon(); if (!connect_to_daemon()) {
return ns_rpc_create_error(buf, len, req, daemon_connection_error,
"Couldn't connect to daemon.", "{}");
}
int rc = wap_client_get_info(ipc_client); int rc = wap_client_get_info(ipc_client);
if (rc < 0) { if (rc < 0) {
return ns_rpc_create_error(buf, len, req, daemon_connection_error, return ns_rpc_create_error(buf, len, req, daemon_connection_error,
"Couldn't connect to daemon.", "{}"); "Couldn't connect to daemon.", "{}");
} }
if (wap_client_status(ipc_client) != IPC::STATUS_OK) uint64_t status = wap_client_status(ipc_client);
if (status == IPC::STATUS_CORE_BUSY) {
return ns_rpc_create_error(buf, len, req, internal_error,
"Core busy.", "{}");
}
if (status != IPC::STATUS_OK)
{ {
return ns_rpc_create_error(buf, len, req, invalid_request, return ns_rpc_create_error(buf, len, req, invalid_request,
"Failed to get info", "{}"); "Failed to get info", "{}");
@ -257,7 +324,10 @@ namespace
*/ */
int getpeerlist(char *buf, int len, struct ns_rpc_request *req) int getpeerlist(char *buf, int len, struct ns_rpc_request *req)
{ {
connect_to_daemon(); if (!connect_to_daemon()) {
return ns_rpc_create_error(buf, len, req, daemon_connection_error,
"Couldn't connect to daemon.", "{}");
}
int rc = wap_client_get_peer_list(ipc_client); int rc = wap_client_get_peer_list(ipc_client);
if (rc < 0) { if (rc < 0) {
return ns_rpc_create_error(buf, len, req, daemon_connection_error, return ns_rpc_create_error(buf, len, req, daemon_connection_error,
@ -309,13 +379,20 @@ namespace
*/ */
int getminingstatus(char *buf, int len, struct ns_rpc_request *req) int getminingstatus(char *buf, int len, struct ns_rpc_request *req)
{ {
connect_to_daemon(); if (!connect_to_daemon()) {
return ns_rpc_create_error(buf, len, req, daemon_connection_error,
"Couldn't connect to daemon.", "{}");
}
int rc = wap_client_get_mining_status(ipc_client); int rc = wap_client_get_mining_status(ipc_client);
if (rc < 0) { if (rc < 0) {
return ns_rpc_create_error(buf, len, req, daemon_connection_error, return ns_rpc_create_error(buf, len, req, daemon_connection_error,
"Couldn't connect to daemon.", "{}"); "Couldn't connect to daemon.", "{}");
} }
uint64_t status = wap_client_status(ipc_client);
if (status == IPC::STATUS_CORE_BUSY) {
return ns_rpc_create_error(buf, len, req, internal_error,
"Core busy.", "{}");
}
rapidjson::Document response_json; rapidjson::Document response_json;
rapidjson::Document::AllocatorType &allocator = response_json.GetAllocator(); rapidjson::Document::AllocatorType &allocator = response_json.GetAllocator();
rapidjson::Value result_json; rapidjson::Value result_json;
@ -346,7 +423,10 @@ namespace
*/ */
int setloghashrate(char *buf, int len, struct ns_rpc_request *req) int setloghashrate(char *buf, int len, struct ns_rpc_request *req)
{ {
connect_to_daemon(); if (!connect_to_daemon()) {
return ns_rpc_create_error(buf, len, req, daemon_connection_error,
"Couldn't connect to daemon.", "{}");
}
if (req->params == NULL) if (req->params == NULL)
{ {
return ns_rpc_create_error(buf, len, req, invalid_params, return ns_rpc_create_error(buf, len, req, invalid_params,
@ -376,8 +456,12 @@ namespace
return ns_rpc_create_error(buf, len, req, daemon_connection_error, return ns_rpc_create_error(buf, len, req, daemon_connection_error,
"Couldn't connect to daemon.", "{}"); "Couldn't connect to daemon.", "{}");
} }
uint64_t status = wap_client_status(ipc_client);
if (wap_client_status(ipc_client) == IPC::STATUS_NOT_MINING) { if (status == IPC::STATUS_CORE_BUSY) {
return ns_rpc_create_error(buf, len, req, internal_error,
"Core busy.", "{}");
}
if (status == IPC::STATUS_NOT_MINING) {
return ns_rpc_create_error(buf, len, req, not_mining_error, return ns_rpc_create_error(buf, len, req, not_mining_error,
"Not mining", "{}"); "Not mining", "{}");
} }
@ -394,7 +478,10 @@ namespace
*/ */
int setloglevel(char *buf, int len, struct ns_rpc_request *req) int setloglevel(char *buf, int len, struct ns_rpc_request *req)
{ {
connect_to_daemon(); if (!connect_to_daemon()) {
return ns_rpc_create_error(buf, len, req, daemon_connection_error,
"Couldn't connect to daemon.", "{}");
}
if (req->params == NULL) if (req->params == NULL)
{ {
return ns_rpc_create_error(buf, len, req, invalid_params, return ns_rpc_create_error(buf, len, req, invalid_params,
@ -423,8 +510,12 @@ namespace
return ns_rpc_create_error(buf, len, req, daemon_connection_error, return ns_rpc_create_error(buf, len, req, daemon_connection_error,
"Couldn't connect to daemon.", "{}"); "Couldn't connect to daemon.", "{}");
} }
uint64_t status = wap_client_status(ipc_client);
if (wap_client_status(ipc_client) == IPC::STATUS_INVALID_LOG_LEVEL) { if (status == IPC::STATUS_CORE_BUSY) {
return ns_rpc_create_error(buf, len, req, internal_error,
"Core busy.", "{}");
}
if (status == IPC::STATUS_INVALID_LOG_LEVEL) {
return ns_rpc_create_error(buf, len, req, invalid_params, return ns_rpc_create_error(buf, len, req, invalid_params,
"Invalid log level", "{}"); "Invalid log level", "{}");
} }
@ -441,12 +532,20 @@ namespace
*/ */
int getblockcount(char *buf, int len, struct ns_rpc_request *req) int getblockcount(char *buf, int len, struct ns_rpc_request *req)
{ {
connect_to_daemon(); if (!connect_to_daemon()) {
return ns_rpc_create_error(buf, len, req, daemon_connection_error,
"Couldn't connect to daemon.", "{}");
}
int rc = wap_client_get_height(ipc_client); int rc = wap_client_get_height(ipc_client);
if (rc < 0) { if (rc < 0) {
return ns_rpc_create_error(buf, len, req, daemon_connection_error, return ns_rpc_create_error(buf, len, req, daemon_connection_error,
"Couldn't connect to daemon.", "{}"); "Couldn't connect to daemon.", "{}");
} }
uint64_t status = wap_client_status(ipc_client);
if (status == IPC::STATUS_CORE_BUSY) {
return ns_rpc_create_error(buf, len, req, internal_error,
"Core busy.", "{}");
}
uint64_t count = wap_client_height(ipc_client); uint64_t count = wap_client_height(ipc_client);
rapidjson::Document response_json; rapidjson::Document response_json;
rapidjson::Value result_json; rapidjson::Value result_json;
@ -469,7 +568,10 @@ namespace
*/ */
int startsavegraph(char *buf, int len, struct ns_rpc_request *req) int startsavegraph(char *buf, int len, struct ns_rpc_request *req)
{ {
connect_to_daemon(); if (!connect_to_daemon()) {
return ns_rpc_create_error(buf, len, req, daemon_connection_error,
"Couldn't connect to daemon.", "{}");
}
int rc = wap_client_start_save_graph(ipc_client); int rc = wap_client_start_save_graph(ipc_client);
if (rc < 0) { if (rc < 0) {
return ns_rpc_create_error(buf, len, req, daemon_connection_error, return ns_rpc_create_error(buf, len, req, daemon_connection_error,
@ -487,7 +589,10 @@ namespace
*/ */
int stopsavegraph(char *buf, int len, struct ns_rpc_request *req) int stopsavegraph(char *buf, int len, struct ns_rpc_request *req)
{ {
connect_to_daemon(); if (!connect_to_daemon()) {
return ns_rpc_create_error(buf, len, req, daemon_connection_error,
"Couldn't connect to daemon.", "{}");
}
int rc = wap_client_stop_save_graph(ipc_client); int rc = wap_client_stop_save_graph(ipc_client);
if (rc < 0) { if (rc < 0) {
return ns_rpc_create_error(buf, len, req, daemon_connection_error, return ns_rpc_create_error(buf, len, req, daemon_connection_error,
@ -495,6 +600,152 @@ namespace
} }
return ns_rpc_create_reply(buf, len, req, "{s:s}", "status", STATUS_OK); return ns_rpc_create_reply(buf, len, req, "{s:s}", "status", STATUS_OK);
} }
/*!
* \brief Implementation of 'getblockhash' method.
* \param buf Buffer to fill in response.
* \param len Max length of response.
* \param req net_skeleton RPC request
* \return Actual response length.
*/
int getblockhash(char *buf, int len, struct ns_rpc_request *req)
{
if (!connect_to_daemon()) {
return ns_rpc_create_error(buf, len, req, daemon_connection_error,
"Couldn't connect to daemon.", "{}");
}
if (req->params == NULL)
{
return ns_rpc_create_error(buf, len, req, invalid_params,
"Parameters missing.", "{}");
}
rapidjson::Document request_json;
char request_buf[1000];
strncpy(request_buf, req->params[0].ptr, req->params[0].len);
request_buf[req->params[0].len] = '\0';
if (request_json.Parse(request_buf).HasParseError())
{
return ns_rpc_create_error(buf, len, req, parse_error,
"Invalid JSON passed", "{}");
}
if (!request_json.IsArray() || request_json.Size() < 1 || !request_json[(unsigned int)0].IsNumber())
{
return ns_rpc_create_error(buf, len, req, invalid_params,
"Incorrect 'height' field", "{}");
}
int height = request_json[(unsigned int)0].GetUint();
int rc = wap_client_get_block_hash(ipc_client, height);
if (rc < 0) {
return ns_rpc_create_error(buf, len, req, daemon_connection_error,
"Couldn't connect to daemon.", "{}");
}
uint64_t status = wap_client_status(ipc_client);
if (status == IPC::STATUS_CORE_BUSY) {
return ns_rpc_create_error(buf, len, req, internal_error,
"Core busy.", "{}");
}
if (status == IPC::STATUS_HEIGHT_TOO_BIG) {
return ns_rpc_create_error(buf, len, req, invalid_params,
"Height too big.", "{}");
}
zchunk_t *hash_chunk = wap_client_hash(ipc_client);
std::string hash((char*)zchunk_data(hash_chunk), zchunk_size(hash_chunk));
std::string response;
rapidjson::Document response_json;
construct_response_string(req, hash, response_json, response);
size_t copy_length = ((uint32_t)len > response.length()) ? response.length() + 1 : (uint32_t)len;
strncpy(buf, response.c_str(), copy_length);
return response.length();
}
/*!
* \brief Implementation of 'getblocktemplate' method.
* \param buf Buffer to fill in response.
* \param len Max length of response.
* \param req net_skeleton RPC request
* \return Actual response length.
*/
int getblocktemplate(char *buf, int len, struct ns_rpc_request *req)
{
if (!connect_to_daemon()) {
return ns_rpc_create_error(buf, len, req, daemon_connection_error,
"Couldn't connect to daemon.", "{}");
}
if (req->params == NULL)
{
return ns_rpc_create_error(buf, len, req, invalid_params,
"Parameters missing.", "{}");
}
rapidjson::Document request_json;
char request_buf[1000];
strncpy(request_buf, req->params[0].ptr, req->params[0].len);
request_buf[req->params[0].len] = '\0';
if (request_json.Parse(request_buf).HasParseError())
{
return ns_rpc_create_error(buf, len, req, parse_error,
"Invalid JSON passed", "{}");
}
if (!request_json.HasMember("reserve_size") || !request_json["reserve_size"].IsNumber())
{
return ns_rpc_create_error(buf, len, req, invalid_params,
"Incorrect 'reserve_size' field", "{}");
}
if (!request_json.HasMember("wallet_address") || !request_json["wallet_address"].IsString())
{
return ns_rpc_create_error(buf, len, req, invalid_params,
"Incorrect 'wallet_address' field", "{}");
}
uint64_t reserve_size = request_json["reserve_size"].GetUint();
std::string wallet_address = request_json["wallet_address"].GetString();
zchunk_t *address_chunk = zchunk_new((void*)wallet_address.c_str(), wallet_address.length());
int rc = wap_client_get_block_template(ipc_client, reserve_size, &address_chunk);
if (rc < 0) {
return ns_rpc_create_error(buf, len, req, daemon_connection_error,
"Couldn't connect to daemon.", "{}");
}
uint64_t status = wap_client_status(ipc_client);
if (status == IPC::STATUS_CORE_BUSY) {
return ns_rpc_create_error(buf, len, req, internal_error,
"Core busy.", "{}");
}
if (status == IPC::STATUS_RESERVE_SIZE_TOO_BIG) {
return ns_rpc_create_error(buf, len, req, invalid_params,
"Reserve size too big.", "{}");
}
if (status == IPC::STATUS_WRONG_ADDRESS) {
return ns_rpc_create_error(buf, len, req, invalid_params,
"Wrong address.", "{}");
}
rapidjson::Document response_json;
rapidjson::Document::AllocatorType &allocator = response_json.GetAllocator();
rapidjson::Value result_json;
result_json.SetObject();
result_json.AddMember("difficulty", wap_client_difficulty(ipc_client), allocator);
result_json.AddMember("height", wap_client_height(ipc_client), allocator);
result_json.AddMember("reserved_offset", wap_client_reserved_offset(ipc_client), allocator);
zchunk_t *prev_hash_chunk = wap_client_prev_hash(ipc_client);
rapidjson::Value string_value(rapidjson::kStringType);
string_value.SetString((char*)zchunk_data(prev_hash_chunk), zchunk_size(prev_hash_chunk));
result_json.AddMember("prev_hash", string_value, allocator);
zchunk_t *block_template_chunk = wap_client_prev_hash(ipc_client);
string_value.SetString((char*)zchunk_data(block_template_chunk), zchunk_size(block_template_chunk));
result_json.AddMember("blocktemplate_blob", string_value, allocator);
std::string response;
construct_response_string(req, result_json, response_json, response);
size_t copy_length = ((uint32_t)len > response.length()) ? response.length() + 1 : (uint32_t)len;
strncpy(buf, response.c_str(), copy_length);
return response.length();
}
// Contains a list of method names. // Contains a list of method names.
const char *method_names[] = { const char *method_names[] = {
"getheight", "getheight",
@ -508,6 +759,8 @@ namespace
"getblockcount", "getblockcount",
"startsavegraph", "startsavegraph",
"stopsavegraph", "stopsavegraph",
"getblockhash",
"getblocktemplate",
NULL NULL
}; };
@ -524,6 +777,8 @@ namespace
getblockcount, getblockcount,
startsavegraph, startsavegraph,
stopsavegraph, stopsavegraph,
getblockhash,
getblocktemplate,
NULL NULL
}; };