mirror of
https://github.com/EvernodeXRPL/hpcore.git
synced 2026-04-29 15:37:59 +00:00
Implementation for message handling
This commit is contained in:
@@ -59,10 +59,10 @@ add_executable(hpcore
|
||||
src/ledger/ledger_sync.cpp
|
||||
src/ledger/ledger_serve.cpp
|
||||
src/ledger/ledger.cpp
|
||||
src/hpsh/hpsh.cpp
|
||||
src/status.cpp
|
||||
src/consensus.cpp
|
||||
src/main.cpp
|
||||
src/hpsh/hpsh.cpp
|
||||
)
|
||||
target_link_libraries(hpcore
|
||||
killswitch
|
||||
@@ -78,7 +78,7 @@ target_link_libraries(hpcore
|
||||
add_custom_command(TARGET hpcore POST_BUILD
|
||||
|
||||
# COMMAND strip ./build/hpcore
|
||||
COMMAND rm -f ./build/hpws ./build/hpfs ./build/hpsh && cp ./test/bin/hpws ./test/bin/hpfs ./test/bin/hpsh ./build/
|
||||
COMMAND cp ./test/bin/hpws ./test/bin/hpfs ./test/bin/hpsh ./build/
|
||||
)
|
||||
|
||||
target_precompile_headers(hpcore PUBLIC src/pchheader.hpp)
|
||||
|
||||
@@ -123,6 +123,9 @@ async function main() {
|
||||
else if (inp === "stat") {
|
||||
hpc.getStatus().then(stat => console.log(stat));
|
||||
}
|
||||
else if (inp.startsWith("hpsh ")) {
|
||||
hpc.submitHpshRequest(inp.substr(5)).then(reply => console.log(reply));
|
||||
}
|
||||
else {
|
||||
|
||||
if (inp.startsWith("upload ")) {
|
||||
|
||||
@@ -84,5 +84,42 @@ const echoContract = async (ctx) => {
|
||||
// await ctx.updateConfig(config);
|
||||
}
|
||||
|
||||
const fallback = async (ctx) => {
|
||||
console.log("This is fallback mode");
|
||||
|
||||
const hpconfig = await ctx.getConfig();
|
||||
|
||||
for (const u of ctx.unl.list()) {
|
||||
const gap = Math.abs(u.activeOn - ctx.timestamp);
|
||||
// If last active timestamp is before the twice of roundtime, This node must be active.
|
||||
if (u.activeOn && gap > (hpconfig.consensus.roundtime * 4)) {
|
||||
console.log("Updating patch config", u);
|
||||
hpconfig.unl = hpconfig.unl.filter(e => e !== u.publicKey);
|
||||
await ctx.updateConfig(hpconfig);
|
||||
}
|
||||
}
|
||||
|
||||
// NPL messages example.
|
||||
// Start listening to incoming NPL messages before we send ours.
|
||||
const promise = new Promise((resolve, reject) => {
|
||||
let timeout = setTimeout(() => {
|
||||
reject('NPL timeout.');
|
||||
}, 4000);
|
||||
|
||||
let list = [];
|
||||
ctx.unl.onMessage((node, msg) => {
|
||||
console.log(`${node.publicKey} said ${msg} to me.`);
|
||||
list.push(msg);
|
||||
if (list.length == ctx.unl.list().length) {
|
||||
clearTimeout(timeout);
|
||||
resolve();
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
await ctx.unl.send("Hello");
|
||||
await promise;
|
||||
}
|
||||
|
||||
const hpc = new HotPocket.Contract();
|
||||
hpc.init(echoContract);
|
||||
32
src/conf.cpp
32
src/conf.cpp
@@ -194,6 +194,8 @@ namespace conf
|
||||
cfg.log.loggers.emplace("console");
|
||||
cfg.log.loggers.emplace("file");
|
||||
|
||||
cfg.hpsh.enabled = false;
|
||||
|
||||
// Save the default settings into the config file.
|
||||
if (write_config(cfg) != 0)
|
||||
return -1;
|
||||
@@ -512,6 +514,28 @@ namespace conf
|
||||
}
|
||||
}
|
||||
|
||||
// hpsh
|
||||
{
|
||||
jpath = "hpsh";
|
||||
|
||||
try
|
||||
{
|
||||
const jsoncons::ojson &hpsh = d["hpsh"];
|
||||
cfg.hpsh.enabled = hpsh["enabled"].as<bool>();
|
||||
|
||||
if (cfg.hpsh.run_as.from_string(hpsh["run_as"].as<std::string>()) == -1)
|
||||
{
|
||||
std::cerr << "Invalid format for hpsh run as config (\"uid>0:gid>0\" expected).\n";
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
catch (const std::exception &e)
|
||||
{
|
||||
print_missing_field_error(jpath, e);
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -624,6 +648,14 @@ namespace conf
|
||||
d.insert_or_assign("log", log_config);
|
||||
}
|
||||
|
||||
// hpsh configs
|
||||
{
|
||||
jsoncons::ojson hpsh_config;
|
||||
hpsh_config.insert_or_assign("enabled", cfg.hpsh.enabled);
|
||||
hpsh_config.insert_or_assign("run_as", cfg.hpsh.run_as.to_string());
|
||||
d.insert_or_assign("hpsh", hpsh_config);
|
||||
}
|
||||
|
||||
return write_json_file(ctx.config_file, d);
|
||||
}
|
||||
|
||||
|
||||
@@ -208,6 +208,12 @@ namespace conf
|
||||
std::vector<std::string> runtime_env_args; // Contract environment variables.
|
||||
};
|
||||
|
||||
struct hpsh_config
|
||||
{
|
||||
bool enabled = false; // Whether or not to enable hpsh.
|
||||
ugid run_as; // The user/groups id to execute the hpsh as.
|
||||
};
|
||||
|
||||
struct user_config
|
||||
{
|
||||
uint16_t port = 0; // Listening port for public user connections
|
||||
@@ -317,6 +323,7 @@ namespace conf
|
||||
hpfs_config hpfs;
|
||||
log_config log;
|
||||
health_config health; // For debugging only. Not included in the config file.
|
||||
hpsh_config hpsh;
|
||||
};
|
||||
|
||||
// Global contract context struct exposed to the application.
|
||||
|
||||
@@ -2,27 +2,27 @@
|
||||
|
||||
namespace hpsh
|
||||
{
|
||||
constexpr const char *HPSH_EXEC_PATH = "./executable/hpsh";
|
||||
constexpr int MAX_BUFFER_LEN = 1024;
|
||||
constexpr int POLL_TIMEOUT = 1000;
|
||||
constexpr uint32_t POLL_TIMEOUT = 1000;
|
||||
constexpr uint32_t READ_BUFFER_SIZE = 128 * 1024;
|
||||
|
||||
hpsh_context ctx;
|
||||
|
||||
int init()
|
||||
{
|
||||
std::cout << "Initializing hpsh process.." << std::endl;
|
||||
// Do not initialize if disabled in config.
|
||||
if (!conf::cfg.hpsh.enabled)
|
||||
return 0;
|
||||
|
||||
if (socketpair(AF_UNIX, SOCK_SEQPACKET, 0, ctx.control_fds) == -1)
|
||||
{
|
||||
std::cerr << errno << "Error initializing socket pair." << std::endl;
|
||||
LOG_ERROR << errno << ": Error initializing socket pair.";
|
||||
return -1;
|
||||
}
|
||||
|
||||
ctx.hpsh_pid = fork();
|
||||
if (ctx.hpsh_pid == -1)
|
||||
{
|
||||
std::cerr << errno << "Error forking." << std::endl;
|
||||
LOG_ERROR << errno << ": Error forking.";
|
||||
close(ctx.control_fds[0]);
|
||||
close(ctx.control_fds[1]);
|
||||
return -1;
|
||||
@@ -39,27 +39,41 @@ namespace hpsh
|
||||
|
||||
close(ctx.control_fds[1]);
|
||||
|
||||
std::cout << "Starting hpsh process... " << std::endl;
|
||||
|
||||
std::string fd_str;
|
||||
fd_str.resize(10);
|
||||
snprintf(fd_str.data(), sizeof(fd_str), "%d", ctx.control_fds[0]);
|
||||
char *argv[] = {(char *)conf::ctx.hpsh_exe_path.data(), fd_str.data(), NULL};
|
||||
|
||||
// Just before we execv the hpsh binary, we set user execution user/group if specified in hp config.
|
||||
// (Must set gid before setting uid)
|
||||
if (!conf::cfg.hpsh.run_as.empty() && (setgid(conf::cfg.hpsh.run_as.gid) == -1 || setuid(conf::cfg.hpsh.run_as.uid) == -1))
|
||||
{
|
||||
std::cerr << errno << ": Hpsh process setgid/uid failed."
|
||||
<< "\n";
|
||||
exit(1);
|
||||
}
|
||||
|
||||
char *argv[] = {(char *)HPSH_EXEC_PATH, (char *)("-s1"), fd_str.data(), NULL};
|
||||
execv(argv[0], argv);
|
||||
|
||||
std::cerr << errno << "Error executing hpfs." << std::endl;
|
||||
std::cerr << errno << ": Error executing hpsh."
|
||||
<< "\n";
|
||||
|
||||
close(ctx.control_fds[0]);
|
||||
exit(EXIT_FAILURE);
|
||||
exit(1);
|
||||
}
|
||||
|
||||
ctx.is_initialized = true;
|
||||
|
||||
LOG_INFO << "Hpsh handler started.";
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void deinit()
|
||||
{
|
||||
std::cout << "De-initializing hpsh process.." << std::endl;
|
||||
// This is not initialized if disabled in config.
|
||||
if (!conf::cfg.hpsh.enabled)
|
||||
return;
|
||||
|
||||
ctx.is_shutting_down = true;
|
||||
|
||||
@@ -89,7 +103,7 @@ namespace hpsh
|
||||
}
|
||||
}
|
||||
|
||||
std::cout << "Stopped hpsh process.." << std::endl;
|
||||
LOG_INFO << "Hpsh handler stopped.";
|
||||
}
|
||||
|
||||
int check_hpsh_exited(const bool block)
|
||||
@@ -103,7 +117,7 @@ namespace hpsh
|
||||
}
|
||||
if (wait_res == -1)
|
||||
{
|
||||
std::cerr << errno << ": hpsh process waitpid error. pid:" << ctx.hpsh_pid << std::endl;
|
||||
LOG_ERROR << errno << ": Hpsh process waitpid error. pid:" << ctx.hpsh_pid;
|
||||
ctx.hpsh_pid = 0;
|
||||
return -1;
|
||||
}
|
||||
@@ -113,18 +127,18 @@ namespace hpsh
|
||||
|
||||
if (WIFEXITED(scstatus))
|
||||
{
|
||||
std::cerr << "Contract process ended normally." << std::endl;
|
||||
LOG_DEBUG << "Hpsh process ended normally.";
|
||||
return 1;
|
||||
}
|
||||
else
|
||||
{
|
||||
std::cerr << "Contract process ended prematurely. Exit code " << WEXITSTATUS(scstatus) << std::endl;
|
||||
LOG_WARNING << "Hpsh process ended prematurely. Exit code " << WEXITSTATUS(scstatus);
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
int execute(std::string_view pubkey, std::string_view message)
|
||||
int execute(std::string_view id, std::string_view pubkey, std::string_view message)
|
||||
{
|
||||
if (ctx.is_shutting_down)
|
||||
return -1;
|
||||
@@ -132,7 +146,7 @@ namespace hpsh
|
||||
int child_fds[2];
|
||||
if (socketpair(AF_UNIX, SOCK_SEQPACKET, 0, child_fds) == -1)
|
||||
{
|
||||
std::cerr << errno << "Error initializing socket pair." << std::endl;
|
||||
LOG_ERROR << errno << ": Error initializing socket pair.";
|
||||
return -1;
|
||||
}
|
||||
|
||||
@@ -161,7 +175,7 @@ namespace hpsh
|
||||
|
||||
if (sendmsg(ctx.control_fds[1], &msg, 0) < 0)
|
||||
{
|
||||
std::cerr << errno << "Error writing to control fd." << std::endl;
|
||||
LOG_ERROR << errno << ": Error writing to control fd.";
|
||||
close(child_fds[0]);
|
||||
close(child_fds[1]);
|
||||
return -1;
|
||||
@@ -169,7 +183,7 @@ namespace hpsh
|
||||
|
||||
if (write(child_fds[1], message.data(), sizeof(message)) < 0)
|
||||
{
|
||||
std::cerr << errno << "Error writing to child fd." << std::endl;
|
||||
LOG_ERROR << errno << ": Error writing to child fd.";
|
||||
close(child_fds[0]);
|
||||
close(child_fds[1]);
|
||||
return -1;
|
||||
@@ -177,7 +191,7 @@ namespace hpsh
|
||||
|
||||
{
|
||||
std::scoped_lock lock(ctx.command_mutex);
|
||||
ctx.commands.push_back(command_context{std::string(pubkey), {child_fds[0], child_fds[1]}, std::string(), false});
|
||||
ctx.commands.push_back(command_context{std::string(id), std::string(pubkey), {child_fds[0], child_fds[1]}, std::string(), false});
|
||||
}
|
||||
|
||||
return 0;
|
||||
@@ -203,7 +217,7 @@ namespace hpsh
|
||||
|
||||
if (poll(&pfd, 1, POLL_TIMEOUT) == -1)
|
||||
{
|
||||
std::cerr << errno << "Error in poll" << std::endl;
|
||||
LOG_ERROR << errno << ": Error in poll";
|
||||
continue;
|
||||
}
|
||||
else if (pfd.revents & POLLIN)
|
||||
@@ -219,7 +233,7 @@ namespace hpsh
|
||||
if (errno == EPIPE || errno == ECONNRESET)
|
||||
itr->read_completed = true;
|
||||
else
|
||||
std::cerr << errno << "Error reading from fd" << std::endl;
|
||||
LOG_ERROR << errno << ": Error reading from fd";
|
||||
}
|
||||
}
|
||||
else
|
||||
@@ -230,10 +244,20 @@ namespace hpsh
|
||||
// Send command back to user;
|
||||
if (itr->read_completed)
|
||||
{
|
||||
std::cout << "Received full output for user " << itr->pubkey << std::endl;
|
||||
std::cout << itr->response.data() << std::endl;
|
||||
{
|
||||
std::scoped_lock<std::mutex> lock(usr::ctx.users_mutex);
|
||||
|
||||
std::list<command_context> collected_commands;
|
||||
// Find the user session by user pubkey.
|
||||
const auto user_itr = usr::ctx.users.find(itr->pubkey);
|
||||
if (user_itr != usr::ctx.users.end()) // match found
|
||||
{
|
||||
const usr::connected_user &user = user_itr->second;
|
||||
msg::usrmsg::usrmsg_parser parser(user.protocol);
|
||||
std::vector<uint8_t> msg;
|
||||
parser.create_hpsh_response_container(msg, itr->id, itr->response);
|
||||
user.session.send(msg);
|
||||
}
|
||||
}
|
||||
{
|
||||
std::scoped_lock<std::mutex> lock(ctx.command_mutex);
|
||||
itr = ctx.commands.erase(itr);
|
||||
|
||||
@@ -1,27 +1,15 @@
|
||||
#ifndef _HP_HPSH_
|
||||
#define _HP_HPSH_
|
||||
|
||||
#include <sys/socket.h>
|
||||
#include <cstring>
|
||||
#include <unistd.h>
|
||||
#include <sys/types.h>
|
||||
#include <cstdlib>
|
||||
#include <sstream>
|
||||
#include <iostream>
|
||||
#include <signal.h>
|
||||
#include <unordered_map>
|
||||
#include <list>
|
||||
#include <thread>
|
||||
#include <poll.h>
|
||||
#include <wait.h>
|
||||
#include <mutex>
|
||||
#include "util.hpp"
|
||||
|
||||
#include "../pchheader.hpp"
|
||||
#include "../conf.hpp"
|
||||
#include "../usr/usr.hpp"
|
||||
|
||||
namespace hpsh
|
||||
{
|
||||
struct command_context
|
||||
{
|
||||
std::string id;
|
||||
std::string pubkey;
|
||||
int child_fds[2];
|
||||
std::string response;
|
||||
@@ -36,6 +24,7 @@ namespace hpsh
|
||||
int hpsh_pid;
|
||||
std::thread watcher_thread;
|
||||
bool is_shutting_down;
|
||||
bool is_initialized = false;
|
||||
};
|
||||
|
||||
extern hpsh_context ctx;
|
||||
@@ -46,7 +35,7 @@ namespace hpsh
|
||||
|
||||
int check_hpsh_exited(const bool block);
|
||||
|
||||
int execute(std::string_view pubkey, std::string_view message);
|
||||
int execute(std::string_view id, std::string_view pubkey, std::string_view message);
|
||||
|
||||
void response_watcher();
|
||||
}
|
||||
|
||||
@@ -1,45 +0,0 @@
|
||||
#include "util.hpp"
|
||||
|
||||
namespace util
|
||||
{
|
||||
constexpr mode_t DIR_PERMS = 0755;
|
||||
|
||||
/**
|
||||
* Sleeps the current thread for specified no. of milliseconds.
|
||||
*/
|
||||
void sleep(const uint64_t milliseconds)
|
||||
{
|
||||
std::this_thread::sleep_for(std::chrono::milliseconds(milliseconds));
|
||||
}
|
||||
|
||||
// Applies signal mask to the calling thread.
|
||||
void mask_signal()
|
||||
{
|
||||
sigset_t mask;
|
||||
sigemptyset(&mask);
|
||||
sigaddset(&mask, SIGINT);
|
||||
sigaddset(&mask, SIGPIPE);
|
||||
pthread_sigmask(SIG_BLOCK, &mask, NULL);
|
||||
}
|
||||
|
||||
/**
|
||||
* Clears signal mask and signal handlers from the caller.
|
||||
* Called by other processes forked from hpcore threads so they get detatched from
|
||||
* the hpcore signal setup.
|
||||
*/
|
||||
void fork_detach()
|
||||
{
|
||||
// Restore signal handlers to defaults.
|
||||
signal(SIGINT, SIG_DFL);
|
||||
signal(SIGSEGV, SIG_DFL);
|
||||
signal(SIGABRT, SIG_DFL);
|
||||
|
||||
// Remove any signal masks applied by hpcore.
|
||||
sigset_t mask;
|
||||
sigemptyset(&mask);
|
||||
pthread_sigmask(SIG_SETMASK, &mask, NULL);
|
||||
|
||||
// Set process group id (so the terminal doesn't send kill signals to forked children).
|
||||
setpgrp();
|
||||
}
|
||||
} // namespace util
|
||||
@@ -1,30 +0,0 @@
|
||||
#ifndef _HP_UTIL_UTIL_
|
||||
#define _HP_UTIL_UTIL_
|
||||
|
||||
#include <sys/socket.h>
|
||||
#include <cstring>
|
||||
#include <unistd.h>
|
||||
#include <sys/types.h>
|
||||
#include <cstdlib>
|
||||
#include <sstream>
|
||||
#include <signal.h>
|
||||
#include <unordered_map>
|
||||
#include <vector>
|
||||
#include <thread>
|
||||
#include <poll.h>
|
||||
|
||||
/**
|
||||
* Contains helper functions and data structures used by multiple other subsystems.
|
||||
*/
|
||||
|
||||
namespace util
|
||||
{
|
||||
void sleep(const uint64_t milliseconds);
|
||||
|
||||
void mask_signal();
|
||||
|
||||
void fork_detach();
|
||||
|
||||
} // namespace util
|
||||
|
||||
#endif
|
||||
@@ -161,6 +161,31 @@ namespace msg::usrmsg::bson
|
||||
encoder.flush();
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructs a hpsh response message.
|
||||
* @param msg Buffer to construct the generated bson message into.
|
||||
* Message format:
|
||||
* {
|
||||
* "type": "hpsh_response",
|
||||
* "reply_for": "<corresponding request id>",
|
||||
* "content": <contract output>
|
||||
* }
|
||||
* @param content The contract binary output content to be put in the message.
|
||||
*/
|
||||
void create_hpsh_response_container(std::vector<uint8_t> &msg, std::string_view reply_for, std::string_view content)
|
||||
{
|
||||
jsoncons::bson::bson_bytes_encoder encoder(msg);
|
||||
encoder.begin_object();
|
||||
encoder.key(msg::usrmsg::FLD_TYPE);
|
||||
encoder.string_value(msg::usrmsg::MSGTYPE_HPSH_RESPONSE);
|
||||
encoder.key(msg::usrmsg::FLD_REPLY_FOR);
|
||||
encoder.string_value(reply_for);
|
||||
encoder.key(msg::usrmsg::FLD_CONTENT);
|
||||
encoder.byte_string_value(content);
|
||||
encoder.end_object();
|
||||
encoder.flush();
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructs a contract read response message.
|
||||
* @param msg Buffer to construct the generated bson message into.
|
||||
@@ -196,7 +221,7 @@ namespace msg::usrmsg::bson
|
||||
* "ledger_hash": <binary lcl hash>,
|
||||
* "outputs": [<binary output 1>, <binary output 2>, ...], // The output order is the hash generation order.
|
||||
* "output_hash": <binary hash of user's outputs>, [output hash = hash(pubkey+all outputs for the user)]
|
||||
* "hash_tree": [<binary merkle hash tree for this round>], // Collapsed merkle tree with user's hash element marked as null.
|
||||
* "hash_tree": [<binary merkle hash tree for this round>], // Collapsed merkle tree with user's hash element marked as null.
|
||||
* "unl_sig": [["<pubkey>", "<sig>"], ...] // Binary UNL pubkeys and signatures of root hash.
|
||||
* }
|
||||
* @param hash This user's combined output hash. [output hash = hash(pubkey+all outputs for the user)]
|
||||
@@ -466,7 +491,7 @@ namespace msg::usrmsg::bson
|
||||
|
||||
/**
|
||||
* Extracts a contract read request message sent by user.
|
||||
*
|
||||
*
|
||||
* @param extracted_content The content to be passed to the contract, extracted from the message.
|
||||
* @param d The bson document holding the read request message.
|
||||
* Accepted signed input container format:
|
||||
@@ -497,30 +522,30 @@ namespace msg::usrmsg::bson
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Extracts a contract shell input message sent by user.
|
||||
*
|
||||
* @param extracted_content The content to be passed to the contract, extracted from the message.
|
||||
* @param d The bson document holding the shell input message.
|
||||
/**
|
||||
* Extracts a hpsh input message sent by user.
|
||||
*
|
||||
* @param extracted_content The content to be passed to the hpsh, extracted from the message.
|
||||
* @param d The bson document holding the hpsh input message.
|
||||
* Accepted signed input container format:
|
||||
* {
|
||||
* "type": "contract_shell_input",
|
||||
* "type": "hpsh_request",
|
||||
* "id": "<any string>",
|
||||
* "content": <binary buffer>
|
||||
* }
|
||||
* @return 0 on successful extraction. -1 for failure.
|
||||
*/
|
||||
int extract_shell_input(std::string &extracted_id, std::string &extracted_content, const jsoncons::ojson &d)
|
||||
int extract_hpsh_request(std::string &extracted_id, std::string &extracted_content, const jsoncons::ojson &d)
|
||||
{
|
||||
if (!d.contains(msg::usrmsg::FLD_ID) || !d[msg::usrmsg::FLD_ID].is<std::string>())
|
||||
{
|
||||
LOG_DEBUG << "Shell input 'id' field missing or invalid.";
|
||||
LOG_DEBUG << "Hpsh input 'id' field missing or invalid.";
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (!d.contains(msg::usrmsg::FLD_CONTENT) || !d[msg::usrmsg::FLD_CONTENT].is_byte_string_view())
|
||||
{
|
||||
LOG_DEBUG << "Shell input 'content' field missing or invalid.";
|
||||
LOG_DEBUG << "Hpsh input 'content' field missing or invalid.";
|
||||
return -1;
|
||||
}
|
||||
|
||||
@@ -532,9 +557,9 @@ namespace msg::usrmsg::bson
|
||||
|
||||
/**
|
||||
* Extracts a signed input container message sent by user.
|
||||
*
|
||||
*
|
||||
* @param extracted_input_container The input container extracted from the message.
|
||||
* @param extracted_sig The binary signature extracted from the message.
|
||||
* @param extracted_sig The binary signature extracted from the message.
|
||||
* @param d The bson document holding the input container.
|
||||
* Accepted signed input container format:
|
||||
* {
|
||||
|
||||
@@ -17,6 +17,8 @@ namespace msg::usrmsg::bson
|
||||
void create_contract_input_status(std::vector<uint8_t> &msg, std::string_view status, std::string_view reason,
|
||||
std::string_view input_hash, const uint64_t ledger_seq_no, const util::h32 &ledger_hash);
|
||||
|
||||
void create_hpsh_response_container(std::vector<uint8_t> &msg, std::string_view reply_for, std::string_view content);
|
||||
|
||||
void create_contract_read_response_container(std::vector<uint8_t> &msg, std::string_view reply_for, std::string_view content);
|
||||
|
||||
void create_contract_output_container(std::vector<uint8_t> &msg, std::string_view hash, const ::std::vector<std::string> &outputs,
|
||||
@@ -43,7 +45,7 @@ namespace msg::usrmsg::bson
|
||||
|
||||
int extract_read_request(std::string &extracted_id, std::string &extracted_content, const jsoncons::ojson &d);
|
||||
|
||||
int extract_shell_input(std::string &extracted_id, std::string &extracted_content, const jsoncons::ojson &d);
|
||||
int extract_hpsh_request(std::string &extracted_id, std::string &extracted_content, const jsoncons::ojson &d);
|
||||
|
||||
int extract_signed_input_container(std::string &extracted_input_container, std::string &extracted_sig,
|
||||
const jsoncons::ojson &d);
|
||||
|
||||
@@ -34,7 +34,7 @@ namespace msg::usrmsg::json
|
||||
* Constructs user challenge message json and the challenge string required for
|
||||
* initial user challenge handshake. This gets called when a user establishes
|
||||
* a web socket connection to HP.
|
||||
*
|
||||
*
|
||||
* @param msg Buffer to construct the generated json message string into.
|
||||
* Message format:
|
||||
* {
|
||||
@@ -84,7 +84,7 @@ namespace msg::usrmsg::json
|
||||
/**
|
||||
* Constructs server challenge response message json. This gets sent when we receive
|
||||
* a challenge from the user.
|
||||
*
|
||||
*
|
||||
* @param msg Buffer to construct the generated json message string into.
|
||||
* Message format:
|
||||
* {
|
||||
@@ -325,6 +325,52 @@ namespace msg::usrmsg::json
|
||||
msg += "\"}";
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructs a hpsh response message.
|
||||
* @param msg Buffer to construct the generated json message string into.
|
||||
* Message format:
|
||||
* {
|
||||
* "type": "hpsh_response",
|
||||
* "reply_for": "<corresponding request id>",
|
||||
* "content": "<response string>"
|
||||
* }
|
||||
* @param content The contract binary output content to be put in the message.
|
||||
*/
|
||||
void create_hpsh_response_container(std::vector<uint8_t> &msg, std::string_view reply_for, std::string_view content)
|
||||
{
|
||||
msg.reserve(content.size() + 256);
|
||||
msg += "{\"";
|
||||
msg += msg::usrmsg::FLD_TYPE;
|
||||
msg += SEP_COLON;
|
||||
msg += msg::usrmsg::MSGTYPE_HPSH_RESPONSE;
|
||||
msg += SEP_COMMA;
|
||||
msg += msg::usrmsg::FLD_REPLY_FOR;
|
||||
msg += SEP_COLON;
|
||||
msg += reply_for;
|
||||
msg += SEP_COMMA;
|
||||
msg += msg::usrmsg::FLD_CONTENT;
|
||||
msg += SEP_COLON_NOQUOTE;
|
||||
|
||||
if (is_json_string(content))
|
||||
{
|
||||
// Process the final string using jsoncons.
|
||||
jsoncons::json jstring = content;
|
||||
jsoncons::json_options options;
|
||||
options.escape_all_non_ascii(true);
|
||||
|
||||
std::string escaped_content;
|
||||
jstring.dump(escaped_content);
|
||||
|
||||
msg += escaped_content;
|
||||
}
|
||||
else
|
||||
{
|
||||
msg += content;
|
||||
}
|
||||
|
||||
msg += "}";
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructs a contract read response message.
|
||||
* @param msg Buffer to construct the generated json message string into.
|
||||
@@ -381,7 +427,7 @@ namespace msg::usrmsg::json
|
||||
* "ledger_hash": "<lcl hash hex>",
|
||||
* "outputs": ["<output string 1>", "<output string 2>", ...], // The output order is the hash generation order.
|
||||
* "output_hash": "<hex hash of user's outputs>", [output hash = hash(pubkey+all outputs for the user)]
|
||||
* "hash_tree": [<hex merkle hash tree>], // Collapsed merkle tree with user's hash element marked as null.
|
||||
* "hash_tree": [<hex merkle hash tree>], // Collapsed merkle tree with user's hash element marked as null.
|
||||
* "unl_sig": [["<pubkey hex>", "<sig hex>"], ...] // UNL pubkeys and signatures of root hash.
|
||||
* }
|
||||
* @param hash This user's combined output hash. [output hash = hash(pubkey+all outputs for the user)]
|
||||
@@ -566,12 +612,12 @@ namespace msg::usrmsg::json
|
||||
* {
|
||||
* "type": "health_event",
|
||||
* "event": "proposal" | "connectivity",
|
||||
*
|
||||
*
|
||||
* // proposal
|
||||
* "comm_latency": {min:0, max:0, avg:0},
|
||||
* "read_latency": {min:0, max:0, avg:0}
|
||||
* "batch_size": 0
|
||||
*
|
||||
*
|
||||
* // connectivity
|
||||
* "peer_count": 0,
|
||||
* "weakly_connected": true | false
|
||||
@@ -697,7 +743,7 @@ namespace msg::usrmsg::json
|
||||
/**
|
||||
* Verifies the user handshake response with the original challenge issued to the user
|
||||
* and the user public key contained in the response.
|
||||
*
|
||||
*
|
||||
* @param extracted_pubkeyhex The hex public key extracted from the response.
|
||||
* @param extracted_protocol The protocol code extracted from the response.
|
||||
* @param extracted_server_challenge Any server challenge issued by user.
|
||||
@@ -842,7 +888,7 @@ namespace msg::usrmsg::json
|
||||
|
||||
/**
|
||||
* Extracts a contract read request message sent by user.
|
||||
*
|
||||
*
|
||||
* @param extracted_content The content to be passed to the contract, extracted from the message.
|
||||
* @param d The json document holding the read request message.
|
||||
* Accepted signed input container format:
|
||||
@@ -872,30 +918,30 @@ namespace msg::usrmsg::json
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Extracts a contract shell input message sent by user.
|
||||
*
|
||||
* @param extracted_content The content to be passed to the contract, extracted from the message.
|
||||
* @param d The json document holding the shell input message.
|
||||
/**
|
||||
* Extracts a hpsh input message sent by user.
|
||||
*
|
||||
* @param extracted_content The content to be passed to the, extracted from the message.
|
||||
* @param d The json document holding the hpsh input message.
|
||||
* Accepted signed input container format:
|
||||
* {
|
||||
* "type": "contract_shell_input",
|
||||
* "type": "hpsh_request",
|
||||
* "id": "<any string>",
|
||||
* "content": "<any string>"
|
||||
* }
|
||||
* @return 0 on successful extraction. -1 for failure.
|
||||
*/
|
||||
int extract_shell_input(std::string &extracted_id, std::string &extracted_content, const jsoncons::json &d)
|
||||
int extract_hpsh_request(std::string &extracted_id, std::string &extracted_content, const jsoncons::json &d)
|
||||
{
|
||||
if (!d.contains(msg::usrmsg::FLD_ID) || !d[msg::usrmsg::FLD_ID].is<std::string>())
|
||||
{
|
||||
LOG_DEBUG << "Shell input 'id' field missing or invalid.";
|
||||
LOG_DEBUG << "Hpsh input 'id' field missing or invalid.";
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (!d.contains(msg::usrmsg::FLD_CONTENT) || !d[msg::usrmsg::FLD_CONTENT].is<std::string>())
|
||||
{
|
||||
LOG_DEBUG << "Shell input 'content' field missing or invalid.";
|
||||
LOG_DEBUG << "Hpsh input 'content' field missing or invalid.";
|
||||
return -1;
|
||||
}
|
||||
|
||||
@@ -906,9 +952,9 @@ namespace msg::usrmsg::json
|
||||
|
||||
/**
|
||||
* Extracts a signed input container message sent by user.
|
||||
*
|
||||
*
|
||||
* @param extracted_input_container The input container extracted from the message.
|
||||
* @param extracted_sig The binary signature extracted from the message.
|
||||
* @param extracted_sig The binary signature extracted from the message.
|
||||
* @param d The json document holding the input container.
|
||||
* Accepted signed input container format:
|
||||
* {
|
||||
|
||||
@@ -21,6 +21,8 @@ namespace msg::usrmsg::json
|
||||
void create_contract_input_status(std::vector<uint8_t> &msg, std::string_view status, std::string_view reason,
|
||||
std::string_view input_hash, const uint64_t ledger_seq_no, const util::h32 &ledger_hash);
|
||||
|
||||
void create_hpsh_response_container(std::vector<uint8_t> &msg, std::string_view reply_for, std::string_view content);
|
||||
|
||||
void create_contract_read_response_container(std::vector<uint8_t> &msg, std::string_view reply_for, std::string_view content);
|
||||
|
||||
void create_contract_output_container(std::vector<uint8_t> &msg, std::string_view hash, const ::std::vector<std::string> &outputs,
|
||||
@@ -47,7 +49,7 @@ namespace msg::usrmsg::json
|
||||
|
||||
int extract_read_request(std::string &extracted_id, std::string &extracted_content, const jsoncons::json &d);
|
||||
|
||||
int extract_shell_input(std::string &extracted_id, std::string &extracted_content, const jsoncons::json &d);
|
||||
int extract_hpsh_request(std::string &extracted_id, std::string &extracted_content, const jsoncons::json &d);
|
||||
|
||||
int extract_signed_input_container(std::string &extracted_input_container, std::string &extracted_sig,
|
||||
const jsoncons::json &d);
|
||||
|
||||
@@ -80,8 +80,8 @@ namespace msg::usrmsg
|
||||
constexpr const char *MSGTYPE_SERVER_CHALLENGE_RESPONSE = "server_challenge_response";
|
||||
constexpr const char *MSGTYPE_CONTRACT_READ_REQUEST = "contract_read_request";
|
||||
constexpr const char *MSGTYPE_CONTRACT_READ_RESPONSE = "contract_read_response";
|
||||
constexpr const char *MSGTYPE_CONTRACT_SHELL_INPUT = "contract_shell_input";
|
||||
constexpr const char *MSGTYPE_CONTRACT_SHELL_OUTPUT = "contract_shell_output";
|
||||
constexpr const char *MSGTYPE_HPSH_REQUEST = "hpsh_request";
|
||||
constexpr const char *MSGTYPE_HPSH_RESPONSE = "hpsh_response";
|
||||
constexpr const char *MSGTYPE_CONTRACT_INPUT = "contract_input";
|
||||
constexpr const char *MSGTYPE_CONTRACT_INPUT_STATUS = "contract_input_status";
|
||||
constexpr const char *MSGTYPE_CONTRACT_OUTPUT = "contract_output";
|
||||
|
||||
@@ -38,6 +38,14 @@ namespace msg::usrmsg
|
||||
busrmsg::create_contract_input_status(msg, status, reason, input_hash, ledger_seq_no, ledger_hash);
|
||||
}
|
||||
|
||||
void usrmsg_parser::create_hpsh_response_container(std::vector<uint8_t> &msg, std::string_view reply_for, std::string_view content) const
|
||||
{
|
||||
if (protocol == util::PROTOCOL::JSON)
|
||||
jusrmsg::create_hpsh_response_container(msg, reply_for, content);
|
||||
else
|
||||
busrmsg::create_hpsh_response_container(msg, reply_for, content);
|
||||
}
|
||||
|
||||
void usrmsg_parser::create_contract_read_response_container(std::vector<uint8_t> &msg, std::string_view reply_for, std::string_view content) const
|
||||
{
|
||||
if (protocol == util::PROTOCOL::JSON)
|
||||
@@ -121,12 +129,12 @@ namespace msg::usrmsg
|
||||
return busrmsg::extract_read_request(extracted_id, extracted_content, bdoc);
|
||||
}
|
||||
|
||||
int usrmsg_parser::extract_shell_input(std::string &extracted_id, std::string &extracted_content) const
|
||||
int usrmsg_parser::extract_hpsh_request(std::string &extracted_id, std::string &extracted_content) const
|
||||
{
|
||||
if (protocol == util::PROTOCOL::JSON)
|
||||
return jusrmsg::extract_shell_input(extracted_id, extracted_content, jdoc);
|
||||
return jusrmsg::extract_hpsh_request(extracted_id, extracted_content, jdoc);
|
||||
else
|
||||
return busrmsg::extract_shell_input(extracted_id, extracted_content, bdoc);
|
||||
return busrmsg::extract_hpsh_request(extracted_id, extracted_content, bdoc);
|
||||
}
|
||||
|
||||
int usrmsg_parser::extract_signed_input_container(std::string &extracted_input_container, std::string &extracted_sig) const
|
||||
|
||||
@@ -26,6 +26,8 @@ namespace msg::usrmsg
|
||||
void create_contract_input_status(std::vector<uint8_t> &msg, std::string_view status, std::string_view reason,
|
||||
std::string_view input_hash, const uint64_t ledger_seq_no, const util::h32 &ledger_hash) const;
|
||||
|
||||
void create_hpsh_response_container(std::vector<uint8_t> &msg, std::string_view reply_for, std::string_view content) const;
|
||||
|
||||
void create_contract_read_response_container(std::vector<uint8_t> &msg, std::string_view reply_for, std::string_view content) const;
|
||||
|
||||
void create_contract_output_container(std::vector<uint8_t> &msg, std::string_view hash, const ::std::vector<std::string> &outputs,
|
||||
@@ -49,7 +51,7 @@ namespace msg::usrmsg
|
||||
|
||||
int extract_read_request(std::string &extracted_id, std::string &extracted_content) const;
|
||||
|
||||
int extract_shell_input(std::string &extracted_id, std::string &extracted_content) const;
|
||||
int extract_hpsh_request(std::string &extracted_id, std::string &extracted_content) const;
|
||||
|
||||
int extract_signed_input_container(std::string &extracted_input_container, std::string &extracted_sig) const;
|
||||
|
||||
|
||||
@@ -273,19 +273,13 @@ namespace usr
|
||||
user.session.send(resp);
|
||||
return 0;
|
||||
}
|
||||
else if (msg_type == msg::usrmsg::MSGTYPE_CONTRACT_SHELL_INPUT)
|
||||
else if (msg_type == msg::usrmsg::MSGTYPE_HPSH_REQUEST)
|
||||
{
|
||||
std::string id, content;
|
||||
if (parser.extract_shell_input(id, content) != -1)
|
||||
if (hpsh::ctx.is_initialized && parser.extract_hpsh_request(id, content) != -1)
|
||||
{
|
||||
|
||||
LOG_INFO << "shell input received:" << content;
|
||||
// std::string response = hpsh::serve(content.c_str());
|
||||
if (hpsh::execute(std::string("user_").append(std::to_string(1)), content.c_str()) == -1)
|
||||
{
|
||||
std::cout << "\nError sending message:" << content.c_str() << std::endl;
|
||||
}
|
||||
// LOG_INFO << "response: " << response;
|
||||
if (hpsh::execute(id, user.pubkey, content.c_str()) == -1)
|
||||
return -1;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
BIN
test/bin/hpsh
BIN
test/bin/hpsh
Binary file not shown.
Reference in New Issue
Block a user