Commit tx IPC

This commit is contained in:
Oran Juice 2015-03-31 21:50:38 +05:30
parent 322900b374
commit bcbc24a456
No known key found for this signature in database
GPG Key ID: 71C5AF46CCB28124
13 changed files with 1031 additions and 173 deletions

View File

@ -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<out_entry>::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<rapidjson::StringBuffer> 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);
}
}
}

View File

@ -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<cryptonote::t_cryptonote_protocol_handler<cryptonote::core> > *p_p2p,
bool p_testnet);

View File

@ -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);

View File

@ -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;
}

View File

@ -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 <czmq.h>
@ -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);

View File

@ -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);

View File

@ -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));
}

View File

@ -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);
@ -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;
@ -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;
@ -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) {
@ -682,7 +747,7 @@ wap_proto_print (wap_proto_t *self)
case WAP_PROTO_PUT:
zsys_debug ("WAP_PROTO_PUT:");
zsys_debug (" tx_data=[ ... ]");
zsys_debug (" tx_as_hex=[ ... ]");
break;
case WAP_PROTO_PUT_OK:
@ -708,6 +773,26 @@ wap_proto_print (wap_proto_t *self)
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)
@ -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
@ -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);

View File

@ -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);
}

View File

@ -1065,9 +1065,10 @@ bool simple_wallet::show_blockchain_height(const std::vector<std::string>& args)
//----------------------------------------------------------------------------------------------------
bool simple_wallet::transfer(const std::vector<std::string> &args_)
{
if (!try_connect_to_daemon())
return true;
/*if (!try_connect_to_daemon())
return true;*/
std::cout << "1\n";
std::vector<std::string> local_args = args_;
if(local_args.size() < 3)
{
@ -1075,6 +1076,7 @@ bool simple_wallet::transfer(const std::vector<std::string> &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<std::string> &args_)
}
local_args.erase(local_args.begin());
std::cout << "3\n";
std::vector<uint8_t> extra;
if (1 == local_args.size() % 2)
{
@ -1105,6 +1108,7 @@ bool simple_wallet::transfer(const std::vector<std::string> &args_)
}
}
std::cout << "4\n";
vector<cryptonote::tx_destination_entry> dsts;
for (size_t i = 0; i < local_args.size(); i += 2)
{
@ -1179,14 +1183,17 @@ bool simple_wallet::transfer(const std::vector<std::string> &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<std::string> &args_)
}
}
std::cout << "6\n";
// actually commit the transactions
while (!ptx_vector.empty())
{
@ -1219,6 +1227,7 @@ bool simple_wallet::transfer(const std::vector<std::string> &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)

View File

@ -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::pending_tx> wallet2::create_transactions(std::vector<crypto
// failsafe split attempt counter
size_t attempt_count = 0;
std::cout << "a\n";
for(attempt_count = 1; ;attempt_count++)
{
auto split_values = split_amounts(dsts, attempt_count);
@ -1190,11 +1199,14 @@ std::vector<wallet2::pending_tx> wallet2::create_transactions(std::vector<crypto
cryptonote::transaction tx;
pending_tx ptx;
std::cout << "b\n";
// loop until fee is met without increasing tx size to next KB boundary.
uint64_t needed_fee = 0;
do
{
std::cout << "c\n";
transfer(dst_vector, fake_outs_count, unlock_time, needed_fee, extra, tx, ptx);
std::cout << "d\n";
auto txBlob = t_serializable_object_to_blob(ptx.tx);
uint64_t txSize = txBlob.size();
uint64_t numKB = txSize / 1024;

View File

@ -471,23 +471,54 @@ namespace tools
COMMAND_RPC_GET_RANDOM_OUTPUTS_FOR_AMOUNTS::response daemon_resp = AUTO_VAL_INIT(daemon_resp);
if(fake_outputs_count)
{
COMMAND_RPC_GET_RANDOM_OUTPUTS_FOR_AMOUNTS::request req = AUTO_VAL_INIT(req);
req.outs_count = fake_outputs_count + 1;// add one to make possible (if need) to skip real output key
// COMMAND_RPC_GET_RANDOM_OUTPUTS_FOR_AMOUNTS::request req = AUTO_VAL_INIT(req);
// req.outs_count = fake_outputs_count + 1;// add one to make possible (if need) to skip real output key
uint64_t outs_count = fake_outputs_count + 1;
std::vector<uint64_t> 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<char*>(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<COMMAND_RPC_GET_RANDOM_OUTPUTS_FOR_AMOUNTS::outs_for_amount> scanty_outs;
BOOST_FOREACH(COMMAND_RPC_GET_RANDOM_OUTPUTS_FOR_AMOUNTS::outs_for_amount& amount_outs, daemon_resp.outs)

View File

@ -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