Added user input max ledger seq offset limit config (#256)

- Added new config for max input ledger offset inside contract section.
- Updated implementation of getting and updating patch config inside node and c contracts.
- Skip inputs if max ledger offset exceeds, when handling user inputs and nup messages.
This commit is contained in:
Chalith Desaman
2021-02-24 09:19:36 +05:30
committed by GitHub
parent 137c199b07
commit 363116fc2a
6 changed files with 41 additions and 7 deletions

View File

@@ -154,9 +154,10 @@ struct hp_config
struct hp_unl_collection unl;
char *bin_path;
char *bin_args;
u_int16_t roundtime;
uint32_t roundtime;
char *consensus;
char *npl;
uint16_t max_input_ledger_offset;
struct hp_appbill_config appbill;
struct hp_round_limits_config round_limits;
};
@@ -505,6 +506,9 @@ int hp_update_config(const struct hp_config *config)
if (config->roundtime <= 0)
__HP_UPDATE_CONFIG_ERROR("Round time must be higher than 0.");
if (config->max_input_ledger_offset < 0)
__HP_UPDATE_CONFIG_ERROR("Invalid max input ledger offset.");
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");
@@ -643,14 +647,17 @@ int __hp_write_to_patch_file(const int fd, const struct hp_config *config)
// 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";
" \"consensus\": \"%s\",\n \"npl\": \"%s\",\n \"max_input_ledger_offset\": %s,\n";
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 max_input_ledger_offset_str[16];
sprintf(max_input_ledger_offset_str, "%d", config->max_input_ledger_offset);
const size_t json_string_len = 128 + strlen(config->bin_path) + strlen(config->bin_args) + strlen(roundtime_str) + strlen(config->consensus) + strlen(config->npl) + strlen(max_input_ledger_offset_str);
char json_buf[json_string_len];
sprintf(json_buf, json_string, config->bin_path, config->bin_args, roundtime_str, config->consensus, config->npl);
sprintf(json_buf, json_string, config->bin_path, config->bin_args, roundtime_str, config->consensus, config->npl, max_input_ledger_offset_str);
iov_vec[2].iov_base = json_buf;
iov_vec[2].iov_len = json_string_len;
@@ -746,6 +753,11 @@ void __hp_populate_patch_from_json_object(struct hp_config *config, const struct
const struct json_number_s *value = (struct json_number_s *)elem->value->payload;
config->roundtime = strtol(value->number, NULL, 0);
}
else if (strcmp(k->string, "max_input_ledger_offset") == 0)
{
const struct json_number_s *value = (struct json_number_s *)elem->value->payload;
config->max_input_ledger_offset = strtoul(value->number, NULL, 0);
}
else if (strcmp(k->string, "consensus") == 0)
{
__HP_ASSIGN_CHAR_PTR(config->consensus, elem);

View File

@@ -149,6 +149,8 @@ class PatchConfig {
if (config.round_limits.user_input_bytes < 0 || config.round_limits.user_output_bytes < 0 || config.round_limits.npl_output_bytes < 0 ||
config.round_limits.proc_cpu_seconds < 0 || config.round_limits.proc_mem_bytes < 0 || config.round_limits.proc_ofd_count < 0)
throw "Invalid round limits.";
if (config.max_input_ledger_offset < 0)
throw "Invalid max input ledger offset";
}
}

View File

