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

Commit

Permalink
Merge pull request #99 from wusyong/mam
Browse files Browse the repository at this point in the history
feat(api): Implement receive mam message API
  • Loading branch information
jserv committed Mar 14, 2019
2 parents c9f7dc1 + 6735f99 commit 0e95a45
Show file tree
Hide file tree
Showing 12 changed files with 279 additions and 1 deletion.
3 changes: 3 additions & 0 deletions accelerator/BUILD
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,9 @@ cc_library(
":common_core",
":ta_errors",
"//serializer",
"@entangled//common/trinary:trit_tryte",
"@entangled//common/trinary:tryte_ascii",
"@entangled//mam/api",
],
)

Expand Down
71 changes: 71 additions & 0 deletions accelerator/apis.c
Original file line number Diff line number Diff line change
@@ -1,5 +1,28 @@
#include "apis.h"

// TODO: Generate actual pre shared keys
static mam_psk_t const psk = {
.id = {1, 0, -1, -1, 0, -1, -1, 0, 0, 1, -1, 0, 1, 0, 0, 1, 1,
1, -1, 1, 1, 0, 1, 1, 0, 0, -1, 1, -1, -1, -1, -1, -1, -1,
-1, 1, -1, -1, 0, -1, -1, 1, 0, -1, -1, -1, 1, 1, 1, 0, 0,
-1, 1, -1, -1, -1, 0, -1, 1, -1, -1, -1, 1, 1, -1, 1, 0, 0,
1, 1, 1, -1, -1, 0, 0, -1, -1, 1, 0, -1, 1},
.key = {-1, 1, -1, -1, 1, -1, -1, 0, 0, 0, -1, -1, 1, 1, 1, -1, -1,
-1, 0, 0, 0, 0, -1, -1, 1, 1, 1, 0, -1, -1, -1, 0, 0, 0,
-1, -1, 1, -1, 0, 0, 1, 0, 0, -1, 1, 1, 0, -1, 0, 0, 1,
-1, 1, 0, 1, 0, 0, -1, 1, 1, -1, 1, 0, -1, 0, -1, 1, -1,
-1, -1, 0, -1, -1, 0, -1, -1, 0, 0, -1, -1, 1, -1, 0, 0, -1,
-1, -1, -1, 0, -1, -1, -1, 1, -1, -1, 1, 1, 1, 1, 1, 0, 1,
0, 1, -1, 0, 0, 1, 0, 1, 0, 0, 1, 0, -1, 0, 1, 1, 0,
0, -1, -1, 1, 1, 0, 0, 1, -1, 1, 1, 1, 0, 1, 1, 1, 0,
0, -1, -1, -1, -1, 1, 1, 1, 0, 0, -1, 0, 1, -1, 1, 1, 1,
0, 0, 1, -1, -1, 0, -1, 1, -1, 1, 0, 0, 1, -1, 0, 1, -1,
0, 0, 1, 1, 1, 1, 1, 0, 0, 1, -1, 1, -1, 1, 0, 1, 1,
1, -1, 0, 0, -1, 1, 1, 0, -1, -1, 0, 0, -1, 1, 0, 1, -1,
0, 0, -1, 1, -1, 1, 1, 1, -1, 0, 1, 1, 0, 0, -1, -1, -1,
0, 0, 1, 0, 1, 0, -1, 1, -1, 0, 1, 0, -1, 1, 1, -1, -1,
0, 0, -1, 0, -1}};

