diff --git a/src/conf.cpp b/src/conf.cpp index 27157876..760f6d4e 100644 --- a/src/conf.cpp +++ b/src/conf.cpp @@ -1,9 +1,6 @@ #include #include #include -#include -#include -#include #include #include #include @@ -20,7 +17,39 @@ namespace conf ContractCtx ctx; ContractConfig cfg; -void load_config() +// v1 < v2 -> -1 +// v1 == v2 -> 0 +// v1 > v2 -> +1 +int version_compare(std::string v1, std::string v2) +{ + size_t i = 0, j = 0; + while (i < v1.length() || j < v2.length()) + { + int acc1 = 0, acc2 = 0; + + while (i < v1.length() && v1[i] != '.') + { + acc1 = acc1 * 10 + (v1[i] - '0'); + i++; + } + while (j < v2.length() && v2[j] != '.') + { + acc2 = acc2 * 10 + (v2[j] - '0'); + j++; + } + + if (acc1 < acc2) + return -1; + if (acc1 > acc2) + return +1; + + ++i; + ++j; + } + return 0; +} + +int load_config() { ifstream ifs(ctx.configFile); IStreamWrapper isw(ifs); @@ -28,6 +57,16 @@ void load_config() Document d; d.ParseStream(isw); + //Check contract version. + string cfgVersion = d["version"].GetString(); + if (version_compare(cfgVersion, _HP_MIN_CONTRACT_VERSION_) == -1) + { + cerr << "Contract version too old. Minimum " + << _HP_MIN_CONTRACT_VERSION_ << " required. " + << cfgVersion << " found.\n"; + return 0; + } + cfg.pubkeyb64 = d["pubkeyb64"].GetString(); cfg.seckeyb64 = d["seckeyb64"].GetString(); cfg.binary = d["binary"].GetString(); @@ -47,6 +86,8 @@ void load_config() cfg.pubport = d["pubport"].GetInt(); cfg.pubmaxsize = d["pubmaxsize"].GetInt(); cfg.pubmaxcpm = d["pubmaxcpm"].GetInt(); + + return 1; } void save_config() @@ -54,6 +95,7 @@ void save_config() Document d; d.SetObject(); Document::AllocatorType &allocator = d.GetAllocator(); + d.AddMember("version", StringRef(_HP_VERSION_), allocator); d.AddMember("pubkeyb64", StringRef(cfg.pubkeyb64.c_str()), allocator); d.AddMember("seckeyb64", StringRef(cfg.seckeyb64.c_str()), allocator); d.AddMember("binary", StringRef(cfg.binary.c_str()), allocator); @@ -91,46 +133,21 @@ void save_config() d.Accept(writer); } -int parse_cmd(int argc, char **argv) +void set_contract_dir_paths(string basedir) { - if (argc == 3) //We get working dir as an arg anyway. So we need to check for 1+2 args. - { - string command(argv[1]); - if (command == "run" || command == "new" || command == "rekey") - { - ctx.command = command; - string dir = argv[2]; - if (dir[dir.size() - 1] == '/') - dir = dir.substr(0, dir.size() - 1); + if (basedir[basedir.size() - 1] == '/') + basedir = basedir.substr(0, basedir.size() - 1); - ctx.contractDir = dir; - ctx.configDir = dir + "/cfg"; - ctx.configFile = ctx.configDir + "/hp.cfg"; - ctx.histDir = dir + "/hist"; - ctx.stateDir = dir + "/state"; - ctx.binDir = dir + "/bin"; - return 1; - } - else - { - cerr << "Invalid command. 'run | new | rekey' expected.\n"; - } - } - else - { - cerr << "Argument count mismatch.\n"; - } - - cout << "Usage: hpcore (command = run | new |rekey)\n"; - cout << "Example: hpcore run ~/mycontract\n"; - - return 0; + ctx.contractDir = basedir; + ctx.configDir = basedir + "/cfg"; + ctx.configFile = ctx.configDir + "/hp.cfg"; + ctx.histDir = basedir + "/hist"; + ctx.stateDir = basedir + "/state"; + ctx.binDir = basedir + "/bin"; } int create_contract() { - struct stat dirInfo; - if (boost::filesystem::exists(ctx.contractDir)) { cerr << "Contract dir already exists.\n"; @@ -153,9 +170,8 @@ int create_contract() return 1; } -int rekey() +int clear_keys() { - //Clear the keys and save the config. crpyto::init will automatically init the keys. cfg.pubkeyb64 = ""; cfg.seckeyb64 = ""; save_config(); @@ -163,23 +179,22 @@ int rekey() int init(int argc, char **argv) { - if (!parse_cmd(argc, argv)) - return 0; - if (ctx.command == "new") { if (!create_contract()) return 0; - load_config(); } - else if (ctx.command == "rekey") + + if (!load_config()) + return 0; + + if (ctx.command == "rekey") { - load_config(); - rekey(); + //Clear the keys. crpyto::init will automatically init the keys. + clear_keys(); } else if (ctx.command == "run") { - load_config(); //TO DO: Contract run logic. } diff --git a/src/conf.h b/src/conf.h index 98b6fc00..5a424f7e 100644 --- a/src/conf.h +++ b/src/conf.h @@ -1,6 +1,14 @@ #ifndef _HP_CONF_H_ #define _HP_CONF_H_ +//Hot Pocket version. Displayed on 'hotpocket version' and written to new contract configs. +#define _HP_VERSION_ "0.1" +//minimum compatible contract config version (this will be used to validate contract configs) +#define _HP_MIN_CONTRACT_VERSION_ "0.1" +//minimum compatible peer message version (this will be used to accept/reject incoming peer connections) +//(Keeping this as int for effcient msg payload and comparison) +#define _HP_MIN_PEERMSG_VERSION_ 1 + #include #include @@ -23,10 +31,19 @@ struct ContractCtx struct ContractConfig { + /* + Config elements which are only initialized in memory (these are not loaded from the config file) + */ + //public key bytes + unsigned char *pubkey; + //secret key bytes + unsigned char *seckey; + + /* + Config elements which are loaded from the config file. + */ string pubkeyb64; string seckeyb64; - unsigned char* pubkey; - unsigned char* seckey; string binary; string binargs; string listenip; @@ -42,7 +59,7 @@ struct ContractConfig extern ContractCtx ctx; extern ContractConfig cfg; int init(int argc, char **argv); -void load_config(); +void set_contract_dir_paths(string basedir); void save_config(); } // namespace conf diff --git a/src/main.cpp b/src/main.cpp index 1b83cc10..fbb58387 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -9,26 +9,61 @@ using namespace std; +int parse_cmd(int argc, char **argv); + int main(int argc, char **argv) { - if (!(conf::init(argc, argv) && crypto::init())) - { - cerr << "Init error\n"; + if (!parse_cmd(argc, argv)) return -1; + + if (conf::ctx.command == "version") + { + cout << _HP_VERSION_ << endl; } - - //Example sign and verification. - string msg = "hotpocket"; - string sigb64 = crypto::sign_b64(msg); - cout << "Message: " << msg << endl; - cout << "Signature: " << sigb64 << endl; - - bool isValid = crypto::verify_b64(msg, sigb64, conf::cfg.pubkeyb64); - if (isValid) - cout << "Signature verified.\n"; else - cout << "Invalid signature.\n"; + { + bool initSuccess = conf::init(argc, argv) && crypto::init(); + if (!initSuccess) + { + cerr << "Init error\n"; + return -1; + } + } cout << "exited normally\n"; return 0; } + +int parse_cmd(int argc, char **argv) +{ + if (argc > 1) //We get working dir as an arg anyway. So we need to check for >1 args. + { + string command = argv[1]; + conf::ctx.command = command; + if (command == "run" || command == "new" || command == "rekey") + { + if (argc != 3) + { + cerr << "Contract directory not specified.\n"; + } + else + { + conf::set_contract_dir_paths(argv[2]); + return 1; + } + } + else if (command == "version") + { + if (argc == 2) + return 1; + } + } + + cerr << "Arguments mismatch.\n"; + cout << "Usage:\n"; + cout << "hpcore version\n"; + cout << "hpcore (command = run | new | rekey)\n"; + cout << "Example: hpcore run ~/mycontract\n"; + + return 0; +} \ No newline at end of file