Added bson support for user message protocol. (#99)

This commit is contained in:
Ravin Perera
2020-07-02 21:40:55 +05:30
committed by GitHub
parent 8103ef7af6
commit 96f23cb0ff
47 changed files with 1424 additions and 810 deletions

View File

@@ -0,0 +1,252 @@
#include "../../pchheader.hpp"
#include "../../util.hpp"
#include "../../cons/cons.hpp"
#include "../../hplog.hpp"
#include "../usrmsg_common.hpp"
#include "usrmsg_bson.hpp"
namespace msg::usrmsg::bson
{
/**
* Constructs a status response message.
* @param msg String reference to copy the generated bson message into.
* Message format:
* {
* "type": "stat_response",
* "lcl": "<lcl id>",
* "lcl_seqno": <integer>
* }
*/
void create_status_response(std::vector<uint8_t> &msg)
{
jsoncons::bson::bson_bytes_encoder encoder(msg);
encoder.begin_object();
encoder.key(msg::usrmsg::FLD_TYPE);
encoder.string_value(msg::usrmsg::MSGTYPE_STAT_RESPONSE);
encoder.key(msg::usrmsg::FLD_LCL);
encoder.string_value(cons::ctx.lcl);
encoder.key(msg::usrmsg::FLD_LCL_SEQ);
encoder.int64_value(cons::ctx.led_seq_no);
encoder.end_object();
encoder.flush();
}
/**
* Constructs a contract input status message.
* @param msg String reference to copy the generated bson message into.
* Message format:
* {
* "type": "contract_input_status",
* "status": "<accepted|rejected>",
* "reason": "<reson>",
* "input_sig": <signature of original input message>
* }
* @param is_accepted Whether the original message was accepted or not.
* @param reason Rejected reason. Empty if accepted.
* @param input_sig Binary signature of the original input message which generated this result.
*/
void create_contract_input_status(std::vector<uint8_t> &msg, std::string_view status, std::string_view reason, std::string_view input_sig)
{
jsoncons::bson::bson_bytes_encoder encoder(msg);
encoder.begin_object();
encoder.key(msg::usrmsg::FLD_TYPE);
encoder.string_value(msg::usrmsg::MSGTYPE_CONTRACT_INPUT_STATUS);
encoder.key(msg::usrmsg::FLD_STATUS);
encoder.string_value(status);
encoder.key(msg::usrmsg::FLD_REASON);
encoder.string_value(reason);
encoder.key(msg::usrmsg::FLD_INPUT_SIG);
encoder.byte_string_value(input_sig);
encoder.end_object();
encoder.flush();
}
/**
* Constructs a contract read response message.
* @param msg String reference to copy the generated bson message into.
* Message format:
* {
* "type": "contract_read_response",
* "content": <contract output>
* }
* @param content The contract binary output content to be put in the message.
*/
void create_contract_read_response_container(std::vector<uint8_t> &msg, 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_CONTRACT_READ_RESPONSE);
encoder.key(msg::usrmsg::FLD_CONTENT);
encoder.byte_string_value(content);
encoder.end_object();
encoder.flush();
}
/**
* Constructs a contract output container message.
* @param msg String reference to copy the generated bson message into.
* Message format:
* {
* "type": "contract_output",
* "lcl": "<lcl id>"
* "lcl_seqno": <integer>,
* "content": <contract output>
* }
* @param content The contract binary output content to be put in the message.
*/
void create_contract_output_container(std::vector<uint8_t> &msg, 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_CONTRACT_OUTPUT);
encoder.key(msg::usrmsg::FLD_LCL);
encoder.string_value(cons::ctx.lcl);
encoder.key(msg::usrmsg::FLD_LCL_SEQ);
encoder.int64_value(cons::ctx.led_seq_no);
encoder.key(msg::usrmsg::FLD_CONTENT);
encoder.byte_string_value(content);
encoder.end_object();
encoder.flush();
}
/**
* Parses a bson message sent by a user.
* @param d BSON document to which the parsed bson 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(jsoncons::ojson &d, std::string_view message)
{
try
{
d = jsoncons::bson::decode_bson<jsoncons::ojson>(message);
}
catch (const std::exception &e)
{
LOG_DBG << "User bson message parsing failed.";
return -1;
}
if (!d[FLD_TYPE].is_string())
{
LOG_DBG << "User bson message 'type' missing or invalid.";
return -1;
}
return 0;
}
/**
* Extracts the message 'type' value from the bson document.
*/
int extract_type(std::string &extracted_type, const jsoncons::ojson &d)
{
extracted_type = d[FLD_TYPE].as<std::string>();
return 0;
}
/**
* 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:
* {
* "type": "contract_read_request",
* "content": <content to be passed to the contract>
* }
* @return 0 on successful extraction. -1 for failure.
*/
int extract_read_request(std::string &extracted_content, const jsoncons::ojson &d)
{
if (!d[msg::usrmsg::FLD_CONTENT].is_byte_string_view())
{
LOG_DBG << "Read request 'content' fields missing or invalid.";
return -1;
}
const jsoncons::byte_string_view &bsv = d[msg::usrmsg::FLD_CONTENT].as_byte_string_view();
extracted_content = std::string_view(reinterpret_cast<const char *>(bsv.data()), bsv.size());
return 0;
}
/**
* 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 d The bson document holding the input container.
* Accepted signed input container format:
* {
* "type": "contract_input",
* "input_container": <bson input container message>,
* "sig": <signature of the content>
* }
* @return 0 on successful extraction. -1 for failure.
*/
int extract_signed_input_container(
std::string &extracted_input_container, std::string &extracted_sig, const jsoncons::ojson &d)
{
if (!d[msg::usrmsg::FLD_INPUT_CONTAINER].is_byte_string_view() || !d[msg::usrmsg::FLD_SIG].is_byte_string_view())
{
LOG_DBG << "User signed input required fields missing or invalid.";
return -1;
}
const jsoncons::byte_string_view &bsv1 = d[msg::usrmsg::FLD_INPUT_CONTAINER].as_byte_string_view();
extracted_input_container = std::string_view(reinterpret_cast<const char *>(bsv1.data()), bsv1.size());
const jsoncons::byte_string_view &bsv2 = d[msg::usrmsg::FLD_SIG].as_byte_string_view();
extracted_sig = std::string_view(reinterpret_cast<const char *>(bsv2.data()), bsv2.size());
return 0;
}
/**
* Extract the individual components of a given input container bson.
* @param input The extracted input.
* @param nonce The extracted nonce.
* @param max_lcl_seqno The extracted max ledger sequence no.
* @param contentjson The bson input container message.
* {
* "input": <contract input content>,
* "nonce": "<random string with optional sorted order>",
* "max_lcl_seqno": <integer>
* }
* @return 0 on succesful extraction. -1 on failure.
*/
int extract_input_container(std::string &input, std::string &nonce, uint64_t &max_lcl_seqno, std::string_view contentbson)
{
jsoncons::ojson d;
try
{
d = jsoncons::bson::decode_bson<jsoncons::ojson>(contentbson);
}
catch (const std::exception &e)
{
LOG_DBG << "User input container bson parsing failed.";
return -1;
}
if (!d[msg::usrmsg::FLD_INPUT].is_byte_string_view() || !d[msg::usrmsg::FLD_NONCE].is_string() || !d[msg::usrmsg::FLD_MAX_LCL_SEQ].is_uint64())
{
LOG_DBG << "User input container required fields missing or invalid.";
return -1;
}
const jsoncons::byte_string_view &bsv = d[msg::usrmsg::FLD_INPUT].as_byte_string_view();
input = std::string_view(reinterpret_cast<const char *>(bsv.data()), bsv.size());
nonce = d[msg::usrmsg::FLD_NONCE].as<std::string>();
max_lcl_seqno = d[msg::usrmsg::FLD_MAX_LCL_SEQ].as<uint64_t>();
return 0;
}
} // namespace msg::usrmsg::bson

View File

@@ -0,0 +1,37 @@
#ifndef _HP_MSG_BSON_USRMSG_BSON_
#define _HP_MSG_BSON_USRMSG_BSON_
#include "../../pchheader.hpp"
namespace msg::usrmsg::bson
{
void create_user_challenge(std::vector<uint8_t> &msg, std::string &challengehex);
void create_status_response(std::vector<uint8_t> &msg);
void create_contract_input_status(std::vector<uint8_t> &msg, std::string_view status, std::string_view reason,
std::string_view input_sig);
void create_contract_read_response_container(std::vector<uint8_t> &msg, std::string_view content);
void create_contract_output_container(std::vector<uint8_t> &msg, std::string_view content);
int verify_user_handshake_response(std::string &extracted_pubkeyhex, std::string &extracted_protocol,
std::string_view response, std::string_view original_challenge);
int parse_user_message(jsoncons::ojson &d, std::string_view message);
int extract_type(std::string &extracted_type, const jsoncons::ojson &d);
int extract_read_request(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);
int extract_input_container(std::string &input, std::string &nonce,
uint64_t &max_lcl_seqno, std::string_view contentbson);
} // namespace msg::usrmsg::bson
#endif

View File

@@ -0,0 +1,126 @@
#include "common_helpers.hpp"
namespace msg::fbuf
{
//---Conversion helpers from flatbuffers data types to std data types---//
/**
* Returns string_view from flat buffer data pointer and length.
*/
std::string_view flatbuff_bytes_to_sv(const uint8_t *data, const flatbuffers::uoffset_t length)
{
const char *signature_content_str = reinterpret_cast<const char *>(data);
return std::string_view(signature_content_str, length);
}
/**
* Returns string_view from Flat Buffer vector of bytes.
*/
std::string_view flatbuff_bytes_to_sv(const flatbuffers::Vector<uint8_t> *buffer)
{
return flatbuff_bytes_to_sv(buffer->Data(), buffer->size());
}
/**
* Returns return string_view from Flat Buffer string.
*/
std::string_view flatbuff_str_to_sv(const flatbuffers::String *buffer)
{
return flatbuff_bytes_to_sv(buffer->Data(), buffer->size());
}
/**
* Returns hash from Flat Buffer vector of bytes.
*/
hpfs::h32 flatbuff_bytes_to_hash(const flatbuffers::Vector<uint8_t> *buffer)
{
return *reinterpret_cast<const hpfs::h32 *>(buffer->data());
}
/**
* Returns set from Flatbuffer vector of ByteArrays.
*/
const std::set<std::string> flatbuf_bytearrayvector_to_stringlist(const flatbuffers::Vector<flatbuffers::Offset<ByteArray>> *fbvec)
{
std::set<std::string> set;
for (auto el : *fbvec)
set.emplace(std::string(flatbuff_bytes_to_sv(el->array())));
return set;
}
/**
* Returns a map from Flatbuffer vector of key value pairs.
*/
const std::unordered_map<std::string, const std::string>
flatbuf_pairvector_to_stringmap(const flatbuffers::Vector<flatbuffers::Offset<BytesKeyValuePair>> *fbvec)
{
std::unordered_map<std::string, const std::string> map;
map.reserve(fbvec->size());
for (auto el : *fbvec)
map.emplace(flatbuff_bytes_to_sv(el->key()), flatbuff_bytes_to_sv(el->value()));
return map;
}
//---Conversion helpers from std data types to flatbuffers data types---//
//---These are used in constructing Flatbuffer messages using builders---//
/**
* Returns Flatbuffer bytes vector from string_view.
*/
const flatbuffers::Offset<flatbuffers::Vector<uint8_t>>
sv_to_flatbuff_bytes(flatbuffers::FlatBufferBuilder &builder, std::string_view sv)
{
return builder.CreateVector(reinterpret_cast<const uint8_t *>(sv.data()), sv.size());
}
/**
* Returns Flatbuffer string from string_view.
*/
const flatbuffers::Offset<flatbuffers::String>
sv_to_flatbuff_str(flatbuffers::FlatBufferBuilder &builder, std::string_view sv)
{
return builder.CreateString(sv);
}
/**
* Returns Flatbuffer bytes vector from hash.
*/
const flatbuffers::Offset<flatbuffers::Vector<uint8_t>>
hash_to_flatbuff_bytes(flatbuffers::FlatBufferBuilder &builder, const hpfs::h32 hash)
{
return builder.CreateVector(reinterpret_cast<const uint8_t *>(&hash), sizeof(hpfs::h32));
}
/**
* Returns Flatbuffer vector of ByteArrays from given set of strings.
*/
const flatbuffers::Offset<flatbuffers::Vector<flatbuffers::Offset<ByteArray>>>
stringlist_to_flatbuf_bytearrayvector(flatbuffers::FlatBufferBuilder &builder, const std::set<std::string> &set)
{
std::vector<flatbuffers::Offset<ByteArray>> fbvec;
fbvec.reserve(set.size());
for (std::string_view str : set)
fbvec.push_back(CreateByteArray(builder, sv_to_flatbuff_bytes(builder, str)));
return builder.CreateVector(fbvec);
}
/**
* Returns Flatbuffer vector of key value pairs from given map.
*/
const flatbuffers::Offset<flatbuffers::Vector<flatbuffers::Offset<BytesKeyValuePair>>>
stringmap_to_flatbuf_bytepairvector(flatbuffers::FlatBufferBuilder &builder, const std::unordered_map<std::string, const std::string> &map)
{
std::vector<flatbuffers::Offset<BytesKeyValuePair>> fbvec;
fbvec.reserve(map.size());
for (auto const &[key, value] : map)
{
fbvec.push_back(CreateBytesKeyValuePair(
builder,
sv_to_flatbuff_bytes(builder, key),
sv_to_flatbuff_bytes(builder, value)));
}
return builder.CreateVector(fbvec);
}
} // namespace msg::fbuf

