mirror of
https://github.com/EvernodeXRPL/hpcore.git
synced 2026-04-29 15:37:59 +00:00
224 lines
6.2 KiB
C++
224 lines
6.2 KiB
C++
/**
|
|
Entry point for HP Core
|
|
**/
|
|
|
|
#include "pchheader.hpp"
|
|
#include "util.hpp"
|
|
#include "conf.hpp"
|
|
#include "crypto.hpp"
|
|
#include "sc.hpp"
|
|
#include "hplog.hpp"
|
|
#include "usr/usr.hpp"
|
|
#include "usr/read_req.hpp"
|
|
#include "p2p/p2p.hpp"
|
|
#include "consensus.hpp"
|
|
#include "ledger.hpp"
|
|
#include "hpfs/hpfs.hpp"
|
|
#include "state/state_sync.hpp"
|
|
#include "state/state_serve.hpp"
|
|
|
|
/**
|
|
* Parses CLI args and extracts hot pocket command and parameters given.
|
|
* HP command line accepts command and the contract directory(optional)
|
|
*/
|
|
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.
|
|
{
|
|
// We populate the global contract ctx with the detected command.
|
|
conf::ctx.command = argv[1];
|
|
|
|
// For run/new/rekey, contract directory argument must be specified.
|
|
|
|
if (conf::ctx.command == "run" || conf::ctx.command == "new" || conf::ctx.command == "rekey")
|
|
{
|
|
if (argc != 3)
|
|
{
|
|
std::cerr << "Contract directory not specified.\n";
|
|
}
|
|
else
|
|
{
|
|
// We inform the conf subsystem to populate the contract directory context values
|
|
// based on the directory argument from the command line.
|
|
conf::set_contract_dir_paths(argv[0], argv[2]);
|
|
|
|
return 0;
|
|
}
|
|
}
|
|
else if (conf::ctx.command == "version")
|
|
{
|
|
if (argc == 2)
|
|
return 0;
|
|
}
|
|
}
|
|
|
|
// If all extractions fail display help message.
|
|
|
|
std::cerr << "Arguments mismatch.\n";
|
|
std::cout << "Usage:\n";
|
|
std::cout << "hpcore version\n";
|
|
std::cout << "hpcore <command> <contract dir> (command = run | new | rekey)\n";
|
|
std::cout << "Example: hpcore run ~/mycontract\n";
|
|
|
|
return -1;
|
|
}
|
|
|
|
/**
|
|
* Performs any cleanup on graceful application termination.
|
|
*/
|
|
void deinit()
|
|
{
|
|
consensus::deinit();
|
|
ledger::deinit();
|
|
state_sync::deinit();
|
|
state_serve::deinit();
|
|
read_req::deinit();
|
|
sc::deinit();
|
|
usr::deinit();
|
|
p2p::deinit();
|
|
}
|
|
|
|
void sigint_handler(int signum)
|
|
{
|
|
LOG_WARNING << "Interrupt signal (" << signum << ") received.";
|
|
deinit();
|
|
std::cout << "hpcore exiting\n";
|
|
exit(signum);
|
|
}
|
|
|
|
void segfault_handler(int signum)
|
|
{
|
|
std::cerr << boost::stacktrace::stacktrace() << "\n";
|
|
exit(SIGABRT);
|
|
}
|
|
|
|
/**
|
|
* Global exception handler for std exceptions.
|
|
*/
|
|
void std_terminate() noexcept
|
|
{
|
|
std::exception_ptr exptr = std::current_exception();
|
|
if (exptr != 0)
|
|
{
|
|
try
|
|
{
|
|
std::rethrow_exception(exptr);
|
|
}
|
|
catch (std::exception &ex)
|
|
{
|
|
LOG_ERROR << "std error: " << ex.what();
|
|
}
|
|
catch (...)
|
|
{
|
|
LOG_ERROR << "std error: Terminated due to unknown exception";
|
|
}
|
|
}
|
|
else
|
|
{
|
|
LOG_ERROR << "std error: Terminated due to unknown reason";
|
|
}
|
|
|
|
LOG_ERROR << boost::stacktrace::stacktrace();
|
|
|
|
exit(1);
|
|
}
|
|
|
|
int main(int argc, char **argv)
|
|
{
|
|
// Register exception and segfault handlers.
|
|
std::set_terminate(&std_terminate);
|
|
signal(SIGSEGV, &segfault_handler);
|
|
signal(SIGABRT, &segfault_handler);
|
|
|
|
// seed rand
|
|
srand(util::get_epoch_milliseconds());
|
|
|
|
// Disable SIGPIPE to avoid crashing on broken pipe IO.
|
|
{
|
|
sigset_t mask;
|
|
sigemptyset(&mask);
|
|
sigaddset(&mask, SIGPIPE);
|
|
pthread_sigmask(SIG_BLOCK, &mask, NULL);
|
|
}
|
|
|
|
// Extract the CLI args
|
|
// This call will populate conf::ctx
|
|
if (parse_cmd(argc, argv) != 0)
|
|
return -1;
|
|
|
|
if (conf::ctx.command == "version")
|
|
{
|
|
// Print the version
|
|
std::cout << util::HP_VERSION << std::endl;
|
|
}
|
|
else
|
|
{
|
|
// This block is about contract operations (new/rekey/run)
|
|
// All the contract operations will be executed on the contract directory specified
|
|
// in the command line args. 'parse_cmd()' above takes care of populating the contexual directory paths.
|
|
|
|
// For any contract opreation to execute, we should init the crypto subsystem.
|
|
if (crypto::init() != 0)
|
|
return -1;
|
|
|
|
if (conf::ctx.command == "new")
|
|
{
|
|
// This will create a new contract with all the required files.
|
|
if (conf::create_contract() != 0)
|
|
return -1;
|
|
}
|
|
else
|
|
{
|
|
if (conf::ctx.command == "rekey")
|
|
{
|
|
// This will generate new signing keys for the contract.
|
|
if (conf::rekey() != 0)
|
|
return -1;
|
|
}
|
|
else if (conf::ctx.command == "run")
|
|
{
|
|
// In order to host the contract we should init some required sub systems.
|
|
|
|
if (conf::init() != 0)
|
|
return -1;
|
|
|
|
// Set HP process cwd to the contract directory. This will make both HP and contract process
|
|
// both have the same cwd.
|
|
chdir(conf::ctx.contract_dir.c_str());
|
|
|
|
hplog::init();
|
|
|
|
LOG_INFO << "Operating mode: "
|
|
<< (conf::cfg.startup_mode == conf::OPERATING_MODE::OBSERVER ? "Observer" : "Proposer");
|
|
LOG_INFO << "Public key: " << conf::cfg.pubkeyhex.substr(2); // Public key without 'ed' prefix.
|
|
|
|
if (p2p::init() != 0 ||
|
|
usr::init() != 0 ||
|
|
sc::init() ||
|
|
read_req::init() != 0 ||
|
|
state_serve::init() != 0 ||
|
|
state_sync::init() != 0 ||
|
|
ledger::init() ||
|
|
consensus::init() != 0)
|
|
{
|
|
deinit();
|
|
return -1;
|
|
}
|
|
|
|
// After initializing primary subsystems, register the SIGINT handler.
|
|
signal(SIGINT, &sigint_handler);
|
|
|
|
// Wait until consensus thread finishes.
|
|
consensus::wait();
|
|
|
|
// deinit() here only gets called when there is an error in consensus.
|
|
// If not deinit in the sigint handler is called when a SIGINT is received.
|
|
deinit();
|
|
}
|
|
}
|
|
}
|
|
|
|
std::cout << "exited normally\n";
|
|
return 0;
|
|
}
|