diff --git a/.bazelrc b/.bazelrc index dc09b0aa..fb99d6e2 100644 --- a/.bazelrc +++ b/.bazelrc @@ -1,4 +1,9 @@ test --copt='-ggdb3' +coverage -s +coverage --experimental_cc_coverage +coverage --combined_report=lcov +coverage --coverage_report_generator=@bazel_tools//tools/test/CoverageOutputGenerator/java/com/google/devtools/coverageoutputgenerator:Main +coverage --instrumentation_filter="-/tests[/:]" # Address Sanitizer:--config asan build:asan --strip=never diff --git a/LICENSE b/LICENSE index f842c60f..2f88229f 100644 --- a/LICENSE +++ b/LICENSE @@ -1,6 +1,6 @@ The MIT License (MIT) -Copyright (C) 2018-2019 BiiLabs, Co. Ltd. and Contributors +Copyright (C) 2018-2019 BiiLabs Co., Ltd. and Contributors All Rights Reserved. Permission is hereby granted, free of charge, to any person obtaining a copy diff --git a/Makefile b/Makefile index 3ea81037..01e845cc 100644 --- a/Makefile +++ b/Makefile @@ -10,7 +10,6 @@ all: $(DEPS) $(DCURL_LIB): $(DCURL_DIR) git submodule update --init $^ - git submodule update --remote $^ $(MAKE) -C $^ config @echo $(info Modify $^/build/local.mk for your environments.) diff --git a/README.md b/README.md index 4627ac1d..2a5cd048 100644 --- a/README.md +++ b/README.md @@ -1,5 +1,7 @@ # Tangle-accelerator +[![Build Status](https://badge.buildkite.com/46ec07b122bde13f984c241fe8b38e64698c5c0d816ee6c7e4.svg)](https://buildkite.com/dltcollab/dcurl-test) [![Gitter](https://img.shields.io/gitter/room/DLTcollab/tangle-accelerator.svg)](https://gitter.im/DLTcollab/tangle-accelerator) ![GitHub release](https://img.shields.io/github/release-pre/DLTcollab/tangle-accelerator.svg) + `Tangle-accelerator` is a caching proxy server for [IOTA](https://www.iota.org/), which can cache API requests and rewrite their responses as needed to be routed through full nodes. Thus, one instance of `Tangle-accelerator` can serve thousands of Tangle requests @@ -69,6 +71,20 @@ Before running tangle-accelerator, please edit binding address/port of accelerat $ make && bazel run //accelerator ``` +### Build from docker + +If you prefer building a docker image, tangle-accelerator also provides build rules for it. Note that you still have to edit configurations in `accelerator/config.h`. + +``` +$ make && bazel run //accelerator:ta_image +``` + +There's also an easier option to pull image from docker hub then simply run with default configs. Please do remember a redis-server is still required in this way. + +``` +$ docker run -d --net=host --name tangle-accelerator wusyong/tangel-accelerator:latest +``` + ## Developing The codebase of this repository follows [Google's C++ guidelines](https://google.github.io/styleguide/cppguide.html): diff --git a/WORKSPACE b/WORKSPACE index e4e9d051..9a4d5050 100644 --- a/WORKSPACE +++ b/WORKSPACE @@ -2,13 +2,13 @@ load("@bazel_tools//tools/build_defs/repo:git.bzl", "git_repository", "new_git_r git_repository( name = "rules_iota", - commit = "b15744b9ea520717752c866d5afc769c3b6b68f3", + commit = "1cb59eea62fd1d071de213a9aa46e61e8273472d", remote = "https://github.com/iotaledger/rules_iota.git", ) git_repository( name = "entangled", - commit = "8d847ffcecd50f8f3760bfee07d7ed33ecc067bf", + commit = "4960865730640d23e75ffbce84d3f74264cfcd28", remote = "https://github.com/iotaledger/entangled.git", ) @@ -18,6 +18,15 @@ git_repository( remote = "https://github.com/meltwater/served.git", ) +git_repository( + name = "io_bazel_rules_docker", + remote = "https://github.com/bazelbuild/rules_docker.git", + tag = "v0.6.0", +) + load("@rules_iota//:defs.bzl", "iota_deps") +load("@io_bazel_rules_docker//cc:image.bzl", _cc_image_repos = "repositories") iota_deps() + +_cc_image_repos() diff --git a/accelerator/BUILD b/accelerator/BUILD index 497cd5ce..e959d048 100644 --- a/accelerator/BUILD +++ b/accelerator/BUILD @@ -1,5 +1,7 @@ package(default_visibility = ["//visibility:public"]) +load("@io_bazel_rules_docker//cc:image.bzl", "cc_image") + cc_binary( name = "accelerator", srcs = ["server.cc"], @@ -11,6 +13,11 @@ cc_binary( ], ) +cc_image( + name = "ta_image", + binary = ":accelerator", +) + cc_library( name = "apis", srcs = ["apis.c"], @@ -36,11 +43,7 @@ cc_library( ":ta_errors", "//request", "//response", - "//utils:cache", - "//utils:pow", "@com_github_uthash//:uthash", - "@entangled//cclient/api", - "@entangled//cclient/types", "@entangled//common/model:bundle", "@entangled//utils:time", ], @@ -48,8 +51,16 @@ cc_library( cc_library( name = "ta_config", + srcs = ["config.c"], hdrs = ["config.h"], visibility = ["//visibility:public"], + deps = [ + ":ta_errors", + "//utils:cache", + "//utils:pow", + "@entangled//cclient/api", + "@entangled//cclient/types", + ], ) cc_library( diff --git a/accelerator/apis.c b/accelerator/apis.c index 1c254420..b1707583 100644 --- a/accelerator/apis.c +++ b/accelerator/apis.c @@ -44,7 +44,8 @@ status_t api_get_tips(const iota_client_service_t* const service, return ret; } -status_t api_get_tips_pair(const iota_client_service_t* const service, +status_t api_get_tips_pair(const iota_config_t* const tangle, + const iota_client_service_t* const service, char** json_result) { status_t ret = SC_OK; ta_get_tips_res_t* res = ta_get_tips_res_new(); @@ -53,7 +54,7 @@ status_t api_get_tips_pair(const iota_client_service_t* const service, goto done; } - ret = cclient_get_txn_to_approve(service, res); + ret = cclient_get_txn_to_approve(service, tangle->depth, res); if (ret) { goto done; } @@ -65,7 +66,8 @@ status_t api_get_tips_pair(const iota_client_service_t* const service, return ret; } -status_t api_generate_address(const iota_client_service_t* const service, +status_t api_generate_address(const iota_config_t* const tangle, + const iota_client_service_t* const service, char** json_result) { status_t ret = SC_OK; ta_generate_address_res_t* res = ta_generate_address_res_new(); @@ -74,7 +76,7 @@ status_t api_generate_address(const iota_client_service_t* const service, goto done; } - ret = ta_generate_address(service, res); + ret = ta_generate_address(tangle, service, res); if (ret) { goto done; } @@ -152,54 +154,75 @@ status_t api_find_transactions_obj_by_tag( } 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; + const char* const bundle_hash, + char** json_result) { mam_api_t mam; - + status_t ret = SC_OK; tryte_t* payload_trytes = NULL; + tryte_t* none_chid_trytes = NULL; + char* payload = 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; + if (mam_api_init(&mam, (tryte_t*)SEED) != RC_OK) { + ret = SC_MAM_FAILED_INIT; goto done; } - // Get bundle which is find_transactions_by_bundle - ret = ta_get_bundle(service, (tryte_t*)obj, bundle); - if (ret) { + ret = ta_get_bundle(service, (tryte_t*)bundle_hash, bundle); + if (ret != SC_OK) { goto done; } - // Read MAM message from bundle + // Set first transaction's address as chid, if no `chid` specified mam_psk_t_set_add(&mam.psks, &psk); + iota_transaction_t* curr_tx = (iota_transaction_t*)utarray_eltptr(bundle, 0); + none_chid_trytes = (tryte_t*)malloc(sizeof(tryte_t) * NUM_TRYTES_ADDRESS); + flex_trits_to_trytes(none_chid_trytes, NUM_TRYTES_ADDRESS, + transaction_address(curr_tx), NUM_TRITS_ADDRESS, + NUM_TRITS_ADDRESS); + mam_api_add_trusted_channel_pk(&mam, none_chid_trytes); + 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; + ret = SC_MAM_NO_PAYLOAD; + goto done; } else { - char* payload = calloc(payload_size * 2 + 1, sizeof(char)); - + payload = calloc(payload_size * 2 + 1, sizeof(char)); + if (payload == NULL) { + ret = SC_TA_NULL; + goto done; + } trytes_to_ascii(payload_trytes, payload_size, payload); - *json_result = payload; - - payload = NULL; - free(payload_trytes); } } else { - ret = SC_MAM_FAILED_RESPONSE; + ret = SC_MAM_NOT_FOUND; + goto done; } + ret = receive_mam_message_serialize(json_result, &payload); + done: - mam_api_destroy(&mam); + // Destroying MAM API + if (ret != SC_MAM_FAILED_INIT) { + if (mam_api_destroy(&mam) != RC_OK) { + ret = SC_MAM_FAILED_DESTROYED; + } + } + free(none_chid_trytes); + free(payload_trytes); + free(payload); bundle_transactions_free(&bundle); + return ret; } -status_t api_send_transfer(const iota_client_service_t* const service, +status_t api_send_transfer(const iota_config_t* const tangle, + const iota_client_service_t* const service, const char* const obj, char** json_result) { status_t ret = SC_OK; char hash_trytes[NUM_TRYTES_HASH + 1]; @@ -218,7 +241,7 @@ status_t api_send_transfer(const iota_client_service_t* const service, goto done; } - ret = ta_send_transfer(service, req, res); + ret = ta_send_transfer(tangle, service, req, res); if (ret) { goto done; } diff --git a/accelerator/apis.h b/accelerator/apis.h index c7bdf22f..c9be5fe2 100644 --- a/accelerator/apis.h +++ b/accelerator/apis.h @@ -7,6 +7,7 @@ #include "common/trinary/trit_tryte.h" #include "common/trinary/tryte_ascii.h" #include "mam/api/api.h" +#include "mam/mam/mam_channel_t_set.h" #include "serializer/serializer.h" #ifdef __cplusplus @@ -28,6 +29,7 @@ extern "C" { * Generate and return an unused address from the seed. An unused address means * the address does not have any transaction with it yet. * + * @param[in] tangle IOTA API parameter configurations * @param[in] service IRI node end point service * @param[out] json_result Result containing an unused address in json format * @@ -35,7 +37,8 @@ extern "C" { * - SC_OK on success * - non-zero on error */ -status_t api_generate_address(const iota_client_service_t* const service, +status_t api_generate_address(const iota_config_t* const tangle, + const iota_client_service_t* const service, char** json_result); /** @@ -44,6 +47,7 @@ status_t api_generate_address(const iota_client_service_t* const service, * Get a tips pair as trunk/branch transactions for transaction construction. * The result is char array in json format: * + * @param[in] tangle IOTA API parameter configurations * @param[in] service IRI node end point service * @param[out] json_result Result containing a tips pair in json format * @@ -51,7 +55,8 @@ status_t api_generate_address(const iota_client_service_t* const service, * - SC_OK on success * - non-zero on error */ -status_t api_get_tips_pair(const iota_client_service_t* const service, +status_t api_get_tips_pair(const iota_config_t* const tangle, + const iota_client_service_t* const service, char** json_result); /** @@ -76,7 +81,7 @@ status_t api_get_tips(const iota_client_service_t* const service, * Receive a MAM message from given bundle hash. * * @param[in] service IRI node end point service - * @param[out] obj bundle hash in trytes + * @param[in] bundle_hash bundle hash decoded in trytes string * @param[out] json_result Result containing an unused address in json format * * @return @@ -84,7 +89,8 @@ status_t api_get_tips(const iota_client_service_t* const service, * - non-zero on error */ status_t api_receive_mam_message(const iota_client_service_t* const service, - const char* const obj, char** json_result); + const char* const bundle_hash, + char** json_result); /** * @brief Send transfer to tangle. @@ -93,6 +99,7 @@ status_t api_receive_mam_message(const iota_client_service_t* const service, * fields include address, value, tag, and message. This API would also try to * find the transactions after bundle sent. * + * @param[in] tangle IOTA API parameter configurations * @param[in] service IRI node end point service * @param[in] obj Input data in JSON * @param[out] json_result Result containing transaction objects in json format @@ -101,7 +108,8 @@ status_t api_receive_mam_message(const iota_client_service_t* const service, * - SC_OK on success * - non-zero on error */ -status_t api_send_transfer(const iota_client_service_t* const service, +status_t api_send_transfer(const iota_config_t* const tangle, + const iota_client_service_t* const service, const char* const obj, char** json_result); /** diff --git a/accelerator/common_core.c b/accelerator/common_core.c index 1e4364c4..1cedbc68 100644 --- a/accelerator/common_core.c +++ b/accelerator/common_core.c @@ -1,9 +1,8 @@ #include "common_core.h" #include -#include "utils/cache.h" -#include "utils/pow.h" status_t cclient_get_txn_to_approve(const iota_client_service_t* const service, + uint8_t const depth, ta_get_tips_res_t* res) { if (res == NULL) { return SC_TA_NULL; @@ -19,7 +18,7 @@ status_t cclient_get_txn_to_approve(const iota_client_service_t* const service, goto done; } // The depth at which Random Walk starts. Mininal is 3, and max is 15. - get_transactions_to_approve_req_set_depth(get_txn_req, DEPTH); + get_transactions_to_approve_req_set_depth(get_txn_req, depth); ret = iota_client_get_transactions_to_approve(service, get_txn_req, get_txn_res); @@ -113,8 +112,6 @@ status_t ta_attach_to_tangle(const attach_to_tangle_req_t* const req, flex_trit_t* elt = NULL; char cache_key[NUM_TRYTES_HASH] = {0}; char cache_value[NUM_TRYTES_SERIALIZED_TRANSACTION] = {0}; - cache_t* cache = cache_init(); - pow_init(); // create bundle bundle_transactions_new(&bundle); @@ -128,7 +125,7 @@ status_t ta_attach_to_tangle(const attach_to_tangle_req_t* const req, flex_trits_to_trytes( (tryte_t*)cache_value, NUM_TRYTES_SERIALIZED_TRANSACTION, elt, NUM_TRITS_SERIALIZED_TRANSACTION, NUM_TRITS_SERIALIZED_TRANSACTION); - ret = cache_set(cache, cache_key, cache_value); + ret = cache_set(cache_key, cache_value); if (ret) { goto done; } @@ -155,13 +152,12 @@ status_t ta_attach_to_tangle(const attach_to_tangle_req_t* const req, } done: - cache_stop(&cache); - pow_destroy(); bundle_transactions_free(&bundle); return ret; } -status_t ta_send_trytes(const iota_client_service_t* const service, +status_t ta_send_trytes(const iota_config_t* const tangle, + const iota_client_service_t* const service, hash8019_array_p trytes) { status_t ret = SC_OK; ta_get_tips_res_t* get_txn_res = ta_get_tips_res_new(); @@ -173,21 +169,23 @@ status_t ta_send_trytes(const iota_client_service_t* const service, } // get transaction to approve - ret = cclient_get_txn_to_approve(service, get_txn_res); + ret = cclient_get_txn_to_approve(service, tangle->depth, get_txn_res); if (ret) { goto done; } // attach to tangle - memcpy(attach_req->trunk, hash243_stack_peek(get_txn_res->tips), FLEX_TRIT_SIZE_243); hash243_stack_pop(&get_txn_res->tips); memcpy(attach_req->branch, hash243_stack_peek(get_txn_res->tips), FLEX_TRIT_SIZE_243); hash243_stack_pop(&get_txn_res->tips); - attach_req->mwm = MWM; - attach_req->trytes = trytes; + attach_req->mwm = tangle->mwm; + + flex_trit_t* elt = NULL; + HASH_ARRAY_FOREACH(trytes, elt) { hash_array_push(attach_req->trytes, elt); } + ret = ta_attach_to_tangle(attach_req, attach_res); if (ret) { goto done; @@ -202,13 +200,13 @@ status_t ta_send_trytes(const iota_client_service_t* const service, done: ta_get_tips_res_free(&get_txn_res); - attach_req->trytes = NULL; attach_to_tangle_req_free(&attach_req); attach_to_tangle_res_free(&attach_res); return ret; } -status_t ta_generate_address(const iota_client_service_t* const service, +status_t ta_generate_address(const iota_config_t* const tangle, + const iota_client_service_t* const service, ta_generate_address_res_t* res) { if (res == NULL) { return SC_TA_NULL; @@ -217,8 +215,9 @@ status_t ta_generate_address(const iota_client_service_t* const service, status_t ret = SC_OK; hash243_queue_t out_address = NULL; flex_trit_t seed_trits[FLEX_TRIT_SIZE_243]; - flex_trits_from_trytes(seed_trits, NUM_TRITS_HASH, (const tryte_t*)SEED, - NUM_TRYTES_HASH, NUM_TRYTES_HASH); + flex_trits_from_trytes(seed_trits, NUM_TRITS_HASH, + (const tryte_t*)tangle->seed, NUM_TRYTES_HASH, + NUM_TRYTES_HASH); address_opt_t opt = {.security = 3, .start = 0, .total = 0}; ret = iota_client_get_new_address(service, seed_trits, opt, &out_address); @@ -231,7 +230,8 @@ status_t ta_generate_address(const iota_client_service_t* const service, return ret; } -status_t ta_send_transfer(const iota_client_service_t* const service, +status_t ta_send_transfer(const iota_config_t* const tangle, + const iota_client_service_t* const service, const ta_send_transfer_req_t* const req, ta_send_transfer_res_t* res) { if (req == NULL || res == NULL) { @@ -270,7 +270,7 @@ status_t ta_send_transfer(const iota_client_service_t* const service, free(serialized_txn); } - ret = ta_send_trytes(service, raw_tx); + ret = ta_send_trytes(tangle, service, raw_tx); if (ret) { goto done; } @@ -353,16 +353,15 @@ status_t ta_get_transaction_object(const iota_client_service_t* const service, char cache_value[FLEX_TRIT_SIZE_8019] = {0}; // get raw transaction data of transaction hashes - cache_t* cache = cache_init(); get_trytes_req_t* get_trytes_req = get_trytes_req_new(); get_trytes_res_t* get_trytes_res = get_trytes_res_new(); - if (cache == NULL || get_trytes_req == NULL || get_trytes_res == NULL) { + if (get_trytes_req == NULL || get_trytes_res == NULL) { ret = SC_CCLIENT_OOM; goto done; } // get in cache first, then get from full node if no result in cache - ret = cache_get(cache, req, cache_value); + ret = cache_get(req, cache_value); if (ret == SC_OK) { flex_trits_from_trytes( tx_trits, NUM_TRITS_SERIALIZED_TRANSACTION, (const tryte_t*)cache_value, @@ -388,7 +387,10 @@ status_t ta_get_transaction_object(const iota_client_service_t* const service, flex_trits_to_trytes( (tryte_t*)cache_value, NUM_TRYTES_SERIALIZED_TRANSACTION, tx_trits, NUM_TRITS_SERIALIZED_TRANSACTION, NUM_TRITS_SERIALIZED_TRANSACTION); - cache_set(cache, req, cache_value); + cache_set(req, cache_value); + } else { + ret = SC_CCLIENT_NOT_FOUND; + goto done; } } @@ -401,7 +403,6 @@ status_t ta_get_transaction_object(const iota_client_service_t* const service, transaction_set_hash(res->txn, hash_trits); done: - cache_stop(&cache); get_trytes_req_free(&get_trytes_req); get_trytes_res_free(&get_trytes_res); return ret; @@ -467,7 +468,7 @@ static int idx_sort(void const* lhs, void const* rhs) { } static void get_first_bundle_from_transactions( - transaction_array_t const transactions, + transaction_array_t const* transactions, bundle_transactions_t* const bundle) { iota_transaction_t* tail = NULL; iota_transaction_t* curr_tx = NULL; @@ -493,9 +494,8 @@ 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(); + 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; diff --git a/accelerator/common_core.h b/accelerator/common_core.h index 12530a60..c372272d 100644 --- a/accelerator/common_core.h +++ b/accelerator/common_core.h @@ -2,10 +2,6 @@ #define ACCELERATOR_COMMON_CORE_H_ #include "accelerator/config.h" -#include "accelerator/errors.h" -#include "cclient/api/core/core_api.h" -#include "cclient/api/extended/extended_api.h" -#include "cclient/types/types.h" #include "common/model/bundle.h" #include "common/model/transfer.h" #include "request/request.h" @@ -35,6 +31,7 @@ extern "C" { * The result is a 243 long flex trits hash stack. * * @param[in] service IRI node end point service + * @param[in] depth Depth of get transaction to approve * @param[out] res Result containing a tips pair in ta_get_tips_res_t * * @return @@ -42,6 +39,7 @@ extern "C" { * - non-zero on error */ status_t cclient_get_txn_to_approve(const iota_client_service_t* const service, + uint8_t const depth, ta_get_tips_res_t* res); /** @@ -66,6 +64,7 @@ status_t cclient_get_tips(const iota_client_service_t* const service, * Generate and return an unused address from the seed. An unused address means * the address does not have any transaction with it yet. * + * @param[in] tangle IOTA API parameter configurations * @param[in] service IRI node end point service * @param[out] res Result containing an unused address in * ta_generate_address_res_t @@ -74,7 +73,8 @@ status_t cclient_get_tips(const iota_client_service_t* const service, * - SC_OK on success * - non-zero on error */ -status_t ta_generate_address(const iota_client_service_t* const service, +status_t ta_generate_address(const iota_config_t* const tangle, + const iota_client_service_t* const service, ta_generate_address_res_t* res); /** @@ -84,6 +84,7 @@ status_t ta_generate_address(const iota_client_service_t* const service, * fields include address, value, tag, and message. This API would also try to * find the transactions after bundle sent. * + * @param[in] tangle IOTA API parameter configurations * @param[in] service IRI node end point service * @param[in] req Request containing address value, message, tag in * ta_send_transfer_req_t @@ -93,7 +94,8 @@ status_t ta_generate_address(const iota_client_service_t* const service, * - SC_OK on success * - non-zero on error */ -status_t ta_send_transfer(const iota_client_service_t* const service, +status_t ta_send_transfer(const iota_config_t* const tangle, + const iota_client_service_t* const service, const ta_send_transfer_req_t* const req, ta_send_transfer_res_t* res); @@ -104,6 +106,7 @@ status_t ta_send_transfer(const iota_client_service_t* const service, * bundle and do PoW in `ta_attach_to_tangle` and store and broadcast * transaction to tangle. * + * @param[in] tangle IOTA API parameter configurations * @param[in] service IRI node end point service * @param[in] trytes Trytes that will be attached to tangle * @@ -111,7 +114,8 @@ status_t ta_send_transfer(const iota_client_service_t* const service, * - SC_OK on success * - non-zero on error */ -status_t ta_send_trytes(const iota_client_service_t* const service, +status_t ta_send_trytes(const iota_config_t* const tangle, + const iota_client_service_t* const service, hash8019_array_p trytes); /** diff --git a/accelerator/config.c b/accelerator/config.c new file mode 100644 index 00000000..97c78eaf --- /dev/null +++ b/accelerator/config.c @@ -0,0 +1,61 @@ +#include "config.h" +#include "utils/logger_helper.h" + +#define CONFIG_LOGGER_ID "TA" + +static logger_id_t logger_id; + +status_t ta_config_init(ta_config_t* const info, iota_config_t* const tangle, + iota_client_service_t* const service) { + status_t ret = SC_OK; + if (info == NULL || tangle == NULL || service == NULL) { + return SC_TA_NULL; + } + + logger_id = logger_helper_enable(CONFIG_LOGGER_ID, LOGGER_DEBUG, true); + log_info(logger_id, "[%s:%d] enable logger %s.\n", __func__, __LINE__, + CONFIG_LOGGER_ID); + + log_info(logger_id, "Initializing TA information\n"); + info->version = TA_VERSION; + info->host = TA_HOST; + info->port = TA_PORT; + info->thread_count = TA_THREAD_COUNT; + + log_info(logger_id, "Initializing IRI configuration\n"); + tangle->depth = DEPTH; + tangle->mwm = MWM; + tangle->seed = SEED; + + log_info(logger_id, "Initializing IRI connection\n"); + 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; + if (iota_client_core_init(service)) { + log_critical(logger_id, "Initializing IRI connection failed!\n"); + ret = SC_TA_OOM; + } + iota_client_extended_init(); + + log_info(logger_id, "Initializing PoW implementation context\n"); + pow_init(); + + log_info(logger_id, "Initializing cache connection\n"); + cache_init(REDIS_HOST, REDIS_PORT); + + return ret; +} + +void ta_config_destroy(iota_client_service_t* const service) { + log_info(logger_id, "Destroying IRI connection\n"); + iota_client_extended_destroy(); + iota_client_core_destroy(service); + + pow_destroy(); + cache_stop(); + logger_helper_release(logger_id); +} diff --git a/accelerator/config.h b/accelerator/config.h index df7475c2..0348f7d9 100644 --- a/accelerator/config.h +++ b/accelerator/config.h @@ -1,33 +1,33 @@ #ifndef ACCELERATOR_CONFIG_H_ #define ACCELERATOR_CONFIG_H_ +#include "accelerator/errors.h" +#include "cclient/api/core/core_api.h" +#include "cclient/api/extended/extended_api.h" +#include "cclient/types/types.h" +#include "utils/cache.h" +#include "utils/pow.h" + #ifdef __cplusplus extern "C" { #endif /** * @file config.h - * @brief Configuration of tangle-acclerator + * @brief Configuration of tangle-accelerator */ -/** @name tangle-accelerator config */ -/** @{ */ -#define TA_HOST "localhost" /**< Binding address of tangle-acclerator */ -#define TA_PORT "8000" /**< Binding port of tangle-acclerator */ -#define TA_THREAD_COUNT 10 /**< Thread count of tangle-acclerator instance */ -/** @} */ - -/** @name IRI connection config */ -/** @{ */ -#define IRI_HOST "localhost" /**< Address of IRI */ -#define IRI_PORT 14265 /**< Port of IRI */ -#define DEPTH 3 /**< Depth of API argument */ -#define MWM 14 /**< Maximum weight magnitude of API argument */ -/** Seed to generate address. This does not do any signature yet. */ +#define TA_VERSION "tangle-accelerator/0.3.0" +#define TA_HOST "localhost" +#define TA_PORT "8000" +#define TA_THREAD_COUNT 10 +#define IRI_HOST "localhost" +#define IRI_PORT 14265 +#define DEPTH 3 +#define MWM 14 #define SEED \ "AMRWQP9BUMJALJHBXUCHOD9HFFD9LGTGEAWMJWWXSDVOF9PI9YGJAPBQLQUOMNYEQCZPGCTHGV" \ "NNAPGHA" -/** @} */ /** @name Redis connection config */ /** @{ */ @@ -35,6 +35,51 @@ extern "C" { #define REDIS_PORT 6379 /**< poer of Redis server */ /** @} */ +/** struct type of accelerator configuration */ +typedef struct ta_info_s { + char* version; /**< Binding version of tangle-accelerator */ + char* host; /**< Binding address of tangle-accelerator */ + char* port; /**< Binding port of tangle-accelerator */ + uint8_t thread_count; /**< Thread count of tangle-accelerator instance */ +} ta_config_t; + +/** struct type of iota configuration */ +typedef struct ta_config_s { + uint8_t depth; /**< Depth of API argument */ + uint8_t mwm; /**< Minimum weight magnitude of API argument */ + /** Seed to generate address. This does not do any signature yet. */ + const char* seed; +} iota_config_t; + +/** struct type of accelerator core */ +typedef struct ta_core_s { + ta_config_t info; /**< accelerator configiuration structure */ + iota_config_t tangle; /**< iota configuration structure */ + iota_client_service_t service; /**< iota connection structure */ +} ta_core_t; + +/** + * Initializes configurations with default values + * Should be called first + * + * @param info[in] Tangle-accelerator configuration variables + * @param tangle[in] iota configuration variables + * @param service[in] IRI connection configuration variables + * + * @return + * - SC_OK on success + * - non-zero on error + */ +status_t ta_config_init(ta_config_t* const info, iota_config_t* const tangle, + iota_client_service_t* const service); + +/** + * Free memory of configuration variables + * + * @param service[in] IRI connection configuration variables + */ +void ta_config_destroy(iota_client_service_t* const service); + #ifdef __cplusplus } #endif diff --git a/accelerator/errors.h b/accelerator/errors.h index 672aa09f..e191e750 100644 --- a/accelerator/errors.h +++ b/accelerator/errors.h @@ -24,10 +24,10 @@ extern "C" { #define SC_SEVERITY_MASK 0x18 #define SC_SEVERITY_SHIFT 3 -#define SC_SEVERITY_MINOR (0x0 << SC_SEVERITY_MASK) -#define SC_SEVERITY_MODERATE (0x01 << SC_SEVERITY_MASK) -#define SC_SEVERITY_MAJOR (0x02 << SC_SEVERITY_MASK) -#define SC_SEVERITY_FATAL (0x03 << SC_SEVERITY_MASK) +#define SC_SEVERITY_MINOR (0x0 << SC_SEVERITY_SHIFT) +#define SC_SEVERITY_MODERATE (0x01 << SC_SEVERITY_SHIFT) +#define SC_SEVERITY_MAJOR (0x02 << SC_SEVERITY_SHIFT) +#define SC_SEVERITY_FATAL (0x03 << SC_SEVERITY_SHIFT) /** @} */ /** @name module code */ @@ -47,16 +47,16 @@ extern "C" { #define SC_ERROR_MASK 0x07 /** @} */ -/** @name http error code */ -/** @{ */ -#define SC_BAD_REQUEST 400 -#define SC_NOT_FOUND 404 -/** @} */ - /* status code */ typedef enum { SC_OK = 0, /**< No error */ + SC_HTTP_OK = 200, /**< HTTP response OK */ + SC_HTTP_BAD_REQUEST = 400, /**< HTTP response, error when parsing request */ + SC_HTTP_NOT_FOUND = 404, /**< HTTP request not found */ + SC_HTTP_INTERNAL_SERVICE_ERROR = 500, + /**< HTTP response, other errors in TA */ + SC_TA_OOM = 0x01 | SC_MODULE_TA | SC_SEVERITY_FATAL, /**< Fail to create TA object */ SC_TA_NULL = 0x02 | SC_MODULE_TA | SC_SEVERITY_FATAL, @@ -65,27 +65,27 @@ typedef enum { // CClient module SC_CCLIENT_OOM = 0x01 | SC_MODULE_CCLIENT | SC_SEVERITY_FATAL, /**< Fail to create cclient object */ - SC_CCLIENT_NOT_FOUND = 0x02 | SC_MODULE_CCLIENT | SC_SEVERITY_FATAL, + SC_CCLIENT_NOT_FOUND = 0x03 | SC_MODULE_CCLIENT | SC_SEVERITY_FATAL, /**< Empty result from cclient */ - SC_CCLIENT_FAILED_RESPONSE = 0x03 | SC_MODULE_CCLIENT | SC_SEVERITY_FATAL, + SC_CCLIENT_FAILED_RESPONSE = 0x04 | SC_MODULE_CCLIENT | SC_SEVERITY_FATAL, /**< Error in cclient response */ - SC_CCLIENT_INVALID_FLEX_TRITS = 0x04 | SC_MODULE_CCLIENT | SC_SEVERITY_MAJOR, + SC_CCLIENT_INVALID_FLEX_TRITS = 0x05 | SC_MODULE_CCLIENT | SC_SEVERITY_MAJOR, /**< flex_trits conversion error */ - SC_CCLIENT_HASH = 0x05 | SC_MODULE_CCLIENT | SC_SEVERITY_MAJOR, + SC_CCLIENT_HASH = 0x06 | SC_MODULE_CCLIENT | SC_SEVERITY_MAJOR, /**< hash container operation error */ // Serializer module SC_SERIALIZER_JSON_CREATE = 0x01 | SC_MODULE_SERIALIZER | SC_SEVERITY_FATAL, /**< Fail to create JSON object in serializer */ - SC_SERIALIZER_JSON_PARSE = 0x02 | SC_MODULE_SERIALIZER | SC_SEVERITY_FATAL, - /**< Fail to parse JSON object in serializer */ - SC_SERIALIZER_NULL = 0x03 | SC_MODULE_SERIALIZER | SC_SEVERITY_FATAL, + SC_SERIALIZER_NULL = 0x02 | SC_MODULE_SERIALIZER | SC_SEVERITY_FATAL, /**< NULL object in serializer */ + SC_SERIALIZER_JSON_PARSE = 0x07 | SC_MODULE_SERIALIZER | SC_SEVERITY_FATAL, + /**< Fail to parse JSON object in serializer */ // Cache module - SC_CACHE_NULL = 0x01 | SC_MODULE_CACHE | SC_SEVERITY_FATAL, + SC_CACHE_NULL = 0x02 | SC_MODULE_CACHE | SC_SEVERITY_FATAL, /**< NULL parameters in cache */ - SC_CACHE_FAILED_RESPONSE = 0x02 | SC_MODULE_CACHE | SC_SEVERITY_FATAL, + SC_CACHE_FAILED_RESPONSE = 0x04 | SC_MODULE_CACHE | SC_SEVERITY_FATAL, /**< Fail in cache operations */ // MAM module @@ -93,10 +93,24 @@ typedef enum { /**< 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, + SC_MAM_NOT_FOUND = 0x03 | SC_MODULE_MAM | SC_SEVERITY_FATAL, + /**< Empty result from mam */ + SC_MAM_FAILED_INIT = 0x04 | SC_MODULE_MAM | SC_SEVERITY_FATAL, + /**< Error in mam initialization */ + SC_MAM_FAILED_RESPONSE = 0x05 | SC_MODULE_MAM | SC_SEVERITY_FATAL, /**< Error in mam response */ + SC_MAM_FAILED_DESTROYED = 0x06 | SC_MODULE_MAM | SC_SEVERITY_FATAL, + /**< Error in mam destroy */ + SC_MAM_NO_PAYLOAD = 0x07 | SC_MODULE_MAM | SC_SEVERITY_FATAL, + /**< No payload or no chid */ } status_t; +typedef enum { + HTTP_METHOD_GET = 0, /**< HTTP GET method */ + HTTP_METHOD_POST = 1, /**< HTTP POST method */ + HTTP_METHOD_OPTIONS = 2, /**< HTTP OPTIONS method */ +} http_method_t; + #ifdef __cplusplus } #endif diff --git a/accelerator/server.cc b/accelerator/server.cc index 485d8e70..7ee9173b 100644 --- a/accelerator/server.cc +++ b/accelerator/server.cc @@ -5,48 +5,78 @@ #include "accelerator/config.h" #include "accelerator/errors.h" #include "cJSON.h" +#include "utils/logger_helper.h" -void set_options_method_header(served::response& res) { +#define MAIN_LOGGER_ID "main" + +static ta_core_t ta_core; +static logger_id_t logger_id; + +void set_method_header(served::response& res, http_method_t method) { + res.set_header("Server", ta_core.info.version); res.set_header("Access-Control-Allow-Origin", "*"); - res.set_header("Access-Control-Allow-Methods", "GET, POST, OPTIONS"); - res.set_header("Access-Control-Allow-Headers", - "Origin, Content-Type, Accept"); - res.set_header("Access-Control-Max-Age", "86400"); + + switch (method) { + case HTTP_METHOD_OPTIONS: + res.set_header("Access-Control-Allow-Methods", "GET, POST, OPTIONS"); + res.set_header("Access-Control-Allow-Headers", + "Origin, Content-Type, Accept"); + res.set_header("Access-Control-Max-Age", "86400"); + break; + default: + res.set_header("Content-Type", "application/json"); + break; + } +} + +status_t set_response_content(status_t ret, char** json_result) { + status_t http_ret; + if (ret == SC_OK) { + return SC_HTTP_OK; + } + + cJSON* json_obj = cJSON_CreateObject(); + if ((ret & SC_ERROR_MASK) == 0x03) { + http_ret = SC_HTTP_NOT_FOUND; + cJSON_AddStringToObject(json_obj, "message", "Request not found"); + } else if ((ret & SC_ERROR_MASK) == 0x07) { + http_ret = SC_HTTP_BAD_REQUEST; + cJSON_AddStringToObject(json_obj, "message", "Invalid request header"); + } else { + http_ret = SC_HTTP_INTERNAL_SERVICE_ERROR; + cJSON_AddStringToObject(json_obj, "message", "Internal service error"); + } + *json_result = cJSON_PrintUnformatted(json_obj); + return http_ret; } int main(int, char const**) { served::multiplexer mux; mux.use_after(served::plugin::access_log); - 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(); + if (logger_helper_init() != RC_OK) { + return EXIT_FAILURE; + } + logger_id = logger_helper_enable(MAIN_LOGGER_ID, LOGGER_DEBUG, true); + + ta_config_init(&ta_core.info, &ta_core.tangle, &ta_core.service); mux.handle("/mam/{bundle:[A-Z9]{81}}") .method(served::method::OPTIONS, [&](served::response& res, const served::request& req) { - set_options_method_header(res); + set_method_header(res, HTTP_METHOD_OPTIONS); }) .get([&](served::response& res, const served::request& req) { + status_t ret = SC_OK; char* json_result = NULL; - api_receive_mam_message(&service, req.params["bundle"].c_str(), - &json_result); + ret = api_receive_mam_message( + &ta_core.service, req.params["bundle"].c_str(), &json_result); + ret = set_response_content(ret, &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; - } + set_method_header(res, HTTP_METHOD_GET); + res.set_status(ret); + res << json_result; }); /** @@ -59,15 +89,17 @@ int main(int, char const**) { mux.handle("/tag/{tag:[A-Z9]{1,27}}/hashes") .method(served::method::OPTIONS, [&](served::response& res, const served::request& req) { - set_options_method_header(res); + set_method_header(res, HTTP_METHOD_OPTIONS); }) .get([&](served::response& res, const served::request& req) { + status_t ret = SC_OK; char* json_result; - api_find_transactions_by_tag(&service, req.params["tag"].c_str(), - &json_result); - res.set_header("Content-Type", "application/json"); - res.set_header("Access-Control-Allow-Origin", "*"); + ret = api_find_transactions_by_tag( + &ta_core.service, req.params["tag"].c_str(), &json_result); + ret = set_response_content(ret, &json_result); + set_method_header(res, HTTP_METHOD_GET); + res.set_status(ret); res << json_result; }); @@ -81,15 +113,17 @@ int main(int, char const**) { mux.handle("/transaction/{tx:[A-Z9]{81}}") .method(served::method::OPTIONS, [&](served::response& res, const served::request& req) { - set_options_method_header(res); + set_method_header(res, HTTP_METHOD_OPTIONS); }) .get([&](served::response& res, const served::request& req) { + status_t ret = SC_OK; char* json_result; - api_get_transaction_object(&service, req.params["tx"].c_str(), - &json_result); - res.set_header("Content-Type", "application/json"); - res.set_header("Access-Control-Allow-Origin", "*"); + ret = api_get_transaction_object( + &ta_core.service, req.params["tx"].c_str(), &json_result); + ret = set_response_content(ret, &json_result); + set_method_header(res, HTTP_METHOD_GET); + res.set_status(ret); res << json_result; }); @@ -103,15 +137,17 @@ int main(int, char const**) { mux.handle("/tag/{tag:[A-Z9]{1,27}}") .method(served::method::OPTIONS, [&](served::response& res, const served::request& req) { - set_options_method_header(res); + set_method_header(res, HTTP_METHOD_OPTIONS); }) .get([&](served::response& res, const served::request& req) { + status_t ret = SC_OK; char* json_result; - api_find_transactions_obj_by_tag(&service, req.params["tag"].c_str(), - &json_result); - res.set_header("Content-Type", "application/json"); - res.set_header("Access-Control-Allow-Origin", "*"); + ret = api_find_transactions_obj_by_tag( + &ta_core.service, req.params["tag"].c_str(), &json_result); + ret = set_response_content(ret, &json_result); + set_method_header(res, HTTP_METHOD_GET); + res.set_status(ret); res << json_result; }); @@ -123,14 +159,17 @@ int main(int, char const**) { mux.handle("/tips/pair") .method(served::method::OPTIONS, [&](served::response& res, const served::request& req) { - set_options_method_header(res); + set_method_header(res, HTTP_METHOD_OPTIONS); }) .get([&](served::response& res, const served::request& req) { + status_t ret = SC_OK; char* json_result; - api_get_tips_pair(&service, &json_result); - res.set_header("Content-Type", "application/json"); - res.set_header("Access-Control-Allow-Origin", "*"); + ret = + api_get_tips_pair(&ta_core.tangle, &ta_core.service, &json_result); + ret = set_response_content(ret, &json_result); + set_method_header(res, HTTP_METHOD_GET); + res.set_status(ret); res << json_result; }); @@ -142,14 +181,16 @@ int main(int, char const**) { mux.handle("/tips") .method(served::method::OPTIONS, [&](served::response& res, const served::request& req) { - set_options_method_header(res); + set_method_header(res, HTTP_METHOD_OPTIONS); }) .get([&](served::response& res, const served::request& req) { + status_t ret = SC_OK; char* json_result; - api_get_tips(&service, &json_result); - res.set_header("Content-Type", "application/json"); - res.set_header("Access-Control-Allow-Origin", "*"); + ret = api_get_tips(&ta_core.service, &json_result); + ret = set_response_content(ret, &json_result); + set_method_header(res, HTTP_METHOD_GET); + res.set_status(ret); res << json_result; }); @@ -161,14 +202,17 @@ int main(int, char const**) { mux.handle("/address") .method(served::method::OPTIONS, [&](served::response& res, const served::request& req) { - set_options_method_header(res); + set_method_header(res, HTTP_METHOD_OPTIONS); }) .get([&](served::response& res, const served::request& req) { + status_t ret = SC_OK; char* json_result; - api_generate_address(&service, &json_result); - res.set_header("Content-Type", "application/json"); - res.set_header("Access-Control-Allow-Origin", "*"); + ret = api_generate_address(&ta_core.tangle, &ta_core.service, + &json_result); + ret = set_response_content(ret, &json_result); + set_method_header(res, HTTP_METHOD_GET); + res.set_status(ret); res << json_result; }); @@ -180,9 +224,10 @@ int main(int, char const**) { mux.handle("/transaction") .method(served::method::OPTIONS, [&](served::response& res, const served::request& req) { - set_options_method_header(res); + set_method_header(res, HTTP_METHOD_OPTIONS); }) .post([&](served::response& res, const served::request& req) { + status_t ret = SC_OK; char* json_result; if (req.header("content-type").find("application/json") == @@ -192,14 +237,16 @@ int main(int, char const**) { "Invalid request header"); json_result = cJSON_PrintUnformatted(json_obj); - res.set_status(SC_BAD_REQUEST); + res.set_status(SC_HTTP_BAD_REQUEST); cJSON_Delete(json_obj); } else { - api_send_transfer(&service, req.body().c_str(), &json_result); + ret = api_send_transfer(&ta_core.tangle, &ta_core.service, + req.body().c_str(), &json_result); + ret = set_response_content(ret, &json_result); + res.set_status(ret); } - res.set_header("Content-Type", "application/json"); - res.set_header("Access-Control-Allow-Origin", "*"); + set_method_header(res, HTTP_METHOD_POST); res << json_result; }); @@ -212,26 +259,28 @@ int main(int, char const**) { mux.handle("{*}") .method(served::method::OPTIONS, [&](served::response& res, const served::request& req) { - set_options_method_header(res); + set_method_header(res, HTTP_METHOD_OPTIONS); }) .get([](served::response& res, const served::request&) { cJSON* json_obj = cJSON_CreateObject(); cJSON_AddStringToObject(json_obj, "message", "Invalid path"); const char* json = cJSON_PrintUnformatted(json_obj); - res.set_status(SC_BAD_REQUEST); - res.set_header("Content-Type", "application/json"); - res.set_header("Access-Control-Allow-Origin", "*"); + res.set_status(SC_HTTP_BAD_REQUEST); + set_method_header(res, HTTP_METHOD_GET); res << json; cJSON_Delete(json_obj); }); std::cout << "Starting..." << std::endl; - served::net::server server(TA_HOST, TA_PORT, mux); - server.run(TA_THREAD_COUNT); + served::net::server server(ta_core.info.host, ta_core.info.port, mux); + server.run(ta_core.info.thread_count); - iota_client_extended_destroy(); - iota_client_core_destroy(&service); + ta_config_destroy(&ta_core.service); + logger_helper_release(logger_id); + if (logger_helper_destroy() != RC_OK) { + return EXIT_FAILURE; + } return 0; } diff --git a/response/ta_get_transaction_object.c b/response/ta_get_transaction_object.c index 56969e49..fb435fc6 100644 --- a/response/ta_get_transaction_object.c +++ b/response/ta_get_transaction_object.c @@ -11,11 +11,13 @@ ta_get_transaction_object_res_t* ta_get_transaction_object_res_new() { } void ta_get_transaction_object_res_free(ta_get_transaction_object_res_t** res) { - if (!res || !(*res) || !(*res)->txn) { + if (!res || !(*res)) { return; } - transaction_free((*res)->txn); + if ((*res)->txn) { + transaction_free((*res)->txn); + } free(*res); *res = NULL; } diff --git a/serializer/serializer.c b/serializer/serializer.c index 6dd26114..fb38b94d 100644 --- a/serializer/serializer.c +++ b/serializer/serializer.c @@ -386,3 +386,24 @@ status_t ta_find_transactions_obj_res_serialize( cJSON_Delete(json_root); return ret; } + +status_t receive_mam_message_serialize(char** obj, const char** res) { + status_t ret = SC_OK; + cJSON* json_root = cJSON_CreateObject(); + if (json_root == NULL) { + ret = SC_SERIALIZER_JSON_CREATE; + goto done; + } + + cJSON_AddStringToObject(json_root, "message", *res); + + *obj = cJSON_PrintUnformatted(json_root); + if (*obj == NULL) { + ret = SC_SERIALIZER_JSON_PARSE; + goto done; + } + +done: + cJSON_Delete(json_root); + return ret; +} diff --git a/serializer/serializer.h b/serializer/serializer.h index abc578f4..bca7d18e 100644 --- a/serializer/serializer.h +++ b/serializer/serializer.h @@ -111,6 +111,17 @@ status_t ta_find_transactions_res_serialize( status_t ta_find_transactions_obj_res_serialize( char** obj, const ta_find_transactions_obj_res_t* const res); +/** + * @brief Serialize mam message + * + * @param[out] obj message formed in JSON + * @param[in] res Response of payload message + * + * @return + * - SC_OK on success + * - non-zero on error + */ +status_t receive_mam_message_serialize(char** obj, const char** res); #ifdef __cplusplus } #endif diff --git a/tests/BUILD b/tests/BUILD index abc6e349..95c38883 100644 --- a/tests/BUILD +++ b/tests/BUILD @@ -86,7 +86,7 @@ cc_library( name = "test_define", hdrs = ["test_define.h"], deps = [ - "@entangled//cclient/types", + "//accelerator:ta_config", "@unity", ], ) diff --git a/tests/driver.c b/tests/driver.c index 9580701d..c7e2183e 100644 --- a/tests/driver.c +++ b/tests/driver.c @@ -2,7 +2,7 @@ #include "accelerator/apis.h" #include "test_define.h" -iota_client_service_t service; +static ta_core_t ta_core; struct timespec start_time, end_time; #if defined(ENABLE_STAT) @@ -23,21 +23,31 @@ double diff_time(struct timespec start, struct timespec end) { return (diff.tv_sec + diff.tv_nsec / 1000000000.0); } +void test_time_start(struct timespec* start) { + clock_gettime(CLOCK_REALTIME, start); +} + +void test_time_end(struct timespec* start, struct timespec* end, double* sum) { + clock_gettime(CLOCK_REALTIME, end); + double difference = diff_time(*start, *end); +#if defined(ENABLE_STAT) + printf("%lf\n", difference); +#endif + *sum += difference; +} + void test_generate_address(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_generate_address(&service, &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); + test_time_start(&start_time); + TEST_ASSERT_FALSE( + api_generate_address(&ta_core.tangle, &ta_core.service, &json_result)); + test_time_end(&start_time, &end_time, &sum); + free(json_result); } printf("Average time of generate_address: %lf\n", sum / TEST_COUNT); - free(json_result); } void test_get_tips_pair(void) { @@ -45,16 +55,13 @@ void test_get_tips_pair(void) { double sum = 0; for (size_t count = 0; count < TEST_COUNT; count++) { - clock_gettime(CLOCK_REALTIME, &start_time); - TEST_ASSERT_FALSE(api_get_tips_pair(&service, &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); + test_time_start(&start_time); + TEST_ASSERT_FALSE( + api_get_tips_pair(&ta_core.tangle, &ta_core.service, &json_result)); + test_time_end(&start_time, &end_time, &sum); + free(json_result); } printf("Average time of get_tips_pair: %lf\n", sum / TEST_COUNT); - free(json_result); } void test_get_tips(void) { @@ -62,16 +69,12 @@ void test_get_tips(void) { double sum = 0; for (size_t count = 0; count < TEST_COUNT; count++) { - clock_gettime(CLOCK_REALTIME, &start_time); - TEST_ASSERT_FALSE(api_get_tips(&service, &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); + test_time_start(&start_time); + TEST_ASSERT_FALSE(api_get_tips(&ta_core.service, &json_result)); + test_time_end(&start_time, &end_time, &sum); + free(json_result); } printf("Average time of get_tips: %lf\n", sum / TEST_COUNT); - free(json_result); } void test_send_transfer(void) { @@ -84,35 +87,27 @@ void test_send_transfer(void) { double sum = 0; for (size_t count = 0; count < TEST_COUNT; count++) { - clock_gettime(CLOCK_REALTIME, &start_time); - TEST_ASSERT_FALSE(api_send_transfer(&service, json, &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); + test_time_start(&start_time); + TEST_ASSERT_FALSE(api_send_transfer(&ta_core.tangle, &ta_core.service, json, + &json_result)); + test_time_end(&start_time, &end_time, &sum); + free(json_result); } printf("Average time of send_transfer: %lf\n", sum / TEST_COUNT); - free(json_result); } void test_get_transaction_object(void) { char* json_result; double sum = 0; - clock_gettime(CLOCK_REALTIME, &start_time); for (size_t count = 0; count < TEST_COUNT; count++) { - clock_gettime(CLOCK_REALTIME, &start_time); - TEST_ASSERT_FALSE( - api_get_transaction_object(&service, TRYTES_81_1, &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); + test_time_start(&start_time); + TEST_ASSERT_FALSE(api_get_transaction_object(&ta_core.service, TRYTES_81_3, + &json_result)); + test_time_end(&start_time, &end_time, &sum); + free(json_result); } printf("Average time of get_transaction_object: %lf\n", sum / TEST_COUNT); - free(json_result); } void test_find_transactions_by_tag(void) { @@ -120,17 +115,13 @@ void test_find_transactions_by_tag(void) { double sum = 0; for (size_t count = 0; count < TEST_COUNT; count++) { - clock_gettime(CLOCK_REALTIME, &start_time); - TEST_ASSERT_FALSE( - api_find_transactions_by_tag(&service, TAG_MSG, &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); + test_time_start(&start_time); + TEST_ASSERT_FALSE(api_find_transactions_by_tag(&ta_core.service, + FIND_TAG_MSG, &json_result)); + test_time_end(&start_time, &end_time, &sum); + free(json_result); } printf("Average time of find_transactions_by_tag: %lf\n", sum / TEST_COUNT); - free(json_result); } void test_find_transactions_obj_by_tag(void) { @@ -138,45 +129,34 @@ void test_find_transactions_obj_by_tag(void) { double sum = 0; for (size_t count = 0; count < TEST_COUNT; count++) { - clock_gettime(CLOCK_REALTIME, &start_time); - TEST_ASSERT_FALSE( - api_find_transactions_obj_by_tag(&service, TAG_MSG, &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); + test_time_start(&start_time); + TEST_ASSERT_FALSE(api_find_transactions_obj_by_tag( + &ta_core.service, FIND_TAG_MSG, &json_result)); + test_time_end(&start_time, &end_time, &sum); + free(json_result); } printf("Average time of find_tx_obj_by_tag: %lf\n", sum / TEST_COUNT); - free(json_result); } void test_receive_mam_message(void) { char* json_result; double sum = 0; - + status_t ret = SC_OK; 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)); + ret = api_receive_mam_message(&ta_core.service, TEST_BUNDLE_HASH, + &json_result); + TEST_ASSERT_EQUAL_INT32(ret, SC_OK); 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); + free(json_result); } printf("Average time of receive_mam_message: %lf\n", sum / TEST_COUNT); - free(json_result); } int main(void) { UNITY_BEGIN(); - service.http.path = "/"; - 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); + + ta_config_init(&ta_core.info, &ta_core.tangle, &ta_core.service); printf("Total samples for each API test: %d\n", TEST_COUNT); RUN_TEST(test_generate_address); @@ -187,6 +167,6 @@ int main(void) { 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); + ta_config_destroy(&ta_core.service); return UNITY_END(); } diff --git a/tests/iota_api_mock.cc b/tests/iota_api_mock.cc index ae3ea4c1..b6e3c37d 100644 --- a/tests/iota_api_mock.cc +++ b/tests/iota_api_mock.cc @@ -41,7 +41,7 @@ retcode_t iota_client_find_transactions( 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) { + 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; @@ -77,7 +77,8 @@ retcode_t iota_client_get_trytes(const iota_client_service_t* const service, return APIMockObj.iota_client_get_trytes(service, req, res); } -status_t ta_send_trytes(const iota_client_service_t* const service, +status_t ta_send_trytes(const iota_config_t* const tangle, + const iota_client_service_t* const service, hash8019_array_p trytes) { - return APIMockObj.ta_send_trytes(service, trytes); + return APIMockObj.ta_send_trytes(tangle, service, trytes); } diff --git a/tests/iota_api_mock.hh b/tests/iota_api_mock.hh index ac59aef9..e8e3ffe0 100644 --- a/tests/iota_api_mock.hh +++ b/tests/iota_api_mock.hh @@ -29,7 +29,7 @@ class IotaAPI { } 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) { + const find_transactions_req_t* const req, transaction_array_t* tx_objs) { return RC_OK; } virtual retcode_t iota_client_get_new_address( @@ -42,7 +42,8 @@ class IotaAPI { get_trytes_res_t* res) { return RC_OK; } - virtual status_t ta_send_trytes(const iota_client_service_t* const service, + virtual status_t ta_send_trytes(const iota_config_t* const tangle, + const iota_client_service_t* const service, hash8019_array_p trytes) { return SC_OK; } @@ -70,7 +71,7 @@ class APIMock : public IotaAPI { 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)); + 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, @@ -79,7 +80,8 @@ class APIMock : public IotaAPI { MOCK_METHOD3(iota_client_get_trytes, retcode_t(const iota_client_service_t* const service, get_trytes_req_t* const req, get_trytes_res_t* res)); - MOCK_METHOD2(ta_send_trytes, - status_t(const iota_client_service_t* const service, + MOCK_METHOD3(ta_send_trytes, + status_t(const iota_config_t* const tangle, + const iota_client_service_t* const service, hash8019_array_p trytes)); }; diff --git a/tests/test_cache.c b/tests/test_cache.c index 9b79c027..daaf6c88 100644 --- a/tests/test_cache.c +++ b/tests/test_cache.c @@ -2,35 +2,30 @@ #include "utils/cache.h" void test_cache_del(void) { - cache_t* cache = cache_init(); const char* key = TRYTES_81_1; - cache_del(cache, key); - cache_stop(&cache); + cache_del(key); } void test_cache_get(void) { - cache_t* cache = cache_init(); const char* key = TRYTES_81_1; char res[TRYTES_2673_LEN + 1] = {0}; - cache_get(cache, key, res); + cache_get(key, res); res[TRYTES_2673_LEN] = '\0'; TEST_ASSERT_EQUAL_STRING(res, TRYTES_2673_1); - cache_stop(&cache); } void test_cache_set(void) { - cache_t* cache = cache_init(); const char* key = TRYTES_81_1; const char* value = TRYTES_2673_1; - cache_set(cache, key, value); - cache_stop(&cache); + cache_set(key, value); } int main(void) { UNITY_BEGIN(); - + cache_init(REDIS_HOST, REDIS_PORT); RUN_TEST(test_cache_set); RUN_TEST(test_cache_get); RUN_TEST(test_cache_del); + cache_stop(); return UNITY_END(); } diff --git a/tests/test_common.cc b/tests/test_common.cc index 9e276721..b5e44f3c 100644 --- a/tests/test_common.cc +++ b/tests/test_common.cc @@ -8,6 +8,7 @@ using ::testing::AtLeast; using ::testing::ElementsAreArray; APIMock APIMockObj; +iota_config_t tangle; iota_client_service_t service; TEST(GetTxnToApproveTest, TrunkBranchHashTest) { @@ -24,7 +25,7 @@ TEST(GetTxnToApproveTest, TrunkBranchHashTest) { EXPECT_CALL(APIMockObj, iota_client_get_transactions_to_approve(_, _, _)) .Times(AtLeast(1)); - EXPECT_EQ(cclient_get_txn_to_approve(&service, res), 0); + EXPECT_EQ(cclient_get_txn_to_approve(&service, 3, res), 0); EXPECT_FALSE(memcmp(res->tips->hash, hash_trits_1, sizeof(flex_trit_t) * FLEX_TRIT_SIZE_243)); hash243_stack_pop(&res->tips); @@ -72,6 +73,7 @@ TEST(FindTxnTest, TxnHashTest) { } TEST(GenAdressTest, GetNewAddressTest) { + tangle.seed = SEED; hash243_queue_entry_t* q_iter = NULL; ta_generate_address_res_t* res = ta_generate_address_res_new(); flex_trit_t hash_trits_1[FLEX_TRIT_SIZE_243]; @@ -82,7 +84,7 @@ TEST(GenAdressTest, GetNewAddressTest) { EXPECT_CALL(APIMockObj, iota_client_get_new_address(_, _, _, _)) .Times(AtLeast(1)); - EXPECT_EQ(ta_generate_address(&service, res), 0); + EXPECT_EQ(ta_generate_address(&tangle, &service, res), 0); CDL_FOREACH(res->addresses, q_iter) { EXPECT_FALSE(memcmp(q_iter->hash, hash_trits_1, sizeof(flex_trit_t) * FLEX_TRIT_SIZE_243)); @@ -154,11 +156,11 @@ TEST(SendTransferTest, SendTransferTest) { flex_trits_slice(req->message, req->msg_len, msg_trits, req->msg_len, 0, req->msg_len); - EXPECT_CALL(APIMockObj, ta_send_trytes(_, _)).Times(AtLeast(1)); + EXPECT_CALL(APIMockObj, ta_send_trytes(_, _, _)).Times(AtLeast(1)); EXPECT_CALL(APIMockObj, iota_client_find_transactions(_, _, _)) .Times(AtLeast(1)); - EXPECT_EQ(ta_send_transfer(&service, req, res), 0); + EXPECT_EQ(ta_send_transfer(&tangle, &service, req, res), 0); txn_hash = hash243_queue_peek(res->hash); EXPECT_FALSE( memcmp(txn_hash, hash_trits_1, sizeof(flex_trit_t) * FLEX_TRIT_SIZE_243)); @@ -192,6 +194,8 @@ TEST(GetBundleTest, RetreiveBundleTest) { } int main(int argc, char** argv) { + // GTest manage to cleanup after testing, so only need to initialize here + cache_init(REDIS_HOST, REDIS_PORT); ::testing::GTEST_FLAG(throw_on_failure) = true; ::testing::InitGoogleMock(&argc, argv); return RUN_ALL_TESTS(); diff --git a/tests/test_define.h b/tests/test_define.h index 86674d14..cd9995a2 100644 --- a/tests/test_define.h +++ b/tests/test_define.h @@ -2,7 +2,7 @@ #define TESTS_TEST_DEFINE_H_ #include -#include "cclient/types/types.h" +#include "accelerator/config.h" #ifdef __cplusplus extern "C" { @@ -17,10 +17,14 @@ extern "C" { #define TRYTES_81_2 \ "RVORZ9SIIP9RCYMREUIXXVPQIPHVCNPQ9HZWYKFWYWZRE9JQKG9REPKIASHUUECPSQO9JT9XNM" \ "VKWYGVA" +#define TRYTES_81_3 \ + "FPPBU9AOXZHSJEWDCPWGCPKGOVIUWWPDTIIXDJUKYYNNPTWCGDWFBZLKVCLOKGYEHJUMABSTA9" \ + "OP99999" #define BUNDLE_HASH \ "LVXEVZABVCIFEDSCONKEVEYBSIRMXGHLJDKSKQHTKZC9ULEAPSLKOOWCCZJGWSIISDDSEVUQHV" \ "GPFOSIW" #define TAG_MSG "TANGLEACCELERATOR9999999999" +#define FIND_TAG_MSG "TAFINDTXN999999999999999999" #define TAG_MSG_LEN 27 #define VALUE 100 #define TIMESTAMP 1546436542 @@ -102,6 +106,13 @@ extern "C" { "999999999999999999999999999999999999999999999999999999999999999999999999" \ "999999999999999999999999999" +#define TEST_BUNDLE_HASH \ + "QBFXQETKSHDYPFUDO9ILVCAVQIXOHXKCECZYFLPBNVIX9JUXQZJE9URQEEUWPWYZOIACTCGZX9" \ + "IDIODCA " +#define TEST_CHID \ + "WYEVIWJN9DF9SBQHBUWYUECD9KD9BQHQXHOGQDTVKKYBRQUFQYGOFOTHREGVSKSSEVXMFOEHWN" \ + "KHLHDKQ" + #ifdef __cplusplus } #endif diff --git a/third_party/dcurl b/third_party/dcurl index e5bbddde..778dcdbf 160000 --- a/third_party/dcurl +++ b/third_party/dcurl @@ -1 +1 @@ -Subproject commit e5bbdddeec33504bbfd2c649b2c4c85d233f0fd6 +Subproject commit 778dcdbf40967ff957415e81b5a207567cca5985 diff --git a/utils/BUILD b/utils/BUILD index 857158c9..eac468e1 100644 --- a/utils/BUILD +++ b/utils/BUILD @@ -5,7 +5,6 @@ cc_library( srcs = ["backend_redis.c"], hdrs = ["cache.h"], deps = [ - "//accelerator:ta_config", "//accelerator:ta_errors", "//third_party:hiredis", "@entangled//cclient/types", @@ -17,7 +16,6 @@ cc_library( srcs = ["pow.c"], hdrs = ["pow.h"], deps = [ - "//accelerator:ta_config", "//accelerator:ta_errors", "//third_party:dcurl", "@entangled//cclient/types", diff --git a/utils/backend_redis.c b/utils/backend_redis.c index a57aea99..49acce38 100644 --- a/utils/backend_redis.c +++ b/utils/backend_redis.c @@ -1,4 +1,3 @@ -#include "accelerator/config.h" #include "cache.h" #include "third_party/hiredis/hiredis.h" @@ -6,7 +5,9 @@ typedef struct { redisContext* rc; } connection_private; -#define CONN(c) ((connection_private*)(c->conn)) +#define CONN(c) ((connection_private*)(c.conn)) + +static cache_t cache; /* * Private functions @@ -68,39 +69,33 @@ static status_t redis_set(redisContext* c, const char* const key, * Public functions */ -cache_t* cache_init() { - cache_t* cache = (cache_t*)malloc(sizeof(cache_t)); - if (cache != NULL) { - cache->conn = (connection_private*)malloc(sizeof(connection_private)); - CONN(cache)->rc = redisConnect(REDIS_HOST, REDIS_PORT); - return cache; +bool cache_init(const char* host, int port) { + cache.conn = (connection_private*)malloc(sizeof(connection_private)); + CONN(cache)->rc = redisConnect(host, port); + if (CONN(cache)->rc) { + return true; } - return NULL; + return false; } -void cache_stop(cache_t** cache) { - if (*cache) { - redisFree(CONN((*cache))->rc); +void cache_stop() { + if (CONN(cache)->rc) { + redisFree(CONN(cache)->rc); - if (CONN((*cache))) { - free(CONN((*cache))); + if (CONN(cache)) { + free(CONN(cache)); } - - free(*cache); - *cache = NULL; } } -status_t cache_del(const cache_t* const cache, const char* const key) { +status_t cache_del(const char* const key) { return redis_del(CONN(cache)->rc, key); } -status_t cache_get(const cache_t* const cache, const char* const key, - char* res) { +status_t cache_get(const char* const key, char* res) { return redis_get(CONN(cache)->rc, key, res); } -status_t cache_set(const cache_t* const cache, const char* const key, - const char* const value) { +status_t cache_set(const char* const key, const char* const value) { return redis_set(CONN(cache)->rc, key, value); } diff --git a/utils/cache.h b/utils/cache.h index 198bc9b7..52744c30 100644 --- a/utils/cache.h +++ b/utils/cache.h @@ -8,6 +8,10 @@ #include "accelerator/errors.h" #include "cclient/types/types.h" +#ifdef __cplusplus +extern "C" { +#endif + /** * @file cache.h * @brief Implementation of cache interface @@ -24,46 +28,44 @@ typedef struct { /** * Initiate cache module * + * @param[in] host cache server host + * @param[in] port cache server port + * * @return - * - struct of cache_t on success - * - NULL on error + * - True on success + * - False on error */ -cache_t* cache_init(); +bool cache_init(const char* host, int port); /** * Stop interacting with cache module * - * @param cache Data type for Cache module - * * @return NULL */ -void cache_stop(cache_t** cache); +void cache_stop(); /** * Delete certain key-value store from cache * - * @param[in] cache Data type for Cache module * @param[in] key Key string to search * * @return * - SC_OK on success - * - 1 on error + * - non-zero on error */ -status_t cache_del(const cache_t* const cache, const char* const key); +status_t cache_del(const char* const key); /** * Get key-value store from in-memory cache * - * @param[in] cache Data type for Cache module * @param[in] key Key string to search * @param[out] res Result of GET key * * @return * - SC_OK on success - * - 1 on error + * - non-zero on error */ -status_t cache_get(const cache_t* const cache, const char* const key, - char* res); +status_t cache_get(const char* const key, char* res); /** * Set key-value store into in-memory cache @@ -74,10 +76,9 @@ status_t cache_get(const cache_t* const cache, const char* const key, * * @return * - SC_OK on success - * - 1 on error + * - non-zero on error */ -status_t cache_set(const cache_t* const cache, const char* const key, - const char* const value); +status_t cache_set(const char* const key, const char* const value); #ifdef __cplusplus } diff --git a/utils/pow.c b/utils/pow.c index f5f27334..373ad324 100644 --- a/utils/pow.c +++ b/utils/pow.c @@ -39,12 +39,17 @@ flex_trit_t* ta_pow_flex(const flex_trit_t* const trits_in, const uint8_t mwm) { status_t ta_pow(const bundle_transactions_t* bundle, const flex_trit_t* const trunk, const flex_trit_t* const branch, const uint8_t mwm) { + status_t ret = SC_OK; iota_transaction_t* tx; flex_trit_t* ctrunk = (flex_trit_t*)calloc(FLEX_TRIT_SIZE_243, sizeof(flex_trit_t)); size_t cur_idx = 0; tx = (iota_transaction_t*)utarray_front(bundle); + if (tx == NULL) { + ret = SC_TA_NULL; + goto done; + } cur_idx = transaction_last_index(tx) + 1; memcpy(ctrunk, trunk, FLEX_TRIT_SIZE_243); @@ -60,13 +65,15 @@ status_t ta_pow(const bundle_transactions_t* bundle, flex_trit_t* tx_trits = transaction_serialize(tx); if (tx_trits == NULL) { - return SC_CCLIENT_INVALID_FLEX_TRITS; + ret = SC_CCLIENT_INVALID_FLEX_TRITS; + goto done; } // get nonce flex_trit_t* nonce = ta_pow_flex(tx_trits, mwm); if (nonce == NULL) { - return SC_TA_OOM; + ret = SC_TA_OOM; + goto done; } transaction_set_nonce(tx, nonce); @@ -76,6 +83,7 @@ status_t ta_pow(const bundle_transactions_t* bundle, free(tx_trits); } while (cur_idx != 0); +done: free(ctrunk); - return SC_OK; + return ret; }