View File

@@ -0,0 +1,49 @@
#ifndef _HP_MSG_FBUF_COMMON_HELPERS_
#define _HP_MSG_FBUF_COMMON_HELPERS_
#include "../../pchheader.hpp"
#include "../../hpfs/h32.hpp"
#include "common_schema_generated.h"
namespace msg::fbuf
{
/**
* This section contains common Flatbuffer message reading/writing helpers.
*/
//---Conversion helpers from flatbuffers data types to std data types---//
std::string_view flatbuff_bytes_to_sv(const uint8_t *data, const flatbuffers::uoffset_t length);
std::string_view flatbuff_bytes_to_sv(const flatbuffers::Vector<uint8_t> *buffer);
std::string_view flatbuff_str_to_sv(const flatbuffers::String *buffer);
hpfs::h32 flatbuff_bytes_to_hash(const flatbuffers::Vector<uint8_t> *buffer);
const std::set<std::string>
flatbuf_bytearrayvector_to_stringlist(const flatbuffers::Vector<flatbuffers::Offset<ByteArray>> *fbvec);
const std::unordered_map<std::string, const std::string>
flatbuf_pairvector_to_stringmap(const flatbuffers::Vector<flatbuffers::Offset<BytesKeyValuePair>> *fbvec);
//---Conversion helpers from std data types to flatbuffers data types---//
const flatbuffers::Offset<flatbuffers::Vector<uint8_t>>
sv_to_flatbuff_bytes(flatbuffers::FlatBufferBuilder &builder, std::string_view sv);
const flatbuffers::Offset<flatbuffers::String>
sv_to_flatbuff_str(flatbuffers::FlatBufferBuilder &builder, std::string_view sv);
const flatbuffers::Offset<flatbuffers::Vector<uint8_t>>
hash_to_flatbuff_bytes(flatbuffers::FlatBufferBuilder &builder, hpfs::h32 hash);
const flatbuffers::Offset<flatbuffers::Vector<flatbuffers::Offset<ByteArray>>>
stringlist_to_flatbuf_bytearrayvector(flatbuffers::FlatBufferBuilder &builder, const std::set<std::string> &set);
const flatbuffers::Offset<flatbuffers::Vector<flatbuffers::Offset<BytesKeyValuePair>>>
stringmap_to_flatbuf_bytepairvector(flatbuffers::FlatBufferBuilder &builder, const std::unordered_map<std::string, const std::string> &map);
} // namespace msg::fbuf
#endif

View File

@@ -0,0 +1,11 @@
//IDL file for common types.
namespace msg.fbuf;
table BytesKeyValuePair { //A key, value pair of byte[].
key:[ubyte];
value:[ubyte];
}
table ByteArray { //To represent list of byte arrays
array:[ubyte];
}

View File

@@ -0,0 +1,146 @@
// automatically generated by the FlatBuffers compiler, do not modify
#ifndef FLATBUFFERS_GENERATED_COMMONSCHEMA_MSG_FBUF_H_
#define FLATBUFFERS_GENERATED_COMMONSCHEMA_MSG_FBUF_H_
#include "flatbuffers/flatbuffers.h"
namespace msg {
namespace fbuf {
struct BytesKeyValuePair;
struct BytesKeyValuePairBuilder;
struct ByteArray;
struct ByteArrayBuilder;
struct BytesKeyValuePair FLATBUFFERS_FINAL_CLASS : private flatbuffers::Table {
typedef BytesKeyValuePairBuilder Builder;
enum FlatBuffersVTableOffset FLATBUFFERS_VTABLE_UNDERLYING_TYPE {
VT_KEY = 4,
VT_VALUE = 6
};
const flatbuffers::Vector<uint8_t> *key() const {
return GetPointer<const flatbuffers::Vector<uint8_t> *>(VT_KEY);
}
flatbuffers::Vector<uint8_t> *mutable_key() {
return GetPointer<flatbuffers::Vector<uint8_t> *>(VT_KEY);
}
const flatbuffers::Vector<uint8_t> *value() const {
return GetPointer<const flatbuffers::Vector<uint8_t> *>(VT_VALUE);
}
flatbuffers::Vector<uint8_t> *mutable_value() {
return GetPointer<flatbuffers::Vector<uint8_t> *>(VT_VALUE);
}
bool Verify(flatbuffers::Verifier &verifier) const {
return VerifyTableStart(verifier) &&
VerifyOffset(verifier, VT_KEY) &&
verifier.VerifyVector(key()) &&
VerifyOffset(verifier, VT_VALUE) &&
verifier.VerifyVector(value()) &&
verifier.EndTable();
}
};
struct BytesKeyValuePairBuilder {
typedef BytesKeyValuePair Table;
flatbuffers::FlatBufferBuilder &fbb_;
flatbuffers::uoffset_t start_;
void add_key(flatbuffers::Offset<flatbuffers::Vector<uint8_t>> key) {
fbb_.AddOffset(BytesKeyValuePair::VT_KEY, key);
}
void add_value(flatbuffers::Offset<flatbuffers::Vector<uint8_t>> value) {
fbb_.AddOffset(BytesKeyValuePair::VT_VALUE, value);
}
explicit BytesKeyValuePairBuilder(flatbuffers::FlatBufferBuilder &_fbb)
: fbb_(_fbb) {
start_ = fbb_.StartTable();
}
flatbuffers::Offset<BytesKeyValuePair> Finish() {
const auto end = fbb_.EndTable(start_);
auto o = flatbuffers::Offset<BytesKeyValuePair>(end);
return o;
}
};
inline flatbuffers::Offset<BytesKeyValuePair> CreateBytesKeyValuePair(
flatbuffers::FlatBufferBuilder &_fbb,
flatbuffers::Offset<flatbuffers::Vector<uint8_t>> key = 0,
flatbuffers::Offset<flatbuffers::Vector<uint8_t>> value = 0) {
BytesKeyValuePairBuilder builder_(_fbb);
builder_.add_value(value);
builder_.add_key(key);
return builder_.Finish();
}
inline flatbuffers::Offset<BytesKeyValuePair> CreateBytesKeyValuePairDirect(
flatbuffers::FlatBufferBuilder &_fbb,
const std::vector<uint8_t> *key = nullptr,
const std::vector<uint8_t> *value = nullptr) {
auto key__ = key ? _fbb.CreateVector<uint8_t>(*key) : 0;
auto value__ = value ? _fbb.CreateVector<uint8_t>(*value) : 0;
return msg::fbuf::CreateBytesKeyValuePair(
_fbb,
key__,
value__);
}
struct ByteArray FLATBUFFERS_FINAL_CLASS : private flatbuffers::Table {
typedef ByteArrayBuilder Builder;
enum FlatBuffersVTableOffset FLATBUFFERS_VTABLE_UNDERLYING_TYPE {
VT_ARRAY = 4
};
const flatbuffers::Vector<uint8_t> *array() const {
return GetPointer<const flatbuffers::Vector<uint8_t> *>(VT_ARRAY);
}
flatbuffers::Vector<uint8_t> *mutable_array() {
return GetPointer<flatbuffers::Vector<uint8_t> *>(VT_ARRAY);
}
bool Verify(flatbuffers::Verifier &verifier) const {
return VerifyTableStart(verifier) &&
VerifyOffset(verifier, VT_ARRAY) &&
verifier.VerifyVector(array()) &&
verifier.EndTable();
}
};
struct ByteArrayBuilder {
typedef ByteArray Table;
flatbuffers::FlatBufferBuilder &fbb_;
flatbuffers::uoffset_t start_;
void add_array(flatbuffers::Offset<flatbuffers::Vector<uint8_t>> array) {
fbb_.AddOffset(ByteArray::VT_ARRAY, array);
}
explicit ByteArrayBuilder(flatbuffers::FlatBufferBuilder &_fbb)
: fbb_(_fbb) {
start_ = fbb_.StartTable();
}
flatbuffers::Offset<ByteArray> Finish() {
const auto end = fbb_.EndTable(start_);
auto o = flatbuffers::Offset<ByteArray>(end);
return o;
}
};
inline flatbuffers::Offset<ByteArray> CreateByteArray(
flatbuffers::FlatBufferBuilder &_fbb,
flatbuffers::Offset<flatbuffers::Vector<uint8_t>> array = 0) {
ByteArrayBuilder builder_(_fbb);
builder_.add_array(array);
return builder_.Finish();
}
inline flatbuffers::Offset<ByteArray> CreateByteArrayDirect(
flatbuffers::FlatBufferBuilder &_fbb,
const std::vector<uint8_t> *array = nullptr) {
auto array__ = array ? _fbb.CreateVector<uint8_t>(*array) : 0;
return msg::fbuf::CreateByteArray(
_fbb,
array__);
}
} // namespace fbuf
} // namespace msg
#endif // FLATBUFFERS_GENERATED_COMMONSCHEMA_MSG_FBUF_H_

View File

@@ -0,0 +1,31 @@
#include "../../pchheader.hpp"
#include "../../p2p/p2p.hpp"
#include "ledger_schema_generated.h"
#include "common_helpers.hpp"
#include "ledger_helpers.hpp"
namespace msg::fbuf::ledger
{
/**
* Create ledger from the given proposal struct.
* @param p The proposal struct to be placed in ledger.
*/
const std::string_view create_ledger_from_proposal(flatbuffers::FlatBufferBuilder &builder, const p2p::proposal &p, const uint64_t seq_no)
{
flatbuffers::Offset<ledger::Ledger> ledger =
ledger::CreateLedger(
builder,
seq_no,
p.time,
sv_to_flatbuff_bytes(builder, p.lcl),
sv_to_flatbuff_bytes(builder, p.state.to_string_view()),
stringlist_to_flatbuf_bytearrayvector(builder, p.users),
stringlist_to_flatbuf_bytearrayvector(builder, p.hash_inputs),
stringlist_to_flatbuf_bytearrayvector(builder, p.hash_outputs));
builder.Finish(ledger); // Finished building message content to get serialised content.
return flatbuff_bytes_to_sv(builder.GetBufferPointer(), builder.GetSize());
}
} // namespace msg::fbuf::ledger

View File

@@ -0,0 +1,14 @@
#ifndef _HP_MSG_FBUF_LEDGER_HELPERS_
#define _HP_MSG_FBUF_LEDGER_HELPERS_
#include "../../pchheader.hpp"
#include "../../p2p/p2p.hpp"
#include "ledger_schema_generated.h"
namespace msg::fbuf::ledger
{
const std::string_view create_ledger_from_proposal(flatbuffers::FlatBufferBuilder &builder, const p2p::proposal &p, const uint64_t seq_no);
}
#endif

View File

@@ -0,0 +1,20 @@
include "common_schema.fbs";
namespace msg.fbuf.ledger;
table Ledger {
seq_no:uint64;
time:uint64;
lcl:[ubyte];
state:[ubyte];
users: [ByteArray];
inputs: [ByteArray];
outputs: [ByteArray];
}
table RawInputList {
hash:[ubyte];
inputs:[ByteArray];
}
root_type Ledger;

View File

