Skip to content
This repository has been archived by the owner on Dec 26, 2022. It is now read-only.

Commit

Permalink
feat(api): Implement api_fetch_txn_with_uuid()
Browse files Browse the repository at this point in the history
Client can fetch the buffered transactions with responded UUID from
last API call.
  • Loading branch information
howjmay committed Apr 28, 2020
1 parent 1c908fa commit cc37bb0
Show file tree
Hide file tree
Showing 16 changed files with 543 additions and 54 deletions.
88 changes: 56 additions & 32 deletions accelerator/core/apis.c
Original file line number Diff line number Diff line change
Expand Up @@ -648,6 +648,62 @@ status_t api_send_trytes(const ta_config_t* const info, const iota_config_t* con
return ret;
}

status_t api_get_iri_status(const iota_client_service_t* const service, char** json_result) {
status_t ret = SC_OK;

ret = ta_get_iri_status(service);
switch (ret) {
/*
* The values of each status_t are listed as the following. Not listed status code are unexpected errors which
* would cause TA return error.
*
* SC_CCLIENT_FAILED_RESPONSE: Can't connect to IRI host
* SC_CORE_IRI_UNSYNC: IRI host is not at the latest milestone
* SC_OK: IRI host works fine.
**/
case SC_CCLIENT_FAILED_RESPONSE:
case SC_CORE_IRI_UNSYNC:
case SC_OK:
ret = get_iri_status_res_serialize(ret, json_result);
if (ret) {
ta_log_error("failed to serialize. status code: %d\n", ret);
}
break;

default:
ta_log_error("check IRI connection failed. status code: %d\n", ret);
break;
}

return ret;
}

status_t api_fetch_txn_with_uuid(const ta_cache_t* const cache, const char* const uuid, char** json_result) {
status_t ret = SC_OK;

ta_fetch_txn_with_uuid_res_t* res = ta_fetch_txn_with_uuid_res_new();
if (res == NULL) {
ret = SC_CORE_OOM;
ta_log_error("%s\n", ta_error_to_string(ret));
return ret;
}

ret = ta_fetch_txn_with_uuid(cache, uuid, res);
if (ret) {
ta_log_error("%s\n", ta_error_to_string(ret));
goto done;
}

ret = fetch_txn_with_uuid_res_serialize(res, json_result);
if (ret) {
ta_log_error("%s\n", ta_error_to_string(ret));
}

done:
ta_fetch_txn_with_uuid_res_free(&res);
return ret;
}

