Contract execute config flag. (#226)

* Added contract execute flag. Made bin_path optional.
* Updated docker cluster default config.
* Renamed contract config to hp config.
This commit is contained in:
Ravin Perera
2021-01-22 14:33:07 +05:30
committed by GitHub
parent eef6448f08
commit 610b67cec0
10 changed files with 67 additions and 52 deletions

View File

@@ -35,7 +35,7 @@ Example: When you make a change to `p2pmsg_content.fbc` defnition file, you need
## Code structure
Code is divided into subsystems via namespaces.
**conf::** Handles contract configuration. Loads and holds the central configuration object. Used by most of the subsystems.
**conf::** Handles configuration. Loads and holds the central configuration object. Used by most of the subsystems.
**crypto::** Handles cryptographic activities. Wraps libsodium and offers convenience functions.

View File

@@ -11,7 +11,7 @@ namespace conf
contract_ctx ctx;
// Global configuration struct exposed to the application.
contract_config cfg;
hp_config cfg;
// Stores the initial startup mode of the node.
ROLE startup_mode;
@@ -26,17 +26,17 @@ namespace conf
bool init_success = false;
/**
* Loads and initializes the contract config for execution. Must be called once during application startup.
* Loads and initializes the config for execution. Must be called once during application startup.
* @return 0 for success. -1 for failure.
*/
int init()
{
// The validations/loading needs to be in this order.
// 1. Validate contract directories
// 2. Read and load the contract config into memory
// 2. Read and load the config into memory
// 4. Validate the loaded config values
// 5. Initialize logging subsystem.
// 6. Update and validate contract config if patch file exists.
// 6. Update and validate config if patch file exists.
if (validate_contract_dir_paths() == -1 ||
set_config_lock() == -1 ||
@@ -64,7 +64,7 @@ namespace conf
}
/**
* Generates and saves new signing keys in the contract config.
* Generates and saves new signing keys in the config.
*/
int rekey()
{
@@ -72,8 +72,8 @@ namespace conf
if (set_config_lock() == -1)
return -1;
// Load the contract config and re-save with the newly generated keys.
contract_config cfg = {};
// Load the config and re-save with the newly generated keys.
hp_config cfg = {};
if (read_config(cfg) != 0)
return -1;
@@ -93,7 +93,7 @@ namespace conf
}
/**
* Creates a new contract directory with the default contract config.
* Creates a new contract directory with the default config.
* By the time this gets called, the 'ctx' struct must be populated.
* This function makes use of the paths populated in the ctx.
*/
@@ -106,14 +106,14 @@ namespace conf
}
// Recursivly create contract directories. Return an error if unable to create
if(util::create_dir_tree_recursive(ctx.config_dir) == -1 ||
if (util::create_dir_tree_recursive(ctx.config_dir) == -1 ||
util::create_dir_tree_recursive(ctx.hist_dir) == -1 ||
util::create_dir_tree_recursive(ctx.full_hist_dir) == -1 ||
util::create_dir_tree_recursive(ctx.log_dir) == -1 ||
util::create_dir_tree_recursive(ctx.hpfs_dir + "/seed" + hpfs::STATE_DIR_PATH) == -1 ||
util::create_dir_tree_recursive(ctx.hpfs_mount_dir) == -1)
{
std::cerr << "ERROR: unable to create directories.\n";
std::cerr << "ERROR: unable to create directories.\n";
return -1;
}
@@ -121,7 +121,7 @@ namespace conf
//We populate the in-memory struct with default settings and then save it to the file.
contract_config cfg = {};
hp_config cfg = {};
crypto::generate_signing_keys(cfg.node.public_key, cfg.node.private_key);
cfg.node.public_key_hex = util::to_hex(cfg.node.public_key);
@@ -133,6 +133,7 @@ namespace conf
cfg.node.full_history = false;
cfg.contract.id = crypto::generate_uuid();
cfg.contract.execute = true;
cfg.contract.version = "1.0";
//Add self pubkey to the unl.
cfg.contract.unl.emplace(cfg.node.public_key);
@@ -211,7 +212,7 @@ namespace conf
* Reads the config file on disk and populates the in-memory 'cfg' struct.
* @return 0 for successful loading of config. -1 for failure.
*/
int read_config(contract_config &cfg)
int read_config(hp_config &cfg)
{
// Read the config file into json document object.
std::string buf;
@@ -239,7 +240,7 @@ namespace conf
cfg.hp_version = d["hp_version"].as<std::string>();
if (cfg.hp_version.empty())
{
std::cerr << "Contract config HP version missing.\n";
std::cerr << "Config HP version missing.\n";
return -1;
}
@@ -307,7 +308,8 @@ namespace conf
// contract
{
parse_contract_section_json(cfg.contract, d["contract"], true);
if (parse_contract_section_json(cfg.contract, d["contract"], false) == -1)
return -1;
}
// mesh
@@ -420,7 +422,7 @@ namespace conf
* Saves the provided 'cfg' struct into the config file.
* @return 0 for successful save. -1 for failure.
*/
int write_config(const contract_config &cfg)
int write_config(const hp_config &cfg)
{
// Popualte json document with 'cfg' values.
// ojson is used instead of json to preserve insertion order.
@@ -437,7 +439,7 @@ namespace conf
// Contract config section.
jsoncons::ojson contract;
populate_contract_section_json(contract, cfg.contract, true);
populate_contract_section_json(contract, cfg.contract, false);
d.insert_or_assign("contract", contract);
// Mesh configs.
@@ -499,7 +501,7 @@ namespace conf
*
* @return 0 for successful validation. -1 for failure.
*/
int validate_config(const contract_config &cfg)
int validate_config(const hp_config &cfg)
{
// Check for non-empty signing keys.
// We also check for key pair validity as well in the below code.
@@ -513,7 +515,6 @@ namespace conf
bool fields_missing = false;
fields_missing |= cfg.contract.bin_path.empty() && std::cerr << "Missing cfg field: bin_path\n";
fields_missing |= cfg.contract.roundtime == 0 && std::cerr << "Missing cfg field: roundtime\n";
fields_missing |= cfg.contract.unl.empty() && std::cerr << "Missing cfg field: unl. Unl list cannot be empty.\n";
fields_missing |= cfg.contract.id.empty() && std::cerr << "Missing cfg field: contract id.\n";
@@ -651,14 +652,14 @@ namespace conf
int populate_patch_config()
{
jsoncons::ojson jdoc;
populate_contract_section_json(jdoc, cfg.contract, false);
populate_contract_section_json(jdoc, cfg.contract, true);
const std::string patch_file_path = hpfs::physical_path(hpfs::RW_SESSION_NAME, hpfs::PATCH_FILE_PATH);
return write_json_file(patch_file_path, jdoc);
}
/**
* Validate and update contract config section if a patch file detected. Whenever patch file change is detected,
* Validate and update config section if a patch file detected. Whenever patch file change is detected,
* we also persist it to hp.cfg so that both config files are consistent with each other.
* @param hpfs_session_name The current hpfs session hosting the patch config.
* @return -1 on error and 0 in successful update.
@@ -699,7 +700,7 @@ namespace conf
buf.clear();
// Persist new changes to HP config file.
if (parse_contract_section_json(cfg.contract, jdoc, false) == -1 ||
if (parse_contract_section_json(cfg.contract, jdoc, true) == -1 ||
write_config(cfg) == -1)
{
LOG_ERROR << "Error applying patch config.";
@@ -751,12 +752,15 @@ namespace conf
* Populates contract section field values into the provided json doc.
* @param jdoc The json doc to populate contract section field values.
* @param contract The contract fields struct containing current field values.
* @param include_id Whether to populate the contract id field or not.
* @param is_patch_config Whether this is called for patch config or not.
*/
void populate_contract_section_json(jsoncons::ojson &jdoc, const contract_params &contract, const bool include_id)
void populate_contract_section_json(jsoncons::ojson &jdoc, const contract_config &contract, const bool is_patch_config)
{
if (include_id)
if (!is_patch_config)
{
jdoc.insert_or_assign("id", contract.id);
jdoc.insert_or_assign("execute", contract.execute);
}
jdoc.insert_or_assign("version", contract.version);
jsoncons::ojson unl(jsoncons::json_array_arg);
@@ -782,14 +786,14 @@ namespace conf
* Validates the provided json doc and populate the provided contract struct with values from json doc.
* @param contract The contract fields struct to populate.
* @param jdoc The json doc containing the contract section field values.
* @param parse_id Whether to parse the contract id field or not.
* @param is_patch_config Whether this is called for patch config or not.
* @return 0 on success. -1 on error.
*/
int parse_contract_section_json(contract_params &contract, const jsoncons::ojson &jdoc, const bool parse_id)
int parse_contract_section_json(contract_config &contract, const jsoncons::ojson &jdoc, const bool is_patch_config)
{
try
{
if (parse_id)
if (!is_patch_config)
{
contract.id = jdoc["id"].as<std::string>();
if (contract.id.empty())
@@ -797,6 +801,8 @@ namespace conf
std::cerr << "Contract id not specified.\n";
return -1;
}
contract.execute = jdoc["execute"].as<bool>();
}
contract.version = jdoc["version"].as<std::string>();
@@ -863,7 +869,7 @@ namespace conf
}
catch (const std::exception &e)
{
std::cerr << "Required contract config field " << extract_missing_field(e.what()) << " missing at " << ctx.config_file << std::endl;
std::cerr << "Required contract config field '" << extract_missing_field(e.what()) << "' missing at " << ctx.config_file << std::endl;
return -1;
}

View File

@@ -4,8 +4,8 @@
#include "pchheader.hpp"
/**
* Manages the central contract config and context structs.
* Contains functions to contract config operations such as create/rekey/load.
* Manages the central config and context structs.
* Contains functions to config operations such as create/rekey/load.
*/
namespace conf
{
@@ -80,9 +80,10 @@ namespace conf
// Config element which are initialized in memory (This is not directly loaded from the config file)
std::vector<std::string> runtime_args; // Appbill execution args used during runtime.
};
struct contract_params
struct contract_config
{
std::string id; // Contract guid.
bool execute; // Whether or not to execute the contract on the node.
std::string version; // Contract version string.
std::set<std::string> unl; // Unique node list (list of binary public keys)
std::string bin_path; // Full path to the contract binary
@@ -144,8 +145,8 @@ namespace conf
std::string hpfs_mount_dir; // hpfs fuse file system mount path.
std::string hpfs_rw_dir; // hpfs read/write fs session path.
std::string log_dir; // Contract log dir full path.
std::string config_dir; // Contract config dir full path.
std::string config_file; // Full path to the contract config file.
std::string config_dir; // Config dir full path.
std::string config_file; // Full path to the config file.
std::string tls_key_file; // Full path to the tls private key file.
std::string tls_cert_file; // Full path to the tls certificate.
@@ -153,13 +154,13 @@ namespace conf
struct flock config_lock; // Config file lock.
};
// Holds all the contract config values.
struct contract_config
// Holds all the config values.
struct hp_config
{
// Config elements which are loaded from the config file.
std::string hp_version; // Version of Hot Pocket that generated the config.
node_config node;
contract_params contract;
contract_config contract;
mesh_config mesh;
user_config user;
log_config log;
@@ -171,7 +172,7 @@ namespace conf
// Global configuration struct exposed to the application.
// Other modeuls will access config values via this.
extern contract_config cfg;
extern hp_config cfg;
int init();
@@ -185,11 +186,11 @@ namespace conf
//------Internal-use functions for this namespace.
int read_config(contract_config &cfg);
int read_config(hp_config &cfg);
int write_config(const contract_config &cfg);
int write_config(const hp_config &cfg);
int validate_config(const contract_config &cfg);
int validate_config(const hp_config &cfg);
int validate_contract_dir_paths();
@@ -207,9 +208,9 @@ namespace conf
int release_config_lock();
void populate_contract_section_json(jsoncons::ojson &jdoc, const contract_params &contract, const bool include_id);
void populate_contract_section_json(jsoncons::ojson &jdoc, const contract_config &contract, const bool is_patch_config);
int parse_contract_section_json(contract_params &contract, const jsoncons::ojson &json, const bool parse_id);
int parse_contract_section_json(contract_config &contract, const jsoncons::ojson &json, const bool is_patch_config);
int write_json_file(const std::string &file_path, const jsoncons::ojson &d);

View File

@@ -849,7 +849,7 @@ namespace consensus
return -1;
// Execute the contract
if (!ctx.is_shutting_down)
if (conf::cfg.contract.execute && !ctx.is_shutting_down)
{
{
std::scoped_lock lock(ctx.contract_ctx_mutex);

View File

@@ -5,7 +5,7 @@
/**
* Offers convenience functions for cryptographic operations wrapping libsodium.
* These functions are used for contract config and user/peer message authentication.
* These functions are used for config and user/peer message authentication.
*/
namespace crypto
{

View File

@@ -23,7 +23,7 @@ namespace p2p
util::rollover_hashset recent_peermsg_hashes(200);
/**
* This gets hit every time a peer connects to HP via the peer port (configured in contract config).
* This gets hit every time a peer connects to HP via the peer port (configured in config).
* @param session connected session.
* @return returns 0 if connection is successful and peer challenge is sent otherwise, -1.
*/

View File

@@ -11,7 +11,7 @@ namespace jusrmsg = msg::usrmsg::json;
namespace usr
{
/**
* This gets hit every time a client connects to HP via the public port (configured in contract config).
* This gets hit every time a client connects to HP via the public port (configured in config).
* @param session connected session.
* @return returns 0 if connection is successful and user challenge is sent, otherwise -1.
*/

View File

@@ -12,10 +12,10 @@
namespace util
{
// Hot Pocket version. Displayed on 'hotpocket version' and written to new contract configs.
// Hot Pocket version. Displayed on 'hotpocket version' and written to new configs.
constexpr const char *HP_VERSION = "0.1";
// Minimum compatible config version (this will be used to validate contract configs)
// Minimum compatible config version (this will be used to validate configs)
constexpr const char *MIN_CONFIG_VERSION = "0.1";
// Current version of the peer message protocol.

View File

@@ -82,18 +82,26 @@ do
# So each node is reachable via 'node<id>' name.
peers[i]="node${n}:${peerport}"
# Update contract config.
# Update config.
contract_json=$(node -p "JSON.stringify({...require('./tmp.json').contract,
id: '3c349abe-4d70-4f50-9fa6-018f1f2530ab', \
bin_path: '$binary', \
bin_args: '$binargs', \
roundtime: $roundtime, \
consensus: 'public', \
npl: 'public', \
appbill: { \
mode: '', \
bin_args: '' \
},}, null, 2)")
mesh_json=$(node -p "JSON.stringify({...require('./tmp.json').mesh, port:${peerport}}, null, 2)")
mesh_json=$(node -p "JSON.stringify({...require('./tmp.json').mesh, \
port:${peerport}, \
peer_discovery: { \
enabled: true, \
interval: 10000 \
}
}, null, 2)")
user_json=$(node -p "JSON.stringify({...require('./tmp.json').user, port:${pubport}}, null, 2)")
node -p "JSON.stringify({...require('./tmp.json'), \

View File

@@ -362,7 +362,7 @@ do
# Skip param is passed as -1 to stop skipping self pubkey.
myunl=$(joinarr pubkeys -1)
# Merge json contents to produce final contract config.
# Merge json contents to produce final config.
echo "$(cat ./cfg/node$n.cfg)" \
'{"contract": {"id": "3c349abe-4d70-4f50-9fa6-018f1f2530ab", "bin_path": "/usr/bin/node", "bin_args": "'$basedir'/hpfiles/nodejs_contract/echo_contract.js", "unl": '${myunl}'}}'\
'{"mesh": {"known_peers": '${mypeers}'}}'\