@@ -0,0 +1,286 @@
// automatically generated by the FlatBuffers compiler, do not modify
#ifndef FLATBUFFERS_GENERATED_LEDGERSCHEMA_MSG_FBUF_LEDGER_H_
#define FLATBUFFERS_GENERATED_LEDGERSCHEMA_MSG_FBUF_LEDGER_H_
#include "flatbuffers/flatbuffers.h"
#include "common_schema_generated.h"
namespace msg {
namespace fbuf {
namespace ledger {
struct Ledger;
struct LedgerBuilder;
struct RawInputList;
struct RawInputListBuilder;
struct Ledger FLATBUFFERS_FINAL_CLASS : private flatbuffers::Table {
typedef LedgerBuilder Builder;
enum FlatBuffersVTableOffset FLATBUFFERS_VTABLE_UNDERLYING_TYPE {
VT_SEQ_NO = 4,
VT_TIME = 6,
VT_LCL = 8,
VT_STATE = 10,
VT_USERS = 12,
VT_INPUTS = 14,
VT_OUTPUTS = 16
};
uint64_t seq_no() const {
return GetField<uint64_t>(VT_SEQ_NO, 0);
}
bool mutate_seq_no(uint64_t _seq_no) {
return SetField<uint64_t>(VT_SEQ_NO, _seq_no, 0);
}
uint64_t time() const {
return GetField<uint64_t>(VT_TIME, 0);
}
bool mutate_time(uint64_t _time) {
return SetField<uint64_t>(VT_TIME, _time, 0);
}
const flatbuffers::Vector<uint8_t> *lcl() const {
return GetPointer<const flatbuffers::Vector<uint8_t> *>(VT_LCL);
}
flatbuffers::Vector<uint8_t> *mutable_lcl() {
return GetPointer<flatbuffers::Vector<uint8_t> *>(VT_LCL);
}
const flatbuffers::Vector<uint8_t> *state() const {
return GetPointer<const flatbuffers::Vector<uint8_t> *>(VT_STATE);
}
flatbuffers::Vector<uint8_t> *mutable_state() {
return GetPointer<flatbuffers::Vector<uint8_t> *>(VT_STATE);
}
const flatbuffers::Vector<flatbuffers::Offset<msg::fbuf::ByteArray>> *users() const {
return GetPointer<const flatbuffers::Vector<flatbuffers::Offset<msg::fbuf::ByteArray>> *>(VT_USERS);
}
flatbuffers::Vector<flatbuffers::Offset<msg::fbuf::ByteArray>> *mutable_users() {
return GetPointer<flatbuffers::Vector<flatbuffers::Offset<msg::fbuf::ByteArray>> *>(VT_USERS);
}
const flatbuffers::Vector<flatbuffers::Offset<msg::fbuf::ByteArray>> *inputs() const {
return GetPointer<const flatbuffers::Vector<flatbuffers::Offset<msg::fbuf::ByteArray>> *>(VT_INPUTS);
}
flatbuffers::Vector<flatbuffers::Offset<msg::fbuf::ByteArray>> *mutable_inputs() {
return GetPointer<flatbuffers::Vector<flatbuffers::Offset<msg::fbuf::ByteArray>> *>(VT_INPUTS);
}
const flatbuffers::Vector<flatbuffers::Offset<msg::fbuf::ByteArray>> *outputs() const {
return GetPointer<const flatbuffers::Vector<flatbuffers::Offset<msg::fbuf::ByteArray>> *>(VT_OUTPUTS);
}
flatbuffers::Vector<flatbuffers::Offset<msg::fbuf::ByteArray>> *mutable_outputs() {
return GetPointer<flatbuffers::Vector<flatbuffers::Offset<msg::fbuf::ByteArray>> *>(VT_OUTPUTS);
}
bool Verify(flatbuffers::Verifier &verifier) const {
return VerifyTableStart(verifier) &&
VerifyField<uint64_t>(verifier, VT_SEQ_NO) &&
VerifyField<uint64_t>(verifier, VT_TIME) &&
VerifyOffset(verifier, VT_LCL) &&
verifier.VerifyVector(lcl()) &&
VerifyOffset(verifier, VT_STATE) &&
verifier.VerifyVector(state()) &&
VerifyOffset(verifier, VT_USERS) &&
verifier.VerifyVector(users()) &&
verifier.VerifyVectorOfTables(users()) &&
VerifyOffset(verifier, VT_INPUTS) &&
verifier.VerifyVector(inputs()) &&
verifier.VerifyVectorOfTables(inputs()) &&
VerifyOffset(verifier, VT_OUTPUTS) &&
verifier.VerifyVector(outputs()) &&
verifier.VerifyVectorOfTables(outputs()) &&
verifier.EndTable();
}
};
struct LedgerBuilder {
typedef Ledger Table;
flatbuffers::FlatBufferBuilder &fbb_;
flatbuffers::uoffset_t start_;
void add_seq_no(uint64_t seq_no) {
fbb_.AddElement<uint64_t>(Ledger::VT_SEQ_NO, seq_no, 0);
}
void add_time(uint64_t time) {
fbb_.AddElement<uint64_t>(Ledger::VT_TIME, time, 0);
}
void add_lcl(flatbuffers::Offset<flatbuffers::Vector<uint8_t>> lcl) {
fbb_.AddOffset(Ledger::VT_LCL, lcl);
}
void add_state(flatbuffers::Offset<flatbuffers::Vector<uint8_t>> state) {
fbb_.AddOffset(Ledger::VT_STATE, state);
}
void add_users(flatbuffers::Offset<flatbuffers::Vector<flatbuffers::Offset<msg::fbuf::ByteArray>>> users) {
fbb_.AddOffset(Ledger::VT_USERS, users);
}
void add_inputs(flatbuffers::Offset<flatbuffers::Vector<flatbuffers::Offset<msg::fbuf::ByteArray>>> inputs) {
fbb_.AddOffset(Ledger::VT_INPUTS, inputs);
}
void add_outputs(flatbuffers::Offset<flatbuffers::Vector<flatbuffers::Offset<msg::fbuf::ByteArray>>> outputs) {
fbb_.AddOffset(Ledger::VT_OUTPUTS, outputs);
}
explicit LedgerBuilder(flatbuffers::FlatBufferBuilder &_fbb)
: fbb_(_fbb) {
start_ = fbb_.StartTable();
}
flatbuffers::Offset<Ledger> Finish() {
const auto end = fbb_.EndTable(start_);
auto o = flatbuffers::Offset<Ledger>(end);
return o;
}
};
inline flatbuffers::Offset<Ledger> CreateLedger(
flatbuffers::FlatBufferBuilder &_fbb,
uint64_t seq_no = 0,
uint64_t time = 0,
flatbuffers::Offset<flatbuffers::Vector<uint8_t>> lcl = 0,
flatbuffers::Offset<flatbuffers::Vector<uint8_t>> state = 0,
flatbuffers::Offset<flatbuffers::Vector<flatbuffers::Offset<msg::fbuf::ByteArray>>> users = 0,
flatbuffers::Offset<flatbuffers::Vector<flatbuffers::Offset<msg::fbuf::ByteArray>>> inputs = 0,
flatbuffers::Offset<flatbuffers::Vector<flatbuffers::Offset<msg::fbuf::ByteArray>>> outputs = 0) {
LedgerBuilder builder_(_fbb);
builder_.add_time(time);
builder_.add_seq_no(seq_no);
builder_.add_outputs(outputs);
builder_.add_inputs(inputs);
builder_.add_users(users);
builder_.add_state(state);
builder_.add_lcl(lcl);
return builder_.Finish();
}
inline flatbuffers::Offset<Ledger> CreateLedgerDirect(
flatbuffers::FlatBufferBuilder &_fbb,
uint64_t seq_no = 0,
uint64_t time = 0,
const std::vector<uint8_t> *lcl = nullptr,
const std::vector<uint8_t> *state = nullptr,
const std::vector<flatbuffers::Offset<msg::fbuf::ByteArray>> *users = nullptr,
const std::vector<flatbuffers::Offset<msg::fbuf::ByteArray>> *inputs = nullptr,
const std::vector<flatbuffers::Offset<msg::fbuf::ByteArray>> *outputs = nullptr) {
auto lcl__ = lcl ? _fbb.CreateVector<uint8_t>(*lcl) : 0;
auto state__ = state ? _fbb.CreateVector<uint8_t>(*state) : 0;
auto users__ = users ? _fbb.CreateVector<flatbuffers::Offset<msg::fbuf::ByteArray>>(*users) : 0;
auto inputs__ = inputs ? _fbb.CreateVector<flatbuffers::Offset<msg::fbuf::ByteArray>>(*inputs) : 0;
auto outputs__ = outputs ? _fbb.CreateVector<flatbuffers::Offset<msg::fbuf::ByteArray>>(*outputs) : 0;
return msg::fbuf::ledger::CreateLedger(
_fbb,
seq_no,
time,
lcl__,
state__,
users__,
inputs__,
outputs__);
}
struct RawInputList FLATBUFFERS_FINAL_CLASS : private flatbuffers::Table {
typedef RawInputListBuilder Builder;
enum FlatBuffersVTableOffset FLATBUFFERS_VTABLE_UNDERLYING_TYPE {
VT_HASH = 4,
VT_INPUTS = 6
};
const flatbuffers::Vector<uint8_t> *hash() const {
return GetPointer<const flatbuffers::Vector<uint8_t> *>(VT_HASH);
}
flatbuffers::Vector<uint8_t> *mutable_hash() {
return GetPointer<flatbuffers::Vector<uint8_t> *>(VT_HASH);
}
const flatbuffers::Vector<flatbuffers::Offset<msg::fbuf::ByteArray>> *inputs() const {
return GetPointer<const flatbuffers::Vector<flatbuffers::Offset<msg::fbuf::ByteArray>> *>(VT_INPUTS);
}
flatbuffers::Vector<flatbuffers::Offset<msg::fbuf::ByteArray>> *mutable_inputs() {
return GetPointer<flatbuffers::Vector<flatbuffers::Offset<msg::fbuf::ByteArray>> *>(VT_INPUTS);
}
bool Verify(flatbuffers::Verifier &verifier) const {
return VerifyTableStart(verifier) &&
VerifyOffset(verifier, VT_HASH) &&
verifier.VerifyVector(hash()) &&
VerifyOffset(verifier, VT_INPUTS) &&
verifier.VerifyVector(inputs()) &&
verifier.VerifyVectorOfTables(inputs()) &&
verifier.EndTable();
}
};
struct RawInputListBuilder {
typedef RawInputList Table;
flatbuffers::FlatBufferBuilder &fbb_;
flatbuffers::uoffset_t start_;
void add_hash(flatbuffers::Offset<flatbuffers::Vector<uint8_t>> hash) {
fbb_.AddOffset(RawInputList::VT_HASH, hash);
}
void add_inputs(flatbuffers::Offset<flatbuffers::Vector<flatbuffers::Offset<msg::fbuf::ByteArray>>> inputs) {
fbb_.AddOffset(RawInputList::VT_INPUTS, inputs);
}
explicit RawInputListBuilder(flatbuffers::FlatBufferBuilder &_fbb)
: fbb_(_fbb) {
start_ = fbb_.StartTable();
}
flatbuffers::Offset<RawInputList> Finish() {
const auto end = fbb_.EndTable(start_);
auto o = flatbuffers::Offset<RawInputList>(end);
return o;
}
};
inline flatbuffers::Offset<RawInputList> CreateRawInputList(
flatbuffers::FlatBufferBuilder &_fbb,
flatbuffers::Offset<flatbuffers::Vector<uint8_t>> hash = 0,
flatbuffers::Offset<flatbuffers::Vector<flatbuffers::Offset<msg::fbuf::ByteArray>>> inputs = 0) {
RawInputListBuilder builder_(_fbb);
builder_.add_inputs(inputs);
builder_.add_hash(hash);
return builder_.Finish();
}
inline flatbuffers::Offset<RawInputList> CreateRawInputListDirect(
flatbuffers::FlatBufferBuilder &_fbb,
const std::vector<uint8_t> *hash = nullptr,
const std::vector<flatbuffers::Offset<msg::fbuf::ByteArray>> *inputs = nullptr) {
auto hash__ = hash ? _fbb.CreateVector<uint8_t>(*hash) : 0;
auto inputs__ = inputs ? _fbb.CreateVector<flatbuffers::Offset<msg::fbuf::ByteArray>>(*inputs) : 0;
return msg::fbuf::ledger::CreateRawInputList(
_fbb,
hash__,
inputs__);
}
inline const msg::fbuf::ledger::Ledger *GetLedger(const void *buf) {
return flatbuffers::GetRoot<msg::fbuf::ledger::Ledger>(buf);
}
inline const msg::fbuf::ledger::Ledger *GetSizePrefixedLedger(const void *buf) {
return flatbuffers::GetSizePrefixedRoot<msg::fbuf::ledger::Ledger>(buf);
}
inline Ledger *GetMutableLedger(void *buf) {
return flatbuffers::GetMutableRoot<Ledger>(buf);
}
inline bool VerifyLedgerBuffer(
flatbuffers::Verifier &verifier) {
return verifier.VerifyBuffer<msg::fbuf::ledger::Ledger>(nullptr);
}
inline bool VerifySizePrefixedLedgerBuffer(
flatbuffers::Verifier &verifier) {
return verifier.VerifySizePrefixedBuffer<msg::fbuf::ledger::Ledger>(nullptr);
}
inline void FinishLedgerBuffer(
flatbuffers::FlatBufferBuilder &fbb,
flatbuffers::Offset<msg::fbuf::ledger::Ledger> root) {
fbb.Finish(root);
}
inline void FinishSizePrefixedLedgerBuffer(
flatbuffers::FlatBufferBuilder &fbb,
flatbuffers::Offset<msg::fbuf::ledger::Ledger> root) {
fbb.FinishSizePrefixed(root);
}
} // namespace ledger
} // namespace fbuf
} // namespace msg
#endif // FLATBUFFERS_GENERATED_LEDGERSCHEMA_MSG_FBUF_LEDGER_H_

View File

@@ -0,0 +1,17 @@
//IDL file for p2p message container schema.
/*Message content need to be serialised and parsed into container, we need two root types in flatbuffs to generat
needed api methods. Since Flatbuff only support one rrot at each IDL files, we had to seperate message schema to 2 files.
*/
include "p2pmsg_content.fbs";
namespace msg.fbuf.p2pmsg;
table Container { //root type for message
version:uint16;
timestamp:uint64;
pubkey:[ubyte];
lcl:[ubyte];
signature:[ubyte]; // signature of the message content
content:[ubyte]; // message content: byte array of proposal,npl,etc
}
root_type Container;

View File

