Commit 2f557f5e authored by xpetrak2's avatar xpetrak2
Browse files

Trade processing and basic order operations

parent b19772f1
......@@ -29,8 +29,10 @@
#include "hosts.h"
#include "json_parser.h"
#include "log.h"
#include "market.h"
#include "neighbours.h"
#include "routing.h"
#include "trade.h"
/** The minimum time in seconds that has to pass between the announcements of
* presence of one identity. */
......@@ -43,6 +45,26 @@ static enum process_message_result
neighbour_t *sender,
global_state_t *global_state);
static int process_encrypted(const encrypted_t *encrypted_payload,
identity_t *identity,
const unsigned char *sender_id,
global_state_t *global_state);
static int process_trade_execution(const trade_execution_t *trade_execution,
enum trade_step execution_step,
trade_t *trade,
identity_t *identity,
const unsigned char *sender_id,
global_state_t *global_state);
static int process_trade_proposal(const trade_proposal_t *trade_proposal,
identity_t *identity,
const unsigned char *sender_id,
global_state_t *global_state);
static int process_trade_reject(const trade_reject_t *trade_reject,
const identity_t *my_identity,
const unsigned char *sender_id,
trade_t *trade);
static int process_p2p_bye(const message_t *message,
const char *json_message,
neighbour_t *sender,
......@@ -339,6 +361,12 @@ static enum process_message_result
}
switch (msg_type) {
case ENCRYPTED:
res = process_encrypted(msg_body->data,
identity,
sender_peer->identifier,
global_state);
break;
case P2P_BYE:
res = process_p2p_bye(message,
json_message,
......@@ -414,6 +442,127 @@ static enum process_message_result
return PMR_DONE;
}
/**
* Process encrypted message.
*
* @param encrypted_payload The encrypted payload.
* @param identity Process under this identity.
* @param sender_id Sender's identifier.
* @param global_state Global state.
*
* @return 0 Successfully processed.
* @return 1 Failure.
*/
static int process_encrypted(const encrypted_t *encrypted_payload,
identity_t *identity,
const unsigned char *sender_id,
global_state_t *global_state)
{
void *data;
char *json_payload;
char *json_payload_data;
enum trade_step next_step;
enum payload_type payload_type;
int res;
trade_t *trade;
enum trade_type trade_type;
if (decrypt_message(encrypted_payload->payload,
identity->keypair.public_key,
identity->keypair.secret_key,
&json_payload)) {
log_debug("process_encrypted - decrypting message payload has "
"failed. Payload:\n%s", encrypted_payload->payload);
return 1;
}
if (decode_payload_type(json_payload,
&payload_type,
&json_payload_data)) {
log_debug("process_encrypted - decoding decrypted payload "
"has failed. Payload:\n%s", json_payload);
free(json_payload);
return 1;
}
free(json_payload);
/* trade.execution has its own parsing function */
if (payload_type != TRADE_EXECUTION) {
if (decode_payload_data(json_payload_data,
payload_type,
&data)) {
log_debug("process_encrypted - decoding payload's data "
"has failed. Data:\n%s", json_payload_data);
free(json_payload_data);
return 1;
}
}
switch (payload_type) {
case TRADE_EXECUTION:
if (!(trade = trade_find(&global_state->trades,
identity,
trade_cmp_identity))) {
log_debug("process_encrypted - execution of "
"unknown trade received");
free(json_payload_data);
return 1;
}
trade_type = trade->type;
next_step = trade_step_get_next(trade);
/* attept to decode the next step of the agreed
* trading protocol */
if (decode_trade_execution(json_payload_data,
trade_type,
next_step,
&data)) {
log_debug("process_encrypted - decoding "
"trade.execution failed");
free(json_payload_data);
return 1;
}
res = process_trade_execution(data,
next_step,
trade,
identity,
sender_id,
global_state);
trade_execution_delete(data, trade_type, next_step);
break;
case TRADE_PROPOSAL:
res = process_trade_proposal(data,
identity,
sender_id,
global_state);
break;
case TRADE_REJECT:
if (!(trade = trade_find(&global_state->trades,
identity,
trade_cmp_identity))) {
log_debug("process_encrypted - rejection of "
"an unknown trade arrived");
break;
}
res = process_trade_reject(data,
identity,
sender_id,
trade);
break;
default:
log_debug("process_encrypted - wrong message type");
res = 1;
}
free(json_payload_data);
/* trade.execution has its own clean up function */
if (payload_type != TRADE_EXECUTION) {
payload_delete(payload_type, data);
}
return res;
}
/**
* Process p2p.bye.
*
......@@ -717,3 +866,178 @@ static int process_p2p_route_sol(const message_t *message,
return 0;
}
/**
* Process trade.execution.
*
* @param trade_execution trade.execution to be processed.
* @param execution_step trade.execution's step.
* @param trade trade.execution related to this trade.
* @param identity trade.execution sent to this identity.
* @param sender_id trade.execution from this identifier.
* @param global_state The global state.
*
* @return 0 Successfully processed.
* @return 1 Failure.
*/
static int process_trade_execution(const trade_execution_t *trade_execution,
enum trade_step execution_step,
trade_t *trade,
identity_t *identity,
const unsigned char *sender_id,
global_state_t *global_state)
{
/* counterparty's identifier must remain the same, unless this is
* the trade acceptance */
if (memcmp(trade->cp_identifier, sender_id, PUBLIC_KEY_SIZE)) {
if (trade->step != TS_PROPOSAL) {
log_debug("process_trade_execution - received "
"trade.execution from a wrong peer");
return 0;
}
memcpy(trade->cp_identifier, sender_id, PUBLIC_KEY_SIZE);
}
if (memcmp(trade->order->id, trade_execution->order, SHA3_256_SIZE)) {
log_debug("process_trade_execution - counterparty's "
"trade.execution refering to a different order");
linkedlist_delete_safely(trade->node, trade_clear);
return 0;
}
if (trade_update(trade, execution_step, trade_execution->data)) {
log_debug("process_trade_execution - received incorrect trade "
"data");
linkedlist_delete_safely(trade->node, trade_clear);
return 0;
}
trade->step = trade_step_get_next(trade);
if (trade_step_perform(trade, global_state)) {
log_debug("process_trade_execution - performing next step of "
"a trade has failed");
linkedlist_delete_safely(trade->node, trade_clear);
return 0;
}
return 0;
}
/**
* Process trade.proposal.
*
* @param trade_proposal Trade proposal to be processed.
* @param identity Process under this identity.
* @param sender_id trade.proposal from this peer.
* @param global_state The global state.
*
* @return 0 Successfully processed.
* @return 1 Failure.
*/
static int process_trade_proposal(const trade_proposal_t *trade_proposal,
identity_t *identity,
const unsigned char *sender_id,
global_state_t *global_state)
{
order_t *order;
trade_t *trade;
if (!(order = order_find(&global_state->orders,
trade_proposal->order))) {
log_debug("process_trade_proposal - received trade proposal "
"for unknown order");
return 0;
}
if (order->flags & ORDER_FOREIGN) {
log_debug("process_trade_proposal - received trade proposal "
"for order that does not belong to us");
return 0;
}
if (order->owner.me != identity) {
log_debug("process_trade_proposal - received trade proposal "
"for incorrect identity");
return 0;
}
if ((trade = trade_find(&global_state->trades,
order->id,
trade_cmp_order_id))) {
/* 2nd proposal from the trading counterparty => abort trade */
if (!memcmp(trade->cp_identifier, sender_id, PUBLIC_KEY_SIZE)) {
linkedlist_delete_safely(trade->node, trade_clear);
order_flags_unset(order, ORDER_TRADING);
/* the order is now available again; we don't want to
* accept possible 3rd proposal from the same peer */
if (order_blacklist_append(&order->blacklist,
sender_id)) {
log_error("Storing sender ID into "
"order blacklist");
return 0;
}
log_debug("process_trade_proposal - received 2nd trade "
"proposal from the same peer");
return 0;
}
send_trade_reject(&global_state->routing_table,
identity,
sender_id,
order->id);
return 0;
}
if (order_blacklist_find(&order->blacklist, sender_id)) {
log_debug("process_trade_proposal - received trade proposal "
"from a blacklisted peer");
return 0;
}
if (!(trade = trade_create(&global_state->trades,
&global_state->identities,
order,
sender_id,
trade_proposal->protocol))) {
log_error("Storing a new trade");
return 1;
}
trade_update(trade, TS_PROPOSAL, trade_proposal);
trade->step = trade_step_get_next(trade);
if (trade_step_perform(trade, global_state)) {
log_error("Executing trade step failed");
linkedlist_delete_safely(trade->node, trade_clear);
return 1;
}
send_market_cancel(&global_state->neighbours, order);
order_flags_set(order, ORDER_TRADING);
return 0;
}
/**
* Process trade.reject.
*
* @param trade_reject The trade.reject to process.
* @param my_identity Process under this identity.
* @param sender_id Trade reject from this identifier.
* @param trade trade.reject related to this trade.
*
* @return 0 Successfully processed.
*/
static int process_trade_reject(const trade_reject_t *trade_reject,
const identity_t *my_identity,
const unsigned char *sender_id,
trade_t *trade)
{
if (trade->step == TS_PROPOSAL &&
trade->my_identity == my_identity &&
!memcmp(trade->cp_identifier, sender_id, PUBLIC_KEY_SIZE)) {
order_flags_unset(trade->order, ORDER_TRADING);
linkedlist_delete_safely(trade->node, trade_clear);
}
return 0;
}
......@@ -34,9 +34,11 @@
*/
void global_state_clear(global_state_t *global_state)
{
linkedlist_destroy(&global_state->trades, trade_clear);
linkedlist_destroy(&global_state->routing_table, route_clear);
linkedlist_destroy(&global_state->pending_neighbours, clear_neighbour);
linkedlist_destroy(&global_state->peers, peer_clear);
linkedlist_destroy(&global_state->orders, order_clear);
linkedlist_destroy(&global_state->neighbours, clear_neighbour);
linkedlist_destroy(&global_state->message_traces, NULL);
linkedlist_destroy(&global_state->hosts, NULL);
......@@ -79,10 +81,17 @@ int global_state_init(global_state_t *global_state)
linkedlist_init(&global_state->hosts);
linkedlist_init(&global_state->message_traces);
linkedlist_init(&global_state->neighbours);
linkedlist_init(&global_state->orders);
linkedlist_init(&global_state->peers);
linkedlist_init(&global_state->pending_neighbours);
linkedlist_init(&global_state->routing_table);
linkedlist_init(&global_state->trades);
if (trades_load(&global_state->trades,
global_state->filepaths.trades_dir)) {
log_warn("Loading trades in progress has failed");
}
global_state->port = 0;
return 0;
......
......@@ -44,6 +44,8 @@ typedef struct s_global_state {
linkedlist_t message_traces;
/** Linked list of our neighbours. */
linkedlist_t neighbours;
/** Known orders. */
linkedlist_t orders;
/** Known peers. */
linkedlist_t peers;
/** Hosts that didn't accept/reject us yet. */
......@@ -52,6 +54,8 @@ typedef struct s_global_state {
unsigned short port;
/** Routes to hosts. */
linkedlist_t routing_table;
/** List of our trades. */
linkedlist_t trades;
/** Our true identity. */
identity_t *true_identity;
} global_state_t;
......
......@@ -130,6 +130,16 @@ int decode_message_data(const char *json_data,
*data = NULL;
switch (type) {
case ENCRYPTED:
if (json_data == NULL) {
return 1;
}
*data = (encrypted_t *) malloc(sizeof(encrypted_t));
if (!*data) {
log_error("Allocating encrypted");
return 1;
}
return 0;
case P2P_BYE:
return 0;
case P2P_HELLO:
......@@ -180,6 +190,118 @@ int decode_message_data(const char *json_data,
return 1;
}
/* TODO: Implement */
/**
* Fetch the type and the JSON data from a JSON payload.
*
* @param json_payload Decode this JSON payload.
* @param type Store the payload type in here.
* @param json_data Store the payload's JSON data in here.
*
* @return 0 Successfully decoded.
* @return 1 Failure.
*/
int decode_payload_type(const char *json_payload,
enum payload_type *type,
char **json_data)
{
return 0;
}
/* TODO: Implement */
/**
* Decode JSON payload into an internal representation.
*
* @param json_data Decode this JSON payload.
* @param type Type of the JSON payload.
* @param data Dynamically allocated structure storing the
* payload data.
*
* @return 0 Successfully decoded.
* @return 1 Failure.
*/
int decode_payload_data(const char *json_data,
enum payload_type type,
void **data)
{
return 0;
}
/* TODO: Implement */
/**
* Decode JSON trade.execution of type basic into internal representation.
*
* @param json_data The JSON trade.execution.
* @param step Trade step to be decoded.
* @param execution The internal representation.
*
* @return 0 Success.
* @return 1 Failure.
*/
static int decode_trade_basic(const char *json_data,
enum trade_step step,
trade_execution_t *execution)
{
trade_execution_basic_t *data;
data = (trade_execution_basic_t *) malloc(
sizeof(trade_execution_basic_t));
if (!data) {
log_error("Creating trade.execution's data");
return 1;
}
execution->data = data;
switch (step) {
case TS_KEY_AND_COMMITTED_EXCHANGE:
/* if json_data doesn't contain script, set data->script
* to NULL, otherwise it must also contain 'hx' */
break;
}
return 0;
}
/* TODO: Implement */
/**
* Knowing the trading protocol type and the trade step, decode a JSON trade
* execution into internal representation.
*
* @param json_data JSON trade execution to be decoded.
* @param type Type of the trading protocol.
* @param step Step of the trade execution.
* @param data Dynamically allocated structure storing the
* trade execution data.
*
* @return 0 Decoding successful.
* @return 1 Failure.
*/
int decode_trade_execution(const char *json_data,
enum trade_type type,
enum trade_step step,
trade_execution_t **data)
{
int ret = 1;
*data = (trade_execution_t *) malloc(sizeof(trade_execution_t));
if (!*data) {
log_error("Creating trade.execution");
return 1;
}
switch (type) {
case TT_BASIC:
ret = decode_trade_basic(json_data, step, *data);
}
if (ret == 1) {
free(*data);
}
return ret;
}
/* TODO: Implement */
/**
* Decode a JSON trade.
......@@ -260,6 +382,44 @@ int encode_message_body(const message_body_t *body, char **json_body)
return 0;
}
/* TODO: Implement */
/**
* Encode a payload into JSON.
*
* @param type Type of the payload.
* @param data Payload to be encoded.
* @param encoded Dynamically allocated string of JSON payload.
*
* @return 0 Successfully encoded.
* @return 1 Failure.
*/
int encode_payload(enum payload_type type, const void *data, char **encoded)
{
return 0;
}
/* TODO: Implement */
/**
* Knowing the trading protocol type and the trade step, encode a
* trade.execution into JSON.
*
* @param trade_execution trade.execution to be encoded.
* @param type Type of the trading protocol.
* @param step Step of the trade execution.
* @param encoded Dynamically allocated string of JSON
* trade.execution.
*
* @return 0 Encoding successful.
* @return 1 Failure.
*/
int encode_trade_execution(const trade_execution_t *trade_execution,
enum trade_type type,
enum trade_step step,
char **encoded)
{
return 0;
}
/* TODO: Implement */
/**
* Encode a trade into JSON.
......
......@@ -20,10 +20,14 @@
#define JSON_PARSER_H
#include "daemon_messages.h"
#include "trade.h"
/* the order of these strings must be the same as the order of enums within
* enum message_type at daemon_messages.h */
static const char *msg_type_str[] = {
/* encrypted */
"encrypted",
/* p2p */
"p2p.bye",
"p2p.hello",
"p2p.peers.adv",
......@@ -34,6 +38,14 @@ static const char *msg_type_str[] = {
"p2p.route.sol"
};
/* the order of these strings must be the same as the order of enums within
* enum payload_type at daemon_messages.h */
static const char *payload_type_str[] = {
"trade.execution",
"trade.proposal",
"trade.reject"
};
int decode_message(const char *json_message,
message_t *message,
char **json_body);
......@@ -44,11 +56,28 @@ int decode_message_data(const char *json_data,
const enum message_type type,
void **data);
int decode_payload_type(const char *json_payload,
enum payload_type *type,
char **json_data);
int decode_payload_data(const char *json_data,
enum payload_type type,
void **data);
int decode_trade_execution(const char *json_data,
enum trade_type type,
enum trade_step step,
trade_execution_t **data);
int decode_trade(const char *json_trade, trade_t **