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

Commit 0e95a45

Browse files
authored
Merge pull request #99 from wusyong/mam
feat(api): Implement receive mam message API
2 parents c9f7dc1 + 6735f99 commit 0e95a45

File tree

12 files changed

+279
-1
lines changed

12 files changed

+279
-1
lines changed

accelerator/BUILD

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,9 @@ cc_library(
2020
":common_core",
2121
":ta_errors",
2222
"//serializer",
23+
"@entangled//common/trinary:trit_tryte",
24+
"@entangled//common/trinary:tryte_ascii",
25+
"@entangled//mam/api",
2326
],
2427
)
2528

accelerator/apis.c

Lines changed: 71 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,28 @@
11
#include "apis.h"
22

3+
// TODO: Generate actual pre shared keys
4+
static mam_psk_t const psk = {
5+
.id = {1, 0, -1, -1, 0, -1, -1, 0, 0, 1, -1, 0, 1, 0, 0, 1, 1,
6+
1, -1, 1, 1, 0, 1, 1, 0, 0, -1, 1, -1, -1, -1, -1, -1, -1,
7+
-1, 1, -1, -1, 0, -1, -1, 1, 0, -1, -1, -1, 1, 1, 1, 0, 0,
8+
-1, 1, -1, -1, -1, 0, -1, 1, -1, -1, -1, 1, 1, -1, 1, 0, 0,
9+
1, 1, 1, -1, -1, 0, 0, -1, -1, 1, 0, -1, 1},
10+
.key = {-1, 1, -1, -1, 1, -1, -1, 0, 0, 0, -1, -1, 1, 1, 1, -1, -1,
11+
-1, 0, 0, 0, 0, -1, -1, 1, 1, 1, 0, -1, -1, -1, 0, 0, 0,
12+
-1, -1, 1, -1, 0, 0, 1, 0, 0, -1, 1, 1, 0, -1, 0, 0, 1,
13+
-1, 1, 0, 1, 0, 0, -1, 1, 1, -1, 1, 0, -1, 0, -1, 1, -1,
14+
-1, -1, 0, -1, -1, 0, -1, -1, 0, 0, -1, -1, 1, -1, 0, 0, -1,
15+
-1, -1, -1, 0, -1, -1, -1, 1, -1, -1, 1, 1, 1, 1, 1, 0, 1,
16+
0, 1, -1, 0, 0, 1, 0, 1, 0, 0, 1, 0, -1, 0, 1, 1, 0,
17+
0, -1, -1, 1, 1, 0, 0, 1, -1, 1, 1, 1, 0, 1, 1, 1, 0,
18+
0, -1, -1, -1, -1, 1, 1, 1, 0, 0, -1, 0, 1, -1, 1, 1, 1,
19+
0, 0, 1, -1, -1, 0, -1, 1, -1, 1, 0, 0, 1, -1, 0, 1, -1,
20+
0, 0, 1, 1, 1, 1, 1, 0, 0, 1, -1, 1, -1, 1, 0, 1, 1,
21+
1, -1, 0, 0, -1, 1, 1, 0, -1, -1, 0, 0, -1, 1, 0, 1, -1,
22+
0, 0, -1, 1, -1, 1, 1, 1, -1, 0, 1, 1, 0, 0, -1, -1, -1,
23+
0, 0, 1, 0, 1, 0, -1, 1, -1, 0, 1, 0, -1, 1, 1, -1, -1,
24+
0, 0, -1, 0, -1}};
25+
326
status_t api_get_tips(const iota_client_service_t* const service,
427
char** json_result) {
528
status_t ret = SC_OK;
@@ -128,6 +151,54 @@ status_t api_find_transactions_obj_by_tag(
128151
return ret;
129152
}
130153

154+
status_t api_receive_mam_message(const iota_client_service_t* const service,
155+
const char* const obj, char** json_result) {
156+
status_t ret = SC_OK;
157+
mam_api_t mam;
158+
159+
tryte_t* payload_trytes = NULL;
160+
size_t payload_size = 0;
161+
bundle_transactions_t* bundle = NULL;
162+
bundle_transactions_new(&bundle);
163+
bool is_last_packet;
164+
165+
// Creating MAM API
166+
if (mam_api_init(&mam, (tryte_t*)SEED)) {
167+
ret = SC_MAM_OOM;
168+
goto done;
169+
}
170+
171+
// Get bundle which is find_transactions_by_bundle
172+
ret = ta_get_bundle(service, (tryte_t*)obj, bundle);
173+
if (ret) {
174+
goto done;
175+
}
176+
177+
// Read MAM message from bundle
178+
mam_psk_t_set_add(&mam.psks, &psk);
179+
if (mam_api_bundle_read(&mam, bundle, &payload_trytes, &payload_size,
180+
&is_last_packet) == RC_OK) {
181+
if (payload_trytes == NULL || payload_size == 0) {
182+
ret = SC_MAM_NULL;
183+
} else {
184+
char* payload = calloc(payload_size * 2 + 1, sizeof(char));
185+
186+
trytes_to_ascii(payload_trytes, payload_size, payload);
187+
*json_result = payload;
188+
189+
payload = NULL;
190+
free(payload_trytes);
191+
}
192+
} else {
193+
ret = SC_MAM_FAILED_RESPONSE;
194+
}
195+
196+
done:
197+
mam_api_destroy(&mam);
198+
bundle_transactions_free(&bundle);
199+
return ret;
200+
}
201+
131202
status_t api_send_transfer(const iota_client_service_t* const service,
132203
const char* const obj, char** json_result) {
133204
status_t ret = SC_OK;

accelerator/apis.h

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,9 @@
44
#include "accelerator/common_core.h"
55
#include "accelerator/errors.h"
66
#include "cclient/types/types.h"
7+
#include "common/trinary/trit_tryte.h"
8+
#include "common/trinary/tryte_ascii.h"
9+
#include "mam/api/api.h"
710
#include "serializer/serializer.h"
811

912
#ifdef __cplusplus
@@ -67,6 +70,22 @@ status_t api_get_tips_pair(const iota_client_service_t* const service,
6770
status_t api_get_tips(const iota_client_service_t* const service,
6871
char** json_result);
6972

73+
/**
74+
* @brief Receive a MAM message.
75+
*
76+
* Receive a MAM message from given bundle hash.
77+
*
78+
* @param[in] service IRI node end point service
79+
* @param[out] obj bundle hash in trytes
80+
* @param[out] json_result Result containing an unused address in json format
81+
*
82+
* @return
83+
* - SC_OK on success
84+
* - non-zero on error
85+
*/
86+
status_t api_receive_mam_message(const iota_client_service_t* const service,
87+
const char* const obj, char** json_result);
88+
7089
/**
7190
* @brief Send transfer to tangle.
7291
*

accelerator/common_core.c

Lines changed: 65 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -455,3 +455,68 @@ status_t ta_find_transactions_obj_by_tag(
455455
ta_find_transactions_res_free(&hash_res);
456456
return ret;
457457
}
458+
459+
static int idx_sort(void const* lhs, void const* rhs) {
460+
iota_transaction_t* _lhs = (iota_transaction_t*)lhs;
461+
iota_transaction_t* _rhs = (iota_transaction_t*)rhs;
462+
463+
return (transaction_current_index(_lhs) < transaction_current_index(_rhs))
464+
? -1
465+
: (transaction_current_index(_lhs) >
466+
transaction_current_index(_rhs));
467+
}
468+
469+
static void get_first_bundle_from_transactions(
470+
transaction_array_t const transactions,
471+
bundle_transactions_t* const bundle) {
472+
iota_transaction_t* tail = NULL;
473+
iota_transaction_t* curr_tx = NULL;
474+
iota_transaction_t* prev = NULL;
475+
476+
utarray_sort(transactions, idx_sort);
477+
tail = (iota_transaction_t*)utarray_eltptr(transactions, 0);
478+
bundle_transactions_add(bundle, tail);
479+
480+
prev = tail;
481+
TX_OBJS_FOREACH(transactions, curr_tx) {
482+
if (transaction_current_index(curr_tx) ==
483+
(transaction_current_index(prev) + 1) &&
484+
(memcmp(transaction_hash(curr_tx), transaction_trunk(prev),
485+
FLEX_TRIT_SIZE_243) == 0)) {
486+
bundle_transactions_add(bundle, curr_tx);
487+
prev = curr_tx;
488+
}
489+
}
490+
}
491+
492+
status_t ta_get_bundle(const iota_client_service_t* const service,
493+
tryte_t const* const bundle_hash,
494+
bundle_transactions_t* const bundle) {
495+
status_t ret = SC_OK;
496+
iota_transaction_t* curr_tx = NULL;
497+
flex_trit_t bundle_hash_flex[FLEX_TRIT_SIZE_243];
498+
transaction_array_t tx_objs = transaction_array_new();
499+
find_transactions_req_t* find_tx_req = find_transactions_req_new();
500+
if (find_tx_req == NULL) {
501+
ret = SC_CCLIENT_OOM;
502+
goto done;
503+
}
504+
505+
// find transactions by bundle hash
506+
flex_trits_from_trytes(bundle_hash_flex, NUM_TRITS_BUNDLE, bundle_hash,
507+
NUM_TRITS_HASH, NUM_TRYTES_BUNDLE);
508+
hash243_queue_push(&find_tx_req->bundles, bundle_hash_flex);
509+
ret = iota_client_find_transaction_objects(service, find_tx_req, tx_objs);
510+
if (ret) {
511+
ret = SC_CCLIENT_FAILED_RESPONSE;
512+
goto done;
513+
}
514+
515+
// retreive only first bundle
516+
get_first_bundle_from_transactions(tx_objs, bundle);
517+
518+
done:
519+
transaction_array_free(tx_objs);
520+
find_transactions_req_free(&find_tx_req);
521+
return ret;
522+
}

accelerator/common_core.h

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -172,6 +172,25 @@ status_t ta_get_transaction_object(const iota_client_service_t* const service,
172172
const char* const req,
173173
ta_get_transaction_object_res_t* res);
174174

175+
/**
176+
* @brief Return bundle object with given bundle hash.
177+
*
178+
* Explore transaction hash information with given bundle hash. This would
179+
* return only one bundle objects in bundle_transactions_t instead of all
180+
* transactions like reattached ones.
181+
*
182+
* @param[in] service IRI node end point service
183+
* @param[in] bundle_hash bundle hash in trytes
184+
* @param[out] bundle Result containing bundle object in bundle_transactions_t
185+
*
186+
* @return
187+
* - SC_OK on success
188+
* - non-zero on error
189+
*/
190+
status_t ta_get_bundle(const iota_client_service_t* const service,
191+
tryte_t const* const bundle_hash,
192+
bundle_transactions_t* const bundle);
193+
175194
#ifdef __cplusplus
176195
}
177196
#endif

accelerator/errors.h

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,7 @@ extern "C" {
3939
#define SC_MODULE_CCLIENT (0x02 << SC_MODULE_SHIFT)
4040
#define SC_MODULE_SERIALIZER (0x03 << SC_MODULE_SHIFT)
4141
#define SC_MODULE_CACHE (0x04 << SC_MODULE_SHIFT)
42+
#define SC_MODULE_MAM (0x05 << SC_MODULE_SHIFT)
4243
/** @} */
4344

4445
/** @name serverity code */
@@ -86,6 +87,14 @@ typedef enum {
8687
/**< NULL parameters in cache */
8788
SC_CACHE_FAILED_RESPONSE = 0x02 | SC_MODULE_CACHE | SC_SEVERITY_FATAL,
8889
/**< Fail in cache operations */
90+
91+
// MAM module
92+
SC_MAM_OOM = 0x01 | SC_MODULE_MAM | SC_SEVERITY_FATAL,
93+
/**< Fail to create mam object */
94+
SC_MAM_NULL = 0x02 | SC_MODULE_MAM | SC_SEVERITY_FATAL,
95+
/**< NULL object in mam */
96+
SC_MAM_FAILED_RESPONSE = 0x03 | SC_MODULE_MAM | SC_SEVERITY_FATAL,
97+
/**< Error in mam response */
8998
} status_t;
9099

91100
#ifdef __cplusplus

accelerator/server.cc

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,11 +20,34 @@ int main(int, char const**) {
2020

2121
iota_client_service_t service;
2222
service.http.path = "/";
23+
service.http.content_type = "application/json";
24+
service.http.accept = "application/json";
2325
service.http.host = IRI_HOST;
2426
service.http.port = IRI_PORT;
2527
service.http.api_version = 1;
2628
service.serializer_type = SR_JSON;
2729
iota_client_core_init(&service);
30+
iota_client_extended_init();
31+
32+
mux.handle("/mam/{bundle:[A-Z9]{81}}")
33+
.method(served::method::OPTIONS,
34+
[&](served::response& res, const served::request& req) {
35+
set_options_method_header(res);
36+
})
37+
.get([&](served::response& res, const served::request& req) {
38+
char* json_result = NULL;
39+
40+
api_receive_mam_message(&service, req.params["bundle"].c_str(),
41+
&json_result);
42+
43+
res.set_header("Content-Type", "application/json");
44+
res.set_header("Access-Control-Allow-Origin", "*");
45+
if (!json_result) {
46+
res.set_status(SC_NOT_FOUND);
47+
} else {
48+
res << json_result;
49+
}
50+
});
2851

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

234+
iota_client_extended_destroy();
211235
iota_client_core_destroy(&service);
212236
return 0;
213237
}

tests/driver.c

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -151,6 +151,24 @@ void test_find_transactions_obj_by_tag(void) {
151151
free(json_result);
152152
}
153153

154+
void test_receive_mam_message(void) {
155+
char* json_result;
156+
double sum = 0;
157+
158+
for (size_t count = 0; count < TEST_COUNT; count++) {
159+
clock_gettime(CLOCK_REALTIME, &start_time);
160+
TEST_ASSERT_FALSE(
161+
api_receive_mam_message(&service, BUNDLE_HASH, &json_result));
162+
clock_gettime(CLOCK_REALTIME, &end_time);
163+
#if defined(ENABLE_STAT)
164+
printf("%lf\n", diff_time(start_time, end_time));
165+
#endif
166+
sum += diff_time(start_time, end_time);
167+
}
168+
printf("Average time of receive_mam_message: %lf\n", sum / TEST_COUNT);
169+
free(json_result);
170+
}
171+
154172
int main(void) {
155173
UNITY_BEGIN();
156174
service.http.path = "/";
@@ -168,6 +186,7 @@ int main(void) {
168186
RUN_TEST(test_get_transaction_object);
169187
RUN_TEST(test_find_transactions_by_tag);
170188
RUN_TEST(test_find_transactions_obj_by_tag);
189+
RUN_TEST(test_receive_mam_message);
171190
iota_client_core_destroy(&service);
172191
return UNITY_END();
173192
}

tests/iota_api_mock.cc

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,20 @@ retcode_t iota_client_find_transactions(
3939
return APIMockObj.iota_client_find_transactions(service, req, res);
4040
}
4141

42+
retcode_t iota_client_find_transaction_objects(
43+
const iota_client_service_t* const service,
44+
const find_transactions_req_t* const req, transaction_array_t tx_objs) {
45+
flex_trit_t tx_trits[FLEX_TRIT_SIZE_8019];
46+
iota_transaction_t tx;
47+
48+
flex_trits_from_trytes(
49+
tx_trits, NUM_TRITS_SERIALIZED_TRANSACTION, (const tryte_t*)TRYTES_2673_1,
50+
NUM_TRYTES_SERIALIZED_TRANSACTION, NUM_TRYTES_SERIALIZED_TRANSACTION);
51+
transaction_deserialize_from_trits(&tx, tx_trits, false);
52+
transaction_array_push_back(tx_objs, &tx);
53+
return APIMockObj.iota_client_find_transaction_objects(service, req, tx_objs);
54+
}
55+
4256
retcode_t iota_client_get_new_address(iota_client_service_t const* const serv,
4357
flex_trit_t const* const seed,
4458
address_opt_t const addr_opt,

tests/iota_api_mock.hh

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,11 @@ class IotaAPI {
2727
const find_transactions_req_t* const req, find_transactions_res_t* res) {
2828
return RC_OK;
2929
}
30+
virtual retcode_t iota_client_find_transaction_objects(
31+
const iota_client_service_t* const service,
32+
const find_transactions_req_t* const req, transaction_array_t tx_objs) {
33+
return RC_OK;
34+
}
3035
virtual retcode_t iota_client_get_new_address(
3136
iota_client_service_t const* const serv, flex_trit_t const* const seed,
3237
address_opt_t const addr_opt, hash243_queue_t* out_addresses) {
@@ -37,7 +42,6 @@ class IotaAPI {
3742
get_trytes_res_t* res) {
3843
return RC_OK;
3944
}
40-
4145
virtual status_t ta_send_trytes(const iota_client_service_t* const service,
4246
hash8019_array_p trytes) {
4347
return SC_OK;
@@ -63,6 +67,10 @@ class APIMock : public IotaAPI {
6367
retcode_t(const iota_client_service_t* const service,
6468
const find_transactions_req_t* const req,
6569
find_transactions_res_t* res));
70+
MOCK_METHOD3(iota_client_find_transaction_objects,
71+
retcode_t(const iota_client_service_t* const service,
72+
const find_transactions_req_t* const req,
73+
transaction_array_t tx_objs));
6674
MOCK_METHOD4(iota_client_get_new_address,
6775
retcode_t(iota_client_service_t const* const serv,
6876
flex_trit_t const* const seed,

0 commit comments

Comments
 (0)