@@ -0,0 +1,192 @@
// automatically generated by the FlatBuffers compiler, do not modify
#ifndef FLATBUFFERS_GENERATED_P2PMSGCONTAINER_MSG_FBUF_P2PMSG_H_
#define FLATBUFFERS_GENERATED_P2PMSGCONTAINER_MSG_FBUF_P2PMSG_H_
#include "flatbuffers/flatbuffers.h"
#include "common_schema_generated.h"
#include "p2pmsg_content_generated.h"
namespace msg {
namespace fbuf {
namespace p2pmsg {
struct Container;
struct ContainerBuilder;
struct Container FLATBUFFERS_FINAL_CLASS : private flatbuffers::Table {
typedef ContainerBuilder Builder;
enum FlatBuffersVTableOffset FLATBUFFERS_VTABLE_UNDERLYING_TYPE {
VT_VERSION = 4,
VT_TIMESTAMP = 6,
VT_PUBKEY = 8,
VT_LCL = 10,
VT_SIGNATURE = 12,
VT_CONTENT = 14
};
uint16_t version() const {
return GetField<uint16_t>(VT_VERSION, 0);
}
bool mutate_version(uint16_t _version) {
return SetField<uint16_t>(VT_VERSION, _version, 0);
}
uint64_t timestamp() const {
return GetField<uint64_t>(VT_TIMESTAMP, 0);
}
bool mutate_timestamp(uint64_t _timestamp) {
return SetField<uint64_t>(VT_TIMESTAMP, _timestamp, 0);
}
const flatbuffers::Vector<uint8_t> *pubkey() const {
return GetPointer<const flatbuffers::Vector<uint8_t> *>(VT_PUBKEY);
}
flatbuffers::Vector<uint8_t> *mutable_pubkey() {
return GetPointer<flatbuffers::Vector<uint8_t> *>(VT_PUBKEY);
}
const flatbuffers::Vector<uint8_t> *lcl() const {
return GetPointer<const flatbuffers::Vector<uint8_t> *>(VT_LCL);
}
flatbuffers::Vector<uint8_t> *mutable_lcl() {
return GetPointer<flatbuffers::Vector<uint8_t> *>(VT_LCL);
}
const flatbuffers::Vector<uint8_t> *signature() const {
return GetPointer<const flatbuffers::Vector<uint8_t> *>(VT_SIGNATURE);
}
flatbuffers::Vector<uint8_t> *mutable_signature() {
return GetPointer<flatbuffers::Vector<uint8_t> *>(VT_SIGNATURE);
}
const flatbuffers::Vector<uint8_t> *content() const {
return GetPointer<const flatbuffers::Vector<uint8_t> *>(VT_CONTENT);
}
flatbuffers::Vector<uint8_t> *mutable_content() {
return GetPointer<flatbuffers::Vector<uint8_t> *>(VT_CONTENT);
}
bool Verify(flatbuffers::Verifier &verifier) const {
return VerifyTableStart(verifier) &&
VerifyField<uint16_t>(verifier, VT_VERSION) &&
VerifyField<uint64_t>(verifier, VT_TIMESTAMP) &&
VerifyOffset(verifier, VT_PUBKEY) &&
verifier.VerifyVector(pubkey()) &&
VerifyOffset(verifier, VT_LCL) &&
verifier.VerifyVector(lcl()) &&
VerifyOffset(verifier, VT_SIGNATURE) &&
verifier.VerifyVector(signature()) &&
VerifyOffset(verifier, VT_CONTENT) &&
verifier.VerifyVector(content()) &&
verifier.EndTable();
}
};
struct ContainerBuilder {
typedef Container Table;
flatbuffers::FlatBufferBuilder &fbb_;
flatbuffers::uoffset_t start_;
void add_version(uint16_t version) {
fbb_.AddElement<uint16_t>(Container::VT_VERSION, version, 0);
}
void add_timestamp(uint64_t timestamp) {
fbb_.AddElement<uint64_t>(Container::VT_TIMESTAMP, timestamp, 0);
}
void add_pubkey(flatbuffers::Offset<flatbuffers::Vector<uint8_t>> pubkey) {
fbb_.AddOffset(Container::VT_PUBKEY, pubkey);
}
void add_lcl(flatbuffers::Offset<flatbuffers::Vector<uint8_t>> lcl) {
fbb_.AddOffset(Container::VT_LCL, lcl);
}
void add_signature(flatbuffers::Offset<flatbuffers::Vector<uint8_t>> signature) {
fbb_.AddOffset(Container::VT_SIGNATURE, signature);
}
void add_content(flatbuffers::Offset<flatbuffers::Vector<uint8_t>> content) {
fbb_.AddOffset(Container::VT_CONTENT, content);
}
explicit ContainerBuilder(flatbuffers::FlatBufferBuilder &_fbb)
: fbb_(_fbb) {
start_ = fbb_.StartTable();
}
flatbuffers::Offset<Container> Finish() {
const auto end = fbb_.EndTable(start_);
auto o = flatbuffers::Offset<Container>(end);
return o;
}
};
inline flatbuffers::Offset<Container> CreateContainer(
flatbuffers::FlatBufferBuilder &_fbb,
uint16_t version = 0,
uint64_t timestamp = 0,
flatbuffers::Offset<flatbuffers::Vector<uint8_t>> pubkey = 0,
flatbuffers::Offset<flatbuffers::Vector<uint8_t>> lcl = 0,
flatbuffers::Offset<flatbuffers::Vector<uint8_t>> signature = 0,
flatbuffers::Offset<flatbuffers::Vector<uint8_t>> content = 0) {
ContainerBuilder builder_(_fbb);
builder_.add_timestamp(timestamp);
builder_.add_content(content);
builder_.add_signature(signature);
builder_.add_lcl(lcl);
builder_.add_pubkey(pubkey);
builder_.add_version(version);
return builder_.Finish();
}
inline flatbuffers::Offset<Container> CreateContainerDirect(
flatbuffers::FlatBufferBuilder &_fbb,
uint16_t version = 0,
uint64_t timestamp = 0,
const std::vector<uint8_t> *pubkey = nullptr,
const std::vector<uint8_t> *lcl = nullptr,
const std::vector<uint8_t> *signature = nullptr,
const std::vector<uint8_t> *content = nullptr) {
auto pubkey__ = pubkey ? _fbb.CreateVector<uint8_t>(*pubkey) : 0;
auto lcl__ = lcl ? _fbb.CreateVector<uint8_t>(*lcl) : 0;
auto signature__ = signature ? _fbb.CreateVector<uint8_t>(*signature) : 0;
auto content__ = content ? _fbb.CreateVector<uint8_t>(*content) : 0;
return msg::fbuf::p2pmsg::CreateContainer(
_fbb,
version,
timestamp,
pubkey__,
lcl__,
signature__,
content__);
}
inline const msg::fbuf::p2pmsg::Container *GetContainer(const void *buf) {
return flatbuffers::GetRoot<msg::fbuf::p2pmsg::Container>(buf);
}
inline const msg::fbuf::p2pmsg::Container *GetSizePrefixedContainer(const void *buf) {
return flatbuffers::GetSizePrefixedRoot<msg::fbuf::p2pmsg::Container>(buf);
}
inline Container *GetMutableContainer(void *buf) {
return flatbuffers::GetMutableRoot<Container>(buf);
}
inline bool VerifyContainerBuffer(
flatbuffers::Verifier &verifier) {
return verifier.VerifyBuffer<msg::fbuf::p2pmsg::Container>(nullptr);
}
inline bool VerifySizePrefixedContainerBuffer(
flatbuffers::Verifier &verifier) {
return verifier.VerifySizePrefixedBuffer<msg::fbuf::p2pmsg::Container>(nullptr);
}
inline void FinishContainerBuffer(
flatbuffers::FlatBufferBuilder &fbb,
flatbuffers::Offset<msg::fbuf::p2pmsg::Container> root) {
fbb.Finish(root);
}
inline void FinishSizePrefixedContainerBuffer(
flatbuffers::FlatBufferBuilder &fbb,
flatbuffers::Offset<msg::fbuf::p2pmsg::Container> root) {
fbb.FinishSizePrefixed(root);
}
} // namespace p2pmsg
} // namespace fbuf
} // namespace msg
#endif // FLATBUFFERS_GENERATED_P2PMSGCONTAINER_MSG_FBUF_P2PMSG_H_

View File