status_t api_get_tips(const iota_client_service_t* const service,
char** json_result) {
status_t ret = SC_OK;
Expand Down Expand Up @@ -128,6 +151,54 @@ status_t api_find_transactions_obj_by_tag(
return ret;
}

status_t api_receive_mam_message(const iota_client_service_t* const service,
const char* const obj, char** json_result) {
status_t ret = SC_OK;
mam_api_t mam;

tryte_t* payload_trytes = NULL;
size_t payload_size = 0;
bundle_transactions_t* bundle = NULL;
bundle_transactions_new(&bundle);
bool is_last_packet;

// Creating MAM API
if (mam_api_init(&mam, (tryte_t*)SEED)) {
ret = SC_MAM_OOM;
goto done;
}

// Get bundle which is find_transactions_by_bundle
ret = ta_get_bundle(service, (tryte_t*)obj, bundle);
if (ret) {
goto done;
}

// Read MAM message from bundle
mam_psk_t_set_add(&mam.psks, &psk);
if (mam_api_bundle_read(&mam, bundle, &payload_trytes, &payload_size,
&is_last_packet) == RC_OK) {
if (payload_trytes == NULL || payload_size == 0) {
ret = SC_MAM_NULL;
} else {
char* payload = calloc(payload_size * 2 + 1, sizeof(char));

trytes_to_ascii(payload_trytes, payload_size, payload);
*json_result = payload;

payload = NULL;
free(payload_trytes);
}
} else {
ret = SC_MAM_FAILED_RESPONSE;
}

done:
mam_api_destroy(&mam);
bundle_transactions_free(&bundle);
return ret;
}

status_t api_send_transfer(const iota_client_service_t* const service,
const char* const obj, char** json_result) {
status_t ret = SC_OK;
Expand Down
19 changes: 19 additions & 0 deletions accelerator/apis.h
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,9 @@
#include "accelerator/common_core.h"
#include "accelerator/errors.h"
#include "cclient/types/types.h"
#include "common/trinary/trit_tryte.h"
#include "common/trinary/tryte_ascii.h"
#include "mam/api/api.h"
#include "serializer/serializer.h"

#ifdef __cplusplus
Expand Down Expand Up @@ -67,6 +70,22 @@ status_t api_get_tips_pair(const iota_client_service_t* const service,
status_t api_get_tips(const iota_client_service_t* const service,
char** json_result);

/**
* @brief Receive a MAM message.
*
* Receive a MAM message from given bundle hash.
*
* @param[in] service IRI node end point service
* @param[out] obj bundle hash in trytes
* @param[out] json_result Result containing an unused address in json format
*
* @return
* - SC_OK on success
* - non-zero on error
*/
status_t api_receive_mam_message(const iota_client_service_t* const service,
const char* const obj, char** json_result);

/**
* @brief Send transfer to tangle.
*
Expand Down
65 changes: 65 additions & 0 deletions accelerator/common_core.c
Original file line number Diff line number Diff line change
Expand Up @@ -455,3 +455,68 @@ status_t ta_find_transactions_obj_by_tag(
ta_find_transactions_res_free(&hash_res);
return ret;
}

static int idx_sort(void const* lhs, void const* rhs) {
iota_transaction_t* _lhs = (iota_transaction_t*)lhs;
iota_transaction_t* _rhs = (iota_transaction_t*)rhs;

return (transaction_current_index(_lhs) < transaction_current_index(_rhs))
? -1
: (transaction_current_index(_lhs) >
transaction_current_index(_rhs));
}

static void get_first_bundle_from_transactions(
transaction_array_t const transactions,
bundle_transactions_t* const bundle) {
iota_transaction_t* tail = NULL;
iota_transaction_t* curr_tx = NULL;
iota_transaction_t* prev = NULL;

utarray_sort(transactions, idx_sort);
tail = (iota_transaction_t*)utarray_eltptr(transactions, 0);
bundle_transactions_add(bundle, tail);

prev = tail;
TX_OBJS_FOREACH(transactions, curr_tx) {
if (transaction_current_index(curr_tx) ==
(transaction_current_index(prev) + 1) &&
(memcmp(transaction_hash(curr_tx), transaction_trunk(prev),
FLEX_TRIT_SIZE_243) == 0)) {
bundle_transactions_add(bundle, curr_tx);
prev = curr_tx;
}
}
}

status_t ta_get_bundle(const iota_client_service_t* const service,
tryte_t const* const bundle_hash,
bundle_transactions_t* const bundle) {
status_t ret = SC_OK;
iota_transaction_t* curr_tx = NULL;
flex_trit_t bundle_hash_flex[FLEX_TRIT_SIZE_243];
transaction_array_t tx_objs = transaction_array_new();
find_transactions_req_t* find_tx_req = find_transactions_req_new();
if (find_tx_req == NULL) {
ret = SC_CCLIENT_OOM;
goto done;
}

// find transactions by bundle hash
flex_trits_from_trytes(bundle_hash_flex, NUM_TRITS_BUNDLE, bundle_hash,
NUM_TRITS_HASH, NUM_TRYTES_BUNDLE);
hash243_queue_push(&find_tx_req->bundles, bundle_hash_flex);
ret = iota_client_find_transaction_objects(service, find_tx_req, tx_objs);
if (ret) {
ret = SC_CCLIENT_FAILED_RESPONSE;
goto done;
}

// retreive only first bundle
get_first_bundle_from_transactions(tx_objs, bundle);

done:
transaction_array_free(tx_objs);
find_transactions_req_free(&find_tx_req);
return ret;
}
19 changes: 19 additions & 0 deletions accelerator/common_core.h
Original file line number Diff line number Diff line change
Expand Up @@ -172,6 +172,25 @@ status_t ta_get_transaction_object(const iota_client_service_t* const service,
const char* const req,
ta_get_transaction_object_res_t* res);

/**
* @brief Return bundle object with given bundle hash.
*
* Explore transaction hash information with given bundle hash. This would
* return only one bundle objects in bundle_transactions_t instead of all
* transactions like reattached ones.
*
* @param[in] service IRI node end point service
* @param[in] bundle_hash bundle hash in trytes
* @param[out] bundle Result containing bundle object in bundle_transactions_t
*
* @return
* - SC_OK on success
* - non-zero on error
*/
status_t ta_get_bundle(const iota_client_service_t* const service,
tryte_t const* const bundle_hash,
bundle_transactions_t* const bundle);

#ifdef __cplusplus
}
#endif
Expand Down
9 changes: 9 additions & 0 deletions accelerator/errors.h
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,7 @@ extern "C" {
#define SC_MODULE_CCLIENT (0x02 << SC_MODULE_SHIFT)
#define SC_MODULE_SERIALIZER (0x03 << SC_MODULE_SHIFT)
#define SC_MODULE_CACHE (0x04 << SC_MODULE_SHIFT)
#define SC_MODULE_MAM (0x05 << SC_MODULE_SHIFT)
/** @} */

/** @name serverity code */
Expand Down Expand Up @@ -86,6 +87,14 @@ typedef enum {
/**< NULL parameters in cache */
SC_CACHE_FAILED_RESPONSE = 0x02 | SC_MODULE_CACHE | SC_SEVERITY_FATAL,
/**< Fail in cache operations */

// MAM module
SC_MAM_OOM = 0x01 | SC_MODULE_MAM | SC_SEVERITY_FATAL,
/**< Fail to create mam object */
SC_MAM_NULL = 0x02 | SC_MODULE_MAM | SC_SEVERITY_FATAL,
/**< NULL object in mam */
SC_MAM_FAILED_RESPONSE = 0x03 | SC_MODULE_MAM | SC_SEVERITY_FATAL,
/**< Error in mam response */
} status_t;

#ifdef __cplusplus
Expand Down
24 changes: 24 additions & 0 deletions accelerator/server.cc
Original file line number Diff line number Diff line change
Expand Up @@ -20,11 +20,34 @@ int main(int, char const**) {

iota_client_service_t service;
service.http.path = "/";
service.http.content_type = "application/json";
service.http.accept = "application/json";
service.http.host = IRI_HOST;
service.http.port = IRI_PORT;
service.http.api_version = 1;
service.serializer_type = SR_JSON;
iota_client_core_init(&service);
iota_client_extended_init();

mux.handle("/mam/{bundle:[A-Z9]{81}}")
.method(served::method::OPTIONS,
[&](served::response& res, const served::request& req) {
set_options_method_header(res);
})
.get([&](served::response& res, const served::request& req) {
char* json_result = NULL;

api_receive_mam_message(&service, req.params["bundle"].c_str(),
&json_result);

res.set_header("Content-Type", "application/json");
res.set_header("Access-Control-Allow-Origin", "*");
if (!json_result) {
res.set_status(SC_NOT_FOUND);
} else {
res << json_result;
}
});

/**
* @method {get} /tag/:tag Find transactions by tag
Expand Down Expand Up @@ -208,6 +231,7 @@ int main(int, char const**) {
served::net::server server(TA_HOST, TA_PORT, mux);
server.run(TA_THREAD_COUNT);

iota_client_extended_destroy();
iota_client_core_destroy(&service);
return 0;
}
19 changes: 19 additions & 0 deletions tests/driver.c
Original file line number Diff line number Diff line change
Expand Up @@ -151,6 +151,24 @@ void test_find_transactions_obj_by_tag(void) {
free(json_result);
}

void test_receive_mam_message(void) {
char* json_result;
double sum = 0;

for (size_t count = 0; count < TEST_COUNT; count++) {
clock_gettime(CLOCK_REALTIME, &start_time);
TEST_ASSERT_FALSE(
api_receive_mam_message(&service, BUNDLE_HASH, &json_result));
clock_gettime(CLOCK_REALTIME, &end_time);
#if defined(ENABLE_STAT)
printf("%lf\n", diff_time(start_time, end_time));
#endif
sum += diff_time(start_time, end_time);
}
printf("Average time of receive_mam_message: %lf\n", sum / TEST_COUNT);
free(json_result);
}

int main(void) {
UNITY_BEGIN();
service.http.path = "/";
Expand All @@ -168,6 +186,7 @@ int main(void) {
RUN_TEST(test_get_transaction_object);
RUN_TEST(test_find_transactions_by_tag);
RUN_TEST(test_find_transactions_obj_by_tag);
RUN_TEST(test_receive_mam_message);
iota_client_core_destroy(&service);
return UNITY_END();
}
14 changes: 14 additions & 0 deletions tests/iota_api_mock.cc
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,20 @@ retcode_t iota_client_find_transactions(
return APIMockObj.iota_client_find_transactions(service, req, res);
}

retcode_t iota_client_find_transaction_objects(
const iota_client_service_t* const service,
const find_transactions_req_t* const req, transaction_array_t tx_objs) {
flex_trit_t tx_trits[FLEX_TRIT_SIZE_8019];
iota_transaction_t tx;

flex_trits_from_trytes(
tx_trits, NUM_TRITS_SERIALIZED_TRANSACTION, (const tryte_t*)TRYTES_2673_1,
NUM_TRYTES_SERIALIZED_TRANSACTION, NUM_TRYTES_SERIALIZED_TRANSACTION);
transaction_deserialize_from_trits(&tx, tx_trits, false);
transaction_array_push_back(tx_objs, &tx);
return APIMockObj.iota_client_find_transaction_objects(service, req, tx_objs);
}

retcode_t iota_client_get_new_address(iota_client_service_t const* const serv,
flex_trit_t const* const seed,
address_opt_t const addr_opt,
Expand Down
10 changes: 9 additions & 1 deletion tests/iota_api_mock.hh
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,11 @@ class IotaAPI {
const find_transactions_req_t* const req, find_transactions_res_t* res) {
return RC_OK;
}
virtual retcode_t iota_client_find_transaction_objects(
const iota_client_service_t* const service,
const find_transactions_req_t* const req, transaction_array_t tx_objs) {
return RC_OK;
}
virtual retcode_t iota_client_get_new_address(
iota_client_service_t const* const serv, flex_trit_t const* const seed,
address_opt_t const addr_opt, hash243_queue_t* out_addresses) {
Expand All @@ -37,7 +42,6 @@ class IotaAPI {
get_trytes_res_t* res) {
return RC_OK;
}

virtual status_t ta_send_trytes(const iota_client_service_t* const service,
hash8019_array_p trytes) {
return SC_OK;
Expand All @@ -63,6 +67,10 @@ class APIMock : public IotaAPI {
retcode_t(const iota_client_service_t* const service,
const find_transactions_req_t* const req,
find_transactions_res_t* res));
MOCK_METHOD3(iota_client_find_transaction_objects,
retcode_t(const iota_client_service_t* const service,
const find_transactions_req_t* const req,
transaction_array_t tx_objs));
MOCK_METHOD4(iota_client_get_new_address,
retcode_t(iota_client_service_t const* const serv,
flex_trit_t const* const seed,
Expand Down
Loading

0 comments on commit 0e95a45

Please sign in to comment.