mirror of
https://github.com/EvernodeXRPL/hpcore.git
synced 2026-04-29 15:37:59 +00:00
User outputs round limit. (#241)
Implemented user outputs round limit and upgraded the contract libraries to support the configs.
This commit is contained in:
@@ -53,29 +53,15 @@ int main(int argc, char **argv)
|
||||
// printf("Received %.*s from %.*s", len, msg, HP_KEY_SIZE, sender);
|
||||
// free(msg);
|
||||
|
||||
// // 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);
|
||||
// Config update example:
|
||||
// struct hp_config *config = hp_get_config();
|
||||
// hp_set_config_string(&config->version, "2.0", 4);
|
||||
// config->round_limits.user_input_bytes = 1024;
|
||||
// struct hp_unl_node new_unl[2] = {{"ed726f9f536904b125bdca10bbdd1e66591b274799b92ac8bcfc75bf45d7da4c0f"},
|
||||
// {"ed3e63992d62804ea0c182e5b22fe43c4b652fbbf068ec7520f3020f4c3771416a"}};
|
||||
// hp_set_config_unl(config, new_unl, 2);
|
||||
// hp_update_config(config);
|
||||
// hp_free_config(config);
|
||||
|
||||
hp_deinit_user_input_mmap();
|
||||
hp_deinit_contract();
|
||||
|
||||
@@ -81,26 +81,10 @@
|
||||
ptr = NULL; \
|
||||
}
|
||||
|
||||
#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 - 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); \
|
||||
#define __HP_UPDATE_CONFIG_ERROR(msg) \
|
||||
{ \
|
||||
fprintf(stderr, "%s\n", msg); \
|
||||
return -1; \
|
||||
}
|
||||
|
||||
struct hp_user_input
|
||||
@@ -149,6 +133,12 @@ struct hp_appbill_config
|
||||
char *bin_args;
|
||||
};
|
||||
|
||||
struct hp_round_limits_config
|
||||
{
|
||||
size_t user_input_bytes;
|
||||
size_t user_output_bytes;
|
||||
};
|
||||
|
||||
struct hp_config
|
||||
{
|
||||
char *version;
|
||||
@@ -159,6 +149,7 @@ struct hp_config
|
||||
char *consensus;
|
||||
char *npl;
|
||||
struct hp_appbill_config appbill;
|
||||
struct hp_round_limits_config round_limits;
|
||||
};
|
||||
|
||||
struct hp_contract_context
|
||||
@@ -191,8 +182,10 @@ 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 hp_config *config);
|
||||
struct hp_config *hp_get_config();
|
||||
int hp_update_config(const struct hp_config *config);
|
||||
void hp_set_config_string(char **config_str, const char *value, const size_t value_size);
|
||||
void hp_set_config_unl(struct hp_config *config, const struct hp_unl_node *new_unl, const size_t new_unl_count);
|
||||
void hp_free_config(struct hp_config *config);
|
||||
|
||||
void __hp_parse_args_json(const struct json_object_s *object);
|
||||
@@ -200,7 +193,6 @@ int __hp_write_control_msg(const void *buf, const uint32_t len);
|
||||
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 = {};
|
||||
|
||||
@@ -436,125 +428,6 @@ int hp_read_npl_msg(void *msg_buf, char *pubkey_buf, const int timeout)
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Update the params of the existing config file.
|
||||
* @param config Pointer to the updated config struct.
|
||||
*/
|
||||
int hp_update_config(const struct hp_config *config)
|
||||
{
|
||||
struct hp_contract_context *cctx = __hpc.cctx;
|
||||
|
||||
if (cctx->readonly)
|
||||
{
|
||||
fprintf(stderr, "Config update not allowed in readonly mode.\n");
|
||||
return -1;
|
||||
}
|
||||
const int fd = open(PATCH_FILE_PATH, O_RDWR);
|
||||
if (fd == -1)
|
||||
{
|
||||
fprintf(stderr, "Error opening patch.cfg file.\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
struct hp_config *existing_patch = __hp_read_from_patch_file(fd);
|
||||
if (existing_patch != NULL)
|
||||
{
|
||||
if (config->version)
|
||||
{
|
||||
if (strlen(config->version) != 0)
|
||||
{
|
||||
__HP_STRING_COPY(existing_patch->version, config->version);
|
||||
}
|
||||
else
|
||||
{
|
||||
__HP_UPDATE_CONFIG_ERROR("Version cannot be empty.");
|
||||
}
|
||||
}
|
||||
|
||||
if (config->unl.count)
|
||||
{
|
||||
for (size_t i = 0; i < config->unl.count; i++)
|
||||
{
|
||||
const size_t pubkey_len = strlen(config->unl.list[i].pubkey);
|
||||
if (pubkey_len == 0)
|
||||
{
|
||||
__HP_UPDATE_CONFIG_ERROR("Unl pubkey cannot be empty.");
|
||||
}
|
||||
|
||||
if (pubkey_len != HP_KEY_SIZE)
|
||||
{
|
||||
__HP_UPDATE_CONFIG_ERROR("Unl pubkey invalid. Invalid length.");
|
||||
}
|
||||
|
||||
if (config->unl.list[i].pubkey[0] != 'e' || config->unl.list[i].pubkey[1] != 'd')
|
||||
{
|
||||
__HP_UPDATE_CONFIG_ERROR("Unl pubkey invalid. Invalid format.");
|
||||
}
|
||||
// Checking the validity of hexadecimal portion. (without 'ed').
|
||||
for (size_t j = 2; j < HP_KEY_SIZE; j++)
|
||||
{
|
||||
const char current_char = config->unl.list[i].pubkey[j];
|
||||
if ((current_char < 'A' || current_char > 'F') && (current_char < 'a' || current_char > 'f') && (current_char < '0' || current_char > '9'))
|
||||
{
|
||||
__HP_UPDATE_CONFIG_ERROR("Unl pubkey invalid. Invalid character.");
|
||||
}
|
||||
}
|
||||
}
|
||||
__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);
|
||||
|
||||
if (config->bin_args)
|
||||
__HP_STRING_COPY(existing_patch->bin_args, config->bin_args);
|
||||
|
||||
// if (config->roundtime)
|
||||
// existing_patch->roundtime = config->roundtime;
|
||||
|
||||
if (config->consensus)
|
||||
{
|
||||
if (strlen(config->consensus) == 0 || (strcmp(config->consensus, "public") != 0 && strcmp(config->consensus, "private") != 0))
|
||||
{
|
||||
__HP_UPDATE_CONFIG_ERROR("Invalid consensus flag. Valid values: public|private");
|
||||
}
|
||||
__HP_STRING_COPY(existing_patch->consensus, config->consensus);
|
||||
}
|
||||
|
||||
if (config->npl)
|
||||
{
|
||||
if (strlen(config->npl) == 0 || (strcmp(config->npl, "public") != 0 && strcmp(config->npl, "private")) != 0)
|
||||
{
|
||||
__HP_UPDATE_CONFIG_ERROR("Invalid npl flag. Valid values: public|private");
|
||||
}
|
||||
__HP_STRING_COPY(existing_patch->npl, config->npl);
|
||||
}
|
||||
|
||||
if (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);
|
||||
|
||||
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);
|
||||
}
|
||||
else
|
||||
{
|
||||
fprintf(stderr, "Error reading patch.cfg file.\n");
|
||||
close(fd);
|
||||
return -1;
|
||||
}
|
||||
|
||||
close(fd);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the existing config file values.
|
||||
* @return returns a pointer to a config structure, returns NULL on error.
|
||||
@@ -576,13 +449,119 @@ struct hp_config *hp_get_config()
|
||||
return config;
|
||||
}
|
||||
|
||||
/**
|
||||
* Update the params of the existing config file.
|
||||
* @param config Pointer to the updated config struct.
|
||||
*/
|
||||
int hp_update_config(const struct hp_config *config)
|
||||
{
|
||||
struct hp_contract_context *cctx = __hpc.cctx;
|
||||
|
||||
if (cctx->readonly)
|
||||
{
|
||||
fprintf(stderr, "Config update not allowed in readonly mode.\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
// Validate fields.
|
||||
|
||||
if (!config->version || strlen(config->version) == 0)
|
||||
__HP_UPDATE_CONFIG_ERROR("Version cannot be empty.");
|
||||
|
||||
if (config->unl.count)
|
||||
{
|
||||
for (size_t i = 0; i < config->unl.count; i++)
|
||||
{
|
||||
const size_t pubkey_len = strlen(config->unl.list[i].pubkey);
|
||||
if (pubkey_len == 0)
|
||||
__HP_UPDATE_CONFIG_ERROR("Unl pubkey cannot be empty.");
|
||||
|
||||
if (pubkey_len != HP_KEY_SIZE)
|
||||
__HP_UPDATE_CONFIG_ERROR("Unl pubkey invalid. Invalid length.");
|
||||
|
||||
if (config->unl.list[i].pubkey[0] != 'e' || config->unl.list[i].pubkey[1] != 'd')
|
||||
__HP_UPDATE_CONFIG_ERROR("Unl pubkey invalid. Invalid format.");
|
||||
|
||||
// Checking the validity of hexadecimal portion. (without 'ed').
|
||||
for (size_t j = 2; j < HP_KEY_SIZE; j++)
|
||||
{
|
||||
const char current_char = config->unl.list[i].pubkey[j];
|
||||
if ((current_char < 'A' || current_char > 'F') && (current_char < 'a' || current_char > 'f') && (current_char < '0' || current_char > '9'))
|
||||
__HP_UPDATE_CONFIG_ERROR("Unl pubkey invalid. Invalid character.");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!config->bin_path || strlen(config->bin_path) == 0)
|
||||
__HP_UPDATE_CONFIG_ERROR("Binary path cannot be empty.");
|
||||
|
||||
if (config->roundtime <= 0)
|
||||
__HP_UPDATE_CONFIG_ERROR("Round time must be higher than 0.");
|
||||
|
||||
if (!config->consensus || strlen(config->consensus) == 0 || (strcmp(config->consensus, "public") != 0 && strcmp(config->consensus, "private") != 0))
|
||||
__HP_UPDATE_CONFIG_ERROR("Invalid consensus flag. Valid values: public|private");
|
||||
|
||||
if (!config->npl || strlen(config->npl) == 0 || (strcmp(config->npl, "public") != 0 && strcmp(config->npl, "private")) != 0)
|
||||
__HP_UPDATE_CONFIG_ERROR("Invalid npl flag. Valid values: public|private");
|
||||
|
||||
if (config->round_limits.user_input_bytes < 0 || config->round_limits.user_output_bytes < 0)
|
||||
__HP_UPDATE_CONFIG_ERROR("Invalid round limits.");
|
||||
|
||||
const int fd = open(PATCH_FILE_PATH, O_RDWR);
|
||||
if (fd == -1)
|
||||
__HP_UPDATE_CONFIG_ERROR("Error opening patch.cfg file.");
|
||||
|
||||
if (__hp_write_to_patch_file(fd, config) == -1)
|
||||
{
|
||||
close(fd);
|
||||
__HP_UPDATE_CONFIG_ERROR("Error writing updated config to patch.cfg file.");
|
||||
}
|
||||
|
||||
close(fd);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Assigns the given string value to the specified config string field.
|
||||
* @param config_str Pointer to the string field to populate the new value to.
|
||||
* @param value New string value.
|
||||
* @param value_size String length of the new value.
|
||||
*/
|
||||
void hp_set_config_string(char **config_str, const char *value, const size_t value_size)
|
||||
{
|
||||
*config_str = realloc(*config_str, value_size);
|
||||
strncpy(*config_str, value, value_size);
|
||||
}
|
||||
|
||||
/**
|
||||
* Populates the config unl list with the specified values.
|
||||
* @param config The config struct to populate the unl to.
|
||||
* @param new_unl Pointer to the new unl node array.
|
||||
* @param new_unl_count No. of entries in the new unl node array.
|
||||
*/
|
||||
void hp_set_config_unl(struct hp_config *config, const struct hp_unl_node *new_unl, const size_t new_unl_count)
|
||||
{
|
||||
const size_t mem_size = sizeof(struct hp_unl_node) * new_unl_count;
|
||||
config->unl.list = realloc(config->unl.list, mem_size);
|
||||
memcpy(config->unl.list, new_unl, mem_size);
|
||||
config->unl.count = new_unl_count;
|
||||
}
|
||||
|
||||
/**
|
||||
* 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);
|
||||
__HP_FREE(config->version);
|
||||
__HP_FREE(config->unl.list);
|
||||
__HP_FREE(config->bin_path);
|
||||
__HP_FREE(config->bin_args);
|
||||
__HP_FREE(config->consensus);
|
||||
__HP_FREE(config->npl);
|
||||
__HP_FREE(config->appbill.mode);
|
||||
__HP_FREE(config->appbill.bin_args);
|
||||
__HP_FREE(config);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -622,7 +601,7 @@ struct hp_config *__hp_read_from_patch_file(const int fd)
|
||||
*/
|
||||
int __hp_write_to_patch_file(const int fd, const struct hp_config *config)
|
||||
{
|
||||
struct iovec iov_vec[4];
|
||||
struct iovec iov_vec[5];
|
||||
// {version: + newline + 4 spaces => 21;
|
||||
const size_t version_len = 21 + strlen(config->version);
|
||||
char version_buf[version_len];
|
||||
@@ -652,28 +631,44 @@ int __hp_write_to_patch_file(const int fd, const struct hp_config *config)
|
||||
iov_vec[1].iov_base = unl_buf;
|
||||
iov_vec[1].iov_len = unl_buf_size;
|
||||
|
||||
char *json_string = " \"bin_path\": \"%s\",\n \"bin_args\": \"%s\",\n \"roundtime\": %d,\n \"consensus\": \"%s\",\n \"npl\": \"%s\",\n";
|
||||
// Top-level field values.
|
||||
|
||||
const char *json_string = " \"bin_path\": \"%s\",\n \"bin_args\": \"%s\",\n \"roundtime\": %s,\n \"consensus\": \"%s\",\n \"npl\": \"%s\",\n";
|
||||
|
||||
// Calculating number of digits in roundtime for json length.
|
||||
// String length is taken after converting to string.
|
||||
char roundtime_str[16];
|
||||
sprintf(roundtime_str, "%d", config->roundtime);
|
||||
|
||||
const size_t json_string_len = 95 + strlen(config->bin_path) + strlen(config->bin_args) + strlen(roundtime_str) + strlen(config->consensus) + strlen(config->npl);
|
||||
char json_buf[json_string_len];
|
||||
sprintf(json_buf, json_string, config->bin_path, config->bin_args, config->roundtime, config->consensus, config->npl);
|
||||
sprintf(json_buf, json_string, config->bin_path, config->bin_args, roundtime_str, config->consensus, config->npl);
|
||||
iov_vec[2].iov_base = json_buf;
|
||||
iov_vec[2].iov_len = json_string_len;
|
||||
|
||||
char *appbill_json = " \"appbill\": {\n \"mode\": \"%s\",\n \"bin_args\": \"%s\"\n }\n}";
|
||||
// Appbill field valiues.
|
||||
|
||||
const char *appbill_json = " \"appbill\": {\n \"mode\": \"%s\",\n \"bin_args\": \"%s\"\n },\n";
|
||||
const size_t appbill_json_len = 67 + strlen(config->appbill.mode) + strlen(config->appbill.bin_args);
|
||||
char appbill_buf[appbill_json_len];
|
||||
sprintf(appbill_buf, appbill_json, config->appbill.mode, config->appbill.bin_args);
|
||||
iov_vec[3].iov_base = appbill_buf;
|
||||
iov_vec[3].iov_len = appbill_json_len;
|
||||
|
||||
// Round limits field valies.
|
||||
|
||||
const char *round_limits_json = " \"round_limits\": {\n \"user_input_bytes\": %s,\n \"user_output_bytes\": %s\n }\n}";
|
||||
|
||||
char user_input_bytes_str[20], user_output_bytes_str[20];
|
||||
sprintf(user_input_bytes_str, "%" PRIu64, config->round_limits.user_input_bytes);
|
||||
sprintf(user_output_bytes_str, "%" PRIu64, config->round_limits.user_output_bytes);
|
||||
|
||||
const size_t round_limits_json_len = 89 + strlen(user_input_bytes_str) + strlen(user_output_bytes_str);
|
||||
char round_limits_buf[round_limits_json_len];
|
||||
sprintf(round_limits_buf, round_limits_json, user_input_bytes_str, user_output_bytes_str);
|
||||
iov_vec[4].iov_base = round_limits_buf;
|
||||
iov_vec[4].iov_len = round_limits_json_len;
|
||||
|
||||
if (ftruncate(fd, 0) == -1 || // Clear any previous content in the file.
|
||||
pwritev(fd, iov_vec, 4, 0) == -1) // Start writing from begining.
|
||||
pwritev(fd, iov_vec, 5, 0) == -1) // Start writing from begining.
|
||||
return -1;
|
||||
|
||||
return 0;
|
||||
@@ -754,6 +749,23 @@ void __hp_populate_patch_from_json_object(struct hp_config *config, const struct
|
||||
sub_ele = sub_ele->next;
|
||||
} while (sub_ele);
|
||||
}
|
||||
else if (strcmp(k->string, "round_limits") == 0)
|
||||
{
|
||||
struct json_object_s *object = (struct json_object_s *)elem->value->payload;
|
||||
struct json_object_element_s *sub_ele = object->start;
|
||||
do
|
||||
{
|
||||
if (strcmp(sub_ele->name->string, "user_input_bytes") == 0)
|
||||
{
|
||||
__HP_ASSIGN_UINT64(config->round_limits.user_input_bytes, sub_ele);
|
||||
}
|
||||
else if (strcmp(sub_ele->name->string, "user_output_bytes") == 0)
|
||||
{
|
||||
__HP_ASSIGN_UINT64(config->round_limits.user_output_bytes, sub_ele);
|
||||
}
|
||||
sub_ele = sub_ele->next;
|
||||
} while (sub_ele);
|
||||
}
|
||||
|
||||
elem = elem->next;
|
||||
} while (elem);
|
||||
@@ -882,21 +894,4 @@ int __hp_write_control_msg(const void *buf, const uint32_t len)
|
||||
return write(__hpc.control_fd, buf, 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 hp_config *patch_config)
|
||||
{
|
||||
__HP_FREE(patch_config->version);
|
||||
__HP_FREE(patch_config->unl.list);
|
||||
__HP_FREE(patch_config->bin_path);
|
||||
__HP_FREE(patch_config->bin_args);
|
||||
__HP_FREE(patch_config->consensus);
|
||||
__HP_FREE(patch_config->npl);
|
||||
__HP_FREE(patch_config->appbill.mode);
|
||||
__HP_FREE(patch_config->appbill.bin_args);
|
||||
__HP_FREE(patch_config);
|
||||
}
|
||||
|
||||
#endif
|
||||
@@ -80,7 +80,10 @@
|
||||
console.log('HotPocket Connected.');
|
||||
|
||||
hpc.sendContractReadRequest("Hello");
|
||||
hpc.sendContractInput("World!")
|
||||
hpc.sendContractInput("World!").then(status => {
|
||||
if (status != "ok")
|
||||
console.log(status);
|
||||
});
|
||||
|
||||
// When we need to close HP connection:
|
||||
// await hpc.close();
|
||||
|
||||
@@ -93,7 +93,10 @@ async function main() {
|
||||
if (inp.startsWith("read "))
|
||||
hpc.sendContractReadRequest(inp.substr(5));
|
||||
else {
|
||||
hpc.sendContractInput(inp);
|
||||
hpc.sendContractInput(inp).then(status => {
|
||||
if (status != "ok")
|
||||
console.log(status);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -50,13 +50,9 @@ const echoContract = async (ctx) => {
|
||||
// }
|
||||
|
||||
// Update patch config
|
||||
// await ctx.updateConfig({
|
||||
// version: "2.0",
|
||||
// unl: [
|
||||
// "edf3f3bff36e22d0e1c7abf791ca4900e717754443b8e861dcfbf1cd2bbd0f6159"
|
||||
// ],
|
||||
// consensus: "private"
|
||||
// });
|
||||
// const config = await ctx.getConfig();
|
||||
// config.unl.push("edf3f3bff36e22d0e1c7abf791ca4900e717754443b8e861dcfbf1cd2bbd0f6159");
|
||||
// await ctx.updateConfig(config);
|
||||
}
|
||||
|
||||
const hpc = new HotPocket.Contract();
|
||||
|
||||
@@ -15,6 +15,8 @@ const clientProtocols = {
|
||||
}
|
||||
Object.freeze(clientProtocols);
|
||||
|
||||
const PATCH_CONFIG_PATH = "../patch.cfg";
|
||||
|
||||
class HotPocketContract {
|
||||
|
||||
#controlChannel = null;
|
||||
@@ -66,140 +68,6 @@ class HotPocketContract {
|
||||
}
|
||||
}
|
||||
|
||||
// Represents patch config.
|
||||
class PatchConfig {
|
||||
#patchConfigPath = "../patch.cfg";
|
||||
#version = null;
|
||||
#binPath = null;
|
||||
#binArgs = null;
|
||||
#roundtime = null;
|
||||
#consensus = null;
|
||||
#npl = null;
|
||||
#unl = null;
|
||||
#appbillMode = null;
|
||||
#appbillBinArgs = null;
|
||||
|
||||
// Loads the config value if there's a patch config file. Otherwise throw error.
|
||||
readConfig() {
|
||||
if (!fs.existsSync(this.#patchConfigPath))
|
||||
throw "Patch config file does not exist.";
|
||||
|
||||
const fileContent = fs.readFileSync(this.#patchConfigPath);
|
||||
const config = JSON.parse(fileContent);
|
||||
this.#version = config.version;
|
||||
this.#binPath = config.bin_path;
|
||||
this.#binArgs = config.bin_args;
|
||||
this.#roundtime = +config.roundtime;
|
||||
this.#consensus = config.consensus;
|
||||
this.#npl = config.npl;
|
||||
this.#unl = config.unl;
|
||||
this.#appbillMode = config.appbill.mode;
|
||||
this.#appbillBinArgs = config.appbill.bin_args;
|
||||
}
|
||||
|
||||
setVersion(version) {
|
||||
if (!version)
|
||||
throw "Contract version is not specified.";
|
||||
this.#version = version;
|
||||
}
|
||||
|
||||
setUnl(unl) {
|
||||
if (!unl || !unl.length)
|
||||
throw "UNL list cannot be empty.";
|
||||
|
||||
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 (!(/^(e|E)(d|D)[0-9a-fA-F]{64}$/g.test(pubKey)))
|
||||
throw "Invalid UNL pubKey specified.";
|
||||
|
||||
updatedUnl.push(pubKey);
|
||||
}
|
||||
this.#unl = updatedUnl;
|
||||
}
|
||||
|
||||
setBinPath(binPath) {
|
||||
if (!binPath.length)
|
||||
throw "Binary path cannot be empty.";
|
||||
this.#binPath = binPath;
|
||||
}
|
||||
|
||||
setBinArgs(binArgs) {
|
||||
this.#binArgs = binArgs;
|
||||
}
|
||||
|
||||
setRoundtime(roundtime) {
|
||||
if (roundtime == 0)
|
||||
throw "Round time cannot be zero."
|
||||
this.#roundtime = roundtime;
|
||||
}
|
||||
|
||||
setConsensus(consensus) {
|
||||
if (consensus != "public" && consensus != "private")
|
||||
throw "Invalid consensus flag configured in patch file. Valid values: public|private";
|
||||
this.#consensus = consensus;
|
||||
}
|
||||
|
||||
setNpl(npl) {
|
||||
if (npl != "public" && npl != "private")
|
||||
throw "Invalid npl flag configured in patch file. Valid values: public|private";
|
||||
this.#npl = npl;
|
||||
}
|
||||
|
||||
setAppbillMode(appbillMode) {
|
||||
this.#appbillMode = appbillMode;
|
||||
}
|
||||
|
||||
setAppbillBinArgs(appbillBinArgs) {
|
||||
this.#appbillBinArgs = appbillBinArgs;
|
||||
}
|
||||
|
||||
// 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,
|
||||
appbill: {
|
||||
mode: this.#appbillMode ? this.#appbillMode : "",
|
||||
bin_args: this.#appbillBinArgs ? this.#appbillBinArgs : ""
|
||||
}
|
||||
};
|
||||
|
||||
return new Promise((resolve, reject) => {
|
||||
// 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();
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
// Returns patch config as a JSON object.
|
||||
getConfig() {
|
||||
return {
|
||||
version: this.#version,
|
||||
unl: this.#unl,
|
||||
roundtime: this.#roundtime,
|
||||
consensus: this.#consensus,
|
||||
npl: this.#npl,
|
||||
binPath: this.#binPath,
|
||||
binArgs: this.#binArgs,
|
||||
appbill: {
|
||||
mode: this.#appbillMode,
|
||||
binArgs: this.#appbillBinArgs
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
class ContractContext {
|
||||
|
||||
#controlChannel = null;
|
||||
@@ -215,75 +83,69 @@ class ContractContext {
|
||||
this.#patchConfig = new PatchConfig();
|
||||
}
|
||||
|
||||
// Updates the config with given parameters and save the patch config.
|
||||
// Params,
|
||||
// {
|
||||
// version: contract version as string,
|
||||
// unl: list of unl pubkeys. Expecting "ed" prefixed (ed22519 algorithm) hex pubkeys,
|
||||
// consensus: consensus private|public,
|
||||
// npl: npl private|public,
|
||||
// binPath: contract binary path string,
|
||||
// binArgs: contract binary args string,
|
||||
// appbillMode: appbill mode string,
|
||||
// appbillBinArgs: appbill binary args string
|
||||
// }
|
||||
async updateConfig(params) {
|
||||
if (this.readonly)
|
||||
throw "Config update not allowed in readonly mode.";
|
||||
|
||||
// Read current patch config values before update.
|
||||
this.#patchConfig.readConfig();
|
||||
|
||||
if (params.hasOwnProperty('version')) {
|
||||
this.#patchConfig.setVersion(params.version);
|
||||
}
|
||||
if (params.hasOwnProperty('unl')) {
|
||||
this.#patchConfig.setUnl(params.unl);
|
||||
}
|
||||
// Commented and disabled updating until roundtime sniffing heuristics is implemented in HP.
|
||||
// if (params.hasOwnProperty('roundtime')) {
|
||||
// this.#patchConfig.setRoundtime(params.roundtime);
|
||||
// }
|
||||
if (params.hasOwnProperty('consensus')) {
|
||||
this.#patchConfig.setConsensus(params.consensus);
|
||||
}
|
||||
if (params.hasOwnProperty('npl')) {
|
||||
this.#patchConfig.setNpl(params.npl);
|
||||
}
|
||||
if (params.hasOwnProperty('binPath')) {
|
||||
this.#patchConfig.setBinPath(params.binPath);
|
||||
}
|
||||
if (params.hasOwnProperty('binArgs')) {
|
||||
this.#patchConfig.setBinArgs(params.binArgs);
|
||||
}
|
||||
if (params.hasOwnProperty('appbillMode')) {
|
||||
this.#patchConfig.setAppbillMode(params.appbillMode);
|
||||
}
|
||||
if (params.hasOwnProperty('appbillBinArgs')) {
|
||||
this.#patchConfig.setAppbillBinArgs(params.appbillBinArgs);
|
||||
}
|
||||
await this.#patchConfig.saveChanges();
|
||||
// Returns the config values in patch config.
|
||||
getConfig() {
|
||||
return this.#patchConfig.getConfig();
|
||||
}
|
||||
|
||||
// Returns the config values in patch config.
|
||||
// Returns,
|
||||
// {
|
||||
// version: contract version as string,
|
||||
// unl: list of unl pubkeys. "ed" prefixed (ed22519 algorithm) hex pubkeys,
|
||||
// roundtime: roundtime as Number,
|
||||
// consensus: consensus private|public,
|
||||
// npl: npl private|public,
|
||||
// binPath: contract binary path string,
|
||||
// binArgs: contract binary args string,
|
||||
// appbill: {
|
||||
// mode: appbill mode string,
|
||||
// binArgs: appbill binary args string
|
||||
// }
|
||||
// }
|
||||
// Updates the config with given config object and save the patch config.
|
||||
updateConfig(config) {
|
||||
return this.#patchConfig.updateConfig(config);
|
||||
}
|
||||
}
|
||||
|
||||
// Handles patch config manipulation.
|
||||
class PatchConfig {
|
||||
|
||||
// Loads the config value if there's a patch config file. Otherwise throw error.
|
||||
getConfig() {
|
||||
// Read current patch config values.
|
||||
this.#patchConfig.readConfig()
|
||||
return this.#patchConfig.getConfig();
|
||||
if (!fs.existsSync(PATCH_CONFIG_PATH))
|
||||
throw "Patch config file does not exist.";
|
||||
|
||||
return new Promise((resolve, reject) => {
|
||||
fs.readFile(PATCH_CONFIG_PATH, 'utf8', function (err, data) {
|
||||
if (err) reject(err);
|
||||
else resolve(JSON.parse(data));
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
updateConfig(config) {
|
||||
|
||||
this.validateConfig(config);
|
||||
|
||||
return new Promise((resolve, reject) => {
|
||||
// Format json to match with the patch.cfg json format created by HP at the startup.
|
||||
fs.writeFile(PATCH_CONFIG_PATH, JSON.stringify(config, null, 4), (err) => {
|
||||
if (err) reject(err);
|
||||
else resolve();
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
validateConfig(config) {
|
||||
// Validate all config fields.
|
||||
if (!config.version)
|
||||
throw "Contract version is not specified.";
|
||||
if (!config.unl || !config.unl.length)
|
||||
throw "UNL list cannot be empty.";
|
||||
for (let pubKey of config.unl) {
|
||||
// Pubkeys are validated against length, ed prefix and hex characters.
|
||||
if (!pubKey.length)
|
||||
throw "UNL pubKey not specified.";
|
||||
else if (!(/^(e|E)(d|D)[0-9a-fA-F]{64}$/g.test(pubKey)))
|
||||
throw "Invalid UNL pubKey specified.";
|
||||
}
|
||||
if (!config.bin_path || !config.bin_path.length)
|
||||
throw "Binary path cannot be empty.";
|
||||
if (config.roundtime <= 0)
|
||||
throw "Round time must be higher than zero."
|
||||
if (config.consensus != "public" && config.consensus != "private")
|
||||
throw "Invalid consensus flag configured in patch file. Valid values: public|private";
|
||||
if (config.npl != "public" && config.npl != "private")
|
||||
throw "Invalid npl flag configured in patch file. Valid values: public|private";
|
||||
if (config.round_limits.user_input_bytes < 0 || config.round_limits.user_output_bytes < 0)
|
||||
throw "Invalid round limits.";
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -589,7 +589,7 @@ namespace sc
|
||||
* @param bufmap A map which has a public key and input/output buffer pair for that public key.
|
||||
* @return 0 if no bytes were read. 1 if bytes were read.
|
||||
*/
|
||||
int read_contract_fdmap_outputs(contract_fdmap_t &fdmap, const pollfd *pfds, contract_bufmap_t &bufmap)
|
||||
int read_contract_fdmap_outputs(contract_fdmap_t &fdmap, pollfd *pfds, contract_bufmap_t &bufmap)
|
||||
{
|
||||
bool bytes_read = false;
|
||||
int i = 0;
|
||||
@@ -600,7 +600,7 @@ namespace sc
|
||||
fd_pair &fds = fdmap[pubkey];
|
||||
|
||||
// This returns the total bytes read from the socket.
|
||||
const int total_bytes_read = read_iosocket(true, pfds[i++], output);
|
||||
const int total_bytes_read = (pfds[i].fd == -1) ? 0 : read_iosocket(true, pfds[i], output);
|
||||
|
||||
if (total_bytes_read == -1)
|
||||
{
|
||||
@@ -649,14 +649,29 @@ namespace sc
|
||||
possible_read_len = total_bytes_read - pos;
|
||||
}
|
||||
// Extract the message chunk from the buffer.
|
||||
std::string msgBuf = output.substr(pos, possible_read_len);
|
||||
std::string msg_buf = output.substr(pos, possible_read_len);
|
||||
pos += possible_read_len;
|
||||
// Append the extracted message chunk to the current message.
|
||||
current_output.message += msgBuf;
|
||||
current_output.message += msg_buf;
|
||||
}
|
||||
|
||||
bytes_read = true;
|
||||
// Increment total collected output len for this user.
|
||||
bufs.total_output_len += total_bytes_read;
|
||||
|
||||
// If total outputs exceeds limit for this user, close the user's out fd.
|
||||
if (conf::cfg.contract.round_limits.user_output_bytes > 0 &&
|
||||
bufs.total_output_len > conf::cfg.contract.round_limits.user_output_bytes)
|
||||
{
|
||||
close(pfds[i].fd);
|
||||
pfds[i].fd = -1;
|
||||
}
|
||||
else
|
||||
{
|
||||
bytes_read = true;
|
||||
}
|
||||
}
|
||||
|
||||
i++;
|
||||
}
|
||||
|
||||
return bytes_read ? 1 : 0;
|
||||
|
||||
@@ -43,6 +43,9 @@ namespace sc
|
||||
|
||||
// List of outputs from the contract.
|
||||
std::list<contract_output> outputs;
|
||||
|
||||
// Total output bytes accumulated so far.
|
||||
size_t total_output_len = 0;
|
||||
};
|
||||
|
||||
// Common typedef for a map of pubkey->fdpair.
|
||||
@@ -164,7 +167,7 @@ namespace sc
|
||||
|
||||
int create_iosockets_for_fdmap(contract_fdmap_t &fdmap, contract_bufmap_t &bufmap);
|
||||
|
||||
int read_contract_fdmap_outputs(contract_fdmap_t &fdmap, const pollfd *pfds, contract_bufmap_t &bufmap);
|
||||
int read_contract_fdmap_outputs(contract_fdmap_t &fdmap, pollfd *pfds, contract_bufmap_t &bufmap);
|
||||
|
||||
int create_contract_log_files(execution_context &ctx);
|
||||
|
||||
|
||||
Reference in New Issue
Block a user