#ifdef DB_ENABLE
status_t api_find_transactions_by_id(const iota_client_service_t* const iota_service,
const db_client_service_t* const db_service, const char* const obj,
Expand Down Expand Up @@ -734,35 +790,3 @@ status_t api_get_identity_info_by_id(const db_client_service_t* const db_service
return ret;
}
#endif

status_t api_get_iri_status(const iota_client_service_t* const service, char** json_result) {
status_t ret = SC_OK;

ret = ta_get_iri_status(service);
switch (ret) {
/*
* The statuses of each status_t are listed as the following. Not listed status code are unexpected errors which
* would cause TA return error.
*
* SC_CCLIENT_FAILED_RESPONSE: Can't connect to IRI host
* SC_CORE_IRI_UNSYNC: IRI host is not at the latest milestone
* SC_OK: IRI host works fine.
**/
case SC_CCLIENT_FAILED_RESPONSE:
case SC_CORE_IRI_UNSYNC:
case SC_OK:
break;

default:
ta_log_error("check IRI connection failed. status code: %d\n", ret);
goto done;
}

ret = get_iri_status_res_serialize(ret, json_result);
if (ret) {
ta_log_error("failed to serialize. status code: %d\n", ret);
}

done:
return ret;
}
13 changes: 13 additions & 0 deletions accelerator/core/apis.h
Original file line number Diff line number Diff line change
Expand Up @@ -282,6 +282,19 @@ status_t api_send_trytes(const ta_config_t* const info, const iota_config_t* con
*/
status_t api_get_iri_status(const iota_client_service_t* const service, char** json_result);

/**
* @brief Fetch transaction information with UUID.
*
* @param[in] cache Redis configuration variables
* @param[in] uuid Requesting UUID
* @param[out] json_result Result containing the current connection status.
*
* @return
* - SC_OK on success
* - non-zero on error
*/
status_t api_fetch_txn_with_uuid(const ta_cache_t* const cache, const char* const uuid, char** json_result);

#ifdef DB_ENABLE
/**
* @brief Return transaction object with given single identity number.
Expand Down
131 changes: 124 additions & 7 deletions accelerator/core/core.c
Original file line number Diff line number Diff line change
Expand Up @@ -103,8 +103,13 @@ status_t ta_send_trytes(const ta_config_t* const info, const iota_config_t* cons
goto done;
}

// set the value of attach_res->trytes as output trytes result
memcpy(trytes, attach_res->trytes, hash_array_len(attach_res->trytes) * sizeof(flex_trit_t));
// Clear the old data in the hash_array `trytes`
utarray_clear(trytes);
const int attach_res_trytes_len = hash_array_len(attach_res->trytes);
for (int i = 0; i < attach_res_trytes_len; ++i) {
// set the value of attach_res->trytes as output trytes result
hash_array_push(trytes, hash_array_at(attach_res->trytes, i));
}

done:
get_transactions_to_approve_req_free(&tx_approve_req);
Expand Down Expand Up @@ -619,8 +624,7 @@ status_t push_txn_to_buffer(const ta_cache_t* const cache, hash8019_array_p raw_
goto done;
}

ret =
cache_list_push(cache->buffer_list_name, strlen(cache->buffer_list_name), uuid, UUID_STR_LEN - 1, cache->timeout);
ret = cache_list_push(cache->buffer_list_name, strlen(cache->buffer_list_name), uuid, UUID_STR_LEN - 1);
if (ret) {
ta_log_error("%s\n", ta_error_to_string(ret));
}
Expand All @@ -634,6 +638,31 @@ status_t broadcast_buffered_txn(const ta_core_t* const core) {
int uuid_list_len = 0;
hash8019_array_p txn_trytes_array = hash8019_array_new();

/*
*There are 4 data structures used here.
* 1. List: A list of unsent uuid which can be used to identify an unsent transaction object
* 2. Key-value: UUID to unsent transaction object in `flex_trit_t`
* 3. List: Store all the UUID of sent transaction objects. (We could use set after investigation in the future)
* 4. Key-value: UUID to sent transaction object in `flex_trit_t`
*
* 'push_txn_to_buffer()':
* Push UUID to the unsent UUID list.
* Store UUID as key and unsent transaction `flex_trit_t` as value.
*
* 'broadcast_buffered_txn()':
* Pop an unsent UUID in the unsent UUID list.
* Delete UUID-unsent_transaction pair from key value storage
* Store UUID as key and sent transaction object in `flex_trit_t` as value.
* Push UUID of sent transaction into sent transaction list.
*
* 'ta_fetch_txn_with_uuid()':
* Fetch transaction object with UUID in key-value storage.
* Delete UUID from sent transaction list
* Delete UUID-sent_transaction pair from key-value storage
*/

get_trytes_req_t* req;
get_trytes_res_t* res;
do {
char uuid[UUID_STR_LEN];
flex_trit_t req_txn_flex_trits[NUM_FLEX_TRITS_SERIALIZED_TRANSACTION + 1];
Expand Down Expand Up @@ -664,25 +693,113 @@ status_t broadcast_buffered_txn(const ta_core_t* const core) {
ta_log_error("%s\n", ta_error_to_string(ret));
goto done;
}

// TODO Update the transaction object saved in redis, which allows `ta_fetch_txn_with_uuid()` to return the
// transaction object much faster.
// TODO We assume only one transaction need to be broadcasted each time
req = get_trytes_req_new();
res = get_trytes_res_new();
iota_transaction_t txn;
transaction_deserialize_from_trits(&txn, hash_array_at(txn_trytes_array, 0), true);
flex_trit_t* hash = transaction_hash(&txn);

ret = hash243_queue_push(&req->hashes, hash);
if (ret) {
ret = SC_CCLIENT_HASH;
ta_log_error("%s\n", "SC_CCLIENT_HASH");
goto done;
}
utarray_done(txn_trytes_array);

ret = iota_client_get_trytes(&core->iota_service, req, res);
if (ret) {
ret = SC_CCLIENT_FAILED_RESPONSE;
ta_log_error("%s\n", "SC_CCLIENT_FAILED_RESPONSE");
goto done;
}

// Delete the old transaction object
ret = cache_del(uuid);
if (ret) {
ta_log_error("%s\n", ta_error_to_string(ret));
goto done;
}

ret = cache_set(uuid, UUID_STR_LEN - 1, hash8019_queue_peek(res->trytes), NUM_FLEX_TRITS_SERIALIZED_TRANSACTION,
core->cache.timeout);
if (ret) {
ta_log_error("%s\n", ta_error_to_string(ret));
goto done;
}

// Pop transaction from buffered list
ret = cache_list_pop(core->cache.buffer_list_name, (char*)req_txn_flex_trits);
ret = cache_list_pop(core->cache.buffer_list_name, (char*)uuid);
if (ret) {
ta_log_error("%s\n", ta_error_to_string(ret));
goto done;
}

// Transfer the transaction to another list in where we store all the successfully broadcasted transactions.
ret = cache_list_push(core->cache.done_list_name, strlen(core->cache.done_list_name), uuid, UUID_STR_LEN - 1,
core->cache.timeout);
ret = cache_list_push(core->cache.done_list_name, strlen(core->cache.done_list_name), uuid, UUID_STR_LEN - 1);
if (ret) {
ta_log_error("%s\n", ta_error_to_string(ret));
goto done;
}
get_trytes_req_free(&req);
get_trytes_res_free(&res);
} while (!uuid_list_len);

done:
hash_array_free(txn_trytes_array);
get_trytes_req_free(&req);
get_trytes_res_free(&res);
return ret;
}

status_t ta_fetch_txn_with_uuid(const ta_cache_t* const cache, const char* const uuid,
ta_fetch_txn_with_uuid_res_t* res) {
status_t ret = SC_OK;
flex_trit_t txn_flex_trits[NUM_FLEX_TRITS_SERIALIZED_TRANSACTION + 1];

bool exist = false;
ret = cache_list_exist(cache->buffer_list_name, uuid, UUID_STR_LEN - 1, &exist);
if (ret) {
ta_log_error("%s\n", ta_error_to_string(ret));
goto done;
}
if (exist) {
res->status = UNSENT;
goto done;
}

ret = cache_list_exist(cache->done_list_name, uuid, UUID_STR_LEN - 1, &exist);
if (ret) {
ta_log_error("%s\n", ta_error_to_string(ret));
goto done;
}
if (exist) {
res->status = SENT;

ret = cache_get(uuid, (char*)txn_flex_trits);
if (ret) {
ta_log_error("%s\n", ta_error_to_string(ret));
goto done;
}

res->txn = transaction_deserialize(txn_flex_trits, false);
if (res->txn == NULL) {
ret = SC_CORE_OOM;
ta_log_error("%s\n", ta_error_to_string(ret));
goto done;
}

ret = cache_del(uuid);
if (ret) {
ta_log_error("%s\n", ta_error_to_string(ret));
goto done;
}
}

done:
return ret;
}
22 changes: 21 additions & 1 deletion accelerator/core/core.h
Original file line number Diff line number Diff line change
Expand Up @@ -107,7 +107,8 @@ status_t ta_send_transfer(const ta_config_t* const info, const iota_config_t* co
* @param[in] info Tangle-accelerator configuration variables
* @param[in] iconf IOTA API parameter configurations
* @param[in] service IRI node end point service
* @param[in] trytes Trytes that will be attached to tangle
* @param[in, out] trytes Trytes that will be attached to tangle. The output trytes are the ones with completed PoW and
* Tangle broadcasting, and broadcast to Tangle.
*
* @return
* - SC_OK on success
Expand Down Expand Up @@ -286,6 +287,25 @@ status_t push_txn_to_buffer(const ta_cache_t* const cache, hash8019_array_p raw_
*/
status_t broadcast_buffered_txn(const ta_core_t* const core);

/**
* @brief Return the transaction object status according to the given UUID
*
* If the given UUID points to a sent transaction, then `ta_fetch_txn_with_uuid` will return the content of the
* transaction object. If the transaction have been sent yet, then return unsent. If tangle-accelerator can't find the
* UUID in redis then it will return no_exist. In the current implementation, we used Redis to buffer all the
* transactions.
*
* @param cache[in] redis configuration variables
* @param uuid[in] Given UUID
* @param res[out] ta_fetch_txn_with_uuid_res_t contains the transaction object and status
*
* @return
* - SC_OK on success
* - non-zero on error
*/
status_t ta_fetch_txn_with_uuid(const ta_cache_t* const cache, const char* const uuid,
ta_fetch_txn_with_uuid_res_t* res);

#ifdef __cplusplus
}
#endif
Expand Down
1 change: 1 addition & 0 deletions accelerator/core/response/response.h
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@
#ifndef RESPONSE_RESPONSE_H_
#define RESPONSE_RESPONSE_H_

#include "ta_fetch_txn_with_uuid.h"
#include "ta_find_transactions.h"
#include "ta_find_transactions_obj.h"
#include "ta_generate_address.h"
Expand Down
26 changes: 26 additions & 0 deletions accelerator/core/response/ta_fetch_txn_with_uuid.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
/*
* Copyright (C) 2020 BiiLabs Co., Ltd. and Contributors
* All Rights Reserved.
* This is free software; you can redistribute it and/or modify it under the
* terms of the MIT license. A copy of the license can be found in the file
* "LICENSE" at the root of this distribution.
*/

#include "ta_fetch_txn_with_uuid.h"

ta_fetch_txn_with_uuid_res_t* ta_fetch_txn_with_uuid_res_new() {
ta_fetch_txn_with_uuid_res_t* res = (ta_fetch_txn_with_uuid_res_t*)malloc(sizeof(ta_fetch_txn_with_uuid_res_t));
res->txn = NULL;
res->status = NOT_EXIST;
return res;
}

void ta_fetch_txn_with_uuid_res_free(ta_fetch_txn_with_uuid_res_t** res) {
if (!res || !(*res)) {
return;
}

free((*res)->txn);
free(*res);
*res = NULL;
}
Loading

0 comments on commit cc37bb0

Please sign in to comment.