@@ -0,0 +1,113 @@
// IDL file for p2p message content schema.
// flatc -o src/msg/fbuf/ --gen-mutable --cpp src/msg/fbuf/p2pmsg_content.fbs
include "common_schema.fbs";
namespace msg.fbuf.p2pmsg;
table Peer_Challenge_Message {
challenge:[ubyte];
}
table Peer_Challenge_Response_Message {
challenge:[ubyte];
sig:[ubyte];
}
table UserInput {
input_container:[ubyte];
signature:[ubyte];
protocol:uint8;
}
table UserInputGroup {
pubkey:[ubyte];
messages:[UserInput];
}
union Message { Peer_Challenge_Response_Message, Peer_Challenge_Message, NonUnl_Proposal_Message, Proposal_Message, Npl_Message, State_Request_Message, State_Response_Message, History_Request_Message, History_Response_Message } //message content type
table Content {
message:Message;
}
table NonUnl_Proposal_Message {
user_inputs:[UserInputGroup];
}
table Proposal_Message { //Proposal type message schema
stage:uint8;
time:uint64;
users:[ByteArray];
hash_inputs:[ByteArray]; //stage > 0 inputs (hash of stage 0 inputs)
hash_outputs:[ByteArray]; //stage > 0 outputs (hash of stage 0 outputs)
state: [ubyte];
}
table Npl_Message { //NPL type message schema
data:[ubyte];
}
table History_Request_Message { //Ledger History request type message schema
minimum_lcl:[ubyte];
required_lcl:[ubyte];
}
enum Ledger_Response_Error : ubyte
{
None = 0,
Invalid_Min_Ledger = 1,
Req_Ledger_Not_Found = 2
}
table History_Response_Message { //Ledger History request type message schema
hist_ledgers:[HistoryLedgerPair];
error: Ledger_Response_Error;
}
table HistoryLedgerPair { //A key, value pair of byte[].
seq_no:uint64;
ledger:HistoryLedger;
}
table HistoryLedger {
state:[ubyte];
lcl:[ubyte];
raw_ledger:[ubyte];
}
table State_Request_Message { //State request message schema
parent_path:string;
is_file:bool;
block_id:int32;
expected_hash:[ubyte];
}
union State_Response{ File_HashMap_Response, Block_Response, Fs_Entry_Response }
table State_Response_Message{
state_response:State_Response;
hash:[ubyte];
path: string;
}
table Fs_Entry_Response{
entries: [State_FS_Hash_Entry];
}
table File_HashMap_Response{
file_length:uint64;
hash_map:[ubyte];
}
table Block_Response{
block_id:uint32;
data: [ubyte];
}
table State_FS_Hash_Entry{
name: string;
is_file: bool;
hash: [ubyte];
}
root_type Content; //root type for message content

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,740 @@
#include "../../pchheader.hpp"
#include "../../conf.hpp"
#include "../../crypto.hpp"
#include "../../util.hpp"
#include "../../hplog.hpp"
#include "../../p2p/p2p.hpp"
#include "../../hpfs/h32.hpp"
#include "../../hpfs/hpfs.hpp"
#include "p2pmsg_container_generated.h"
#include "p2pmsg_content_generated.h"
#include "common_helpers.hpp"
#include "p2pmsg_helpers.hpp"
namespace msg::fbuf::p2pmsg
{
// Length of a peer connection challange.
constexpr size_t PEERCHALLENGE_LEN = 16;
// Max size of messages which are subjected to time (too old) check.
constexpr size_t MAX_SIZE_FOR_TIME_CHECK = 1 * 1024 * 1024; // 1 MB
/**
* This section contains Flatbuffer message reading/writing helpers.
* These helpers are mainly used by peer_session_handler.
*
* All Flatbuffer peer messages are 'Container' messages. 'Container' message is a bucket
* which some common headers (version, singature etc..) and the message 'Content' (Proposal, NPL etc..).
*
* Therefore, when constructing peer messages, we have to first construct 'Content' message and then
* place the 'Content' inside a 'Conatiner. 'Content' and 'Container' messages are constructed using
* Flatbuffer builders.
*
* Reading is also 2 steps because of this. We have first interprit the 'Container' message from the
* received data and then interprit the 'Content' portion of it separately to read the actual content.
*/
//---Message validation helpers---/
/**
* Verifies Conatiner message structure and outputs faltbuffer Container pointer to access the given buffer.
*
* @param container_ref A pointer reference to assign the pointer to the Container object.
* @param container_buf The buffer containing the data that should be validated and interpreted
* via the container pointer.
* @return 0 on successful verification. -1 for failure.
*/
int validate_and_extract_container(const Container **container_ref, std::string_view container_buf)
{
//Accessing message buffer
const uint8_t *container_buf_ptr = reinterpret_cast<const uint8_t *>(container_buf.data());
const size_t container_buf_size = container_buf.length();
//Defining Flatbuffer verifier (default max depth = 64, max_tables = 1000000,)
flatbuffers::Verifier container_verifier(container_buf_ptr, container_buf_size);
//Verify container message using flatbuffer verifier
if (!VerifyContainerBuffer(container_verifier))
{
LOG_DBG << "Flatbuffer verify: Bad peer message container.";
return -1;
}
//Get message container
const Container *container = GetContainer(container_buf_ptr);
//check protocol version of message whether it is greater than minimum supported protocol version.
const uint16_t version = container->version();
if (version < util::MIN_PEERMSG_VERSION)
{
LOG_DBG << "Peer message is from unsupported protocol version (" << version << ").";
return -1;
}
//check message timestamp (ignore this for large messages).
if (container_buf_size <= MAX_SIZE_FOR_TIME_CHECK)
{
const int64_t time_now = util::get_epoch_milliseconds();
if (container->timestamp() < (time_now - conf::cfg.roundtime * 4))
{
LOG_DBG << "Peer message is too old.";
return -1;
}
}
//Assign container and content out params.
*container_ref = container;
return 0;
}
/**
* Validates the container message signing keys to see if the message is from a trusted source (UNL).
* @return 0 on successful verification. -1 for failure.
*/
int validate_container_trust(const Container *container)
{
std::string_view msg_pubkey = flatbuff_bytes_to_sv(container->pubkey());
std::string_view msg_sig = flatbuff_bytes_to_sv(container->signature());
if (msg_pubkey.empty() || msg_sig.empty())
{
LOG_DBG << "Peer message key pair incomplete. Trust verification failed.";
return -1;
}
//validate if the message is not from a node of current node's unl list.
if (!conf::cfg.unl.count(std::string(msg_pubkey)))
{
LOG_DBG << "Peer message pubkey verification failed. Not in UNL.";
return -1;
}
//verify message signature.
//this is performed towards end since this is bit expensive
std::string_view msg_content = flatbuff_bytes_to_sv(container->content());
if (crypto::verify(msg_content, msg_sig, msg_pubkey) != 0)
{
LOG_DBG << "Peer message signature verification failed.";
return -1;
}
return 0;
}
/**
* Verifies the Content message structure and outputs faltbuffer Content pointer to access the given buffer.
*
* @param content_ref A pointer reference to assign the pointer to the Content object.
* @param content_ptr Pointer to the the buffer containing the data that should validated and interpreted
* via the container pointer.
* @param content_size Data buffer size.
* @return 0 on successful verification. -1 for failure.
*/
int validate_and_extract_content(const Content **content_ref, const uint8_t *content_ptr, const flatbuffers::uoffset_t content_size)
{
//Defining Flatbuffer verifier for message content verification.
//Since content is also serialised by using Flatbuffer we can verify it using Flatbuffer.
flatbuffers::Verifier content_verifier(content_ptr, content_size);
//verify content message using flatbuffer verifier.
if (!VerifyContainerBuffer(content_verifier))
{
LOG_DBG << "Flatbuffer verify: Bad content.";
return -1;
}
*content_ref = GetContent(content_ptr);
return 0;
}
//---Message reading helpers---/
/**
* Returns challenge from the peer challenge message.
* @param The Flatbuffer peer challenge message received from the peer.
* @return binary challenge.
*/
const std::string_view get_peer_challenge_from_msg(const Peer_Challenge_Message &msg)
{
return flatbuff_bytes_to_sv(msg.challenge());
}
/**
* Creates a peer challenge response struct from the given peer challenge response message.
* @param The Flatbuffer peer challenge response message received from the peer.
* @return A peer challenge response struct representing the message.
*/
const p2p::peer_challenge_response create_peer_challenge_response_from_msg(const Peer_Challenge_Response_Message &msg, const flatbuffers::Vector<uint8_t> *pubkey)
{
p2p::peer_challenge_response pchalresp;
pchalresp.challenge = flatbuff_bytes_to_sv(msg.challenge());
pchalresp.signature = flatbuff_bytes_to_sv(msg.sig());
pchalresp.pubkey = flatbuff_bytes_to_sv(pubkey);
return pchalresp;
}
/**
* Creates a non-unl proposal stuct from the given non-unl proposal message.
* @param The Flatbuffer non-unl poporal received from the peer.
* @return A non-unl proposal struct representing the message.
*/
const p2p::nonunl_proposal create_nonunl_proposal_from_msg(const NonUnl_Proposal_Message &msg, const uint64_t timestamp)
{
p2p::nonunl_proposal nup;
if (msg.user_inputs())
nup.user_inputs = flatbuf_user_input_group_to_user_input_map(msg.user_inputs());
return nup;
}
/**
* Creates a history response stuct from the given histrory response message.
* @param msg Flatbuffer History response message received from the peer.
* @return A History response struct representing the message.
*/
const p2p::history_response create_history_response_from_msg(const History_Response_Message &msg)
{
p2p::history_response hr;
if (msg.hist_ledgers())
hr.hist_ledgers = flatbuf_historyledgermap_to_historyledgermap(msg.hist_ledgers());
if (msg.error())
hr.error = (p2p::LEDGER_RESPONSE_ERROR)msg.error();
return hr;
}
/**
* Creates a proposal stuct from the given proposal message.
* @param The Flatbuffer poposal received from the peer.
* @return A proposal struct representing the message.
*/
const p2p::proposal create_proposal_from_msg(const Proposal_Message &msg, const flatbuffers::Vector<uint8_t> *pubkey, const uint64_t timestamp, const flatbuffers::Vector<uint8_t> *lcl)
{
p2p::proposal p;
p.pubkey = flatbuff_bytes_to_sv(pubkey);
p.timestamp = timestamp;
p.time = msg.time();
p.stage = msg.stage();
p.lcl = flatbuff_bytes_to_sv(lcl);
p.state = flatbuff_bytes_to_sv(msg.state());
if (msg.users())
p.users = flatbuf_bytearrayvector_to_stringlist(msg.users());
if (msg.hash_inputs())
p.hash_inputs = flatbuf_bytearrayvector_to_stringlist(msg.hash_inputs());
if (msg.hash_outputs())
p.hash_outputs = flatbuf_bytearrayvector_to_stringlist(msg.hash_outputs());
return p;
}
/**
* Creates a history request struct from the given history request message.
* @param msg Flatbuffer History request message received from the peer.
* @return A History request struct representing the message.
*/
const p2p::history_request create_history_request_from_msg(const History_Request_Message &msg)
{
p2p::history_request hr;
if (msg.minimum_lcl())
hr.minimum_lcl = flatbuff_bytes_to_sv(msg.minimum_lcl());
if (msg.required_lcl())
hr.required_lcl = flatbuff_bytes_to_sv(msg.required_lcl());
return hr;
}
/**
* Creates a state request struct from the given state request message.
* @param msg Flatbuffer State request message received from the peer.
* @return A State request struct representing the message.
*/
const p2p::state_request create_state_request_from_msg(const State_Request_Message &msg)
{
p2p::state_request sr;
sr.block_id = msg.block_id();
sr.is_file = msg.is_file();
sr.parent_path = flatbuff_str_to_sv(msg.parent_path());
sr.expected_hash = flatbuff_bytes_to_hash(msg.expected_hash());
return sr;
}
//---Message creation helpers---//
/**
* Create peer challenge message from the given challenge.
* @param container_builder Flatbuffer builder for the container message.
* @param challenge Challenge message needed to convert to flatbuffer message.
*/
void create_msg_from_peer_challenge(flatbuffers::FlatBufferBuilder &container_builder, std::string &challenge)
{
flatbuffers::FlatBufferBuilder builder(1024);
// We calculate the peer challenge to be a random string.
// Use libsodium to generate the random challenge bytes.
challenge.resize(PEERCHALLENGE_LEN);
randombytes_buf(challenge.data(), PEERCHALLENGE_LEN);
const flatbuffers::Offset<Peer_Challenge_Message> peer_challenge_msg =
CreatePeer_Challenge_Message(
builder,
sv_to_flatbuff_bytes(builder, challenge));
const flatbuffers::Offset<Content> message = CreateContent(builder, Message_Peer_Challenge_Message, peer_challenge_msg.Union());
builder.Finish(message); // Finished building message content to get serialised content.
// Now that we have built the content message
create_containermsg_from_content(container_builder, builder, nullptr, false);
}
/**
* Create peer challenge response message from the given challenge.
* @param container_builder Flatbuffer builder for the container message.
* @param challenge Message which need to be signed and placed in the container message.
*/
void create_peer_challenge_response_from_challenge(flatbuffers::FlatBufferBuilder &container_builder, const std::string &challenge)
{
flatbuffers::FlatBufferBuilder builder(1024);
const flatbuffers::Offset<Peer_Challenge_Response_Message> challenge_resp_msg =
CreatePeer_Challenge_Response_Message(
builder,
sv_to_flatbuff_bytes(builder, challenge),
sv_to_flatbuff_bytes(builder, crypto::sign(challenge, conf::cfg.seckey)));
const flatbuffers::Offset<Content> message = CreateContent(builder, Message_Peer_Challenge_Response_Message, challenge_resp_msg.Union());
builder.Finish(message); // Finished building message content to get serialised content.
// Now that we have built the content message,
// we need to sign it and place it inside a container message.
create_containermsg_from_content(container_builder, builder, nullptr, true);
}
void create_msg_from_nonunl_proposal(flatbuffers::FlatBufferBuilder &container_builder, const p2p::nonunl_proposal &nup)
{
flatbuffers::FlatBufferBuilder builder(1024);
const flatbuffers::Offset<NonUnl_Proposal_Message> nupmsg =
CreateNonUnl_Proposal_Message(
builder,
user_input_map_to_flatbuf_user_input_group(builder, nup.user_inputs));
const flatbuffers::Offset<Content> message = CreateContent(builder, Message_NonUnl_Proposal_Message, nupmsg.Union());
builder.Finish(message); // Finished building message content to get serialised content.
// Now that we have built the content message,
// we need to sign it and place it inside a container message.
create_containermsg_from_content(container_builder, builder, nullptr, false);
}
/**
* Create proposal peer message from the given proposal struct.
* @param container_builder Flatbuffer builder for the container message.
* @param p The proposal struct to be placed in the container message.
*/
void create_msg_from_proposal(flatbuffers::FlatBufferBuilder &container_builder, const p2p::proposal &p)
{
// todo:get a average propsal message size and allocate content builder based on that.
flatbuffers::FlatBufferBuilder builder(1024);
const flatbuffers::Offset<Proposal_Message> proposal =
CreateProposal_Message(
builder,
p.stage,
p.time,
stringlist_to_flatbuf_bytearrayvector(builder, p.users),
stringlist_to_flatbuf_bytearrayvector(builder, p.hash_inputs),
stringlist_to_flatbuf_bytearrayvector(builder, p.hash_outputs),
sv_to_flatbuff_bytes(builder, p.state.to_string_view()));
const flatbuffers::Offset<Content> message = CreateContent(builder, Message_Proposal_Message, proposal.Union());
builder.Finish(message); // Finished building message content to get serialised content.
// Now that we have built the content message,
// we need to sign it and place it inside a container message.
create_containermsg_from_content(container_builder, builder, p.lcl, true);
}
/**
* Ctreat npl message from the given npl output srtuct.
* @param container_builder Flatbuffer builder for the container message.
* @param n The npl struct to be placed in the container message.
* @param lcl Lcl value to be passed in the container message.
*/
void create_msg_from_npl_output(flatbuffers::FlatBufferBuilder &container_builder, const p2p::npl_message &n, std::string_view lcl)
{
flatbuffers::FlatBufferBuilder builder(1024);
const flatbuffers::Offset<Npl_Message> npl =
CreateNpl_Message(
builder,
sv_to_flatbuff_bytes(builder, n.data));
const flatbuffers::Offset<Content> message = CreateContent(builder, Message_Npl_Message, npl.Union());
builder.Finish(message); // Finished building message content to get serialised content.
// Now that we have built the content message,
// we need to sign it and place it inside a container message.
create_containermsg_from_content(container_builder, builder, lcl, true);
}
/**
* Create history request message from the given history request struct.
* @param container_builder Flatbuffer builder for the container message.
* @param hr The History request struct to be placed in the container message.
*/
void create_msg_from_history_request(flatbuffers::FlatBufferBuilder &container_builder, const p2p::history_request &hr)
{
flatbuffers::FlatBufferBuilder builder(1024);
flatbuffers::Offset<History_Request_Message> hrmsg =
CreateHistory_Request_Message(
builder,
sv_to_flatbuff_bytes(builder, hr.minimum_lcl),
sv_to_flatbuff_bytes(builder, hr.required_lcl));
flatbuffers::Offset<Content> message = CreateContent(builder, Message_History_Request_Message, hrmsg.Union());
builder.Finish(message); // Finished building message content to get serialised content.
// Now that we have built the content message,
// we need to sign it and place it inside a container message.
create_containermsg_from_content(container_builder, builder, nullptr, true);
}
/**
* Create history response message from the given history response struct.
* @param container_builder Flatbuffer builder for the container message.
* @param hr The History response struct to be placed in the container message.
*/
void create_msg_from_history_response(flatbuffers::FlatBufferBuilder &container_builder, const p2p::history_response &hr)
{
flatbuffers::FlatBufferBuilder builder(1024);
flatbuffers::Offset<History_Response_Message> hrmsg =
CreateHistory_Response_Message(
builder,
historyledgermap_to_flatbuf_historyledgermap(builder, hr.hist_ledgers),
(Ledger_Response_Error)hr.error);
flatbuffers::Offset<Content> message = CreateContent(builder, Message_History_Response_Message, hrmsg.Union());
builder.Finish(message); // Finished building message content to get serialised content.
// Now that we have built the content message,
// we need to sign it and place it inside a container message.
create_containermsg_from_content(container_builder, builder, nullptr, true);
}
/**
* Create state request message from the given state request struct.
* @param container_builder Flatbuffer builder for the container message.
* @param sr The state request struct to be placed in the container message.
*/
void create_msg_from_state_request(flatbuffers::FlatBufferBuilder &container_builder, const p2p::state_request &hr, std::string_view lcl)
{
flatbuffers::FlatBufferBuilder builder(1024);
flatbuffers::Offset<State_Request_Message> srmsg =
CreateState_Request_Message(
builder,
sv_to_flatbuff_str(builder, hr.parent_path),
hr.is_file,
hr.block_id,
hash_to_flatbuff_bytes(builder, hr.expected_hash));
flatbuffers::Offset<Content> message = CreateContent(builder, Message_State_Request_Message, srmsg.Union());
builder.Finish(message); // Finished building message content to get serialised content.
// Now that we have built the content message,
// we need to sign it and place it inside a container message.
create_containermsg_from_content(container_builder, builder, lcl, true);
}
/**
* Create content response message from the given content response.
* @param container_builder Flatbuffer builder for the container message.
* @param path The path of the directory.
* @param hash_nodes File or directory entries with hashes in the given parent path.
* @param expected_hash The exptected hash of the requested path.
* @param lcl Lcl to be include in the container msg.
*/
void create_msg_from_fsentry_response(
flatbuffers::FlatBufferBuilder &container_builder, const std::string_view path,
std::vector<hpfs::child_hash_node> &hash_nodes, hpfs::h32 expected_hash, std::string_view lcl)
{
flatbuffers::FlatBufferBuilder builder(1024);
const flatbuffers::Offset<Fs_Entry_Response> resp =
CreateFs_Entry_Response(
builder,
statefshashentry_to_flatbuff_statefshashentry(builder, hash_nodes));
const flatbuffers::Offset<State_Response_Message> st_resp = CreateState_Response_Message(
builder, State_Response_Fs_Entry_Response,
resp.Union(),
hash_to_flatbuff_bytes(builder, expected_hash),
sv_to_flatbuff_str(builder, path));
flatbuffers::Offset<Content> message = CreateContent(builder, Message_State_Response_Message, st_resp.Union());
builder.Finish(message); // Finished building message content to get serialised content.
// Now that we have built the content message,
// we need to sign it and place it inside a container message.
create_containermsg_from_content(container_builder, builder, lcl, true);
}
/**
* Create content response message from the given content response.
* @param container_builder Flatbuffer builder for the container message.
* @param path The path of the directory.
* @param hashmap Hashmap of the file
* @param lcl Lcl to be include in the container msg.
*/
void create_msg_from_filehashmap_response(
flatbuffers::FlatBufferBuilder &container_builder, std::string_view path,
std::vector<hpfs::h32> &hashmap, std::size_t file_length, hpfs::h32 expected_hash, std::string_view lcl)
{
// todo:get a average propsal message size and allocate content builder based on that.
flatbuffers::FlatBufferBuilder builder(1024);
std::string_view hashmap_sv(reinterpret_cast<const char *>(hashmap.data()), hashmap.size() * sizeof(hpfs::h32));
const flatbuffers::Offset<File_HashMap_Response> resp =
CreateFile_HashMap_Response(
builder,
file_length,
sv_to_flatbuff_bytes(builder, hashmap_sv));
const flatbuffers::Offset<State_Response_Message> st_resp = CreateState_Response_Message(
builder,
State_Response_File_HashMap_Response,
resp.Union(),
hash_to_flatbuff_bytes(builder, expected_hash),
sv_to_flatbuff_str(builder, path));
flatbuffers::Offset<Content> message = CreateContent(builder, Message_State_Response_Message, st_resp.Union());
builder.Finish(message); // Finished building message content to get serialised content.
// Now that we have built the content message,
// we need to sign it and place it inside a container message.
create_containermsg_from_content(container_builder, builder, lcl, true);
}
/**
* Create content response message from the given content response.
* @param container_builder Flatbuffer builder for the container message.
* @param block_resp Block response struct to place in the message
* @param lcl Lcl to be include in the container message.
*/
void create_msg_from_block_response(flatbuffers::FlatBufferBuilder &container_builder, p2p::block_response &block_resp, std::string_view lcl)
{
// todo:get a average propsal message size and allocate content builder based on that.
flatbuffers::FlatBufferBuilder builder(1024);
const flatbuffers::Offset<Block_Response> resp =
CreateBlock_Response(
builder,
block_resp.block_id,
sv_to_flatbuff_bytes(builder, block_resp.data));
const flatbuffers::Offset<State_Response_Message> st_resp = CreateState_Response_Message(
builder,
State_Response_Block_Response,
resp.Union(),
hash_to_flatbuff_bytes(builder, block_resp.hash),
sv_to_flatbuff_str(builder, block_resp.path));
flatbuffers::Offset<Content> message = CreateContent(builder, Message_State_Response_Message, st_resp.Union());
builder.Finish(message); // Finished building message content to get serialised content.
// Now that we have built the content message,
// we need to sign it and place it inside a container message.
create_containermsg_from_content(container_builder, builder, lcl, true);
}
/**
* Creates a Flatbuffer container message from the given Content message.
* @param container_builder The Flatbuffer builder to which the final container message should be written to.
* @param content_builder The Flatbuffer builder containing the content message that should be placed
* inside the container message.
* @param sign Whether to sign the message content.
*/
void create_containermsg_from_content(
flatbuffers::FlatBufferBuilder &container_builder, const flatbuffers::FlatBufferBuilder &content_builder, std::string_view lcl, const bool sign)
{
const uint8_t *content_buf = content_builder.GetBufferPointer();
const flatbuffers::uoffset_t content_size = content_builder.GetSize();
// Create container message content from serialised content from previous step.
const flatbuffers::Offset<flatbuffers::Vector<uint8_t>> content = container_builder.CreateVector(content_buf, content_size);
flatbuffers::Offset<flatbuffers::Vector<uint8_t>> pubkey_offset = 0;
flatbuffers::Offset<flatbuffers::Vector<uint8_t>> sig_offset = 0;
flatbuffers::Offset<flatbuffers::Vector<uint8_t>> lcl_offset = 0;
if (sign)
{
// Sign message content with this node's private key.
std::string_view content_to_sign(reinterpret_cast<const char *>(content_buf), content_size);
sig_offset = sv_to_flatbuff_bytes(container_builder, crypto::sign(content_to_sign, conf::cfg.seckey));
pubkey_offset = sv_to_flatbuff_bytes(container_builder, conf::cfg.pubkey);
}
if (!lcl.empty())
lcl_offset = sv_to_flatbuff_bytes(container_builder, lcl);
const flatbuffers::Offset<Container> container_message = CreateContainer(
container_builder,
util::PEERMSG_VERSION,
util::get_epoch_milliseconds(),
pubkey_offset,
lcl_offset,
sig_offset,
content);
// Finish building message container to get serialised message.
container_builder.Finish(container_message);
}
//---Conversion helpers from flatbuffers data types to std data types---//
const std::unordered_map<std::string, const std::list<usr::user_input>>
flatbuf_user_input_group_to_user_input_map(const flatbuffers::Vector<flatbuffers::Offset<UserInputGroup>> *fbvec)
{
std::unordered_map<std::string, const std::list<usr::user_input>> map;
map.reserve(fbvec->size());
for (const UserInputGroup *group : *fbvec)
{
std::list<usr::user_input> user_inputs_list;
for (const auto msg : *group->messages())
{
user_inputs_list.push_back(usr::user_input(
flatbuff_bytes_to_sv(msg->input_container()),
flatbuff_bytes_to_sv(msg->signature()),
static_cast<util::PROTOCOL>(msg->protocol())));
}
map.emplace(flatbuff_bytes_to_sv(group->pubkey()), std::move(user_inputs_list));
}
return map;
}
//---Conversion helpers from std data types to flatbuffers data types---//
//---These are used in constructing Flatbuffer messages using builders---//
const flatbuffers::Offset<flatbuffers::Vector<flatbuffers::Offset<UserInputGroup>>>
user_input_map_to_flatbuf_user_input_group(flatbuffers::FlatBufferBuilder &builder, const std::unordered_map<std::string, const std::list<usr::user_input>> &map)
{
std::vector<flatbuffers::Offset<UserInputGroup>> fbvec;
fbvec.reserve(map.size());
for (const auto &[pubkey, msglist] : map)
{
std::vector<flatbuffers::Offset<UserInput>> fbmsgsvec;
for (const usr::user_input &msg : msglist)
{
fbmsgsvec.push_back(CreateUserInput(
builder,
sv_to_flatbuff_bytes(builder, msg.input_container),
sv_to_flatbuff_bytes(builder, msg.sig),
static_cast<uint8_t>(msg.protocol)));
}
fbvec.push_back(CreateUserInputGroup(
builder,
sv_to_flatbuff_bytes(builder, pubkey),
builder.CreateVector(fbmsgsvec)));
}
return builder.CreateVector(fbvec);
}
const std::map<uint64_t, const p2p::history_ledger>
flatbuf_historyledgermap_to_historyledgermap(const flatbuffers::Vector<flatbuffers::Offset<HistoryLedgerPair>> *fbvec)
{
std::map<uint64_t, const p2p::history_ledger> map;
for (const HistoryLedgerPair *pair : *fbvec)
{
std::list<usr::user_input> msglist;
p2p::history_ledger ledger;
ledger.lcl = flatbuff_bytes_to_sv(pair->ledger()->lcl());
auto raw = pair->ledger()->raw_ledger();
ledger.raw_ledger = std::vector<uint8_t>(raw->begin(), raw->end());
map.emplace(pair->seq_no(), std::move(ledger));
}
return map;
}
const flatbuffers::Offset<flatbuffers::Vector<flatbuffers::Offset<HistoryLedgerPair>>>
historyledgermap_to_flatbuf_historyledgermap(flatbuffers::FlatBufferBuilder &builder, const std::map<uint64_t, const p2p::history_ledger> &map)
{
std::vector<flatbuffers::Offset<HistoryLedgerPair>> fbvec;
fbvec.reserve(map.size());
for (auto const &[seq_no, ledger] : map)
{
flatbuffers::Offset<HistoryLedger> history_ledger = CreateHistoryLedger(
builder,
sv_to_flatbuff_bytes(builder, ledger.state),
sv_to_flatbuff_bytes(builder, ledger.lcl),
builder.CreateVector(ledger.raw_ledger));
fbvec.push_back(CreateHistoryLedgerPair(
builder,
seq_no,
history_ledger));
}
return builder.CreateVector(fbvec);
}
void flatbuf_statefshashentry_to_statefshashentry(std::unordered_map<std::string, p2p::state_fs_hash_entry> &fs_entries, const flatbuffers::Vector<flatbuffers::Offset<State_FS_Hash_Entry>> *fhashes)
{
for (const State_FS_Hash_Entry *f_hash : *fhashes)
{
p2p::state_fs_hash_entry entry;
entry.name = flatbuff_str_to_sv(f_hash->name());
entry.is_file = f_hash->is_file();
entry.hash = flatbuff_bytes_to_hash(f_hash->hash());
fs_entries.emplace(entry.name, std::move(entry));
}
}
flatbuffers::Offset<flatbuffers::Vector<flatbuffers::Offset<State_FS_Hash_Entry>>>
statefshashentry_to_flatbuff_statefshashentry(
flatbuffers::FlatBufferBuilder &builder,
std::vector<hpfs::child_hash_node> &hash_nodes)
{
std::vector<flatbuffers::Offset<State_FS_Hash_Entry>> fbvec;
fbvec.reserve(hash_nodes.size());
for (auto const &hash_node : hash_nodes)
{
flatbuffers::Offset<State_FS_Hash_Entry> state_fs_entry = CreateState_FS_Hash_Entry(
builder,
sv_to_flatbuff_str(builder, hash_node.name),
hash_node.is_file,
hash_to_flatbuff_bytes(builder, hash_node.hash));
fbvec.push_back(state_fs_entry);
}
return builder.CreateVector(fbvec);
}
} // namespace msg::fbuf::p2pmsg

