User control messages. (#56)

This commit is contained in:
Ravin Perera
2019-11-11 15:06:25 +05:30
committed by GitHub
parent 403f2e1b21
commit 39031c3157
10 changed files with 155 additions and 72 deletions

View File

@@ -54,6 +54,29 @@ function main() {
ws.close()
});
function create_input_container(inp) {
let inp_container = {
nonce: (new Date()).getTime().toString(),
input: Buffer.from(inp).toString('hex'),
max_ledger_seqno: 9999999
}
let inp_container_bytes = JSON.stringify(inp_container);
let sig_bytes = sodium.crypto_sign_detached(inp_container_bytes, keys.privateKey);
let signed_inp_container = {
type: "contract_input",
content: inp_container_bytes.toString('hex'),
sig: Buffer.from(sig_bytes).toString('hex')
}
return JSON.stringify(signed_inp_container);
}
function create_status_request() {
let statreq = { type: 'stat' }
return JSON.stringify(statreq);
}
ws.on('message', (m) => {
console.log("-----Received raw message-----")
console.log(m.toString())
@@ -76,8 +99,7 @@ function main() {
// sign the challenge and send back the response
var sigbytes = sodium.crypto_sign_detached(m.challenge, keys.privateKey);
var response = {
version: '0.1',
type: 'challenge_response',
type: 'challenge_resp',
challenge: m.challenge,
sig: Buffer.from(sigbytes).toString('hex'),
pubkey: pkhex
@@ -96,22 +118,13 @@ function main() {
var input_pump = () => {
rl.question('\nProvide an input: ', (inp) => {
let inp_container = {
nonce: (new Date()).getTime().toString(),
input: Buffer.from(inp).toString('hex'),
maxledgerseqno: 9999999
}
let inp_container_bytes = JSON.stringify(inp_container);
let sig_bytes = sodium.crypto_sign_detached(inp_container_bytes, keys.privateKey);
let msgtosend = "";
let signed_inp_container = {
version: "0.1",
type: "contract_input",
content: inp_container_bytes.toString('hex'),
sig: Buffer.from(sig_bytes).toString('hex')
}
let msgtosend = JSON.stringify(signed_inp_container);
if (inp == "stat")
msgtosend = create_status_request();
else
msgtosend = create_input_container(inp);
console.log("Sending message: " + msgtosend);
ws.send(msgtosend)

View File

@@ -83,8 +83,7 @@ function main() {
// sign the challenge and send back the response
var sigbytes = sodium.crypto_sign_detached(m.challenge, keys.privateKey);
var response = {
version: '0.1',
type: 'challenge_response',
type: 'challenge_resp',
challenge: m.challenge,
sig: Buffer.from(sigbytes).toString('hex'),
pubkey: pkhex

View File

@@ -7,10 +7,10 @@ namespace corebill
{
// How many violations can occur for a host before being escalated.
static const uint32_t VIOLATION_THRESHOLD = 10;
constexpr uint32_t VIOLATION_THRESHOLD = 10;
// Violation cooldown interval.
static const uint32_t VIOLATION_REFRESH_INTERVAL = 600 * 1000; // 10 minutes
constexpr uint32_t VIOLATION_REFRESH_INTERVAL = 600 * 1000; // 10 minutes
// Keeps track of violation count against offending hosts.
std::unordered_map<std::string, violation_stat> violation_counter;

View File

@@ -20,6 +20,13 @@ namespace jusrmsg = jsonschema::usrmsg;
namespace cons
{
/**
* Voting thresholds for consensus stages.
*/
constexpr float STAGE1_THRESHOLD = 0.5;
constexpr float STAGE2_THRESHOLD = 0.65;
constexpr float STAGE3_THRESHOLD = 0.8;
consensus_context ctx;
int init()
@@ -574,10 +581,12 @@ void dispatch_user_outputs(const p2p::proposal &cons_prop)
{
std::string outputtosend;
outputtosend.swap(cand_output.output);
usr::user_outbound_message outmsg(std::move(outputtosend));
std::string msg;
jusrmsg::create_contract_output_container(msg, outputtosend);
const usr::connected_user &user = user_itr->second;
user.session->send(std::move(outmsg));
user.session->send(usr::user_outbound_message(std::move(msg)));
}
}
}

View File

@@ -10,13 +10,6 @@
namespace cons
{
//stage 1 vote threshold
static const float STAGE1_THRESHOLD = 0.5;
//stage 2 vote threshold
static const float STAGE2_THRESHOLD = 0.65;
//stage 3 vote threshold
static const float STAGE3_THRESHOLD = 0.8;
/**
* Represents a contract input that takes part in consensus.
*/

View File

@@ -1,18 +1,37 @@
#include "../pchheader.hpp"
#include "../util.hpp"
#include "../crypto.hpp"
#include "../cons/cons.hpp"
#include "../hplog.hpp"
#include "usrmsg_helpers.hpp"
namespace jsonschema::usrmsg
{
// User JSON message schema version
constexpr const char* SCHEMA_VERSION = "0.1";
// Separators
static const char *SEP_COMMA = "\",\"";
static const char *SEP_COLON = "\":\"";
constexpr const char* SEP_COMMA = "\",\"";
constexpr const char* SEP_COLON = "\":\"";
constexpr const char* SEP_COMMA_NOQUOTE = ",\"";
constexpr const char* SEP_COLON_NOQUOTE = "\":";
// Message field names
const char* const FLD_VERSION = "version";
constexpr const char* FLD_TYPE = "type";
constexpr const char* FLD_CHALLENGE = "challenge";
constexpr const char* FLD_SIG = "sig";
constexpr const char* FLD_PUBKEY = "pubkey";
constexpr const char* FLD_INPUT = "input";
constexpr const char* FLD_MAX_LED_SEQ = "max_ledger_seqno";
constexpr const char* FLD_CONTENT = "content";
constexpr const char* FLD_NONCE = "nonce";
constexpr const char* FLD_LCL = "lcl";
constexpr const char* FLD_LCL_SEQ = "lcl_seqno";
// Length of user random challenge bytes.
static const size_t CHALLENGE_LEN = 16;
const size_t CHALLENGE_LEN = 16;
/**
* Constructs user challenge message json and the challenge string required for
@@ -43,8 +62,8 @@ void create_user_challenge(std::string &msg, std::string &challengehex)
// We do not use RapidJson here in favour of performance because this is a simple json message.
// Since we know the rough size of the challenge massage we reserve adequate amount for the holder.
// Only Hot Pocket version number is variable length. Therefore message size is roughly 95 bytes
// so allocating 128bits for heap padding.
// Only Hot Pocket version number is variable length. Therefore message size is roughly 90 bytes
// so allocating 128bytes for heap padding.
msg.reserve(128);
msg.append("{\"")
.append(FLD_VERSION)
@@ -61,6 +80,55 @@ void create_user_challenge(std::string &msg, std::string &challengehex)
.append("\"}");
}
/**
* Constructs a status response message.
* @param msg String reference to copy the generated json message string into.
*/
void create_status_response(std::string &msg)
{
msg.reserve(128);
msg.append("{\"")
.append(FLD_TYPE)
.append(SEP_COLON)
.append(MSGTYPE_STAT_RESP)
.append(SEP_COMMA)
.append(FLD_LCL)
.append(SEP_COLON)
.append(cons::ctx.lcl)
.append(SEP_COMMA)
.append(FLD_LCL_SEQ)
.append(SEP_COLON_NOQUOTE)
.append(std::to_string(cons::ctx.led_seq_no))
.append("}");
}
/**
* Constructs a contract output container message.
* @param msg String reference to copy the generated json message string into.
* @param content The contract output content to be put in the message.
*/
void create_contract_output_container(std::string &msg, std::string_view content)
{
msg.reserve(128);
msg.append("{\"")
.append(FLD_TYPE)
.append(SEP_COLON)
.append(MSGTYPE_CONTRACT_OUTPUT)
.append(SEP_COMMA)
.append(FLD_LCL)
.append(SEP_COLON)
.append(cons::ctx.lcl)
.append(SEP_COMMA)
.append(FLD_LCL_SEQ)
.append(SEP_COLON_NOQUOTE)
.append(std::to_string(cons::ctx.led_seq_no))
.append(SEP_COMMA_NOQUOTE)
.append(FLD_CONTENT)
.append(SEP_COLON)
.append(content)
.append("\"}");
}
/**
* Verifies the user challenge response with the original challenge issued to the user
* and the user public key contained in the response.
@@ -69,8 +137,7 @@ void create_user_challenge(std::string &msg, std::string &challengehex)
* @param response The response bytes to verify. This will be parsed as json.
* Accepted response format:
* {
* "version": "<protocol version>"
* "type": "challenge_response",
* "type": "challenge_resp",
* "challenge": "<original hex challenge the user received>",
* "sig": "<hex signature of the challenge>",
* "pubkey": "<hex public key of the user>"
@@ -136,7 +203,6 @@ int verify_user_challenge_response(std::string &extracted_pubkeyhex, std::string
* @param d The json document holding the input container.
* Accepted signed input container format:
* {
* "version": "<protocol version>"
* "type": "contract_input",
* "content": "<hex encoded input container message>",
* "sig": "<hex encoded signature of the content>"
@@ -176,12 +242,12 @@ int extract_signed_input_container(
* Extract the individual components of a given input container json.
* @param nonce The extracted nonce.
* @param input The extracted input.
* @param max_ledger_seqno The extracted max ledger sequence no.
* @param max_ledger_seqno Themaxledgerseqno extracted max ledger sequence no.
* @param contentjson The json string containing the input container message.
* {
* "nonce": "<random string with optional sorted order>",
* "input": "<hex encoded contract input content>",
* "maxledgerseqno": 4562712334
* "max_ledger_seqno": 4562712334
* }
* @return 0 on succesful extraction. -1 on failure.
*/
@@ -213,9 +279,9 @@ int extract_input_container(std::string &nonce, std::string &input, uint64_t &ma
// Convert hex input to binary.
input.resize(inputhex.length() / 2);
if (util::hex2bin(
reinterpret_cast<unsigned char *>(input.data()),
input.length(),
inputhex) != 0)
reinterpret_cast<unsigned char *>(input.data()),
input.length(),
inputhex) != 0)
{
LOG_DBG << "Contract input format invalid.";
return -1;
@@ -231,6 +297,11 @@ int extract_input_container(std::string &nonce, std::string &input, uint64_t &ma
* Parses a json message sent by a user.
* @param d RapidJson document to which the parsed json should be loaded.
* @param message The message to parse.
* Accepted message format:
* {
* 'type': '<message type>'
* ...
* }
* @return 0 on successful parsing. -1 for failure.
*/
int parse_user_message(rapidjson::Document &d, std::string_view message)
@@ -245,13 +316,6 @@ int parse_user_message(rapidjson::Document &d, std::string_view message)
return -1;
}
// Check existence of msg type field.
if (!d.HasMember(FLD_VERSION) || !d[FLD_VERSION].IsString())
{
LOG_DBG << "User json message 'version' missing or invalid.";
return -1;
}
// Check existence of msg type field.
if (!d.HasMember(FLD_TYPE) || !d[FLD_TYPE].IsString())
{

View File

@@ -6,26 +6,23 @@
namespace jsonschema::usrmsg
{
static const char *SCHEMA_VERSION = "0.1";
// These fields are used on json messages response validation.
static const char *FLD_VERSION = "version";
static const char *FLD_TYPE = "type";
static const char *FLD_CHALLENGE = "challenge";
static const char *FLD_SIG = "sig";
static const char *FLD_PUBKEY = "pubkey";
static const char *FLD_INPUT = "input";
static const char *FLD_MAX_LED_SEQ = "maxledgerseqno";
static const char *FLD_CONTENT = "content";
static const char *FLD_NONCE = "nonce";
// Message field names exposed out of this namespace.
extern const char* const FLD_TYPE;
// Message types
static const char *MSGTYPE_CHALLENGE = "public_challenge";
static const char *MSGTYPE_CHALLENGE_RESP = "challenge_response";
static const char *MSGTYPE_CONTRACT_INPUT = "contract_input";
constexpr const char* MSGTYPE_CHALLENGE = "public_challenge";
constexpr const char* MSGTYPE_CHALLENGE_RESP = "challenge_resp";
constexpr const char* MSGTYPE_CONTRACT_INPUT = "contract_input";
constexpr const char* MSGTYPE_CONTRACT_OUTPUT = "contract_output";
constexpr const char* MSGTYPE_STAT = "stat";
constexpr const char* MSGTYPE_STAT_RESP = "stat_resp";
void create_user_challenge(std::string &msg, std::string &challengehex);
void create_status_response(std::string &msg);
void create_contract_output_container(std::string &msg, std::string_view content);
int verify_user_challenge_response(std::string &extracted_pubkeyhex, std::string_view response, std::string_view original_challenge);
int extract_signed_input_container(std::string &extracted_content, std::string &extracted_sig, const rapidjson::Document &d);

View File

@@ -17,7 +17,7 @@ struct fd_info
};
// File modifications are tracked in 4MB blocks.
static const int BLOCK_SIZE = 4 * 1024 * 1024;
constexpr int BLOCK_SIZE = 4 * 1024 * 1024;
/**
* Blocks the calling thread and captures the child process activity until it exits.

View File

@@ -88,7 +88,7 @@ int verify_challenge(std::string_view message, sock::socket_session<user_outboun
ctx.pending_challenges.erase(session->uniqueid); // Remove the stored challenge
LOG_DBG << "User connection " << session->uniqueid << " authenticated. Public key "
<< userpubkeyhex;
<< userpubkeyhex;
return 0;
}
else
@@ -123,7 +123,7 @@ int handle_user_message(connected_user &user, std::string_view message)
if (jusrmsg::extract_signed_input_container(contentjson, sig, d) == 0)
{
std::lock_guard<std::mutex> lock(ctx.users_mutex);
//Add to the submitted input list.
user.submitted_inputs.push_back(user_submitted_message(
std::move(contentjson),
@@ -131,6 +131,14 @@ int handle_user_message(connected_user &user, std::string_view message)
return 0;
}
}
else if (d[jusrmsg::FLD_TYPE] == jusrmsg::MSGTYPE_STAT)
{
std::string msg;
LOG_DBG << msg;
jusrmsg::create_status_response(msg);
user.session->send(user_outbound_message(std::move(msg)));
return 0;
}
else
{
LOG_DBG << "Invalid user message type: " << d[jusrmsg::FLD_TYPE].GetString();

View File

@@ -11,17 +11,17 @@ namespace util
{
// Hot Pocket version. Displayed on 'hotpocket version' and written to new contract configs.
static const char *HP_VERSION = "0.1";
constexpr const char* HP_VERSION = "0.1";
// Minimum compatible contract config version (this will be used to validate contract configs)
static const char *MIN_CONTRACT_VERSION = "0.1";
constexpr const char* MIN_CONTRACT_VERSION = "0.1";
// Current version of the peer message protocol.
static const uint8_t PEERMSG_VERSION = 1;
constexpr uint8_t PEERMSG_VERSION = 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)
static const uint8_t MIN_PEERMSG_VERSION = 1;
constexpr uint8_t MIN_PEERMSG_VERSION = 1;
/**
* FIFO hash set with a max size.