@@ -150,6 +150,7 @@ namespace conf
cfg.contract.roundtime = 1000;
cfg.contract.is_consensus_public = false;
cfg.contract.is_npl_public = false;
cfg.contract.max_input_ledger_offset = 10;
cfg.mesh.port = 22860;
cfg.mesh.msg_forwarding = true;
@@ -516,12 +517,12 @@ namespace conf
// We always save the startup role to config. Not the current role which might get changed dynamically during syncing.
node_config.insert_or_assign("role", cfg.node.role == ROLE::OBSERVER ? ROLE_OBSERVER : ROLE_VALIDATOR);
node_config.insert_or_assign("history", cfg.node.history == HISTORY::FULL ? HISTORY_FULL : HISTORY_CUSTOM);
jsoncons::ojson history_config;
history_config.insert_or_assign("max_primary_shards", cfg.node.history_config.max_primary_shards);
history_config.insert_or_assign("max_blob_shards", cfg.node.history_config.max_blob_shards);
node_config.insert_or_assign("history_config", history_config);
d.insert_or_assign("node", node_config);
}
@@ -905,6 +906,7 @@ namespace conf
jdoc.insert_or_assign("roundtime", contract.roundtime.load());
jdoc.insert_or_assign("consensus", contract.is_consensus_public ? PUBLIC : PRIVATE);
jdoc.insert_or_assign("npl", contract.is_npl_public ? PUBLIC : PRIVATE);
jdoc.insert_or_assign("max_input_ledger_offset", contract.max_input_ledger_offset);
jsoncons::ojson appbill;
appbill.insert_or_assign("mode", contract.appbill.mode);
@@ -995,6 +997,7 @@ namespace conf
return -1;
}
contract.is_npl_public = jdoc["npl"] == PUBLIC;
contract.max_input_ledger_offset = jdoc["max_input_ledger_offset"].as<uint16_t>();
jpath = "contract.appbill";
contract.appbill.mode = jdoc["appbill"]["mode"].as<std::string>();

View File

@@ -56,7 +56,7 @@ namespace conf
struct history_configuration
{
uint64_t max_primary_shards; // Maximum number of shards for primary shards.
uint64_t max_blob_shards; // Maximum number of shards for blob shards.
uint64_t max_blob_shards; // Maximum number of shards for blob shards.
};
// Log severity levels used in Hot Pocket.
@@ -122,6 +122,7 @@ namespace conf
std::atomic<uint32_t> roundtime = 0; // Consensus round time in ms
bool is_consensus_public = false; // If true, consensus are broadcasted to non-unl nodes as well.
bool is_npl_public = false; // If true, npl messages are broadcasted to non-unl nodes as well.
uint16_t max_input_ledger_offset; // Maximum ledger sequence number offset that can be specified in the input.
appbill_config appbill;
round_limits_config round_limits;

View File

@@ -56,6 +56,7 @@ namespace msg::usrmsg
constexpr const char *REASON_BAD_SIG = "bad_sig";
constexpr const char *REASON_APPBILL_BALANCE_EXCEEDED = "appbill_balance_exceeded";
constexpr const char *REASON_MAX_LEDGER_EXPIRED = "max_ledger_expired";
constexpr const char *REASON_MAX_LEDGER_OFFSET_EXCEEDED = "max_ledger_offset_exceeded";
constexpr const char *REASON_NONCE_EXPIRED = "nonce_expired";
constexpr const char *REASON_ALREADY_SUBMITTED = "already_submitted";
constexpr const char *REASON_NONCE_OVERFLOW = "nonce_overflow";

View File

@@ -176,6 +176,14 @@ namespace usr
uint64_t max_lcl_seq_no;
if (parser.extract_input_container(input_data, nonce, max_lcl_seq_no, input_container) != -1)
{
const p2p::sequence_hash lcl_id = ledger::ctx.get_lcl_id();
// Ignore the input if the max ledger seq number specified is beyond the max offeset.
if (conf::cfg.contract.max_input_ledger_offset != 0 && max_lcl_seq_no > lcl_id.seq_no + conf::cfg.contract.max_input_ledger_offset)
{
send_input_status(parser, user.session, msg::usrmsg::STATUS_REJECTED, msg::usrmsg::REASON_MAX_LEDGER_OFFSET_EXCEEDED, sig);
return -1;
}
// Check for max nonce size.
if (nonce.size() > MAX_INPUT_NONCE_SIZE)
{
@@ -384,6 +392,13 @@ namespace usr
const char *validate_user_input_submission(const std::string &user_pubkey, const usr::extracted_user_input &extracted_input,
const uint64_t lcl_seq_no, size_t &total_input_size, std::string &hash, util::buffer_view &input)
{
// Ignore the input if the max ledger seq number specified is beyond the max offeset.
if (conf::cfg.contract.max_input_ledger_offset != 0 && extracted_input.max_lcl_seq_no > lcl_seq_no + conf::cfg.contract.max_input_ledger_offset)
{
LOG_DEBUG << "User input bad max ledger seq beyond the max offset.";
return msg::usrmsg::REASON_MAX_LEDGER_OFFSET_EXCEEDED;
}
// Ignore the input if our ledger has passed the input TTL.
if (extracted_input.max_lcl_seq_no <= lcl_seq_no)
{