View File

@@ -0,0 +1,100 @@
#ifndef _HP_MSG_FBUF_P2PMSG_HELPERS_
#define _HP_MSG_FBUF_P2PMSG_HELPERS_
#include "../../pchheader.hpp"
#include "../../p2p/p2p.hpp"
#include "../../hpfs/h32.hpp"
#include "../../hpfs/hpfs.hpp"
#include "p2pmsg_container_generated.h"
#include "p2pmsg_content_generated.h"
namespace msg::fbuf::p2pmsg
{
/**
* This section contains Flatbuffer p2p message reading/writing helpers.
*/
//---Message validation helpers---/
int validate_and_extract_container(const Container **container_ref, std::string_view container_buf);
int validate_container_trust(const Container *container);
int validate_and_extract_content(const Content **content_ref, const uint8_t *content_ptr, const flatbuffers::uoffset_t content_size);
//---Message reading helpers---/
const std::string_view get_peer_challenge_from_msg(const Peer_Challenge_Message &msg);
const p2p::peer_challenge_response create_peer_challenge_response_from_msg(const Peer_Challenge_Response_Message &msg, const flatbuffers::Vector<uint8_t> *pubkey);
const p2p::nonunl_proposal create_nonunl_proposal_from_msg(const NonUnl_Proposal_Message &msg, const uint64_t timestamp);
const p2p::proposal create_proposal_from_msg(const Proposal_Message &msg, const flatbuffers::Vector<uint8_t> *pubkey, const uint64_t timestamp, const flatbuffers::Vector<uint8_t> *lcl);
const p2p::history_request create_history_request_from_msg(const History_Request_Message &msg);
const p2p::history_response create_history_response_from_msg(const History_Response_Message &msg);
const p2p::state_request create_state_request_from_msg(const State_Request_Message &msg);
//---Message creation helpers---//
void create_peer_challenge_response_from_challenge(flatbuffers::FlatBufferBuilder &container_builder, const std::string &challenge);
void create_msg_from_peer_challenge(flatbuffers::FlatBufferBuilder &container_builder, std::string &challenge);
void create_msg_from_nonunl_proposal(flatbuffers::FlatBufferBuilder &container_builder, const p2p::nonunl_proposal &nup);
void create_msg_from_proposal(flatbuffers::FlatBufferBuilder &container_builder, const p2p::proposal &p);
void create_msg_from_history_request(flatbuffers::FlatBufferBuilder &container_builder, const p2p::history_request &hr);
void create_msg_from_history_response(flatbuffers::FlatBufferBuilder &container_builder, const p2p::history_response &hr);
void create_msg_from_npl_output(flatbuffers::FlatBufferBuilder &container_builder, const p2p::npl_message &npl, std::string_view lcl);
void create_msg_from_state_request(flatbuffers::FlatBufferBuilder &container_builder, const p2p::state_request &hr, std::string_view lcl);
void create_msg_from_fsentry_response(
flatbuffers::FlatBufferBuilder &container_builder, const std::string_view path,
std::vector<hpfs::child_hash_node> &hash_nodes, hpfs::h32 expected_hash, std::string_view lcl);
void create_msg_from_filehashmap_response(
flatbuffers::FlatBufferBuilder &container_builder, std::string_view path,
std::vector<hpfs::h32> &hashmap, std::size_t file_length, hpfs::h32 expected_hash, std::string_view lcl);
void create_msg_from_block_response(flatbuffers::FlatBufferBuilder &container_builder, p2p::block_response &block_resp, std::string_view lcl);
void create_containermsg_from_content(
flatbuffers::FlatBufferBuilder &container_builder, const flatbuffers::FlatBufferBuilder &content_builder, std::string_view lcl, const bool sign);
//---Conversion helpers from flatbuffers data types to std data types---//
const std::unordered_map<std::string, const std::list<usr::user_input>>
flatbuf_user_input_group_to_user_input_map(const flatbuffers::Vector<flatbuffers::Offset<UserInputGroup>> *fbvec);
//---Conversion helpers from std data types to flatbuffers data types---//
const flatbuffers::Offset<flatbuffers::Vector<flatbuffers::Offset<UserInputGroup>>>
user_input_map_to_flatbuf_user_input_group(flatbuffers::FlatBufferBuilder &builder, const std::unordered_map<std::string, const std::list<usr::user_input>> &map);
const std::map<uint64_t, const p2p::history_ledger>
flatbuf_historyledgermap_to_historyledgermap(const flatbuffers::Vector<flatbuffers::Offset<HistoryLedgerPair>> *fbvec);
const flatbuffers::Offset<flatbuffers::Vector<flatbuffers::Offset<HistoryLedgerPair>>>
historyledgermap_to_flatbuf_historyledgermap(flatbuffers::FlatBufferBuilder &builder, const std::map<uint64_t, const p2p::history_ledger> &map);
void flatbuf_statefshashentry_to_statefshashentry(std::unordered_map<std::string, p2p::state_fs_hash_entry> &fs_entries,
const flatbuffers::Vector<flatbuffers::Offset<State_FS_Hash_Entry>> *fhashes);
void statefilehash_to_flatbuf_statefilehash(flatbuffers::FlatBufferBuilder &builder, std::vector<flatbuffers::Offset<State_FS_Hash_Entry>> &list,
std::string_view full_path, bool is_file, std::string_view hash);
flatbuffers::Offset<flatbuffers::Vector<flatbuffers::Offset<State_FS_Hash_Entry>>>
statefshashentry_to_flatbuff_statefshashentry(
flatbuffers::FlatBufferBuilder &builder,
std::vector<hpfs::child_hash_node> &hash_nodes);
} // namespace msg::fbuf::p2pmsg
#endif

