mirror of
https://github.com/EvernodeXRPL/hpcore.git
synced 2026-04-29 15:37:59 +00:00
Added bson support for user message protocol. (#99)
This commit is contained in:
252
src/msg/bson/usrmsg_bson.cpp
Normal file
252
src/msg/bson/usrmsg_bson.cpp
Normal 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
|
||||
37
src/msg/bson/usrmsg_bson.hpp
Normal file
37
src/msg/bson/usrmsg_bson.hpp
Normal 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
|
||||
126
src/msg/fbuf/common_helpers.cpp
Normal file
126
src/msg/fbuf/common_helpers.cpp
Normal 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
|
||||
49
src/msg/fbuf/common_helpers.hpp
Normal file
49
src/msg/fbuf/common_helpers.hpp
Normal 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
|
||||
11
src/msg/fbuf/common_schema.fbs
Normal file
11
src/msg/fbuf/common_schema.fbs
Normal 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];
|
||||
}
|
||||
146
src/msg/fbuf/common_schema_generated.h
Normal file
146
src/msg/fbuf/common_schema_generated.h
Normal 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_
|
||||
31
src/msg/fbuf/ledger_helpers.cpp
Normal file
31
src/msg/fbuf/ledger_helpers.cpp
Normal 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
|
||||
14
src/msg/fbuf/ledger_helpers.hpp
Normal file
14
src/msg/fbuf/ledger_helpers.hpp
Normal 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
|
||||
20
src/msg/fbuf/ledger_schema.fbs
Normal file
20
src/msg/fbuf/ledger_schema.fbs
Normal 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;
|
||||
286
src/msg/fbuf/ledger_schema_generated.h
Normal file
286
src/msg/fbuf/ledger_schema_generated.h
Normal 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_
|
||||
17
src/msg/fbuf/p2pmsg_container.fbs
Normal file
17
src/msg/fbuf/p2pmsg_container.fbs
Normal 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;
|
||||
192
src/msg/fbuf/p2pmsg_container_generated.h
Normal file
192
src/msg/fbuf/p2pmsg_container_generated.h
Normal 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_
|
||||
113
src/msg/fbuf/p2pmsg_content.fbs
Normal file
113
src/msg/fbuf/p2pmsg_content.fbs
Normal 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
|
||||
1819
src/msg/fbuf/p2pmsg_content_generated.h
Normal file
1819
src/msg/fbuf/p2pmsg_content_generated.h
Normal file
File diff suppressed because it is too large
Load Diff
740
src/msg/fbuf/p2pmsg_helpers.cpp
Normal file
740
src/msg/fbuf/p2pmsg_helpers.cpp
Normal 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
|
||||
100
src/msg/fbuf/p2pmsg_helpers.hpp
Normal file
100
src/msg/fbuf/p2pmsg_helpers.hpp
Normal 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
|
||||
475
src/msg/json/usrmsg_json.cpp
Normal file
475
src/msg/json/usrmsg_json.cpp
Normal 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
|
||||
37
src/msg/json/usrmsg_json.hpp
Normal file
37
src/msg/json/usrmsg_json.hpp
Normal 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
52
src/msg/usrmsg_common.hpp
Normal 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
90
src/msg/usrmsg_parser.cpp
Normal 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
44
src/msg/usrmsg_parser.hpp
Normal 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
|
||||
Reference in New Issue
Block a user