From cf02108576fae73549ce8a46abd6e72d9d0e3b08 Mon Sep 17 00:00:00 2001 From: Chalith Desaman Date: Mon, 18 Jan 2021 14:38:39 +0530 Subject: [PATCH] Interface to read patch config from c contract lib. (#223) --- examples/c_contract/echo_contract.c | 35 ++-- examples/c_contract/hotpocket_contract.h | 171 +++++++++++++------- examples/nodejs_contract/echo_contract.js | 9 ++ examples/nodejs_contract/hp-contract-lib.js | 24 +-- 4 files changed, 154 insertions(+), 85 deletions(-) diff --git a/examples/c_contract/echo_contract.c b/examples/c_contract/echo_contract.c index c1aa24f6..3d122bd9 100644 --- a/examples/c_contract/echo_contract.c +++ b/examples/c_contract/echo_contract.c @@ -53,14 +53,29 @@ int main(int argc, char **argv) // printf("Received %.*s from %.*s", len, msg, HP_KEY_SIZE, sender); // free(msg); - // Patch file update. - // struct patch_config patch = {}; - // patch.version = "2.0"; - // struct hp_unl_node unl[1] = {"ed65aac94e7287d461540523b8ce43b873fc97398bef1b42350feac72ad360b7f3"}; - // patch.unl.list = unl; - // patch.unl.count = 1; - // patch.roundtime = 1000; - // hp_update_config(&patch); + // // Test code segment - Config file will be updated with below values. + // struct hp_config config = {}; + // config.version = "2.0"; + // config.consensus = "public"; + // config.npl = "public"; + // config.appbill.bin_args = "123"; + // struct hp_unl_node unl[1] = {"ed726f9f536904b125bdca10bbdd1e66591b274799b92ac8bcfc75bf45d7da4c0f"}; + // config.unl.list = unl; + // config.unl.count = 1; + // config.roundtime = 1000; + // hp_update_config(&config); + + // // Test code segment - Get current config file values. + // struct hp_config *current_config = hp_get_config(); + // if (current_config != NULL) + // { + // printf("\"version\": \"%s\"\n", current_config->version); + // printf("\"consensus\": \"%s\"\n", current_config->consensus); + // printf("\"npl\": \"%s\"\n", current_config->npl); + // printf("\"appbill_bin_args\": \"%s\"\n", current_config->appbill.bin_args); + // } + // // Returned hp_config struct memory should be freed after it's been used. + // hp_free_config(current_config); hp_deinit_user_input_mmap(); hp_deinit_contract(); @@ -69,13 +84,13 @@ int main(int argc, char **argv) void store_timestamp(const uint64_t timestamp) { - int fd = open("exects.txt", O_RDWR | O_CREAT | O_APPEND); + int fd = open("exects.txt", O_RDWR | O_CREAT | O_APPEND, 0644); if (fd > 0) { char tsbuf[20]; memset(tsbuf, 0, 20); sprintf(tsbuf, "%lu\n", timestamp); - struct iovec vec[2] = {{(void *)"ts:", 4}, {(void *)tsbuf, 20}}; + struct iovec vec[2] = {{(void *)"ts:", 3}, {(void *)tsbuf, strlen(tsbuf)}}; writev(fd, vec, 2); close(fd); } diff --git a/examples/c_contract/hotpocket_contract.h b/examples/c_contract/hotpocket_contract.h index c0f6118f..2214ee09 100644 --- a/examples/c_contract/hotpocket_contract.h +++ b/examples/c_contract/hotpocket_contract.h @@ -81,30 +81,26 @@ ptr = NULL; \ } -#define __HP_UPDATE_CONFIG_ERROR(msg) \ - { \ - fprintf(stderr, "%s\n", msg); \ - if (fd) \ - close(fd); \ - \ - if (root) \ - __HP_FREE(root); \ - \ - if (config) \ - __hp_free_patch_config(&existing_patch); \ - \ - return -1; \ +#define __HP_UPDATE_CONFIG_ERROR(msg) \ + { \ + fprintf(stderr, "%s\n", msg); \ + if (fd) \ + close(fd); \ + if (config) \ + __hp_free_patch_config(existing_patch); \ + \ + return -1; \ } /** - * dest - Pointer to destination pointer. + * dest - Destination pointer. * src - Source pointer. */ #define __HP_STRING_COPY(dest, src) \ { \ - __HP_FREE(*dest); \ - *dest = (char *)malloc(strlen(src) + 1); \ - memcpy(*dest, src, strlen(src) + 1); \ + __HP_FREE(dest); \ + dest = (char *)malloc(strlen(src) + 1); \ + memcpy(dest, src, strlen(src) + 1); \ } struct hp_user_input @@ -153,7 +149,7 @@ struct hp_appbill_config char *bin_args; }; -struct patch_config +struct hp_config { char *version; struct hp_unl_collection unl; @@ -195,13 +191,16 @@ int hp_writev_user_msg(const struct hp_user *user, const struct iovec *bufs, con int hp_write_npl_msg(const void *buf, const uint32_t len); int hp_writev_npl_msg(const struct iovec *bufs, const int buf_count); int hp_read_npl_msg(void *msg_buf, char *pubkey_buf, const int timeout); -int hp_update_config(const struct patch_config *config); +int hp_update_config(const struct hp_config *config); +struct hp_config *hp_get_config(); +void hp_free_config(struct hp_config *config); void __hp_parse_args_json(const struct json_object_s *object); int __hp_write_control_msg(const void *buf, const uint32_t len); -void __hp_populate_patch_from_json_object(struct patch_config *config, struct json_object_s *object); -int __hp_write_to_patch_file(const int fd, const struct patch_config *config); -void __hp_free_patch_config(struct patch_config *patch_config); +void __hp_populate_patch_from_json_object(struct hp_config *config, const struct json_object_s *object); +int __hp_write_to_patch_file(const int fd, const struct hp_config *config); +struct hp_config *__hp_read_from_patch_file(const int fd); +void __hp_free_patch_config(struct hp_config *patch_config); static struct __hp_contract __hpc = {}; @@ -438,18 +437,16 @@ int hp_read_npl_msg(void *msg_buf, char *pubkey_buf, const int timeout) } /** - * Update the params of the existing patch file. - * @param config Pointer to the updated patch config struct. + * Update the params of the existing config file. + * @param config Pointer to the updated config struct. */ -int hp_update_config(const struct patch_config *config) +int hp_update_config(const struct hp_config *config) { struct hp_contract_context *cctx = __hpc.cctx; - struct json_value_s *root = NULL; - struct patch_config existing_patch = {}; if (cctx->readonly) { - fprintf(stderr, "Config update not allowed in readonly mode."); + fprintf(stderr, "Config update not allowed in readonly mode.\n"); return -1; } const int fd = open(PATCH_FILE_PATH, O_RDWR); @@ -458,23 +455,15 @@ int hp_update_config(const struct patch_config *config) fprintf(stderr, "Error opening patch.cfg file.\n"); return -1; } - char buf[4096]; - const size_t len = read(fd, buf, sizeof(buf)); - if (len == -1) - { - __HP_UPDATE_CONFIG_ERROR("Error when reading stdin."); - } - root = json_parse(buf, len); - if (root && root->type == json_type_object) + struct hp_config *existing_patch = __hp_read_from_patch_file(fd); + if (existing_patch != NULL) { - struct json_object_s *object = (struct json_object_s *)root->payload; - __hp_populate_patch_from_json_object(&existing_patch, object); if (config->version) { if (strlen(config->version) != 0) { - __HP_STRING_COPY(&existing_patch.version, config->version); + __HP_STRING_COPY(existing_patch->version, config->version); } else { @@ -511,20 +500,20 @@ int hp_update_config(const struct patch_config *config) } } } - __HP_FREE(existing_patch.unl.list); - existing_patch.unl.list = config->unl.count ? (struct hp_unl_node *)malloc(sizeof(struct hp_unl_node) * config->unl.count) : NULL; - memcpy(existing_patch.unl.list, config->unl.list, sizeof(struct hp_unl_node) * config->unl.count); - existing_patch.unl.count = config->unl.count; + __HP_FREE(existing_patch->unl.list); + existing_patch->unl.list = config->unl.count ? (struct hp_unl_node *)malloc(sizeof(struct hp_unl_node) * config->unl.count) : NULL; + memcpy(existing_patch->unl.list, config->unl.list, sizeof(struct hp_unl_node) * config->unl.count); + existing_patch->unl.count = config->unl.count; } if (config->bin_path) - __HP_STRING_COPY(&existing_patch.bin_path, config->bin_path); + __HP_STRING_COPY(existing_patch->bin_path, config->bin_path); if (config->bin_args) - __HP_STRING_COPY(&existing_patch.bin_args, config->bin_args); + __HP_STRING_COPY(existing_patch->bin_args, config->bin_args); - if (config->roundtime) - existing_patch.roundtime = config->roundtime; + // if (config->roundtime) + // existing_patch->roundtime = config->roundtime; if (config->consensus) { @@ -532,7 +521,7 @@ int hp_update_config(const struct patch_config *config) { __HP_UPDATE_CONFIG_ERROR("Invalid consensus flag. Valid values: public|private"); } - __HP_STRING_COPY(&existing_patch.consensus, config->consensus); + __HP_STRING_COPY(existing_patch->consensus, config->consensus); } if (config->npl) @@ -541,32 +530,97 @@ int hp_update_config(const struct patch_config *config) { __HP_UPDATE_CONFIG_ERROR("Invalid npl flag. Valid values: public|private"); } - __HP_STRING_COPY(&existing_patch.npl, config->npl); + __HP_STRING_COPY(existing_patch->npl, config->npl); } if (config->appbill.mode) - __HP_STRING_COPY(&existing_patch.appbill.mode, config->appbill.mode); + __HP_STRING_COPY(existing_patch->appbill.mode, config->appbill.mode); if (config->appbill.bin_args) - __HP_STRING_COPY(&existing_patch.appbill.bin_args, config->appbill.bin_args); + __HP_STRING_COPY(existing_patch->appbill.bin_args, config->appbill.bin_args); - if (__hp_write_to_patch_file(fd, &existing_patch) == -1) + if (__hp_write_to_patch_file(fd, existing_patch) == -1) __HP_UPDATE_CONFIG_ERROR("Error writing updated config to patch.cfg file."); - __hp_free_patch_config(&existing_patch); + __hp_free_patch_config(existing_patch); + } + else + { + fprintf(stderr, "Error reading patch.cfg file.\n"); + close(fd); + return -1; } - close(fd); - __HP_FREE(root); + close(fd); return 0; } +/** + * Get the existing config file values. + * @return returns a pointer to a config structure, returns NULL on error. +*/ +struct hp_config *hp_get_config() +{ + const int fd = open(PATCH_FILE_PATH, O_RDONLY); + if (fd == -1) + { + fprintf(stderr, "Error opening patch.cfg file.\n"); + return NULL; + } + + struct hp_config *config = __hp_read_from_patch_file(fd); + if (config == NULL) + fprintf(stderr, "Error reading patch.cfg file.\n"); + + close(fd); + return config; +} + +/** + * Frees the memory allocated for the config structure. + * @param config Pointer to the config to be freed. +*/ +void hp_free_config(struct hp_config *config) +{ + __hp_free_patch_config(config); +} + +/** + * Read the values from the existing patch file. + * @param fd File discriptor of the patch.cfg file. + * @return returns a pointer to a patch_config structure, returns NULL on error. +*/ +struct hp_config *__hp_read_from_patch_file(const int fd) +{ + char buf[4096]; + const size_t len = read(fd, buf, sizeof(buf)); + if (len == -1) + return NULL; + + struct json_value_s *root = json_parse(buf, len); + if (root && root->type == json_type_object) + { + struct json_object_s *object = (struct json_object_s *)root->payload; + // Create struct to populate json values. + struct hp_config *config; + // Allocate memory for the patch_config struct. + config = (struct hp_config *)malloc(sizeof(struct hp_config)); + // malloc and populate values to the struct. + __hp_populate_patch_from_json_object(config, object); + __HP_FREE(root); + return config; + } + + __HP_FREE(root); + return NULL; +} + /** * Write values of the given patch config struct to the file discriptor given. * @param fd File discriptor of the patch.cfg file. * @param config Patch config structure. */ -int __hp_write_to_patch_file(const int fd, const struct patch_config *config) +int __hp_write_to_patch_file(const int fd, const struct hp_config *config) { struct iovec iov_vec[4]; // {version: + newline + 4 spaces => 21; @@ -630,7 +684,7 @@ int __hp_write_to_patch_file(const int fd, const struct patch_config *config) * @param config Pointer to the patch config sturct to be populated. * @param object Pointer to the json object. */ -void __hp_populate_patch_from_json_object(struct patch_config *config, struct json_object_s *object) +void __hp_populate_patch_from_json_object(struct hp_config *config, const struct json_object_s *object) { const struct json_object_element_s *elem = object->start; do @@ -832,7 +886,7 @@ int __hp_write_control_msg(const void *buf, const uint32_t len) * Free memory allocated for the given patch config struct. * @param patch_config Pointer of patch config struct to be freed. */ -void __hp_free_patch_config(struct patch_config *patch_config) +void __hp_free_patch_config(struct hp_config *patch_config) { __HP_FREE(patch_config->version); __HP_FREE(patch_config->unl.list); @@ -842,6 +896,7 @@ void __hp_free_patch_config(struct patch_config *patch_config) __HP_FREE(patch_config->npl); __HP_FREE(patch_config->appbill.mode); __HP_FREE(patch_config->appbill.bin_args); + __HP_FREE(patch_config); } #endif \ No newline at end of file diff --git a/examples/nodejs_contract/echo_contract.js b/examples/nodejs_contract/echo_contract.js index 98fdaede..1ce1d503 100644 --- a/examples/nodejs_contract/echo_contract.js +++ b/examples/nodejs_contract/echo_contract.js @@ -48,6 +48,15 @@ const echoContract = async (ctx) => { // }) // await ctx.unl.send("Hello"); // } + + // Update patch config + // await ctx.updateConfig({ + // version: "2.0", + // unl: [ + // "edf3f3bff36e22d0e1c7abf791ca4900e717754443b8e861dcfbf1cd2bbd0f6159" + // ], + // consensus: "private" + // }); } const hpc = new HotPocket.Contract(); diff --git a/examples/nodejs_contract/hp-contract-lib.js b/examples/nodejs_contract/hp-contract-lib.js index b36b8d68..6f56ae7e 100644 --- a/examples/nodejs_contract/hp-contract-lib.js +++ b/examples/nodejs_contract/hp-contract-lib.js @@ -109,19 +109,11 @@ class PatchConfig { let updatedUnl = []; for (let pubKey of unl) { + // Pubkeys are validated against length, ed prefix and hex characters. if (!pubKey.length) throw "UNL pubKey not specified."; - else if (pubKey.length != 66) - throw "Invalid UNL pubKey specified. Invalid length."; - else if (!pubKey.startsWith("ed")) - throw "Invalid UNL pubKey specified. Invalid format."; - - try { - let pubKeyBin = hexToUint8Array(pubKey.substring(2)); - } - catch { - throw "Invalid UNL pubKey specified. Decode error."; - } + else if (!(/^(e|E)(d|D)[0-9a-fA-F]{64}$/g.test(pubKey))) + throw "Invalid UNL pubKey specified."; updatedUnl.push(pubKey); } @@ -166,14 +158,15 @@ class PatchConfig { // Saves the config changes to tha patch config. saveChanges() { + // Property order is simmilar to the property order of the patch.cfg created by HP at the startup. const config = { version: this.#version, + unl: this.#unl, bin_path: this.#binPath, bin_args: this.#binArgs ? this.#binArgs : "", roundtime: this.#roundtime, consensus: this.#consensus, npl: this.#npl, - unl: this.#unl, appbill: { mode: this.#appbillMode ? this.#appbillMode : "", bin_args: this.#appbillBinArgs ? this.#appbillBinArgs : "" @@ -181,7 +174,8 @@ class PatchConfig { }; return new Promise((resolve, reject) => { - fs.writeFile(this.#patchConfigPath, JSON.stringify(config), (err) => { + // Format json to match with the patch.cfg json format created by HP at the startup. + fs.writeFile(this.#patchConfigPath, JSON.stringify(config, null, 4), (err) => { if (err) reject(err); else resolve(); }); @@ -538,10 +532,6 @@ const invokeCallback = async (callback, ...args) => { } } -const hexToUint8Array = (hexString) => { - return new Uint8Array(hexString.match(/.{1,2}/g).map(byte => parseInt(byte, 16))); -} - const errHandler = (err) => console.log(err); module.exports = {