View File

@@ -0,0 +1,475 @@
#include "../../pchheader.hpp"
#include "../../util.hpp"
#include "../../crypto.hpp"
#include "../../cons/cons.hpp"
#include "../../hplog.hpp"
#include "../usrmsg_common.hpp"
#include "usrmsg_json.hpp"
namespace msg::usrmsg::json
{
// JSON separators
constexpr const char *SEP_COMMA = "\",\"";
constexpr const char *SEP_COLON = "\":\"";
constexpr const char *SEP_COMMA_NOQUOTE = ",\"";
constexpr const char *SEP_COLON_NOQUOTE = "\":";
// std::vector overload to concatonate string.
std::vector<uint8_t> &operator+=(std::vector<uint8_t> &vec, std::string_view sv)
{
vec.insert(vec.end(), sv.begin(), sv.end());
return vec;
}
/**
* 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 String reference to copy the generated json message string into.
* Message format:
* {
* "type": "handshake_challenge",
* "challenge": "<hex challenge string>"
* }
* @param challengehex String reference to copy the generated hex challenge string into.
*/
void create_user_challenge(std::vector<uint8_t> &msg, std::string &challengehex)
{
// Use libsodium to generate the random challenge bytes.
unsigned char challenge_bytes[msg::usrmsg::CHALLENGE_LEN];
randombytes_buf(challenge_bytes, msg::usrmsg::CHALLENGE_LEN);
// We pass the hex challenge string separately to the caller even though
// we also include it in the challenge msg as well.
util::bin2hex(challengehex, challenge_bytes, msg::usrmsg::CHALLENGE_LEN);
// Construct the challenge msg json.
// 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 message we reserve adequate amount for the holder.
// 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 += "{\"";
msg += msg::usrmsg::FLD_TYPE;
msg += SEP_COLON;
msg += msg::usrmsg::MSGTYPE_HANDSHAKE_CHALLENGE;
msg += SEP_COMMA;
msg += msg::usrmsg::FLD_CHALLENGE;
msg += SEP_COLON;
msg += challengehex;
msg += "\"}";
}
/**
* Constructs a status response message.
* @param msg String reference to copy the generated json message string into.
* Message format:
* {
* "type": "stat_response",
* "lcl": "<lcl id>",
* "lcl_seqno": <integer>
* }
*/
void create_status_response(std::vector<uint8_t> &msg)
{
msg.reserve(128);
msg += "{\"";
msg += msg::usrmsg::FLD_TYPE;
msg += SEP_COLON;
msg += msg::usrmsg::MSGTYPE_STAT_RESPONSE;
msg += SEP_COMMA;
msg += msg::usrmsg::FLD_LCL;
msg += SEP_COLON;
msg += cons::ctx.lcl;
msg += SEP_COMMA;
msg += msg::usrmsg::FLD_LCL_SEQ;
msg += SEP_COLON_NOQUOTE;
msg += std::to_string(cons::ctx.led_seq_no);
msg += "}";
}
/**
* Constructs a contract input status message.
* @param msg String reference to copy the generated json message string into.
* Message format:
* {
* "type": "contract_input_status",
* "status": "<accepted|rejected>",
* "reason": "<reson>",
* "input_sig": "<hex sig of original input message>"
* }
* @param is_accepted Whether the original message was accepted or not.
* @param reason Rejected reason. Empty if accepted.
* @param input_sig Binary signature of the original input message which generated this result.
*/
void create_contract_input_status(std::vector<uint8_t> &msg, std::string_view status, std::string_view reason, std::string_view input_sig)
{
std::string sighex;
util::bin2hex(sighex, reinterpret_cast<const unsigned char *>(input_sig.data()), input_sig.length());
msg.reserve(128);
msg += "{\"";
msg += msg::usrmsg::FLD_TYPE;
msg += SEP_COLON;
msg += msg::usrmsg::MSGTYPE_CONTRACT_INPUT_STATUS;
msg += SEP_COMMA;
msg += msg::usrmsg::FLD_STATUS;
msg += SEP_COLON;
msg += status;
msg += SEP_COMMA;
msg += msg::usrmsg::FLD_REASON;
msg += SEP_COLON;
msg += reason;
msg += SEP_COMMA;
msg += msg::usrmsg::FLD_INPUT_SIG;
msg += SEP_COLON;
msg += sighex;
msg += "\"}";
}
/**
* Constructs a contract read response message.
* @param msg String reference to copy the generated json message string into.
* Message format:
* {
* "type": "contract_read_response",
* "content": "<hex encoded contract output>"
* }
* @param content The contract binary output content to be put in the message.
*/
void create_contract_read_response_container(std::vector<uint8_t> &msg, std::string_view content)
{
std::string contenthex;
util::bin2hex(
contenthex,
reinterpret_cast<const unsigned char *>(content.data()),
content.length());
msg.reserve(256);
msg += "{\"";
msg += msg::usrmsg::FLD_TYPE;
msg += SEP_COLON;
msg += msg::usrmsg::MSGTYPE_CONTRACT_READ_RESPONSE;
msg += SEP_COMMA;
msg += msg::usrmsg::FLD_CONTENT;
msg += SEP_COLON;
msg += contenthex;
msg += "\"}";
}
/**
* Constructs a contract output container message.
* @param msg String reference to copy the generated json message string into.
* Message format:
* {
* "type": "contract_output",
* "lcl": "<lcl id>"
* "lcl_seqno": <integer>,
* "content": "<hex encoded contract output>"
* }
* @param content The contract binary output content to be put in the message.
*/
void create_contract_output_container(std::vector<uint8_t> &msg, std::string_view content)
{
std::string contenthex;
util::bin2hex(
contenthex,
reinterpret_cast<const unsigned char *>(content.data()),
content.length());
msg.reserve(256);
msg += "{\"";
msg += msg::usrmsg::FLD_TYPE;
msg += SEP_COLON;
msg += msg::usrmsg::MSGTYPE_CONTRACT_OUTPUT;
msg += SEP_COMMA;
msg += msg::usrmsg::FLD_LCL;
msg += SEP_COLON;
msg += cons::ctx.lcl;
msg += SEP_COMMA;
msg += msg::usrmsg::FLD_LCL_SEQ;
msg += SEP_COLON_NOQUOTE;
msg += std::to_string(cons::ctx.led_seq_no);
msg += SEP_COMMA_NOQUOTE;
msg += msg::usrmsg::FLD_CONTENT;
msg += SEP_COLON;
msg += contenthex;
msg += "\"}";
}
/**
* 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 response The response bytes to verify. This will be parsed as json.
* Accepted response format:
* {
* "type": "handshake_response",
* "challenge": "<original hex challenge the user received>",
* "sig": "<hex signature of the challenge>",
* "pubkey": "<hex public key of the user>",
* "protocol": "<json | bson>"
* }
* @param original_challenge The original hex challenge string issued to the user.
* @return 0 if challenge response is verified. -1 if challenge not met or an error occurs.
*/
int verify_user_handshake_response(std::string &extracted_pubkeyhex, std::string &extracted_protocol,
std::string_view response, std::string_view original_challenge)
{
rapidjson::Document d;
if (parse_user_message(d, response) != 0)
return -1;
// Validate msg type.
if (d[msg::usrmsg::FLD_TYPE] != msg::usrmsg::MSGTYPE_HANDSHAKE_RESPONSE)
{
LOG_DBG << "User handshake response type invalid. 'handshake_response' expected.";
return -1;
}
// Compare the response handshake string with the original issued challenge.
if (!d.HasMember(msg::usrmsg::FLD_CHALLENGE) || d[msg::usrmsg::FLD_CHALLENGE] != original_challenge.data())
{
LOG_DBG << "User handshake response 'challenge' invalid.";
return -1;
}
// Check for the 'sig' field existence.
if (!d.HasMember(msg::usrmsg::FLD_SIG) || !d[msg::usrmsg::FLD_SIG].IsString())
{
LOG_DBG << "User handshake response 'challenge signature' invalid.";
return -1;
}
// Check for the 'pubkey' field existence.
if (!d.HasMember(msg::usrmsg::FLD_PUBKEY) || !d[msg::usrmsg::FLD_PUBKEY].IsString())
{
LOG_DBG << "User handshake response 'public key' invalid.";
return -1;
}
// Check for protocol field existence and valid value.
if (!d.HasMember(msg::usrmsg::FLD_PROTOCOL) || !d[msg::usrmsg::FLD_PROTOCOL].IsString())
{
LOG_DBG << "User handshake response 'protocol' invalid.";
return -1;
}
std::string_view protocolsv = util::getsv(d[msg::usrmsg::FLD_PROTOCOL]);
if (protocolsv != "json" && protocolsv != "bson")
{
LOG_DBG << "User handshake response 'protocol' type invalid.";
return -1;
}
// Verify the challenge signature. We do this last due to signature verification cost.
std::string_view pubkeysv = util::getsv(d[msg::usrmsg::FLD_PUBKEY]);
if (crypto::verify_hex(
original_challenge,
util::getsv(d[msg::usrmsg::FLD_SIG]),
pubkeysv) != 0)
{
LOG_DBG << "User challenge response signature verification failed.";
return -1;
}
extracted_pubkeyhex = pubkeysv;
extracted_protocol = protocolsv;
return 0;
}
/**
* 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)
{
// We load response raw bytes into json document.
// Because we project the response message directly from the binary socket buffer in a zero-copy manner, the response
// string is not null terminated. 'kParseStopWhenDoneFlag' avoids rapidjson error in this case.
d.Parse<rapidjson::kParseStopWhenDoneFlag>(message.data());
if (d.HasParseError())
{
LOG_DBG << "User json message parsing failed.";
return -1;
}
// Check existence of msg type field.
if (!d.HasMember(msg::usrmsg::FLD_TYPE) || !d[msg::usrmsg::FLD_TYPE].IsString())
{
LOG_DBG << "User json message 'type' missing or invalid.";
return -1;
}
return 0;
}
/**
* Extracts the message 'type' value from the json document.
*/
int extract_type(std::string &extracted_type, const rapidjson::Document &d)
{
extracted_type = d[msg::usrmsg::FLD_TYPE].GetString();
return 0;
}
/**
* 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:
* {
* "type": "contract_read_request",
* "content": "<hex encoded content to be passed to the contract>"
* }
* @return 0 on successful extraction. -1 for failure.
*/
int extract_read_request(std::string &extracted_content, const rapidjson::Document &d)
{
if (!d.HasMember(msg::usrmsg::FLD_CONTENT))
{
LOG_DBG << "Read request required fields missing.";
return -1;
}
if (!d[msg::usrmsg::FLD_CONTENT].IsString())
{
LOG_DBG << "Read request invalid field values.";
return -1;
}
std::string_view contenthex(d[msg::usrmsg::FLD_CONTENT].GetString(), d[msg::usrmsg::FLD_CONTENT].GetStringLength());
std::string content;
content.resize(contenthex.length() / 2);
if (util::hex2bin(
reinterpret_cast<unsigned char *>(content.data()),
content.length(),
contenthex) != 0)
{
LOG_DBG << "Read request format invalid.";
return -1;
}
extracted_content = std::move(content);
return 0;
}
/**
* 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 d The json document holding the input container.
* Accepted signed input container format:
* {
* "type": "contract_input",
* "input_container": "<hex encoded stringified json input container message>",
* "sig": "<hex encoded signature of the content>"
* }
* @return 0 on successful extraction. -1 for failure.
*/
int extract_signed_input_container(
std::string &extracted_input_container, std::string &extracted_sig, const rapidjson::Document &d)
{
if (!d.HasMember(msg::usrmsg::FLD_INPUT_CONTAINER) || !d.HasMember(msg::usrmsg::FLD_SIG))
{
LOG_DBG << "User signed input required fields missing.";
return -1;
}
if (!d[msg::usrmsg::FLD_INPUT_CONTAINER].IsString() || !d[msg::usrmsg::FLD_SIG].IsString())
{
LOG_DBG << "User signed input invalid field values.";
return -1;
}
// We do not verify the signature of the content here since we need to let each node
// (including self) to verify that individually after we broadcast the NUP proposal.
const std::string_view input_container_hex(d[msg::usrmsg::FLD_INPUT_CONTAINER].GetString(), d[msg::usrmsg::FLD_INPUT_CONTAINER].GetStringLength());
std::string input_container;
input_container.resize(input_container_hex.size() / 2);
util::hex2bin(reinterpret_cast<unsigned char *>(input_container.data()), input_container.length(), input_container_hex);
const std::string_view sig_hex(d[msg::usrmsg::FLD_SIG].GetString(), d[msg::usrmsg::FLD_SIG].GetStringLength());
std::string sig;
sig.resize(crypto_sign_ed25519_BYTES);
util::hex2bin(reinterpret_cast<unsigned char *>(sig.data()), sig.length(), sig_hex);
extracted_input_container = std::move(input_container);
extracted_sig = std::move(sig);
return 0;
}
/**
* Extract the individual components of a given input container json.
* @param input The extracted input.
* @param nonce The extracted nonce.
* @param max_lcl_seqno The extracted max ledger sequence no.
* @param contentjson The json string containing the input container message.
* {
* "input": "<hex encoded contract input content>",
* "nonce": "<random string with optional sorted order>",
* "max_lcl_seqno": <integer>
* }
* @return 0 on succesful extraction. -1 on failure.
*/
int extract_input_container(std::string &input, std::string &nonce, uint64_t &max_lcl_seqno, std::string_view contentjson)
{
rapidjson::Document d;
d.Parse(contentjson.data());
if (d.HasParseError())
{
LOG_DBG << "User input container json parsing failed.";
return -1;
}
if (!d.HasMember(msg::usrmsg::FLD_INPUT) || !d.HasMember(msg::usrmsg::FLD_NONCE) || !d.HasMember(msg::usrmsg::FLD_MAX_LCL_SEQ))
{
LOG_DBG << "User input container required fields missing.";
return -1;
}
if (!d[msg::usrmsg::FLD_INPUT].IsString() || !d[msg::usrmsg::FLD_NONCE].IsString() || !d[msg::usrmsg::FLD_MAX_LCL_SEQ].IsUint64())
{
LOG_DBG << "User input container invalid field values.";
return -1;
}
const rapidjson::Value &inputval = d[msg::usrmsg::FLD_INPUT];
std::string_view inputhex(inputval.GetString(), inputval.GetStringLength());
// Convert hex input to binary.
input.resize(inputhex.length() / 2);
if (util::hex2bin(
reinterpret_cast<unsigned char *>(input.data()),
input.length(),
inputhex) != 0)
{
LOG_DBG << "Contract input format invalid.";
return -1;
}
nonce = d[msg::usrmsg::FLD_NONCE].GetString();
max_lcl_seqno = d[msg::usrmsg::FLD_MAX_LCL_SEQ].GetUint64();
return 0;
}
} // namespace msg::usrmsg::json

