diff --git a/src/ipc/daemon_ipc_handlers.cpp b/src/ipc/daemon_ipc_handlers.cpp index a6ad9d621..31bf78926 100644 --- a/src/ipc/daemon_ipc_handlers.cpp +++ b/src/ipc/daemon_ipc_handlers.cpp @@ -161,7 +161,49 @@ namespace IPC void send_raw_transaction(wap_proto_t *message) { + if (!check_core_busy()) { + wap_proto_set_status(message, STATUS_CORE_BUSY); + return; + } + std::string tx_blob; + zchunk_t *tx_as_hex_chunk = wap_proto_tx_as_hex(message); + char *tx_as_hex = (char*)zchunk_data(tx_as_hex_chunk); + std::string tx_as_hex_string(tx_as_hex, zchunk_size(tx_as_hex_chunk)); + if (!string_tools::parse_hexstr_to_binbuff(tx_as_hex_string, tx_blob)) + { + LOG_PRINT_L0("[on_send_raw_tx]: Failed to parse tx from hexbuff: " << tx_as_hex_string); + wap_proto_set_status(message, STATUS_INVALID_TX); + return; + } + cryptonote::cryptonote_connection_context fake_context = AUTO_VAL_INIT(fake_context); + cryptonote::tx_verification_context tvc = AUTO_VAL_INIT(tvc); + if (!core->handle_incoming_tx(tx_blob, tvc, false)) + { + LOG_PRINT_L0("[on_send_raw_tx]: Failed to process tx"); + wap_proto_set_status(message, STATUS_INVALID_TX); + return; + } + + if (tvc.m_verifivation_failed) + { + LOG_PRINT_L0("[on_send_raw_tx]: tx verification failed"); + wap_proto_set_status(message, STATUS_TX_VERIFICATION_FAILED); + return; + } + + if (!tvc.m_should_be_relayed) + { + LOG_PRINT_L0("[on_send_raw_tx]: tx accepted, but not relayed"); + wap_proto_set_status(message, STATUS_TX_NOT_RELAYED); + return; + } + + cryptonote::NOTIFY_NEW_TRANSACTIONS::request r; + r.txs.push_back(tx_blob); + core->get_protocol()->relay_transactions(r, fake_context); + //TODO: make sure that tx has reached other nodes here, probably wait to receive reflections from other nodes + wap_proto_set_status(message, STATUS_OK); } void get_output_indexes(wap_proto_t *message) @@ -186,5 +228,80 @@ namespace IPC wap_proto_set_o_indexes(message, &frame); wap_proto_set_status(message, STATUS_OK); } + + void get_random_outs(wap_proto_t *message) { + if (!check_core_busy()) { + wap_proto_set_status(message, STATUS_CORE_BUSY); + return; + } + // The core does its stuff with old style RPC objects. + // So we construct and read from those objects. + cryptonote::COMMAND_RPC_GET_RANDOM_OUTPUTS_FOR_AMOUNTS::request req; + uint64_t outs_count = wap_proto_outs_count(message); + req.outs_count = outs_count; + zframe_t *amounts_frame = wap_proto_amounts(message); + uint64_t amounts_count = zframe_size(amounts_frame) / sizeof(uint64_t); + uint64_t *amounts = (uint64_t*)zframe_data(amounts_frame); + for (unsigned int i = 0; i < amounts_count; i++) { + req.amounts.push_back(amounts[i]); + } + cryptonote::COMMAND_RPC_GET_RANDOM_OUTPUTS_FOR_AMOUNTS::response res; + if (!core->get_random_outs_for_amounts(req, res)) + { + wap_proto_set_status(message, STATUS_RANDOM_OUTS_FAILED); + } + + // We have to convert the result into a JSON string. + rapidjson::Document result_json; + result_json.SetObject(); + rapidjson::Document::AllocatorType &allocator = result_json.GetAllocator(); + rapidjson::Value outputs_json(rapidjson::kArrayType); + + typedef cryptonote::COMMAND_RPC_GET_RANDOM_OUTPUTS_FOR_AMOUNTS::outs_for_amount outs_for_amount; + typedef cryptonote::COMMAND_RPC_GET_RANDOM_OUTPUTS_FOR_AMOUNTS::out_entry out_entry; + for (unsigned int i = 0; i < res.outs.size(); i++) { + rapidjson::Value output(rapidjson::kObjectType); + outs_for_amount out = res.outs[i]; + rapidjson::Value output_entries(rapidjson::kArrayType); + for (std::list::iterator it = out.outs.begin(); it != out.outs.end(); it++) { + rapidjson::Value output_entry(rapidjson::kObjectType); + out_entry entry = *it; + output_entry.AddMember("global_amount_index", entry.global_amount_index, allocator); + rapidjson::Value string_value(rapidjson::kStringType); + string_value.SetString(entry.out_key.data, 32, allocator); + output_entry.AddMember("out_key", string_value.Move(), allocator); + output_entries.PushBack(output_entry, allocator); + } + output.AddMember("amount", out.amount, allocator); + output.AddMember("outs", output_entries, allocator); + outputs_json.PushBack(output, allocator); + } + result_json.AddMember("outputs", outputs_json, allocator); + + rapidjson::StringBuffer buffer; + rapidjson::Writer writer(buffer); + result_json.Accept(writer); + std::string block_string = buffer.GetString(); + +std::cout << block_string << std::endl; + + zframe_t *frame = zframe_new(block_string.c_str(), block_string.length()); + wap_proto_set_random_outputs(message, &frame); + + std::stringstream ss; + std::for_each(res.outs.begin(), res.outs.end(), [&](outs_for_amount& ofa) + { + ss << "[" << ofa.amount << "]:"; + CHECK_AND_ASSERT_MES(ofa.outs.size(), ;, "internal error: ofa.outs.size() is empty for amount " << ofa.amount); + std::for_each(ofa.outs.begin(), ofa.outs.end(), [&](out_entry& oe) + { + ss << oe.global_amount_index << " "; + }); + ss << ENDL; + }); + std::string s = ss.str(); + LOG_PRINT_L2("COMMAND_RPC_GET_RANDOM_OUTPUTS_FOR_AMOUNTS: " << ENDL << s); + wap_proto_set_status(message, STATUS_OK); + } } } diff --git a/src/ipc/include/daemon_ipc_handlers.h b/src/ipc/include/daemon_ipc_handlers.h index b46df43ed..9e716d5fd 100644 --- a/src/ipc/include/daemon_ipc_handlers.h +++ b/src/ipc/include/daemon_ipc_handlers.h @@ -60,12 +60,17 @@ namespace IPC const uint64_t STATUS_MINING_NOT_STARTED = 3; const uint64_t STATUS_WRONG_BLOCK_ID_LENGTH = 4; const uint64_t STATUS_INTERNAL_ERROR = 5; + const uint64_t STATUS_INVALID_TX = 6; + const uint64_t STATUS_TX_VERIFICATION_FAILED = 7; + const uint64_t STATUS_TX_NOT_RELAYED = 8; + const uint64_t STATUS_RANDOM_OUTS_FAILED = 9; namespace Daemon { void start_mining(wap_proto_t *message); void retrieve_blocks(wap_proto_t *message); void send_raw_transaction(wap_proto_t *message); void get_output_indexes(wap_proto_t *message); + void get_random_outs(wap_proto_t *message); void init(cryptonote::core *p_core, nodetool::node_server > *p_p2p, bool p_testnet); diff --git a/src/ipc/include/wap_client.h b/src/ipc/include/wap_client.h index b3a47bcee..4d37830bc 100644 --- a/src/ipc/include/wap_client.h +++ b/src/ipc/include/wap_client.h @@ -54,6 +54,12 @@ WAP_EXPORT zactor_t * WAP_EXPORT zsock_t * wap_client_msgpipe (wap_client_t *self); +// Return true if client is currently connected, else false. Note that the +// client will automatically re-connect if the server dies and restarts after +// a successful first connection. +WAP_EXPORT bool + wap_client_connected (wap_client_t *self); + // Connect to server endpoint, with specified timeout in msecs (zero means wait // forever). Constructor succeeds if connection is successful. The caller may // specify its address. @@ -69,7 +75,7 @@ WAP_EXPORT int // Send a raw transaction to the daemon. // Returns >= 0 if successful, -1 if interrupted. WAP_EXPORT int - wap_client_put (wap_client_t *self, zchunk_t **tx_data_p); + wap_client_put (wap_client_t *self, zchunk_t **tx_as_hex_p); // Request a set of blocks from the server. // Returns >= 0 if successful, -1 if interrupted. @@ -86,6 +92,11 @@ WAP_EXPORT int WAP_EXPORT int wap_client_output_indexes (wap_client_t *self, const char *tx_id); +// Ask for tx output indexes. +// Returns >= 0 if successful, -1 if interrupted. +WAP_EXPORT int + wap_client_random_outs (wap_client_t *self, uint64_t outs_count, zframe_t **amounts_p); + // Send start command to server. // Returns >= 0 if successful, -1 if interrupted. WAP_EXPORT int @@ -124,6 +135,10 @@ WAP_EXPORT zchunk_t * WAP_EXPORT zframe_t * wap_client_o_indexes (wap_client_t *self); +// Return last received random_outputs +WAP_EXPORT zframe_t * + wap_client_random_outputs (wap_client_t *self); + // Self test of this class WAP_EXPORT void wap_client_test (bool verbose); diff --git a/src/ipc/include/wap_client_engine.inc b/src/ipc/include/wap_client_engine.inc index 3d1f4f0b0..8c39bfd0e 100644 --- a/src/ipc/include/wap_client_engine.inc +++ b/src/ipc/include/wap_client_engine.inc @@ -31,10 +31,11 @@ typedef enum { expect_start_ok_state = 8, expect_stop_ok_state = 9, expect_output_indexes_ok_state = 10, - expect_close_ok_state = 11, - defaults_state = 12, - have_error_state = 13, - reexpect_open_ok_state = 14 + expect_random_outs_ok_state = 11, + expect_close_ok_state = 12, + defaults_state = 13, + have_error_state = 14, + reexpect_open_ok_state = 15 } state_t; typedef enum { @@ -50,19 +51,22 @@ typedef enum { start_event = 9, stop_event = 10, output_indexes_event = 11, - destructor_event = 12, - blocks_ok_event = 13, - get_ok_event = 14, - put_ok_event = 15, - save_ok_event = 16, - start_ok_event = 17, - stop_ok_event = 18, - output_indexes_ok_event = 19, - close_ok_event = 20, - ping_ok_event = 21, - error_event = 22, - command_invalid_event = 23, - other_event = 24 + random_outs_event = 12, + destructor_event = 13, + blocks_ok_event = 14, + get_ok_event = 15, + put_ok_event = 16, + save_ok_event = 17, + start_ok_event = 18, + stop_ok_event = 19, + output_indexes_ok_event = 20, + random_outs_ok_event = 21, + close_ok_event = 22, + ping_ok_event = 23, + error_event = 24, + exception_event = 25, + command_invalid_event = 26, + other_event = 27 } event_t; // Names for state machine logging and error reporting @@ -79,6 +83,7 @@ s_state_name [] = { "expect start ok", "expect stop ok", "expect output indexes ok", + "expect random outs ok", "expect close ok", "defaults", "have error", @@ -99,6 +104,7 @@ s_event_name [] = { "START", "STOP", "OUTPUT_INDEXES", + "RANDOM_OUTS", "destructor", "BLOCKS_OK", "GET_OK", @@ -107,9 +113,11 @@ s_event_name [] = { "START_OK", "STOP_OK", "OUTPUT_INDEXES_OK", + "RANDOM_OUTS_OK", "CLOSE_OK", "PING_OK", "ERROR", + "exception", "command_invalid", "other" }; @@ -127,8 +135,10 @@ struct _client_args_t { char *identity; zlist_t *block_ids; uint64_t start_height; - zchunk_t *tx_data; + zchunk_t *tx_as_hex; char *tx_id; + uint64_t outs_count; + zframe_t *amounts; char *address; uint64_t thread_count; }; @@ -141,6 +151,7 @@ typedef struct { zloop_t *loop; // Listen to pipe and dealer wap_proto_t *message; // Message received or sent client_args_t args; // Method arguments structure + bool connected; // True if client is connected bool terminated; // True if client is shutdown bool fsm_stopped; // "terminate" action called size_t timeout; // inactivity timeout, msecs @@ -178,7 +189,7 @@ static void static void signal_success (client_t *self); static void - use_heartbeat_timer (client_t *self); + client_is_connected (client_t *self); static void signal_server_not_present (client_t *self); static void @@ -193,6 +204,10 @@ static void prepare_start_command (client_t *self); static void prepare_get_output_indexes_command (client_t *self); +static void + prepare_get_random_outs_command (client_t *self); +static void + check_if_connection_is_dead (client_t *self); static void signal_have_blocks_ok (client_t *self); static void @@ -207,6 +222,8 @@ static void signal_have_stop_ok (client_t *self); static void signal_have_output_indexes_ok (client_t *self); +static void + signal_have_random_outs_ok (client_t *self); static void signal_failure (client_t *self); static void @@ -263,8 +280,9 @@ s_client_destroy (s_client_t **self_p) zstr_free (&self->args.endpoint); zstr_free (&self->args.identity); zlist_destroy (&self->args.block_ids); - zchunk_destroy (&self->args.tx_data); + zchunk_destroy (&self->args.tx_as_hex); zstr_free (&self->args.tx_id); + zframe_destroy (&self->args.amounts); zstr_free (&self->args.address); client_terminate (&self->client); wap_proto_destroy (&self->message); @@ -322,9 +340,11 @@ engine_set_wakeup_event (client_t *client, size_t delay, event_t event) } } -// Set timeout for next protocol read. By default, will wait forever -// or until the process is interrupted. The timeout is in milliseconds. -// The state machine must handle the "expired" event. +// Set heartbeat timeout. By default, the timeout is zero, meaning +// infinite. Setting a non-zero timeout causes the state machine to +// receive an "expired" event if is no incoming traffic for that many +// milliseconds. This cycles over and over until/unless the code sets +// a zero timeout. The state machine must handle the "expired" event. static void engine_set_timeout (client_t *client, size_t timeout) @@ -332,6 +352,10 @@ engine_set_timeout (client_t *client, size_t timeout) if (client) { s_client_t *self = (s_client_t *) client; self->timeout = timeout; + if (self->expiry_timer) { + zloop_timer_end (self->loop, self->expiry_timer); + self->expiry_timer = 0; + } if (self->timeout) self->expiry_timer = zloop_timer ( self->loop, self->timeout, 1, s_client_handle_timeout, self); @@ -356,6 +380,18 @@ engine_handle_socket (client_t *client, zsock_t *sock, zloop_reader_fn handler) } } +// Set connected to true/false. The client must call this if it wants +// to provide the API with the connected status. + +static void +engine_set_connected (client_t *client, bool connected) +{ + if (client) { + s_client_t *self = (s_client_t *) client; + self->connected = connected; + } +} + // Pedantic compilers don't like unused functions, so we call the whole // API, passing null references. It's nasty and horrid and sufficient. @@ -400,6 +436,12 @@ s_protocol_event (s_client_t *self, wap_proto_t *message) case WAP_PROTO_OUTPUT_INDEXES_OK: return output_indexes_ok_event; break; + case WAP_PROTO_RANDOM_OUTS: + return random_outs_event; + break; + case WAP_PROTO_RANDOM_OUTS_OK: + return random_outs_ok_event; + break; case WAP_PROTO_GET: return get_event; break; @@ -526,10 +568,10 @@ s_client_execute (s_client_t *self, event_t event) signal_success (&self->client); } if (!self->exception) { - // use heartbeat timer + // client is connected if (wap_client_verbose) - zsys_debug ("wap_client: $ use heartbeat timer"); - use_heartbeat_timer (&self->client); + zsys_debug ("wap_client: $ client is connected"); + client_is_connected (&self->client); } if (!self->exception) self->state = connected_state; @@ -551,9 +593,12 @@ s_client_execute (s_client_t *self, event_t event) } else if (self->event == ping_ok_event) { - // No action - just logging + if (!self->exception) { + // client is connected if (wap_client_verbose) - zsys_debug ("wap_client: $ ping_ok"); + zsys_debug ("wap_client: $ client is connected"); + client_is_connected (&self->client); + } } else if (self->event == error_event) { @@ -566,6 +611,12 @@ s_client_execute (s_client_t *self, event_t event) 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 @@ -695,6 +746,24 @@ s_client_execute (s_client_t *self, event_t event) self->state = expect_output_indexes_ok_state; } else + if (self->event == random_outs_event) { + if (!self->exception) { + // prepare get random outs command + if (wap_client_verbose) + zsys_debug ("wap_client: $ prepare get random outs command"); + prepare_get_random_outs_command (&self->client); + } + if (!self->exception) { + // send RANDOM_OUTS + if (wap_client_verbose) + zsys_debug ("wap_client: $ send RANDOM_OUTS"); + wap_proto_set_id (self->message, WAP_PROTO_RANDOM_OUTS); + wap_proto_send (self->message, self->dealer); + } + if (!self->exception) + self->state = expect_random_outs_ok_state; + } + else if (self->event == destructor_event) { if (!self->exception) { // send CLOSE @@ -708,6 +777,12 @@ s_client_execute (s_client_t *self, event_t event) } else if (self->event == expired_event) { + if (!self->exception) { + // check if connection is dead + if (wap_client_verbose) + zsys_debug ("wap_client: $ check if connection is dead"); + check_if_connection_is_dead (&self->client); + } if (!self->exception) { // send PING if (wap_client_verbose) @@ -718,9 +793,12 @@ s_client_execute (s_client_t *self, event_t event) } else if (self->event == ping_ok_event) { - // No action - just logging + if (!self->exception) { + // client is connected if (wap_client_verbose) - zsys_debug ("wap_client: $ ping_ok"); + zsys_debug ("wap_client: $ client is connected"); + client_is_connected (&self->client); + } } else if (self->event == error_event) { @@ -733,6 +811,12 @@ s_client_execute (s_client_t *self, event_t event) 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 @@ -754,9 +838,12 @@ s_client_execute (s_client_t *self, event_t event) } else if (self->event == ping_ok_event) { - // No action - just logging + if (!self->exception) { + // client is connected if (wap_client_verbose) - zsys_debug ("wap_client: $ ping_ok"); + zsys_debug ("wap_client: $ client is connected"); + client_is_connected (&self->client); + } } else if (self->event == error_event) { @@ -769,6 +856,12 @@ s_client_execute (s_client_t *self, event_t event) 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 @@ -790,9 +883,12 @@ s_client_execute (s_client_t *self, event_t event) } else if (self->event == ping_ok_event) { - // No action - just logging + if (!self->exception) { + // client is connected if (wap_client_verbose) - zsys_debug ("wap_client: $ ping_ok"); + zsys_debug ("wap_client: $ client is connected"); + client_is_connected (&self->client); + } } else if (self->event == error_event) { @@ -805,6 +901,12 @@ s_client_execute (s_client_t *self, event_t event) 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 @@ -826,9 +928,12 @@ s_client_execute (s_client_t *self, event_t event) } else if (self->event == ping_ok_event) { - // No action - just logging + if (!self->exception) { + // client is connected if (wap_client_verbose) - zsys_debug ("wap_client: $ ping_ok"); + zsys_debug ("wap_client: $ client is connected"); + client_is_connected (&self->client); + } } else if (self->event == error_event) { @@ -841,6 +946,12 @@ s_client_execute (s_client_t *self, event_t event) 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 @@ -862,9 +973,12 @@ s_client_execute (s_client_t *self, event_t event) } else if (self->event == ping_ok_event) { - // No action - just logging + if (!self->exception) { + // client is connected if (wap_client_verbose) - zsys_debug ("wap_client: $ ping_ok"); + zsys_debug ("wap_client: $ client is connected"); + client_is_connected (&self->client); + } } else if (self->event == error_event) { @@ -877,6 +991,12 @@ s_client_execute (s_client_t *self, event_t event) 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 @@ -898,9 +1018,12 @@ s_client_execute (s_client_t *self, event_t event) } else if (self->event == ping_ok_event) { - // No action - just logging + if (!self->exception) { + // client is connected if (wap_client_verbose) - zsys_debug ("wap_client: $ ping_ok"); + zsys_debug ("wap_client: $ client is connected"); + client_is_connected (&self->client); + } } else if (self->event == error_event) { @@ -913,6 +1036,12 @@ s_client_execute (s_client_t *self, event_t event) 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 @@ -934,9 +1063,12 @@ s_client_execute (s_client_t *self, event_t event) } else if (self->event == ping_ok_event) { - // No action - just logging + if (!self->exception) { + // client is connected if (wap_client_verbose) - zsys_debug ("wap_client: $ ping_ok"); + zsys_debug ("wap_client: $ client is connected"); + client_is_connected (&self->client); + } } else if (self->event == error_event) { @@ -949,6 +1081,12 @@ s_client_execute (s_client_t *self, event_t event) 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 @@ -970,9 +1108,12 @@ s_client_execute (s_client_t *self, event_t event) } else if (self->event == ping_ok_event) { - // No action - just logging + if (!self->exception) { + // client is connected if (wap_client_verbose) - zsys_debug ("wap_client: $ ping_ok"); + zsys_debug ("wap_client: $ client is connected"); + client_is_connected (&self->client); + } } else if (self->event == error_event) { @@ -985,6 +1126,57 @@ s_client_execute (s_client_t *self, event_t event) 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_random_outs_ok_state: + if (self->event == random_outs_ok_event) { + if (!self->exception) { + // signal have random outs ok + if (wap_client_verbose) + zsys_debug ("wap_client: $ signal have random outs ok"); + signal_have_random_outs_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 @@ -1025,9 +1217,12 @@ s_client_execute (s_client_t *self, event_t event) } else if (self->event == ping_ok_event) { - // No action - just logging + if (!self->exception) { + // client is connected if (wap_client_verbose) - zsys_debug ("wap_client: $ ping_ok"); + zsys_debug ("wap_client: $ client is connected"); + client_is_connected (&self->client); + } } else if (self->event == error_event) { @@ -1040,6 +1235,12 @@ s_client_execute (s_client_t *self, event_t event) 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 @@ -1050,9 +1251,12 @@ s_client_execute (s_client_t *self, event_t event) case defaults_state: if (self->event == ping_ok_event) { - // No action - just logging + if (!self->exception) { + // client is connected if (wap_client_verbose) - zsys_debug ("wap_client: $ ping_ok"); + zsys_debug ("wap_client: $ client is connected"); + client_is_connected (&self->client); + } } else if (self->event == error_event) { @@ -1065,6 +1269,12 @@ s_client_execute (s_client_t *self, event_t event) 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 @@ -1117,19 +1327,22 @@ s_client_execute (s_client_t *self, event_t event) case reexpect_open_ok_state: if (self->event == open_ok_event) { if (!self->exception) { - // use heartbeat timer + // client is connected if (wap_client_verbose) - zsys_debug ("wap_client: $ use heartbeat timer"); - use_heartbeat_timer (&self->client); + zsys_debug ("wap_client: $ client is connected"); + client_is_connected (&self->client); } if (!self->exception) self->state = connected_state; } else if (self->event == ping_ok_event) { - // No action - just logging + if (!self->exception) { + // client is connected if (wap_client_verbose) - zsys_debug ("wap_client: $ ping_ok"); + zsys_debug ("wap_client: $ client is connected"); + client_is_connected (&self->client); + } } else if (self->event == error_event) { @@ -1142,6 +1355,12 @@ s_client_execute (s_client_t *self, event_t event) 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 @@ -1169,7 +1388,13 @@ s_client_handle_timeout (zloop_t *loop, int timer_id, void *argument) { s_client_t *self = (s_client_t *) argument; s_client_execute (self, expired_event); - return self->terminated? -1: 0; + if (self->terminated) + return -1; + + if (self->timeout > 0) + self->expiry_timer = zloop_timer ( + loop, self->timeout, 1, s_client_handle_timeout, self); + return 0; } // zloop callback when client wakeup timer expires @@ -1198,6 +1423,9 @@ s_client_handle_cmdpipe (zloop_t *loop, zsock_t *reader, void *argument) if (streq (method, "$TERM")) self->terminated = true; // Shutdown the engine else + if (streq (method, "$CONNECTED")) + zsock_send (self->cmdpipe, "i", self->connected); + else if (streq (method, "CONNECT")) { zstr_free (&self->args.endpoint); zstr_free (&self->args.identity); @@ -1216,8 +1444,8 @@ s_client_handle_cmdpipe (zloop_t *loop, zsock_t *reader, void *argument) } else if (streq (method, "PUT")) { - zchunk_destroy (&self->args.tx_data); - zsock_recv (self->cmdpipe, "p", &self->args.tx_data); + zchunk_destroy (&self->args.tx_as_hex); + zsock_recv (self->cmdpipe, "p", &self->args.tx_as_hex); s_client_execute (self, put_event); } else @@ -1237,6 +1465,12 @@ s_client_handle_cmdpipe (zloop_t *loop, zsock_t *reader, void *argument) s_client_execute (self, output_indexes_event); } else + if (streq (method, "RANDOM OUTS")) { + zframe_destroy (&self->args.amounts); + zsock_recv (self->cmdpipe, "8p", &self->args.outs_count, &self->args.amounts); + s_client_execute (self, random_outs_event); + } + else if (streq (method, "START")) { zstr_free (&self->args.address); zsock_recv (self->cmdpipe, "s8", &self->args.address, &self->args.thread_count); @@ -1357,6 +1591,7 @@ wap_client (zsock_t *cmdpipe, void *msgpipe) struct _wap_client_t { zactor_t *actor; // Client actor zsock_t *msgpipe; // Pipe for async message flow + bool connected; // Client currently connected or not int status; // Returned by actor reply char *reason; // Returned by actor reply uint64_t start_height; // Returned by actor reply @@ -1364,6 +1599,7 @@ struct _wap_client_t { zmsg_t *block_data; // Returned by actor reply zchunk_t *tx_data; // Returned by actor reply zframe_t *o_indexes; // Returned by actor reply + zframe_t *random_outputs; // Returned by actor reply }; @@ -1415,6 +1651,7 @@ wap_client_destroy (wap_client_t **self_p) zmsg_destroy (&self->block_data); zchunk_destroy (&self->tx_data); zframe_destroy (&self->o_indexes); + zframe_destroy (&self->random_outputs); free (self); *self_p = NULL; } @@ -1448,6 +1685,22 @@ wap_client_msgpipe (wap_client_t *self) } +// --------------------------------------------------------------------------- +// Return true if client is currently connected, else false. Note that the +// client will automatically re-connect if the server dies and restarts after +// a successful first connection. + +bool +wap_client_connected (wap_client_t *self) +{ + assert (self); + bool connected; + zsock_send (self->actor, "s", "$CONNECTED"); + zsock_recv (self->actor, "i", &connected); + return connected; +} + + // --------------------------------------------------------------------------- // Get valid reply from actor; discard replies that does not match. Current // implementation filters on first frame of message. Blocks until a valid @@ -1500,6 +1753,11 @@ s_accept_reply (wap_client_t *self, ...) zsock_recv (self->actor, "8p", &self->status, &self->o_indexes); } else + if (streq (reply, "RANDOM OUTS OK")) { + zframe_destroy (&self->random_outputs); + zsock_recv (self->actor, "8p", &self->status, &self->random_outputs); + } + else if (streq (reply, "START OK")) { zsock_recv (self->actor, "8", &self->status); } @@ -1580,12 +1838,12 @@ wap_client_blocks (wap_client_t *self, zlist_t **block_ids_p, uint64_t start_hei // Returns >= 0 if successful, -1 if interrupted. int -wap_client_put (wap_client_t *self, zchunk_t **tx_data_p) +wap_client_put (wap_client_t *self, zchunk_t **tx_as_hex_p) { assert (self); - zsock_send (self->actor, "sp", "PUT", *tx_data_p); - *tx_data_p = NULL; // Take ownership of tx_data + zsock_send (self->actor, "sp", "PUT", *tx_as_hex_p); + *tx_as_hex_p = NULL; // Take ownership of tx_as_hex if (s_accept_reply (self, "PUT OK", "FAILURE", NULL)) return -1; // Interrupted or timed-out return self->status; @@ -1640,6 +1898,23 @@ wap_client_output_indexes (wap_client_t *self, const char *tx_id) } +// --------------------------------------------------------------------------- +// Ask for tx output indexes. +// Returns >= 0 if successful, -1 if interrupted. + +int +wap_client_random_outs (wap_client_t *self, uint64_t outs_count, zframe_t **amounts_p) +{ + assert (self); + + zsock_send (self->actor, "s8p", "RANDOM OUTS", outs_count, *amounts_p); + *amounts_p = NULL; // Take ownership of amounts + if (s_accept_reply (self, "RANDOM OUTS OK", "FAILURE", NULL)) + return -1; // Interrupted or timed-out + return self->status; +} + + // --------------------------------------------------------------------------- // Send start command to server. // Returns >= 0 if successful, -1 if interrupted. @@ -1747,3 +2022,14 @@ wap_client_o_indexes (wap_client_t *self) assert (self); return self->o_indexes; } + + +// --------------------------------------------------------------------------- +// Return last received random_outputs + +zframe_t * +wap_client_random_outputs (wap_client_t *self) +{ + assert (self); + return self->random_outputs; +} diff --git a/src/ipc/include/wap_proto.h b/src/ipc/include/wap_proto.h index 115e21254..eb3cadd63 100644 --- a/src/ipc/include/wap_proto.h +++ b/src/ipc/include/wap_proto.h @@ -1,6 +1,6 @@ /* ========================================================================= wap_proto - Wallet Access Protocol - + Codec header for wap_proto. ** WARNING ************************************************************* @@ -43,7 +43,7 @@ BLOCKS-OK, or ERROR if the request is invalid. PUT - Wallet sends a raw transaction to the daemon. Daemon replies with PUT-OK, or ERROR. - tx_data chunk Transaction data + tx_as_hex chunk Transaction as hex PUT_OK - Daemon confirms that it accepted the raw transaction. status number 8 Transaction ID @@ -55,6 +55,14 @@ PUT-OK, or ERROR. status number 8 Status o_indexes frame Output Indexes + RANDOM_OUTS - Get random outputs for amounts. + outs_count number 8 Outs count + amounts frame Amounts + + RANDOM_OUTS_OK - Daemon returns random outputs for amounts. + status number 8 Status + random_outputs frame Outputs + GET - Wallet requests transaction data from the daemon. Daemon replies with GET-OK, or ERROR. tx_id string Transaction ID @@ -113,19 +121,21 @@ Daemon will reply with CLOSE-OK or ERROR. #define WAP_PROTO_PUT_OK 6 #define WAP_PROTO_OUTPUT_INDEXES 7 #define WAP_PROTO_OUTPUT_INDEXES_OK 8 -#define WAP_PROTO_GET 9 -#define WAP_PROTO_GET_OK 10 -#define WAP_PROTO_SAVE 11 -#define WAP_PROTO_SAVE_OK 12 -#define WAP_PROTO_START 13 -#define WAP_PROTO_START_OK 14 -#define WAP_PROTO_STOP 15 -#define WAP_PROTO_STOP_OK 16 -#define WAP_PROTO_CLOSE 17 -#define WAP_PROTO_CLOSE_OK 18 -#define WAP_PROTO_PING 19 -#define WAP_PROTO_PING_OK 20 -#define WAP_PROTO_ERROR 21 +#define WAP_PROTO_RANDOM_OUTS 9 +#define WAP_PROTO_RANDOM_OUTS_OK 10 +#define WAP_PROTO_GET 11 +#define WAP_PROTO_GET_OK 12 +#define WAP_PROTO_SAVE 13 +#define WAP_PROTO_SAVE_OK 14 +#define WAP_PROTO_START 15 +#define WAP_PROTO_START_OK 16 +#define WAP_PROTO_STOP 17 +#define WAP_PROTO_STOP_OK 18 +#define WAP_PROTO_CLOSE 19 +#define WAP_PROTO_CLOSE_OK 20 +#define WAP_PROTO_PING 21 +#define WAP_PROTO_PING_OK 22 +#define WAP_PROTO_ERROR 23 #include @@ -156,7 +166,7 @@ int // Send the wap_proto to the output socket, does not destroy it int wap_proto_send (wap_proto_t *self, zsock_t *output); - + // Print contents of message to stdout void wap_proto_print (wap_proto_t *self); @@ -219,15 +229,15 @@ zmsg_t * void wap_proto_set_block_data (wap_proto_t *self, zmsg_t **msg_p); -// Get a copy of the tx_data field +// Get a copy of the tx_as_hex field zchunk_t * - wap_proto_tx_data (wap_proto_t *self); -// Get the tx_data field and transfer ownership to caller + wap_proto_tx_as_hex (wap_proto_t *self); +// Get the tx_as_hex field and transfer ownership to caller zchunk_t * - wap_proto_get_tx_data (wap_proto_t *self); -// Set the tx_data field, transferring ownership from caller + wap_proto_get_tx_as_hex (wap_proto_t *self); +// Set the tx_as_hex field, transferring ownership from caller void - wap_proto_set_tx_data (wap_proto_t *self, zchunk_t **chunk_p); + wap_proto_set_tx_as_hex (wap_proto_t *self, zchunk_t **chunk_p); // Get/set the tx_id field const char * @@ -245,6 +255,42 @@ zframe_t * void wap_proto_set_o_indexes (wap_proto_t *self, zframe_t **frame_p); +// Get/set the outs_count field +uint64_t + wap_proto_outs_count (wap_proto_t *self); +void + wap_proto_set_outs_count (wap_proto_t *self, uint64_t outs_count); + +// Get a copy of the amounts field +zframe_t * + wap_proto_amounts (wap_proto_t *self); +// Get the amounts field and transfer ownership to caller +zframe_t * + wap_proto_get_amounts (wap_proto_t *self); +// Set the amounts field, transferring ownership from caller +void + wap_proto_set_amounts (wap_proto_t *self, zframe_t **frame_p); + +// Get a copy of the random_outputs field +zframe_t * + wap_proto_random_outputs (wap_proto_t *self); +// Get the random_outputs field and transfer ownership to caller +zframe_t * + wap_proto_get_random_outputs (wap_proto_t *self); +// Set the random_outputs field, transferring ownership from caller +void + wap_proto_set_random_outputs (wap_proto_t *self, zframe_t **frame_p); + +// Get a copy of the tx_data field +zchunk_t * + wap_proto_tx_data (wap_proto_t *self); +// Get the tx_data field and transfer ownership to caller +zchunk_t * + wap_proto_get_tx_data (wap_proto_t *self); +// Set the tx_data field, transferring ownership from caller +void + wap_proto_set_tx_data (wap_proto_t *self, zchunk_t **chunk_p); + // Get/set the address field const char * wap_proto_address (wap_proto_t *self); diff --git a/src/ipc/include/wap_server_engine.inc b/src/ipc/include/wap_server_engine.inc index 54c63ae48..91d74a355 100644 --- a/src/ipc/include/wap_server_engine.inc +++ b/src/ipc/include/wap_server_engine.inc @@ -38,11 +38,12 @@ typedef enum { start_event = 7, stop_event = 8, output_indexes_event = 9, - close_event = 10, - ping_event = 11, - expired_event = 12, - exception_event = 13, - settled_event = 14 + random_outs_event = 10, + close_event = 11, + ping_event = 12, + expired_event = 13, + exception_event = 14, + settled_event = 15 } event_t; // Names for state machine logging and error reporting @@ -67,6 +68,7 @@ s_event_name [] = { "START", "STOP", "OUTPUT_INDEXES", + "RANDOM_OUTS", "CLOSE", "PING", "expired", @@ -148,6 +150,8 @@ static void stop_mining_process (client_t *self); static void output_indexes (client_t *self); +static void + random_outs (client_t *self); static void deregister_wallet (client_t *self); static void @@ -344,6 +348,9 @@ s_protocol_event (wap_proto_t *message) case WAP_PROTO_OUTPUT_INDEXES: return output_indexes_event; break; + case WAP_PROTO_RANDOM_OUTS: + return random_outs_event; + break; case WAP_PROTO_GET: return get_event; break; @@ -691,6 +698,24 @@ s_client_execute (s_client_t *self, event_t event) } } else + if (self->event == random_outs_event) { + if (!self->exception) { + // random outs + if (self->server->verbose) + zsys_debug ("%s: $ random outs", self->log_prefix); + random_outs (&self->client); + } + if (!self->exception) { + // send RANDOM_OUTS_OK + if (self->server->verbose) + zsys_debug ("%s: $ send RANDOM_OUTS_OK", + self->log_prefix); + wap_proto_set_id (self->server->message, WAP_PROTO_RANDOM_OUTS_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->exception) { // send CLOSE_OK @@ -1092,6 +1117,7 @@ s_server_config_service (s_server_t *self) if (zsock_bind (self->router, "%s", endpoint) == -1) zsys_warning ("could not bind to %s (%s)", endpoint, zmq_strerror (zmq_errno ())); } +#if (ZMQ_VERSION_MAJOR >= 4) else if (streq (zconfig_name (section), "security")) { char *mechanism = zconfig_resolve (section, "mechanism", "null"); @@ -1109,6 +1135,7 @@ s_server_config_service (s_server_t *self) else zsys_warning ("mechanism=%s is not supported", mechanism); } +#endif section = zconfig_next (section); } s_server_config_global (self); diff --git a/src/ipc/wap_client/wap_client.c b/src/ipc/wap_client/wap_client.c index 8ac3a18b5..50d737439 100644 --- a/src/ipc/wap_client/wap_client.c +++ b/src/ipc/wap_client/wap_client.c @@ -37,6 +37,7 @@ typedef struct { // Own properties int heartbeat_timer; // Timeout for heartbeats to server + int retries; // How many heartbeats we've tried } client_t; // Include the generated client engine @@ -97,6 +98,32 @@ use_connect_timeout (client_t *self) engine_set_timeout (self, self->args->timeout); } +// --------------------------------------------------------------------------- +// client_is_connected +// + +static void +client_is_connected (client_t *self) +{ + self->retries = 0; + engine_set_connected (self, true); + engine_set_timeout (self, self->heartbeat_timer); +} + +// --------------------------------------------------------------------------- +// check_if_connection_is_dead +// + +static void +check_if_connection_is_dead (client_t *self) +{ + // We send at most 3 heartbeats before expiring the server + if (++self->retries >= 3) { + engine_set_timeout (self, 0); + engine_set_connected (self, false); + engine_set_exception (self, exception_event); + } +} // --------------------------------------------------------------------------- // use_heartbeat_timer @@ -163,7 +190,7 @@ prepare_start_command (client_t *self) static void prepare_put_command (client_t *self) { - wap_proto_set_tx_data (self->message, &self->args->tx_data); + wap_proto_set_tx_as_hex (self->message, &self->args->tx_as_hex); } @@ -174,7 +201,7 @@ prepare_put_command (client_t *self) static void signal_have_put_ok (client_t *self) { - zsock_send (self->cmdpipe, "s8s", "PUT OK", 0, + zsock_send (self->cmdpipe, "s8s", "PUT OK", wap_proto_status(self->message), wap_proto_tx_id (self->message)); } @@ -325,3 +352,25 @@ signal_server_not_present (client_t *self) zsock_send (self->cmdpipe, "sis", "FAILURE", -1, "Server is not reachable"); } +// --------------------------------------------------------------------------- +// prepare_get_random_outs_command +// + +static void +prepare_get_random_outs_command (client_t *self) +{ + wap_proto_set_amounts (self->message, &self->args->amounts); +} + + +// --------------------------------------------------------------------------- +// signal_have_random_outs_ok +// + +static void +signal_have_random_outs_ok (client_t *self) +{ + zsock_send (self->cmdpipe, "s8p", "RANDOM OUTS OK", + wap_proto_status (self->message), + wap_proto_get_random_outputs (self->message)); +} diff --git a/src/ipc/wap_proto.c b/src/ipc/wap_proto.c index 678309e80..16dd0a964 100644 --- a/src/ipc/wap_proto.c +++ b/src/ipc/wap_proto.c @@ -34,29 +34,37 @@ struct _wap_proto_t { int id; // wap_proto message ID byte *needle; // Read/write pointer for serialization byte *ceiling; // Valid upper limit for read pointer - /* Wallet identity */ + // Wallet identity char identity [256]; - /* */ + // block_ids zlist_t *block_ids; - /* */ + // start_height uint64_t start_height; - /* */ + // status uint64_t status; - /* */ + // curr_height uint64_t curr_height; - /* Frames of block data */ + // Frames of block data zmsg_t *block_data; - /* Transaction data */ - zchunk_t *tx_data; - /* Transaction ID */ + // Transaction as hex + zchunk_t *tx_as_hex; + // Transaction ID char tx_id [256]; - /* Output Indexes */ + // Output Indexes zframe_t *o_indexes; - /* */ + // Outs count + uint64_t outs_count; + // Amounts + zframe_t *amounts; + // Outputs + zframe_t *random_outputs; + // Transaction data + zchunk_t *tx_data; + // address char address [256]; - /* */ + // thread_count uint64_t thread_count; - /* Printable explanation */ + // Printable explanation char reason [256]; }; @@ -236,8 +244,11 @@ wap_proto_destroy (wap_proto_t **self_p) if (self->block_ids) zlist_destroy (&self->block_ids); zmsg_destroy (&self->block_data); - zchunk_destroy (&self->tx_data); + zchunk_destroy (&self->tx_as_hex); zframe_destroy (&self->o_indexes); + zframe_destroy (&self->amounts); + zframe_destroy (&self->random_outputs); + zchunk_destroy (&self->tx_data); // Free object itself free (self); @@ -254,7 +265,7 @@ int wap_proto_recv (wap_proto_t *self, zsock_t *input) { assert (input); - + if (zsock_type (input) == ZMQ_ROUTER) { zframe_destroy (&self->routing_id); self->routing_id = zframe_recv (input); @@ -273,7 +284,7 @@ wap_proto_recv (wap_proto_t *self, zsock_t *input) // Get and check protocol signature self->needle = (byte *) zmq_msg_data (&frame); self->ceiling = self->needle + zmq_msg_size (&frame); - + uint16_t signature; GET_NUMBER2 (signature); if (signature != (0xAAA0 | 0)) { @@ -342,11 +353,11 @@ wap_proto_recv (wap_proto_t *self, zsock_t *input) size_t chunk_size; GET_NUMBER4 (chunk_size); if (self->needle + chunk_size > (self->ceiling)) { - zsys_warning ("wap_proto: tx_data is missing data"); + zsys_warning ("wap_proto: tx_as_hex is missing data"); goto malformed; } - zchunk_destroy (&self->tx_data); - self->tx_data = zchunk_new (self->needle, chunk_size); + zchunk_destroy (&self->tx_as_hex); + self->tx_as_hex = zchunk_new (self->needle, chunk_size); self->needle += chunk_size; } break; @@ -370,6 +381,28 @@ wap_proto_recv (wap_proto_t *self, zsock_t *input) self->o_indexes = zframe_recv (input); break; + case WAP_PROTO_RANDOM_OUTS: + GET_NUMBER8 (self->outs_count); + // Get next frame off socket + if (!zsock_rcvmore (input)) { + zsys_warning ("wap_proto: amounts is missing"); + goto malformed; + } + zframe_destroy (&self->amounts); + self->amounts = zframe_recv (input); + break; + + case WAP_PROTO_RANDOM_OUTS_OK: + GET_NUMBER8 (self->status); + // Get next frame off socket + if (!zsock_rcvmore (input)) { + zsys_warning ("wap_proto: random_outputs is missing"); + goto malformed; + } + zframe_destroy (&self->random_outputs); + self->random_outputs = zframe_recv (input); + break; + case WAP_PROTO_GET: GET_STRING (self->tx_id); break; @@ -480,8 +513,8 @@ wap_proto_send (wap_proto_t *self, zsock_t *output) break; case WAP_PROTO_PUT: frame_size += 4; // Size is 4 octets - if (self->tx_data) - frame_size += zchunk_size (self->tx_data); + if (self->tx_as_hex) + frame_size += zchunk_size (self->tx_as_hex); break; case WAP_PROTO_PUT_OK: frame_size += 8; // status @@ -492,6 +525,12 @@ wap_proto_send (wap_proto_t *self, zsock_t *output) case WAP_PROTO_OUTPUT_INDEXES_OK: frame_size += 8; // status break; + case WAP_PROTO_RANDOM_OUTS: + frame_size += 8; // outs_count + break; + case WAP_PROTO_RANDOM_OUTS_OK: + frame_size += 8; // status + break; case WAP_PROTO_GET: frame_size += 1 + strlen (self->tx_id); break; @@ -520,7 +559,7 @@ wap_proto_send (wap_proto_t *self, zsock_t *output) PUT_NUMBER1 (self->id); bool send_block_data = false; size_t nbr_frames = 1; // Total number of frames to send - + switch (self->id) { case WAP_PROTO_OPEN: PUT_STRING ("WAP"); @@ -551,12 +590,12 @@ wap_proto_send (wap_proto_t *self, zsock_t *output) break; case WAP_PROTO_PUT: - if (self->tx_data) { - PUT_NUMBER4 (zchunk_size (self->tx_data)); + if (self->tx_as_hex) { + PUT_NUMBER4 (zchunk_size (self->tx_as_hex)); memcpy (self->needle, - zchunk_data (self->tx_data), - zchunk_size (self->tx_data)); - self->needle += zchunk_size (self->tx_data); + zchunk_data (self->tx_as_hex), + zchunk_size (self->tx_as_hex)); + self->needle += zchunk_size (self->tx_as_hex); } else PUT_NUMBER4 (0); // Empty chunk @@ -575,6 +614,16 @@ wap_proto_send (wap_proto_t *self, zsock_t *output) nbr_frames++; break; + case WAP_PROTO_RANDOM_OUTS: + PUT_NUMBER8 (self->outs_count); + nbr_frames++; + break; + + case WAP_PROTO_RANDOM_OUTS_OK: + PUT_NUMBER8 (self->status); + nbr_frames++; + break; + case WAP_PROTO_GET: PUT_STRING (self->tx_id); break; @@ -608,7 +657,7 @@ wap_proto_send (wap_proto_t *self, zsock_t *output) } // Now send the data frame zmq_msg_send (&frame, zsock_resolve (output), --nbr_frames? ZMQ_SNDMORE: 0); - + // Now send any frame fields, in order if (self->id == WAP_PROTO_OUTPUT_INDEXES_OK) { // If o_indexes isn't set, send an empty frame @@ -617,6 +666,22 @@ wap_proto_send (wap_proto_t *self, zsock_t *output) else zmq_send (zsock_resolve (output), NULL, 0, (--nbr_frames? ZMQ_SNDMORE: 0)); } + // Now send any frame fields, in order + if (self->id == WAP_PROTO_RANDOM_OUTS) { + // If amounts isn't set, send an empty frame + if (self->amounts) + zframe_send (&self->amounts, output, ZFRAME_REUSE + (--nbr_frames? ZFRAME_MORE: 0)); + else + zmq_send (zsock_resolve (output), NULL, 0, (--nbr_frames? ZMQ_SNDMORE: 0)); + } + // Now send any frame fields, in order + if (self->id == WAP_PROTO_RANDOM_OUTS_OK) { + // If random_outputs isn't set, send an empty frame + if (self->random_outputs) + zframe_send (&self->random_outputs, output, ZFRAME_REUSE + (--nbr_frames? ZFRAME_MORE: 0)); + else + zmq_send (zsock_resolve (output), NULL, 0, (--nbr_frames? ZMQ_SNDMORE: 0)); + } // Now send the block_data if necessary if (send_block_data) { if (self->block_data) { @@ -650,11 +715,11 @@ wap_proto_print (wap_proto_t *self) else zsys_debug (" identity="); break; - + case WAP_PROTO_OPEN_OK: zsys_debug ("WAP_PROTO_OPEN_OK:"); break; - + case WAP_PROTO_BLOCKS: zsys_debug ("WAP_PROTO_BLOCKS:"); zsys_debug (" block_ids="); @@ -667,7 +732,7 @@ wap_proto_print (wap_proto_t *self) } zsys_debug (" start_height=%ld", (long) self->start_height); break; - + case WAP_PROTO_BLOCKS_OK: zsys_debug ("WAP_PROTO_BLOCKS_OK:"); zsys_debug (" status=%ld", (long) self->status); @@ -679,17 +744,17 @@ wap_proto_print (wap_proto_t *self) else zsys_debug ("(NULL)"); break; - + case WAP_PROTO_PUT: zsys_debug ("WAP_PROTO_PUT:"); - zsys_debug (" tx_data=[ ... ]"); + zsys_debug (" tx_as_hex=[ ... ]"); break; - + case WAP_PROTO_PUT_OK: zsys_debug ("WAP_PROTO_PUT_OK:"); zsys_debug (" status=%ld", (long) self->status); break; - + case WAP_PROTO_OUTPUT_INDEXES: zsys_debug ("WAP_PROTO_OUTPUT_INDEXES:"); if (self->tx_id) @@ -697,7 +762,7 @@ wap_proto_print (wap_proto_t *self) else zsys_debug (" tx_id="); break; - + case WAP_PROTO_OUTPUT_INDEXES_OK: zsys_debug ("WAP_PROTO_OUTPUT_INDEXES_OK:"); zsys_debug (" status=%ld", (long) self->status); @@ -707,7 +772,27 @@ wap_proto_print (wap_proto_t *self) else zsys_debug ("(NULL)"); break; - + + case WAP_PROTO_RANDOM_OUTS: + zsys_debug ("WAP_PROTO_RANDOM_OUTS:"); + zsys_debug (" outs_count=%ld", (long) self->outs_count); + zsys_debug (" amounts="); + if (self->amounts) + zframe_print (self->amounts, NULL); + else + zsys_debug ("(NULL)"); + break; + + case WAP_PROTO_RANDOM_OUTS_OK: + zsys_debug ("WAP_PROTO_RANDOM_OUTS_OK:"); + zsys_debug (" status=%ld", (long) self->status); + zsys_debug (" random_outputs="); + if (self->random_outputs) + zframe_print (self->random_outputs, NULL); + else + zsys_debug ("(NULL)"); + break; + case WAP_PROTO_GET: zsys_debug ("WAP_PROTO_GET:"); if (self->tx_id) @@ -715,20 +800,20 @@ wap_proto_print (wap_proto_t *self) else zsys_debug (" tx_id="); break; - + case WAP_PROTO_GET_OK: zsys_debug ("WAP_PROTO_GET_OK:"); zsys_debug (" tx_data=[ ... ]"); break; - + case WAP_PROTO_SAVE: zsys_debug ("WAP_PROTO_SAVE:"); break; - + case WAP_PROTO_SAVE_OK: zsys_debug ("WAP_PROTO_SAVE_OK:"); break; - + case WAP_PROTO_START: zsys_debug ("WAP_PROTO_START:"); if (self->address) @@ -737,36 +822,36 @@ wap_proto_print (wap_proto_t *self) zsys_debug (" address="); zsys_debug (" thread_count=%ld", (long) self->thread_count); break; - + case WAP_PROTO_START_OK: zsys_debug ("WAP_PROTO_START_OK:"); zsys_debug (" status=%ld", (long) self->status); break; - + case WAP_PROTO_STOP: zsys_debug ("WAP_PROTO_STOP:"); break; - + case WAP_PROTO_STOP_OK: zsys_debug ("WAP_PROTO_STOP_OK:"); break; - + case WAP_PROTO_CLOSE: zsys_debug ("WAP_PROTO_CLOSE:"); break; - + case WAP_PROTO_CLOSE_OK: zsys_debug ("WAP_PROTO_CLOSE_OK:"); break; - + case WAP_PROTO_PING: zsys_debug ("WAP_PROTO_PING:"); break; - + case WAP_PROTO_PING_OK: zsys_debug ("WAP_PROTO_PING_OK:"); break; - + case WAP_PROTO_ERROR: zsys_debug ("WAP_PROTO_ERROR:"); zsys_debug (" status=%ld", (long) self->status); @@ -775,7 +860,7 @@ wap_proto_print (wap_proto_t *self) else zsys_debug (" reason="); break; - + } } @@ -847,6 +932,12 @@ wap_proto_command (wap_proto_t *self) case WAP_PROTO_OUTPUT_INDEXES_OK: return ("OUTPUT_INDEXES_OK"); break; + case WAP_PROTO_RANDOM_OUTS: + return ("RANDOM_OUTS"); + break; + case WAP_PROTO_RANDOM_OUTS_OK: + return ("RANDOM_OUTS_OK"); + break; case WAP_PROTO_GET: return ("GET"); break; @@ -1035,34 +1126,34 @@ wap_proto_set_block_data (wap_proto_t *self, zmsg_t **msg_p) // -------------------------------------------------------------------------- -// Get the tx_data field without transferring ownership +// Get the tx_as_hex field without transferring ownership zchunk_t * -wap_proto_tx_data (wap_proto_t *self) +wap_proto_tx_as_hex (wap_proto_t *self) { assert (self); - return self->tx_data; + return self->tx_as_hex; } -// Get the tx_data field and transfer ownership to caller +// Get the tx_as_hex field and transfer ownership to caller zchunk_t * -wap_proto_get_tx_data (wap_proto_t *self) +wap_proto_get_tx_as_hex (wap_proto_t *self) { - zchunk_t *tx_data = self->tx_data; - self->tx_data = NULL; - return tx_data; + zchunk_t *tx_as_hex = self->tx_as_hex; + self->tx_as_hex = NULL; + return tx_as_hex; } -// Set the tx_data field, transferring ownership from caller +// Set the tx_as_hex field, transferring ownership from caller void -wap_proto_set_tx_data (wap_proto_t *self, zchunk_t **chunk_p) +wap_proto_set_tx_as_hex (wap_proto_t *self, zchunk_t **chunk_p) { assert (self); assert (chunk_p); - zchunk_destroy (&self->tx_data); - self->tx_data = *chunk_p; + zchunk_destroy (&self->tx_as_hex); + self->tx_as_hex = *chunk_p; *chunk_p = NULL; } @@ -1122,6 +1213,123 @@ wap_proto_set_o_indexes (wap_proto_t *self, zframe_t **frame_p) } +// -------------------------------------------------------------------------- +// Get/set the outs_count field + +uint64_t +wap_proto_outs_count (wap_proto_t *self) +{ + assert (self); + return self->outs_count; +} + +void +wap_proto_set_outs_count (wap_proto_t *self, uint64_t outs_count) +{ + assert (self); + self->outs_count = outs_count; +} + + +// -------------------------------------------------------------------------- +// Get the amounts field without transferring ownership + +zframe_t * +wap_proto_amounts (wap_proto_t *self) +{ + assert (self); + return self->amounts; +} + +// Get the amounts field and transfer ownership to caller + +zframe_t * +wap_proto_get_amounts (wap_proto_t *self) +{ + zframe_t *amounts = self->amounts; + self->amounts = NULL; + return amounts; +} + +// Set the amounts field, transferring ownership from caller + +void +wap_proto_set_amounts (wap_proto_t *self, zframe_t **frame_p) +{ + assert (self); + assert (frame_p); + zframe_destroy (&self->amounts); + self->amounts = *frame_p; + *frame_p = NULL; +} + + +// -------------------------------------------------------------------------- +// Get the random_outputs field without transferring ownership + +zframe_t * +wap_proto_random_outputs (wap_proto_t *self) +{ + assert (self); + return self->random_outputs; +} + +// Get the random_outputs field and transfer ownership to caller + +zframe_t * +wap_proto_get_random_outputs (wap_proto_t *self) +{ + zframe_t *random_outputs = self->random_outputs; + self->random_outputs = NULL; + return random_outputs; +} + +// Set the random_outputs field, transferring ownership from caller + +void +wap_proto_set_random_outputs (wap_proto_t *self, zframe_t **frame_p) +{ + assert (self); + assert (frame_p); + zframe_destroy (&self->random_outputs); + self->random_outputs = *frame_p; + *frame_p = NULL; +} + + +// -------------------------------------------------------------------------- +// Get the tx_data field without transferring ownership + +zchunk_t * +wap_proto_tx_data (wap_proto_t *self) +{ + assert (self); + return self->tx_data; +} + +// Get the tx_data field and transfer ownership to caller + +zchunk_t * +wap_proto_get_tx_data (wap_proto_t *self) +{ + zchunk_t *tx_data = self->tx_data; + self->tx_data = NULL; + return tx_data; +} + +// Set the tx_data field, transferring ownership from caller + +void +wap_proto_set_tx_data (wap_proto_t *self, zchunk_t **chunk_p) +{ + assert (self); + assert (chunk_p); + zchunk_destroy (&self->tx_data); + self->tx_data = *chunk_p; + *chunk_p = NULL; +} + + // -------------------------------------------------------------------------- // Get/set the address field @@ -1191,7 +1399,7 @@ wap_proto_set_reason (wap_proto_t *self, const char *value) int wap_proto_test (bool verbose) { - printf (" * wap_proto: "); + printf (" * wap_proto:"); // Silence an "unused" warning by "using" the verbose variable if (verbose) {;} @@ -1203,13 +1411,16 @@ wap_proto_test (bool verbose) wap_proto_destroy (&self); // Create pair of sockets we can send through - zsock_t *input = zsock_new (ZMQ_ROUTER); - assert (input); - zsock_connect (input, "inproc://selftest-wap_proto"); - + // We must bind before connect if we wish to remain compatible with ZeroMQ < v4 zsock_t *output = zsock_new (ZMQ_DEALER); assert (output); - zsock_bind (output, "inproc://selftest-wap_proto"); + int rc = zsock_bind (output, "inproc://selftest-wap_proto"); + assert (rc == 0); + + zsock_t *input = zsock_new (ZMQ_ROUTER); + assert (input); + rc = zsock_connect (input, "inproc://selftest-wap_proto"); + assert (rc == 0); // Encode/send/decode and verify each message type int instance; @@ -1255,6 +1466,7 @@ wap_proto_test (bool verbose) assert (streq ((char *) zlist_first (block_ids), "Name: Brutus")); assert (streq ((char *) zlist_next (block_ids), "Age: 43")); zlist_destroy (&block_ids); + zlist_destroy (&blocks_block_ids); assert (wap_proto_start_height (self) == 123); } wap_proto_set_id (self, WAP_PROTO_BLOCKS_OK); @@ -1264,7 +1476,7 @@ wap_proto_test (bool verbose) wap_proto_set_curr_height (self, 123); zmsg_t *blocks_ok_block_data = zmsg_new (); wap_proto_set_block_data (self, &blocks_ok_block_data); - zmsg_addstr (wap_proto_block_data (self), "Hello, World"); + zmsg_addstr (wap_proto_block_data (self), "Captcha Diem"); // Send twice wap_proto_send (self, output); wap_proto_send (self, output); @@ -1276,11 +1488,15 @@ wap_proto_test (bool verbose) assert (wap_proto_start_height (self) == 123); assert (wap_proto_curr_height (self) == 123); assert (zmsg_size (wap_proto_block_data (self)) == 1); + char *content = zmsg_popstr (wap_proto_block_data (self)); + assert (streq (content, "Captcha Diem")); + zstr_free (&content); + zmsg_destroy (&blocks_ok_block_data); } wap_proto_set_id (self, WAP_PROTO_PUT); - zchunk_t *put_tx_data = zchunk_new ("Captcha Diem", 12); - wap_proto_set_tx_data (self, &put_tx_data); + zchunk_t *put_tx_as_hex = zchunk_new ("Captcha Diem", 12); + wap_proto_set_tx_as_hex (self, &put_tx_as_hex); // Send twice wap_proto_send (self, output); wap_proto_send (self, output); @@ -1288,7 +1504,8 @@ wap_proto_test (bool verbose) for (instance = 0; instance < 2; instance++) { wap_proto_recv (self, input); assert (wap_proto_routing_id (self)); - assert (memcmp (zchunk_data (wap_proto_tx_data (self)), "Captcha Diem", 12) == 0); + assert (memcmp (zchunk_data (wap_proto_tx_as_hex (self)), "Captcha Diem", 12) == 0); + zchunk_destroy (&put_tx_as_hex); } wap_proto_set_id (self, WAP_PROTO_PUT_OK); @@ -1328,6 +1545,39 @@ wap_proto_test (bool verbose) assert (wap_proto_routing_id (self)); assert (wap_proto_status (self) == 123); assert (zframe_streq (wap_proto_o_indexes (self), "Captcha Diem")); + zframe_destroy (&output_indexes_ok_o_indexes); + } + wap_proto_set_id (self, WAP_PROTO_RANDOM_OUTS); + + wap_proto_set_outs_count (self, 123); + zframe_t *random_outs_amounts = zframe_new ("Captcha Diem", 12); + wap_proto_set_amounts (self, &random_outs_amounts); + // 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_outs_count (self) == 123); + assert (zframe_streq (wap_proto_amounts (self), "Captcha Diem")); + zframe_destroy (&random_outs_amounts); + } + wap_proto_set_id (self, WAP_PROTO_RANDOM_OUTS_OK); + + wap_proto_set_status (self, 123); + zframe_t *random_outs_ok_random_outputs = zframe_new ("Captcha Diem", 12); + wap_proto_set_random_outputs (self, &random_outs_ok_random_outputs); + // 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 (zframe_streq (wap_proto_random_outputs (self), "Captcha Diem")); + zframe_destroy (&random_outs_ok_random_outputs); } wap_proto_set_id (self, WAP_PROTO_GET); @@ -1353,6 +1603,7 @@ wap_proto_test (bool verbose) wap_proto_recv (self, input); assert (wap_proto_routing_id (self)); assert (memcmp (zchunk_data (wap_proto_tx_data (self)), "Captcha Diem", 12) == 0); + zchunk_destroy (&get_ok_tx_data); } wap_proto_set_id (self, WAP_PROTO_SAVE); diff --git a/src/ipc/wap_server/wap_server.c b/src/ipc/wap_server/wap_server.c index 9a71bee6f..71cce48df 100644 --- a/src/ipc/wap_server/wap_server.c +++ b/src/ipc/wap_server/wap_server.c @@ -261,3 +261,13 @@ signal_command_not_valid (client_t *self) { wap_proto_set_status (self->message, WAP_PROTO_COMMAND_INVALID); } + +// --------------------------------------------------------------------------- +// random_outs +// + +static void +random_outs (client_t *self) +{ + IPC::Daemon::get_random_outs(self->message); +} diff --git a/src/simplewallet/simplewallet.cpp b/src/simplewallet/simplewallet.cpp index bf996e55a..4e48142fa 100644 --- a/src/simplewallet/simplewallet.cpp +++ b/src/simplewallet/simplewallet.cpp @@ -1065,9 +1065,10 @@ bool simple_wallet::show_blockchain_height(const std::vector& args) //---------------------------------------------------------------------------------------------------- bool simple_wallet::transfer(const std::vector &args_) { - if (!try_connect_to_daemon()) - return true; + /*if (!try_connect_to_daemon()) + return true;*/ +std::cout << "1\n"; std::vector local_args = args_; if(local_args.size() < 3) { @@ -1075,6 +1076,7 @@ bool simple_wallet::transfer(const std::vector &args_) return true; } +std::cout << "2\n"; size_t fake_outs_count; if(!epee::string_tools::get_xtype_from_string(fake_outs_count, local_args[0])) { @@ -1083,6 +1085,7 @@ bool simple_wallet::transfer(const std::vector &args_) } local_args.erase(local_args.begin()); +std::cout << "3\n"; std::vector extra; if (1 == local_args.size() % 2) { @@ -1105,6 +1108,7 @@ bool simple_wallet::transfer(const std::vector &args_) } } +std::cout << "4\n"; vector dsts; for (size_t i = 0; i < local_args.size(); i += 2) { @@ -1179,14 +1183,17 @@ bool simple_wallet::transfer(const std::vector &args_) dsts.push_back(de); } +std::cout << "5\n"; try { // figure out what tx will be necessary auto ptx_vector = m_wallet->create_transactions(dsts, fake_outs_count, 0 /* unlock_time */, 0 /* unused fee arg*/, extra); +std::cout << "5a\n"; // if more than one tx necessary, prompt user to confirm if (ptx_vector.size() > 1) { +std::cout << "5b\n"; std::string prompt_str = "Your transaction needs to be split into "; prompt_str += std::to_string(ptx_vector.size()); prompt_str += " transactions. This will result in a transaction fee being applied to each transaction"; @@ -1202,6 +1209,7 @@ bool simple_wallet::transfer(const std::vector &args_) } } +std::cout << "6\n"; // actually commit the transactions while (!ptx_vector.empty()) { @@ -1219,6 +1227,7 @@ bool simple_wallet::transfer(const std::vector &args_) } catch (const tools::error::no_connection_to_daemon&) { +std::cout << "7\n"; fail_msg_writer() << "no connection to daemon. Please, make sure daemon is running."; } catch (const tools::error::wallet_rpc_error& e) diff --git a/src/wallet/wallet2.cpp b/src/wallet/wallet2.cpp index 8498e1742..c0f913dc3 100644 --- a/src/wallet/wallet2.cpp +++ b/src/wallet/wallet2.cpp @@ -1130,13 +1130,21 @@ std::string wallet2::address_from_txt_record(const std::string& s) void wallet2::commit_tx(pending_tx& ptx) { using namespace cryptonote; - COMMAND_RPC_SEND_RAW_TX::request req; + /*COMMAND_RPC_SEND_RAW_TX::request req; req.tx_as_hex = epee::string_tools::buff_to_hex_nodelimer(tx_to_blob(ptx.tx)); COMMAND_RPC_SEND_RAW_TX::response daemon_send_resp; bool r = epee::net_utils::invoke_http_json_remote_command2(m_daemon_address + "/sendrawtransaction", req, daemon_send_resp, m_http_client, 200000); THROW_WALLET_EXCEPTION_IF(!r, error::no_connection_to_daemon, "sendrawtransaction"); THROW_WALLET_EXCEPTION_IF(daemon_send_resp.status == CORE_RPC_STATUS_BUSY, error::daemon_busy, "sendrawtransaction"); - THROW_WALLET_EXCEPTION_IF(daemon_send_resp.status != CORE_RPC_STATUS_OK, error::tx_rejected, ptx.tx, daemon_send_resp.status); + THROW_WALLET_EXCEPTION_IF(daemon_send_resp.status != CORE_RPC_STATUS_OK, error::tx_rejected, ptx.tx, daemon_send_resp.status);*/ + + std::string tx_as_hex_string = epee::string_tools::buff_to_hex_nodelimer(tx_to_blob(ptx.tx)); + zchunk_t *tx_as_hex = zchunk_new((void*)tx_as_hex_string.c_str(), tx_as_hex_string.length()); + int rc = wap_client_put(client, &tx_as_hex); + uint64_t status = wap_client_status(client); + THROW_WALLET_EXCEPTION_IF(status == IPC::STATUS_CORE_BUSY, error::daemon_busy, "sendrawtransaction"); + THROW_WALLET_EXCEPTION_IF((status == IPC::STATUS_INVALID_TX) || (status == IPC::STATUS_TX_VERIFICATION_FAILED) || + (status == IPC::STATUS_TX_NOT_RELAYED), error::tx_rejected, ptx.tx, status); add_unconfirmed_tx(ptx.tx, ptx.change_dts.amount); @@ -1171,6 +1179,7 @@ std::vector wallet2::create_transactions(std::vector wallet2::create_transactions(std::vector amounts; BOOST_FOREACH(transfer_container::iterator it, selected_transfers) { THROW_WALLET_EXCEPTION_IF(it->m_tx.vout.size() <= it->m_internal_output_index, error::wallet_internal_error, "m_internal_output_index = " + std::to_string(it->m_internal_output_index) + " is greater or equal to outputs count = " + std::to_string(it->m_tx.vout.size())); - req.amounts.push_back(it->amount()); + amounts.push_back(it->amount()); } - bool r = epee::net_utils::invoke_http_bin_remote_command2(m_daemon_address + "/getrandom_outs.bin", req, daemon_resp, m_http_client, 200000); + zframe_t *amounts_frame = zframe_new(&amounts[0], amounts.size() * sizeof(uint64_t)); + int rc = wap_client_random_outs(client, outs_count, &amounts_frame); + /*bool r = epee::net_utils::invoke_http_bin_remote_command2(m_daemon_address + "/getrandom_outs.bin", req, daemon_resp, m_http_client, 200000); THROW_WALLET_EXCEPTION_IF(!r, error::no_connection_to_daemon, "getrandom_outs.bin"); THROW_WALLET_EXCEPTION_IF(daemon_resp.status == CORE_RPC_STATUS_BUSY, error::daemon_busy, "getrandom_outs.bin"); THROW_WALLET_EXCEPTION_IF(daemon_resp.status != CORE_RPC_STATUS_OK, error::get_random_outs_error, daemon_resp.status); THROW_WALLET_EXCEPTION_IF(daemon_resp.outs.size() != selected_transfers.size(), error::wallet_internal_error, "daemon returned wrong response for getrandom_outs.bin, wrong amounts count = " + - std::to_string(daemon_resp.outs.size()) + ", expected " + std::to_string(selected_transfers.size())); + std::to_string(daemon_resp.outs.size()) + ", expected " + std::to_string(selected_transfers.size()));*/ + + uint64_t status = wap_client_status(client); + THROW_WALLET_EXCEPTION_IF(status == IPC::STATUS_CORE_BUSY, error::daemon_busy, "getrandomouts"); + // TODO: Use a code to string mapping of errors + THROW_WALLET_EXCEPTION_IF(status == IPC::STATUS_RANDOM_OUTS_FAILED, error::get_random_outs_error, "IPC::STATUS_RANDOM_OUTS_FAILED"); + THROW_WALLET_EXCEPTION_IF(status != IPC::STATUS_OK, error::get_random_outs_error, "!IPC:STATUS_OK"); + + // Convert ZMQ response back into RPC response object. + zframe_t *outputs_frame = wap_client_random_outputs(client); + uint64_t frame_size = zframe_size(outputs_frame); + char *frame_data = reinterpret_cast(zframe_data(outputs_frame)); +std::string tmp(frame_data, frame_size); +std::cout << tmp << std::endl; + rapidjson::Document json; + THROW_WALLET_EXCEPTION_IF(json.Parse(frame_data, frame_size).HasParseError(), error::get_random_outs_error, "Couldn't JSON parse random outputs."); + for (rapidjson::SizeType i = 0; i < json["outputs"].Size(); i++) { + COMMAND_RPC_GET_RANDOM_OUTPUTS_FOR_AMOUNTS::outs_for_amount output; + output.amount = json["outputs"][i]["amount"].GetInt(); + for (rapidjson::SizeType j = 0; j < json["outputs"][i]["outs"].Size(); j++) { + COMMAND_RPC_GET_RANDOM_OUTPUTS_FOR_AMOUNTS::out_entry entry; + entry.global_amount_index = json["outputs"][i]["outs"][j]["global_amount_index"].GetInt(); + std::string out_key(json["outputs"][i]["outs"][j]["out_key"].GetString(), json["outputs"][i]["outs"][j]["out_key"].GetStringLength()); + memcpy(entry.out_key.data, out_key.c_str(), 32); + output.outs.push_back(entry); + } + daemon_resp.outs.push_back(output); + } std::vector scanty_outs; BOOST_FOREACH(COMMAND_RPC_GET_RANDOM_OUTPUTS_FOR_AMOUNTS::outs_for_amount& amount_outs, daemon_resp.outs) diff --git a/src/wallet/wallet_errors.h b/src/wallet/wallet_errors.h index 7809c3698..95120269d 100644 --- a/src/wallet/wallet_errors.h +++ b/src/wallet/wallet_errors.h @@ -439,7 +439,7 @@ namespace tools //---------------------------------------------------------------------------------------------------- struct tx_rejected : public transfer_error { - explicit tx_rejected(std::string&& loc, const cryptonote::transaction& tx, const std::string& status) + explicit tx_rejected(std::string&& loc, const cryptonote::transaction& tx, uint64_t status) : transfer_error(std::move(loc), "transaction was rejected by daemon") , m_tx(tx) , m_status(status) @@ -447,7 +447,7 @@ namespace tools } const cryptonote::transaction& tx() const { return m_tx; } - const std::string& status() const { return m_status; } + uint64_t status() const { return m_status; } std::string to_string() const { @@ -460,7 +460,7 @@ namespace tools private: cryptonote::transaction m_tx; - std::string m_status; + uint64_t m_status; }; //---------------------------------------------------------------------------------------------------- struct tx_sum_overflow : public transfer_error