View File

@@ -0,0 +1,37 @@
#ifndef _HP_MSG_JSON_USRMSG_JSON_
#define _HP_MSG_JSON_USRMSG_JSON_
#include "../../pchheader.hpp"
namespace msg::usrmsg::json
{
void create_user_challenge(std::vector<uint8_t> &msg, std::string &challengehex);
void create_status_response(std::vector<uint8_t> &msg);
void create_contract_input_status(std::vector<uint8_t> &msg, std::string_view status, std::string_view reason,
std::string_view input_sig);
void create_contract_read_response_container(std::vector<uint8_t> &msg, std::string_view content);
void create_contract_output_container(std::vector<uint8_t> &msg, std::string_view content);
int verify_user_handshake_response(std::string &extracted_pubkeyhex, std::string &extracted_protocol,
std::string_view response, std::string_view original_challenge);
int parse_user_message(rapidjson::Document &d, std::string_view message);
int extract_type(std::string &extracted_type, const rapidjson::Document &d);
int extract_read_request(std::string &extracted_content, const rapidjson::Document &d);
int extract_signed_input_container(std::string &extracted_input_container, std::string &extracted_sig,
const rapidjson::Document &d);
int extract_input_container(std::string &input, std::string &nonce,
uint64_t &max_lcl_seqno, std::string_view contentjson);
} // namespace msg::usrmsg::json
#endif

52
src/msg/usrmsg_common.hpp Normal file
View File

@@ -0,0 +1,52 @@
#ifndef _HP_MSG_USRMSG_COMMON_
#define _HP_MSG_USRMSG_COMMON_
#include "../pchheader.hpp"
namespace msg::usrmsg
{
// Length of user random challenge bytes.
constexpr size_t CHALLENGE_LEN = 16;
// Message field names
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_PROTOCOL = "protocol";
constexpr const char *FLD_INPUT = "input";
constexpr const char *FLD_INPUT_CONTAINER = "input_container";
constexpr const char *FLD_INPUT_SIG = "input_sig";
constexpr const char *FLD_MAX_LCL_SEQ = "max_lcl_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";
constexpr const char *FLD_STATUS = "status";
constexpr const char *FLD_REASON = "reason";
// Message types
constexpr const char *MSGTYPE_HANDSHAKE_CHALLENGE = "handshake_challenge";
constexpr const char *MSGTYPE_HANDSHAKE_RESPONSE = "handshake_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_INPUT = "contract_input";
constexpr const char *MSGTYPE_CONTRACT_INPUT_STATUS = "contract_input_status";
constexpr const char *MSGTYPE_CONTRACT_OUTPUT = "contract_output";
constexpr const char *MSGTYPE_STAT = "stat";
constexpr const char *MSGTYPE_STAT_RESPONSE = "stat_response";
constexpr const char *MSGTYPE_UNKNOWN = "unknown";
// Values
constexpr const char *STATUS_ACCEPTED = "accepted";
constexpr const char *STATUS_REJECTED = "rejected";
constexpr const char *REASON_BAD_MSG_FORMAT = "bad_msg_format";
constexpr const char *REASON_INVALID_MSG_TYPE = "invalid_msg_type";
constexpr const char *REASON_DUPLICATE_MSG = "dup_msg";
constexpr const char *REASON_BAD_SIG = "bad_sig";
constexpr const char *REASON_APPBILL_BALANCE_EXCEEDED = "appbill_balance_exceeded";
constexpr const char *REASON_MAX_LEDGER_EXPIRED = "max_ledger_expired";
} // namespace msg::usrmsg
#endif

90
src/msg/usrmsg_parser.cpp Normal file
View File

@@ -0,0 +1,90 @@
#include "../pchheader.hpp"
#include "../util.hpp"
#include "json/usrmsg_json.hpp"
#include "bson/usrmsg_bson.hpp"
#include "usrmsg_parser.hpp"
namespace jusrmsg = msg::usrmsg::json;
namespace busrmsg = msg::usrmsg::bson;
namespace msg::usrmsg
{
usrmsg_parser::usrmsg_parser(const util::PROTOCOL protocol) : protocol(protocol)
{
}
void usrmsg_parser::create_status_response(std::vector<uint8_t> &msg) const
{
if (protocol == util::PROTOCOL::JSON)
jusrmsg::create_status_response(msg);
else
busrmsg::create_status_response(msg);
}
void usrmsg_parser::create_contract_input_status(std::vector<uint8_t> &msg, std::string_view status,
std::string_view reason, std::string_view input_sig) const
{
if (protocol == util::PROTOCOL::JSON)
jusrmsg::create_contract_input_status(msg, status, reason, input_sig);
else
busrmsg::create_contract_input_status(msg, status, reason, input_sig);
}
void usrmsg_parser::create_contract_read_response_container(std::vector<uint8_t> &msg, std::string_view content) const
{
if (protocol == util::PROTOCOL::JSON)
jusrmsg::create_contract_read_response_container(msg, content);
else
busrmsg::create_contract_read_response_container(msg, content);
}
void usrmsg_parser::create_contract_output_container(std::vector<uint8_t> &msg, std::string_view content) const
{
if (protocol == util::PROTOCOL::JSON)
jusrmsg::create_contract_output_container(msg, content);
else
busrmsg::create_contract_output_container(msg, content);
}
int usrmsg_parser::parse(std::string_view message)
{
if (protocol == util::PROTOCOL::JSON)
return jusrmsg::parse_user_message(jsonDoc, message);
else
return busrmsg::parse_user_message(bsonDoc, message);
}
int usrmsg_parser::extract_type(std::string &extracted_type) const
{
if (protocol == util::PROTOCOL::JSON)
return jusrmsg::extract_type(extracted_type, jsonDoc);
else
return busrmsg::extract_type(extracted_type, bsonDoc);
}
int usrmsg_parser::extract_read_request(std::string &extracted_content) const
{
if (protocol == util::PROTOCOL::JSON)
return jusrmsg::extract_read_request(extracted_content, jsonDoc);
else
return busrmsg::extract_read_request(extracted_content, bsonDoc);
}
int usrmsg_parser::extract_signed_input_container(std::string &extracted_input_container, std::string &extracted_sig) const
{
if (protocol == util::PROTOCOL::JSON)
return jusrmsg::extract_signed_input_container(extracted_input_container, extracted_sig, jsonDoc);
else
return busrmsg::extract_signed_input_container(extracted_input_container, extracted_sig, bsonDoc);
}
int usrmsg_parser::extract_input_container(std::string &input, std::string &nonce,
uint64_t &max_lcl_seqno, std::string_view encoded_content) const
{
if (protocol == util::PROTOCOL::JSON)
return jusrmsg::extract_input_container(input, nonce, max_lcl_seqno, encoded_content);
else
return busrmsg::extract_input_container(input, nonce, max_lcl_seqno, encoded_content);
}
} // namespace msg::usrmsg

44
src/msg/usrmsg_parser.hpp Normal file
View File

@@ -0,0 +1,44 @@
#ifndef _HP_MSG_USRMSG_PARSER_
#define _HP_MSG_USRMSG_PARSER_
#include "../util.hpp"
#include "../pchheader.hpp"
namespace msg::usrmsg
{
// Forward declaration
class usrmsg_parser;
class usrmsg_parser
{
const util::PROTOCOL protocol;
rapidjson::Document jsonDoc;
jsoncons::ojson bsonDoc;
public:
usrmsg_parser(const util::PROTOCOL protocol);
void create_status_response(std::vector<uint8_t> &msg) const;
void create_contract_input_status(std::vector<uint8_t> &msg, std::string_view status,
std::string_view reason, std::string_view input_sig) const;
void create_contract_read_response_container(std::vector<uint8_t> &msg, std::string_view content) const;
void create_contract_output_container(std::vector<uint8_t> &msg, std::string_view content) const;
int parse(std::string_view message);
int extract_type(std::string &extracted_type) const;
int extract_read_request(std::string &extracted_content) const;
int extract_signed_input_container(std::string &extracted_input_container, std::string &extracted_sig) const;
int extract_input_container(std::string &input, std::string &nonce,
uint64_t &max_lcl_seqno, std::string_view encoded_content) const;
};
} // namespace msg::usrmsg
#endif