mirror of
https://github.com/EvernodeXRPL/hpcore.git
synced 2026-04-29 15:37:59 +00:00
Improved user inputs handling in consensus (#46)
Updated flatbuffer proposal raw_inputs, raw_outputs data structure. Improved user inputs handling in consensus.
This commit is contained in:
@@ -7,6 +7,10 @@ set(CMAKE_RUNTIME_OUTPUT_DIRECTORY build)
|
||||
set(CMAKE_BUILD_TYPE "MinSizeRel" FORCE)
|
||||
|
||||
add_executable(hpcore
|
||||
src/util.cpp
|
||||
src/crypto.cpp
|
||||
src/conf.cpp
|
||||
src/hplog.cpp
|
||||
src/sock/socket_client.cpp
|
||||
src/sock/socket_server.cpp
|
||||
src/sock/socket_session.cpp
|
||||
@@ -15,12 +19,8 @@ add_executable(hpcore
|
||||
src/p2p/p2p.cpp
|
||||
src/usr/user_session_handler.cpp
|
||||
src/usr/usr.cpp
|
||||
src/cons/cons.cpp
|
||||
src/util.cpp
|
||||
src/crypto.cpp
|
||||
src/conf.cpp
|
||||
src/hplog.cpp
|
||||
src/proc.cpp
|
||||
src/cons/cons.cpp
|
||||
src/main.cpp
|
||||
)
|
||||
|
||||
|
||||
@@ -1,5 +1,3 @@
|
||||
#include <unordered_map>
|
||||
#include <list>
|
||||
#include <math.h>
|
||||
#include <thread>
|
||||
#include <flatbuffers/flatbuffers.h>
|
||||
@@ -43,8 +41,8 @@ void consensus()
|
||||
ctx.time_now = util::get_epoch_milliseconds();
|
||||
|
||||
// Throughout consensus, we move over the incoming proposals collected via the network so far into
|
||||
// the candidate proposal set (move and append). This is to have a private working set for the consensus and void
|
||||
// threading conflicts with network incoming proposals list.
|
||||
// the candidate proposal set (move and append). This is to have a private working set for the consensus and avoid
|
||||
// threading conflicts with network incoming proposals.
|
||||
{
|
||||
std::lock_guard<std::mutex> lock(p2p::collected_msgs.proposals_mutex);
|
||||
ctx.candidate_proposals.splice(ctx.candidate_proposals.end(), p2p::collected_msgs.proposals);
|
||||
@@ -54,20 +52,25 @@ void consensus()
|
||||
{
|
||||
// Stage 0 means begining of a consensus round.
|
||||
|
||||
// Remove any useless candidate proposals so we'll have a cleaner proposal set to look at
|
||||
// when we transition to stage 1.
|
||||
auto itr = ctx.candidate_proposals.begin();
|
||||
while (itr != ctx.candidate_proposals.end())
|
||||
{
|
||||
// Remove any proposal from previous round's stage 3.
|
||||
// Remove any proposal from self (pubkey match).
|
||||
// todo: check the state of these to ensure we're running consensus ledger
|
||||
if (itr->stage == 3 || conf::cfg.pubkey == itr->pubkey)
|
||||
ctx.candidate_proposals.erase(itr++);
|
||||
else
|
||||
++itr;
|
||||
// Remove any useless candidate proposals so we'll have a cleaner proposal set to look at
|
||||
// when we transition to stage 1.
|
||||
auto itr = ctx.candidate_proposals.begin();
|
||||
while (itr != ctx.candidate_proposals.end())
|
||||
{
|
||||
// Remove any proposal from previous round's stage 3.
|
||||
// Remove any proposal from self (pubkey match).
|
||||
// todo: check the state of these to ensure we're running consensus ledger
|
||||
if (itr->stage == 3 || conf::cfg.pubkey == itr->pubkey)
|
||||
ctx.candidate_proposals.erase(itr++);
|
||||
else
|
||||
++itr;
|
||||
}
|
||||
}
|
||||
|
||||
// Transfer connected user data onto consensus candidate data.
|
||||
populate_candidate_users_and_inputs();
|
||||
|
||||
// In stage 0 we create a novel proposal and broadcast it.
|
||||
const p2p::proposal stg_prop = create_stage0_proposal();
|
||||
if (broadcast_proposal(stg_prop) != 0)
|
||||
@@ -127,6 +130,25 @@ void consensus()
|
||||
std::this_thread::sleep_for(std::chrono::milliseconds(conf::cfg.roundtime / 4));
|
||||
}
|
||||
|
||||
/**
|
||||
* Populate connected users and their inputs (if any) into consensus candidate data.
|
||||
*/
|
||||
void populate_candidate_users_and_inputs()
|
||||
{
|
||||
// Lock the connected user list until we do this operation.
|
||||
std::lock_guard<std::mutex> lock(usr::users_mutex);
|
||||
for (auto &[sid, con_user] : usr::users)
|
||||
{
|
||||
// Populate the user into candidate user inputs map.
|
||||
// We do this regardless of whether the user has any inputs or not.
|
||||
|
||||
std::list<util::hash_buffer> &inplist = ctx.candidate_users[con_user.pubkey];
|
||||
|
||||
// Transfer the connected user's inputs (if any) to the candidate user's inputs list.
|
||||
inplist.splice(inplist.end(), con_user.inputs);
|
||||
}
|
||||
}
|
||||
|
||||
p2p::proposal create_stage0_proposal()
|
||||
{
|
||||
// The proposal we are going to emit in stage 0.
|
||||
@@ -137,36 +159,36 @@ p2p::proposal create_stage0_proposal()
|
||||
stg_prop.stage = 0;
|
||||
stg_prop.lcl = ctx.lcl;
|
||||
|
||||
// Populate the stg_prop with users list (user pubkey list) and their inputs.
|
||||
{
|
||||
std::lock_guard<std::mutex> lock(usr::users_mutex);
|
||||
for (auto &[sid, user] : usr::users)
|
||||
{
|
||||
// add all the user connections we host
|
||||
stg_prop.users.emplace(user.pubkey);
|
||||
// Populate the poposal with users list (user pubkey list) and their inputs.
|
||||
|
||||
// and all their pending messages
|
||||
if (!user.inbuffer.empty())
|
||||
{
|
||||
std::string input;
|
||||
input.swap(user.inbuffer);
|
||||
stg_prop.raw_inputs.try_emplace(user.pubkey, std::move(input));
|
||||
}
|
||||
for (auto [pubkey, inputs] : ctx.candidate_users)
|
||||
{
|
||||
// Add all the user connections we host.
|
||||
stg_prop.users.emplace(pubkey);
|
||||
|
||||
// Add all their pending inputs.
|
||||
if (!inputs.empty())
|
||||
{
|
||||
std::vector<util::hash_buffer> inpvec;
|
||||
for (util::hash_buffer &hashbuf : inputs)
|
||||
inpvec.push_back(hashbuf); // Copy all hashbufs from candidate inputs into the proposal.
|
||||
|
||||
stg_prop.raw_inputs.emplace(pubkey, std::move(inpvec));
|
||||
}
|
||||
}
|
||||
|
||||
// Populate the stg_prop with any contract outputs from previous round's stage 3.
|
||||
for (auto &[pubkey, bufpair] : ctx.local_userbuf)
|
||||
for (auto &[pubkey, bufpair] : ctx.useriobufmap)
|
||||
{
|
||||
if (!bufpair.second.empty()) // bufpair.second is the output buffer.
|
||||
if (!bufpair.output.empty())
|
||||
{
|
||||
std::string rawoutput;
|
||||
rawoutput.swap(bufpair.second);
|
||||
rawoutput.swap(bufpair.output);
|
||||
|
||||
stg_prop.raw_outputs.try_emplace(pubkey, std::move(rawoutput));
|
||||
stg_prop.raw_outputs.try_emplace(pubkey, util::hash_buffer(rawoutput, pubkey));
|
||||
}
|
||||
}
|
||||
ctx.local_userbuf.clear();
|
||||
ctx.useriobufmap.clear();
|
||||
|
||||
// todo: set propsal states
|
||||
// todo: generate stg_prop hash and check with ctx.novel_proposal, we are sending same stg_prop again.
|
||||
@@ -188,7 +210,7 @@ p2p::proposal create_stage123_proposal(vote_counter &votes)
|
||||
|
||||
//todo:check lcl votes and wait for proposals
|
||||
|
||||
// Vote for rest of the proposal fields
|
||||
// Vote for rest of the proposal fields by looking at candidate proposals.
|
||||
for (const p2p::proposal &cp : ctx.candidate_proposals)
|
||||
{
|
||||
// Vote for times.
|
||||
@@ -202,64 +224,52 @@ p2p::proposal create_stage123_proposal(vote_counter &votes)
|
||||
|
||||
// Vote for user inputs
|
||||
|
||||
// Proposals from stage 0 will have raw inputs in them.
|
||||
// Proposals from stage 0 will have raw inputs (and their hashes) in them.
|
||||
if (!cp.raw_inputs.empty())
|
||||
{
|
||||
for (auto &[pubkey, input] : cp.raw_inputs)
|
||||
for (auto &[pubkey, inputs] : cp.raw_inputs)
|
||||
{
|
||||
// Hash the pubkey+input.
|
||||
std::string str_to_hash;
|
||||
str_to_hash.reserve(pubkey.size() + input.size());
|
||||
str_to_hash.append(pubkey);
|
||||
str_to_hash.append(input);
|
||||
std::string hash = crypto::sha_512_hash(str_to_hash, "INP", 3);
|
||||
// Vote for the input hash.
|
||||
for (util::hash_buffer input : inputs)
|
||||
{
|
||||
increment(votes.inputs, input.hash);
|
||||
|
||||
// Vote for the hash.
|
||||
increment(votes.inputs, hash);
|
||||
|
||||
// Remember the actual input along with the hash for future use for apply-ledger.
|
||||
ctx.possible_inputs.try_emplace(
|
||||
std::move(hash),
|
||||
std::make_pair(pubkey, input));
|
||||
std::string inputbuffer;
|
||||
inputbuffer.swap(input.buffer);
|
||||
// Remember the actual input along with the hash for future use for apply-ledger.
|
||||
ctx.possible_inputs.try_emplace(input.hash, std::make_pair(pubkey, inputbuffer));
|
||||
}
|
||||
}
|
||||
}
|
||||
// Proposals from stage 1, 2, 3 will have hashed inputs in them.
|
||||
// Proposals from stage 1, 2, 3 will have only input hashes in them.
|
||||
else if (!cp.hash_inputs.empty())
|
||||
{
|
||||
for (const std::string &inputhash : cp.hash_inputs)
|
||||
increment(votes.inputs, inputhash);
|
||||
}
|
||||
|
||||
// Vote for user outputs
|
||||
// Vote for contract outputs
|
||||
|
||||
// Proposals from stage 0 will have raw user outputs in them.
|
||||
if (!cp.raw_outputs.empty())
|
||||
{
|
||||
for (auto &[pubkey, output] : cp.raw_outputs)
|
||||
for (auto [pubkey, output] : cp.raw_outputs)
|
||||
{
|
||||
// Hash the pubkey+input.
|
||||
std::string str_to_hash;
|
||||
str_to_hash.reserve(pubkey.size() + output.size());
|
||||
str_to_hash.append(pubkey);
|
||||
str_to_hash.append(output);
|
||||
std::string hash = crypto::sha_512_hash(str_to_hash, "OUT", 3);
|
||||
|
||||
// Vote for the hash.
|
||||
increment<std::string>(votes.outputs, hash);
|
||||
increment<std::string>(votes.outputs, output.hash);
|
||||
|
||||
// Remember the actual output along with the hash for future use for apply-ledger.
|
||||
ctx.possible_outputs.try_emplace(
|
||||
std::move(hash),
|
||||
std::make_pair(pubkey, output));
|
||||
std::string outputbuf;
|
||||
outputbuf.swap(output.buffer);
|
||||
|
||||
// Remember the actual output along with the hash for future use for apply-ledger and sending back to user.
|
||||
ctx.possible_outputs.try_emplace(output.hash, std::make_pair(pubkey, outputbuf));
|
||||
}
|
||||
}
|
||||
// Proposals from stage 1, 2, 3 will have hashed user outputs in them.
|
||||
else if (!cp.hash_outputs.empty())
|
||||
{
|
||||
for (auto outputhash : cp.hash_outputs)
|
||||
{
|
||||
increment<std::string>(votes.outputs, outputhash);
|
||||
}
|
||||
}
|
||||
|
||||
// todo: repeat above for state
|
||||
@@ -458,7 +468,6 @@ void apply_ledger(const p2p::proposal &cons_prop)
|
||||
|
||||
//create input to feed to binary contract run
|
||||
|
||||
//todo:remove entries from pending inputs that made their way into a closed ledger
|
||||
for (const std::string &hash : cons_prop.hash_inputs)
|
||||
{
|
||||
auto itr = ctx.possible_inputs.find(hash);
|
||||
@@ -471,7 +480,7 @@ void apply_ledger(const p2p::proposal &cons_prop)
|
||||
}
|
||||
else
|
||||
{
|
||||
// Prepare ctx.local_userbuf with user inputs to feed to the contract.
|
||||
// Prepare ctx.useriobufmap with user inputs to feed to the contract.
|
||||
|
||||
const std::string &pubkey = itr->second.first;
|
||||
std::string rawinput = itr->second.second;
|
||||
@@ -479,21 +488,45 @@ void apply_ledger(const p2p::proposal &cons_prop)
|
||||
std::string inputtofeed;
|
||||
inputtofeed.swap(rawinput);
|
||||
|
||||
std::pair<std::string, std::string> bufpair;
|
||||
bufpair.first = std::move(inputtofeed);
|
||||
ctx.local_userbuf.try_emplace(pubkey, std::move(bufpair));
|
||||
proc::contract_iobuf_pair &bufpair = ctx.useriobufmap[pubkey];
|
||||
bufpair.inputs.push_back(std::move(inputtofeed));
|
||||
}
|
||||
}
|
||||
ctx.possible_inputs.clear();
|
||||
|
||||
run_contract_binary(cons_prop.time);
|
||||
|
||||
// Remove entries from candidate inputs that made their way into a closed ledger
|
||||
auto cu_itr = ctx.candidate_users.begin();
|
||||
while (cu_itr != ctx.candidate_users.end())
|
||||
{
|
||||
// Delete any ledger inputs for this user.
|
||||
std::list<util::hash_buffer> &inputs = cu_itr->second;
|
||||
auto inp_itr = inputs.begin();
|
||||
while (inp_itr != inputs.end())
|
||||
{
|
||||
// Delete the input from the list, if it was part of consensus proposal.
|
||||
if (cons_prop.hash_inputs.count(inp_itr->hash))
|
||||
inputs.erase(inp_itr++);
|
||||
else
|
||||
++inp_itr;
|
||||
}
|
||||
|
||||
// Delete the user from the list if there are no more unprocessed inputs.
|
||||
if (cu_itr->second.empty())
|
||||
ctx.candidate_users.erase(cu_itr++);
|
||||
else
|
||||
++cu_itr;
|
||||
}
|
||||
}
|
||||
|
||||
void run_contract_binary(int64_t time_now)
|
||||
{
|
||||
std::pair<std::string, std::string> hpscbufpair;
|
||||
std::unordered_map<std::string, std::pair<std::string, std::string>> nplbufs;
|
||||
// todo:implement proper data structures to exchange npl and hpsc bufs
|
||||
proc::contract_bufmap_t nplbufs;
|
||||
proc::contract_iobuf_pair hpscbufpair;
|
||||
|
||||
proc::ContractExecArgs eargs(time_now, ctx.local_userbuf, nplbufs, hpscbufpair);
|
||||
proc::ContractExecArgs eargs(time_now, ctx.useriobufmap, nplbufs, hpscbufpair);
|
||||
proc::exec_contract(eargs);
|
||||
}
|
||||
|
||||
|
||||
@@ -5,6 +5,7 @@
|
||||
#include <unordered_map>
|
||||
#include <list>
|
||||
#include <ctime>
|
||||
#include "../proc.hpp"
|
||||
#include "../p2p/p2p.hpp"
|
||||
|
||||
namespace cons
|
||||
@@ -23,16 +24,18 @@ static const float STAGE3_THRESHOLD = 0.8;
|
||||
struct consensus_context
|
||||
{
|
||||
std::list<p2p::proposal> candidate_proposals;
|
||||
std::unordered_map<std::string, std::list<util::hash_buffer>> candidate_users;
|
||||
|
||||
int8_t stage;
|
||||
int64_t novel_proposal_time;
|
||||
int64_t time_now;
|
||||
std::string lcl;
|
||||
std::string novel_proposal;
|
||||
|
||||
std::map<std::string, std::pair<const std::string, std::string>> possible_inputs;
|
||||
std::map<std::string, std::pair<const std::string, std::string>> possible_outputs;
|
||||
|
||||
std::unordered_map<std::string, std::pair<std::string, std::string>> local_userbuf;
|
||||
std::unordered_map<std::string, proc::contract_iobuf_pair> useriobufmap;
|
||||
|
||||
int32_t next_sleep;
|
||||
};
|
||||
@@ -57,6 +60,8 @@ float_t get_stage_threshold(int8_t stage);
|
||||
|
||||
void timewait_stage(bool reset);
|
||||
|
||||
void populate_candidate_users_and_inputs();
|
||||
|
||||
p2p::proposal create_stage0_proposal();
|
||||
|
||||
p2p::proposal create_stage123_proposal(vote_counter &votes);
|
||||
|
||||
@@ -135,20 +135,14 @@ int verify_hex(std::string_view msg, std::string_view sighex, std::string_view p
|
||||
/**
|
||||
* Generate SHA 512 hash for message prepend with prefix before hashing.
|
||||
*
|
||||
* @param msg message string.
|
||||
* @param prefix prefix char array.
|
||||
* @param char_length length of prefix char array.
|
||||
* @param data String to hash.
|
||||
* @return SHA 512 hash.
|
||||
*/
|
||||
std::string sha_512_hash(std::string_view msg, const char *prefix, size_t char_length)
|
||||
std::string sha_512_hash(std::string_view data)
|
||||
{
|
||||
std::string payload;
|
||||
payload.reserve(char_length + msg.size());
|
||||
payload.append(prefix);
|
||||
payload.append(msg.data());
|
||||
unsigned char hashchars[crypto_hash_sha512_BYTES];
|
||||
crypto_hash_sha512(hashchars, (unsigned char *)payload.data(), payload.length());
|
||||
return std::string((char *)hashchars, crypto_hash_sha512_BYTES);
|
||||
crypto_hash_sha512(hashchars, (unsigned char *)data.data(), data.length());
|
||||
return std::string(reinterpret_cast<char *>(hashchars), crypto_hash_sha512_BYTES);
|
||||
}
|
||||
|
||||
} // namespace crypto
|
||||
@@ -29,7 +29,7 @@ int verify(std::string_view msg, std::string_view sig, std::string_view pubkey);
|
||||
|
||||
int verify_hex(std::string_view msg, std::string_view sighex, std::string_view pubkeyhex);
|
||||
|
||||
std::string sha_512_hash(std::string_view msg, const char *prefix, size_t char_length);
|
||||
std::string sha_512_hash(std::string_view data);
|
||||
|
||||
} // namespace crypto
|
||||
|
||||
|
||||
@@ -1,18 +1,28 @@
|
||||
//IDL file for p2p message content schema.
|
||||
namespace p2p;
|
||||
|
||||
table BytesKeyValuePair { //flatbuff equivalent for dictionary/hashmap for <byte>
|
||||
key:[ubyte];
|
||||
value:[ubyte];
|
||||
}
|
||||
table BytesKeyValuePair { //A key, value pair of byte[].
|
||||
key:[ubyte];
|
||||
value:[ubyte];
|
||||
}
|
||||
|
||||
table ByteArray { //To represent list of byte arrays
|
||||
array:[ubyte];
|
||||
}
|
||||
table RawInputList { //Pubkey bytes with an array of key value pairs.
|
||||
pubkey:[ubyte];
|
||||
inputs:[BytesKeyValuePair];
|
||||
}
|
||||
|
||||
table RawOutput { //Pubkey bytes with a output key value pair.
|
||||
pubkey:[ubyte];
|
||||
output:BytesKeyValuePair;
|
||||
}
|
||||
|
||||
table ByteArray { //To represent list of byte arrays
|
||||
array:[ubyte];
|
||||
}
|
||||
|
||||
union Message { Proposal_Message, Npl_Message } //message content type
|
||||
|
||||
table Content {
|
||||
table Content {
|
||||
message:Message;
|
||||
}
|
||||
|
||||
@@ -23,10 +33,10 @@ table Proposal_Message { //Proposal type message schema
|
||||
time:uint64;
|
||||
lcl:[ubyte];
|
||||
users: [ByteArray];
|
||||
raw_inputs: [BytesKeyValuePair]; //stage 0 inputs
|
||||
hash_inputs:[ByteArray]; //stage > 0 inputs (hash of stage 0 inputs)
|
||||
raw_outputs: [BytesKeyValuePair]; //stage 0 outputs
|
||||
hash_outputs:[ByteArray]; //stage > 0 outputs (hash of stage 0 outputs)
|
||||
raw_inputs: [RawInputList]; //stage 0 inputs (hash and raw value)
|
||||
hash_inputs:[ByteArray]; //stage > 0 inputs (hash of stage 0 inputs)
|
||||
raw_outputs: [RawOutput]; //stage 0 outputs (hash and raw value)
|
||||
hash_outputs:[ByteArray]; //stage > 0 outputs (hash of stage 0 outputs)
|
||||
state: State;
|
||||
}
|
||||
|
||||
|
||||
@@ -10,6 +10,10 @@ namespace p2p {
|
||||
|
||||
struct BytesKeyValuePair;
|
||||
|
||||
struct RawInputList;
|
||||
|
||||
struct RawOutput;
|
||||
|
||||
struct ByteArray;
|
||||
|
||||
struct Content;
|
||||
@@ -140,6 +144,146 @@ inline flatbuffers::Offset<BytesKeyValuePair> CreateBytesKeyValuePairDirect(
|
||||
value__);
|
||||
}
|
||||
|
||||
struct RawInputList FLATBUFFERS_FINAL_CLASS : private flatbuffers::Table {
|
||||
enum FlatBuffersVTableOffset FLATBUFFERS_VTABLE_UNDERLYING_TYPE {
|
||||
VT_PUBKEY = 4,
|
||||
VT_INPUTS = 6
|
||||
};
|
||||
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<flatbuffers::Offset<BytesKeyValuePair>> *inputs() const {
|
||||
return GetPointer<const flatbuffers::Vector<flatbuffers::Offset<BytesKeyValuePair>> *>(VT_INPUTS);
|
||||
}
|
||||
flatbuffers::Vector<flatbuffers::Offset<BytesKeyValuePair>> *mutable_inputs() {
|
||||
return GetPointer<flatbuffers::Vector<flatbuffers::Offset<BytesKeyValuePair>> *>(VT_INPUTS);
|
||||
}
|
||||
bool Verify(flatbuffers::Verifier &verifier) const {
|
||||
return VerifyTableStart(verifier) &&
|
||||
VerifyOffset(verifier, VT_PUBKEY) &&
|
||||
verifier.VerifyVector(pubkey()) &&
|
||||
VerifyOffset(verifier, VT_INPUTS) &&
|
||||
verifier.VerifyVector(inputs()) &&
|
||||
verifier.VerifyVectorOfTables(inputs()) &&
|
||||
verifier.EndTable();
|
||||
}
|
||||
};
|
||||
|
||||
struct RawInputListBuilder {
|
||||
flatbuffers::FlatBufferBuilder &fbb_;
|
||||
flatbuffers::uoffset_t start_;
|
||||
void add_pubkey(flatbuffers::Offset<flatbuffers::Vector<uint8_t>> pubkey) {
|
||||
fbb_.AddOffset(RawInputList::VT_PUBKEY, pubkey);
|
||||
}
|
||||
void add_inputs(flatbuffers::Offset<flatbuffers::Vector<flatbuffers::Offset<BytesKeyValuePair>>> inputs) {
|
||||
fbb_.AddOffset(RawInputList::VT_INPUTS, inputs);
|
||||
}
|
||||
explicit RawInputListBuilder(flatbuffers::FlatBufferBuilder &_fbb)
|
||||
: fbb_(_fbb) {
|
||||
start_ = fbb_.StartTable();
|
||||
}
|
||||
RawInputListBuilder &operator=(const RawInputListBuilder &);
|
||||
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>> pubkey = 0,
|
||||
flatbuffers::Offset<flatbuffers::Vector<flatbuffers::Offset<BytesKeyValuePair>>> inputs = 0) {
|
||||
RawInputListBuilder builder_(_fbb);
|
||||
builder_.add_inputs(inputs);
|
||||
builder_.add_pubkey(pubkey);
|
||||
return builder_.Finish();
|
||||
}
|
||||
|
||||
inline flatbuffers::Offset<RawInputList> CreateRawInputListDirect(
|
||||
flatbuffers::FlatBufferBuilder &_fbb,
|
||||
const std::vector<uint8_t> *pubkey = nullptr,
|
||||
const std::vector<flatbuffers::Offset<BytesKeyValuePair>> *inputs = nullptr) {
|
||||
auto pubkey__ = pubkey ? _fbb.CreateVector<uint8_t>(*pubkey) : 0;
|
||||
auto inputs__ = inputs ? _fbb.CreateVector<flatbuffers::Offset<BytesKeyValuePair>>(*inputs) : 0;
|
||||
return p2p::CreateRawInputList(
|
||||
_fbb,
|
||||
pubkey__,
|
||||
inputs__);
|
||||
}
|
||||
|
||||
struct RawOutput FLATBUFFERS_FINAL_CLASS : private flatbuffers::Table {
|
||||
enum FlatBuffersVTableOffset FLATBUFFERS_VTABLE_UNDERLYING_TYPE {
|
||||
VT_PUBKEY = 4,
|
||||
VT_OUTPUT = 6
|
||||
};
|
||||
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 BytesKeyValuePair *output() const {
|
||||
return GetPointer<const BytesKeyValuePair *>(VT_OUTPUT);
|
||||
}
|
||||
BytesKeyValuePair *mutable_output() {
|
||||
return GetPointer<BytesKeyValuePair *>(VT_OUTPUT);
|
||||
}
|
||||
bool Verify(flatbuffers::Verifier &verifier) const {
|
||||
return VerifyTableStart(verifier) &&
|
||||
VerifyOffset(verifier, VT_PUBKEY) &&
|
||||
verifier.VerifyVector(pubkey()) &&
|
||||
VerifyOffset(verifier, VT_OUTPUT) &&
|
||||
verifier.VerifyTable(output()) &&
|
||||
verifier.EndTable();
|
||||
}
|
||||
};
|
||||
|
||||
struct RawOutputBuilder {
|
||||
flatbuffers::FlatBufferBuilder &fbb_;
|
||||
flatbuffers::uoffset_t start_;
|
||||
void add_pubkey(flatbuffers::Offset<flatbuffers::Vector<uint8_t>> pubkey) {
|
||||
fbb_.AddOffset(RawOutput::VT_PUBKEY, pubkey);
|
||||
}
|
||||
void add_output(flatbuffers::Offset<BytesKeyValuePair> output) {
|
||||
fbb_.AddOffset(RawOutput::VT_OUTPUT, output);
|
||||
}
|
||||
explicit RawOutputBuilder(flatbuffers::FlatBufferBuilder &_fbb)
|
||||
: fbb_(_fbb) {
|
||||
start_ = fbb_.StartTable();
|
||||
}
|
||||
RawOutputBuilder &operator=(const RawOutputBuilder &);
|
||||
flatbuffers::Offset<RawOutput> Finish() {
|
||||
const auto end = fbb_.EndTable(start_);
|
||||
auto o = flatbuffers::Offset<RawOutput>(end);
|
||||
return o;
|
||||
}
|
||||
};
|
||||
|
||||
inline flatbuffers::Offset<RawOutput> CreateRawOutput(
|
||||
flatbuffers::FlatBufferBuilder &_fbb,
|
||||
flatbuffers::Offset<flatbuffers::Vector<uint8_t>> pubkey = 0,
|
||||
flatbuffers::Offset<BytesKeyValuePair> output = 0) {
|
||||
RawOutputBuilder builder_(_fbb);
|
||||
builder_.add_output(output);
|
||||
builder_.add_pubkey(pubkey);
|
||||
return builder_.Finish();
|
||||
}
|
||||
|
||||
inline flatbuffers::Offset<RawOutput> CreateRawOutputDirect(
|
||||
flatbuffers::FlatBufferBuilder &_fbb,
|
||||
const std::vector<uint8_t> *pubkey = nullptr,
|
||||
flatbuffers::Offset<BytesKeyValuePair> output = 0) {
|
||||
auto pubkey__ = pubkey ? _fbb.CreateVector<uint8_t>(*pubkey) : 0;
|
||||
return p2p::CreateRawOutput(
|
||||
_fbb,
|
||||
pubkey__,
|
||||
output);
|
||||
}
|
||||
|
||||
struct ByteArray FLATBUFFERS_FINAL_CLASS : private flatbuffers::Table {
|
||||
enum FlatBuffersVTableOffset FLATBUFFERS_VTABLE_UNDERLYING_TYPE {
|
||||
VT_ARRAY = 4
|
||||
@@ -315,11 +459,11 @@ struct Proposal_Message FLATBUFFERS_FINAL_CLASS : private flatbuffers::Table {
|
||||
flatbuffers::Vector<flatbuffers::Offset<ByteArray>> *mutable_users() {
|
||||
return GetPointer<flatbuffers::Vector<flatbuffers::Offset<ByteArray>> *>(VT_USERS);
|
||||
}
|
||||
const flatbuffers::Vector<flatbuffers::Offset<BytesKeyValuePair>> *raw_inputs() const {
|
||||
return GetPointer<const flatbuffers::Vector<flatbuffers::Offset<BytesKeyValuePair>> *>(VT_RAW_INPUTS);
|
||||
const flatbuffers::Vector<flatbuffers::Offset<RawInputList>> *raw_inputs() const {
|
||||
return GetPointer<const flatbuffers::Vector<flatbuffers::Offset<RawInputList>> *>(VT_RAW_INPUTS);
|
||||
}
|
||||
flatbuffers::Vector<flatbuffers::Offset<BytesKeyValuePair>> *mutable_raw_inputs() {
|
||||
return GetPointer<flatbuffers::Vector<flatbuffers::Offset<BytesKeyValuePair>> *>(VT_RAW_INPUTS);
|
||||
flatbuffers::Vector<flatbuffers::Offset<RawInputList>> *mutable_raw_inputs() {
|
||||
return GetPointer<flatbuffers::Vector<flatbuffers::Offset<RawInputList>> *>(VT_RAW_INPUTS);
|
||||
}
|
||||
const flatbuffers::Vector<flatbuffers::Offset<ByteArray>> *hash_inputs() const {
|
||||
return GetPointer<const flatbuffers::Vector<flatbuffers::Offset<ByteArray>> *>(VT_HASH_INPUTS);
|
||||
@@ -327,11 +471,11 @@ struct Proposal_Message FLATBUFFERS_FINAL_CLASS : private flatbuffers::Table {
|
||||
flatbuffers::Vector<flatbuffers::Offset<ByteArray>> *mutable_hash_inputs() {
|
||||
return GetPointer<flatbuffers::Vector<flatbuffers::Offset<ByteArray>> *>(VT_HASH_INPUTS);
|
||||
}
|
||||
const flatbuffers::Vector<flatbuffers::Offset<BytesKeyValuePair>> *raw_outputs() const {
|
||||
return GetPointer<const flatbuffers::Vector<flatbuffers::Offset<BytesKeyValuePair>> *>(VT_RAW_OUTPUTS);
|
||||
const flatbuffers::Vector<flatbuffers::Offset<RawOutput>> *raw_outputs() const {
|
||||
return GetPointer<const flatbuffers::Vector<flatbuffers::Offset<RawOutput>> *>(VT_RAW_OUTPUTS);
|
||||
}
|
||||
flatbuffers::Vector<flatbuffers::Offset<BytesKeyValuePair>> *mutable_raw_outputs() {
|
||||
return GetPointer<flatbuffers::Vector<flatbuffers::Offset<BytesKeyValuePair>> *>(VT_RAW_OUTPUTS);
|
||||
flatbuffers::Vector<flatbuffers::Offset<RawOutput>> *mutable_raw_outputs() {
|
||||
return GetPointer<flatbuffers::Vector<flatbuffers::Offset<RawOutput>> *>(VT_RAW_OUTPUTS);
|
||||
}
|
||||
const flatbuffers::Vector<flatbuffers::Offset<ByteArray>> *hash_outputs() const {
|
||||
return GetPointer<const flatbuffers::Vector<flatbuffers::Offset<ByteArray>> *>(VT_HASH_OUTPUTS);
|
||||
@@ -396,13 +540,13 @@ struct Proposal_MessageBuilder {
|
||||
void add_users(flatbuffers::Offset<flatbuffers::Vector<flatbuffers::Offset<ByteArray>>> users) {
|
||||
fbb_.AddOffset(Proposal_Message::VT_USERS, users);
|
||||
}
|
||||
void add_raw_inputs(flatbuffers::Offset<flatbuffers::Vector<flatbuffers::Offset<BytesKeyValuePair>>> raw_inputs) {
|
||||
void add_raw_inputs(flatbuffers::Offset<flatbuffers::Vector<flatbuffers::Offset<RawInputList>>> raw_inputs) {
|
||||
fbb_.AddOffset(Proposal_Message::VT_RAW_INPUTS, raw_inputs);
|
||||
}
|
||||
void add_hash_inputs(flatbuffers::Offset<flatbuffers::Vector<flatbuffers::Offset<ByteArray>>> hash_inputs) {
|
||||
fbb_.AddOffset(Proposal_Message::VT_HASH_INPUTS, hash_inputs);
|
||||
}
|
||||
void add_raw_outputs(flatbuffers::Offset<flatbuffers::Vector<flatbuffers::Offset<BytesKeyValuePair>>> raw_outputs) {
|
||||
void add_raw_outputs(flatbuffers::Offset<flatbuffers::Vector<flatbuffers::Offset<RawOutput>>> raw_outputs) {
|
||||
fbb_.AddOffset(Proposal_Message::VT_RAW_OUTPUTS, raw_outputs);
|
||||
}
|
||||
void add_hash_outputs(flatbuffers::Offset<flatbuffers::Vector<flatbuffers::Offset<ByteArray>>> hash_outputs) {
|
||||
@@ -431,9 +575,9 @@ inline flatbuffers::Offset<Proposal_Message> CreateProposal_Message(
|
||||
uint64_t time = 0,
|
||||
flatbuffers::Offset<flatbuffers::Vector<uint8_t>> lcl = 0,
|
||||
flatbuffers::Offset<flatbuffers::Vector<flatbuffers::Offset<ByteArray>>> users = 0,
|
||||
flatbuffers::Offset<flatbuffers::Vector<flatbuffers::Offset<BytesKeyValuePair>>> raw_inputs = 0,
|
||||
flatbuffers::Offset<flatbuffers::Vector<flatbuffers::Offset<RawInputList>>> raw_inputs = 0,
|
||||
flatbuffers::Offset<flatbuffers::Vector<flatbuffers::Offset<ByteArray>>> hash_inputs = 0,
|
||||
flatbuffers::Offset<flatbuffers::Vector<flatbuffers::Offset<BytesKeyValuePair>>> raw_outputs = 0,
|
||||
flatbuffers::Offset<flatbuffers::Vector<flatbuffers::Offset<RawOutput>>> raw_outputs = 0,
|
||||
flatbuffers::Offset<flatbuffers::Vector<flatbuffers::Offset<ByteArray>>> hash_outputs = 0,
|
||||
flatbuffers::Offset<State> state = 0) {
|
||||
Proposal_MessageBuilder builder_(_fbb);
|
||||
@@ -459,17 +603,17 @@ inline flatbuffers::Offset<Proposal_Message> CreateProposal_MessageDirect(
|
||||
uint64_t time = 0,
|
||||
const std::vector<uint8_t> *lcl = nullptr,
|
||||
const std::vector<flatbuffers::Offset<ByteArray>> *users = nullptr,
|
||||
const std::vector<flatbuffers::Offset<BytesKeyValuePair>> *raw_inputs = nullptr,
|
||||
const std::vector<flatbuffers::Offset<RawInputList>> *raw_inputs = nullptr,
|
||||
const std::vector<flatbuffers::Offset<ByteArray>> *hash_inputs = nullptr,
|
||||
const std::vector<flatbuffers::Offset<BytesKeyValuePair>> *raw_outputs = nullptr,
|
||||
const std::vector<flatbuffers::Offset<RawOutput>> *raw_outputs = nullptr,
|
||||
const std::vector<flatbuffers::Offset<ByteArray>> *hash_outputs = nullptr,
|
||||
flatbuffers::Offset<State> state = 0) {
|
||||
auto pubkey__ = pubkey ? _fbb.CreateVector<uint8_t>(*pubkey) : 0;
|
||||
auto lcl__ = lcl ? _fbb.CreateVector<uint8_t>(*lcl) : 0;
|
||||
auto users__ = users ? _fbb.CreateVector<flatbuffers::Offset<ByteArray>>(*users) : 0;
|
||||
auto raw_inputs__ = raw_inputs ? _fbb.CreateVector<flatbuffers::Offset<BytesKeyValuePair>>(*raw_inputs) : 0;
|
||||
auto raw_inputs__ = raw_inputs ? _fbb.CreateVector<flatbuffers::Offset<RawInputList>>(*raw_inputs) : 0;
|
||||
auto hash_inputs__ = hash_inputs ? _fbb.CreateVector<flatbuffers::Offset<ByteArray>>(*hash_inputs) : 0;
|
||||
auto raw_outputs__ = raw_outputs ? _fbb.CreateVector<flatbuffers::Offset<BytesKeyValuePair>>(*raw_outputs) : 0;
|
||||
auto raw_outputs__ = raw_outputs ? _fbb.CreateVector<flatbuffers::Offset<RawOutput>>(*raw_outputs) : 0;
|
||||
auto hash_outputs__ = hash_outputs ? _fbb.CreateVector<flatbuffers::Offset<ByteArray>>(*hash_outputs) : 0;
|
||||
return p2p::CreateProposal_Message(
|
||||
_fbb,
|
||||
|
||||
@@ -19,9 +19,9 @@ struct proposal
|
||||
int8_t stage;
|
||||
std::string lcl;
|
||||
std::unordered_set<std::string> users;
|
||||
std::unordered_map<std::string, const std::string> raw_inputs;
|
||||
std::unordered_map<std::string, const std::vector<util::hash_buffer>> raw_inputs;
|
||||
std::unordered_set<std::string> hash_inputs;
|
||||
std::unordered_map<std::string, const std::string> raw_outputs;
|
||||
std::unordered_map<std::string, util::hash_buffer> raw_outputs;
|
||||
std::unordered_set<std::string> hash_outputs;
|
||||
};
|
||||
|
||||
|
||||
@@ -178,13 +178,13 @@ const proposal create_proposal_from_msg(const Proposal_Message &msg)
|
||||
p.users = flatbuf_bytearrayvector_to_stringlist(msg.users());
|
||||
|
||||
if (msg.raw_inputs())
|
||||
p.raw_inputs = flatbuf_pairvector_to_stringmap(msg.raw_inputs());
|
||||
p.raw_inputs = flatbuf_rawinputs_to_hashbuffermap(msg.raw_inputs());
|
||||
|
||||
if (msg.hash_inputs())
|
||||
p.hash_inputs = flatbuf_bytearrayvector_to_stringlist(msg.hash_inputs());
|
||||
|
||||
if (msg.raw_outputs())
|
||||
p.raw_outputs = flatbuf_pairvector_to_stringmap(msg.raw_outputs());
|
||||
p.raw_outputs = flatbuf_rawoutputs_to_hashbuffermap(msg.raw_outputs());
|
||||
|
||||
if (msg.hash_outputs())
|
||||
p.hash_outputs = flatbuf_bytearrayvector_to_stringlist(msg.hash_outputs());
|
||||
@@ -214,9 +214,9 @@ void create_msg_from_proposal(flatbuffers::FlatBufferBuilder &container_builder,
|
||||
p.time,
|
||||
sv_to_flatbuff_bytes(builder, p.lcl),
|
||||
stringlist_to_flatbuf_bytearrayvector(builder, p.users),
|
||||
stringmap_to_flatbuf_bytepairvector(builder, p.raw_inputs),
|
||||
hashbuffermap_to_flatbuf_rawinputs(builder, p.raw_inputs),
|
||||
stringlist_to_flatbuf_bytearrayvector(builder, p.hash_inputs),
|
||||
stringmap_to_flatbuf_bytepairvector(builder, p.raw_outputs),
|
||||
hashbuffermap_to_flatbuf_rawoutputs(builder, p.raw_outputs),
|
||||
stringlist_to_flatbuf_bytearrayvector(builder, p.hash_outputs));
|
||||
|
||||
flatbuffers::Offset<Content> message = CreateContent(builder, Message_Proposal_Message, proposal.Union());
|
||||
@@ -300,6 +300,52 @@ flatbuf_pairvector_to_stringmap(const flatbuffers::Vector<flatbuffers::Offset<By
|
||||
return map;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a hash buffer map from Flatbuffer proposal raw inputs.
|
||||
*/
|
||||
const std::unordered_map<std::string, const std::vector<util::hash_buffer>>
|
||||
flatbuf_rawinputs_to_hashbuffermap(const flatbuffers::Vector<flatbuffers::Offset<RawInputList>> *fbvec)
|
||||
{
|
||||
std::unordered_map<std::string, const std::vector<util::hash_buffer>> map;
|
||||
map.reserve(fbvec->size());
|
||||
for (const RawInputList *user : *fbvec)
|
||||
{
|
||||
std::vector<util::hash_buffer> bufvec;
|
||||
bufvec.reserve(user->inputs()->size());
|
||||
|
||||
for (auto input : *user->inputs())
|
||||
{
|
||||
// Create hash_buffer object and manually assign the hash from the input.
|
||||
util::hash_buffer buf(flatbuff_bytes_to_sv(input->value())); //input->value() is the raw input.
|
||||
buf.hash = flatbuff_bytes_to_sv(input->key()); //input->key() is the hash of the input.
|
||||
|
||||
bufvec.push_back(buf);
|
||||
}
|
||||
|
||||
map.emplace(flatbuff_bytes_to_sv(user->pubkey()), std::move(bufvec));
|
||||
}
|
||||
return map;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a hash buffer map from Flatbuffer proposal raw outputs.
|
||||
*/
|
||||
const std::unordered_map<std::string, util::hash_buffer>
|
||||
flatbuf_rawoutputs_to_hashbuffermap(const flatbuffers::Vector<flatbuffers::Offset<RawOutput>> *fbvec)
|
||||
{
|
||||
std::unordered_map<std::string, util::hash_buffer> map;
|
||||
map.reserve(fbvec->size());
|
||||
for (const RawOutput *user : *fbvec)
|
||||
{
|
||||
// Create hash_buffer object and manually assign the hash from the output.
|
||||
util::hash_buffer buf(flatbuff_bytes_to_sv(user->output()->value())); //output->value() is the raw output.
|
||||
buf.hash = flatbuff_bytes_to_sv(user->output()->key()); //output->key() is the hash of the output.
|
||||
|
||||
map.emplace(flatbuff_bytes_to_sv(user->pubkey()), std::move(buf));
|
||||
}
|
||||
return map;
|
||||
}
|
||||
|
||||
//---Conversion helpers from std data types to flatbuffers data types---//
|
||||
//---These are used in constructing Flatbuffer messages using builders---//
|
||||
|
||||
@@ -343,4 +389,52 @@ stringmap_to_flatbuf_bytepairvector(flatbuffers::FlatBufferBuilder &builder, con
|
||||
return builder.CreateVector(fbvec);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns Flatbuffer vector of RawInputs from a given map of hash buffer lists.
|
||||
*/
|
||||
const flatbuffers::Offset<flatbuffers::Vector<flatbuffers::Offset<RawInputList>>>
|
||||
hashbuffermap_to_flatbuf_rawinputs(flatbuffers::FlatBufferBuilder &builder, const std::unordered_map<std::string, const std::vector<util::hash_buffer>> &map)
|
||||
{
|
||||
std::vector<flatbuffers::Offset<RawInputList>> fbvec;
|
||||
fbvec.reserve(map.size());
|
||||
for (auto const &[pubkey, bufvec] : map)
|
||||
{
|
||||
std::vector<flatbuffers::Offset<BytesKeyValuePair>> fbinputsvec;
|
||||
for (const util::hash_buffer &buf : bufvec)
|
||||
{
|
||||
fbinputsvec.push_back(CreateBytesKeyValuePair(
|
||||
builder,
|
||||
sv_to_flatbuff_bytes(builder, buf.hash),
|
||||
sv_to_flatbuff_bytes(builder, buf.buffer)));
|
||||
}
|
||||
|
||||
fbvec.push_back(CreateRawInputList(
|
||||
builder,
|
||||
sv_to_flatbuff_bytes(builder, pubkey),
|
||||
builder.CreateVector(fbinputsvec)));
|
||||
}
|
||||
return builder.CreateVector(fbvec);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns Flatbuffer vector of RawOutputs from a given map of hash buffers.
|
||||
*/
|
||||
const flatbuffers::Offset<flatbuffers::Vector<flatbuffers::Offset<RawOutput>>>
|
||||
hashbuffermap_to_flatbuf_rawoutputs(flatbuffers::FlatBufferBuilder &builder, const std::unordered_map<std::string, util::hash_buffer> &map)
|
||||
{
|
||||
std::vector<flatbuffers::Offset<RawOutput>> fbvec;
|
||||
fbvec.reserve(map.size());
|
||||
for (auto const &[pubkey, buf] : map)
|
||||
{
|
||||
fbvec.push_back(CreateRawOutput(
|
||||
builder,
|
||||
sv_to_flatbuff_bytes(builder, pubkey),
|
||||
CreateBytesKeyValuePair(
|
||||
builder,
|
||||
sv_to_flatbuff_bytes(builder, buf.hash),
|
||||
sv_to_flatbuff_bytes(builder, buf.buffer))));
|
||||
}
|
||||
return builder.CreateVector(fbvec);
|
||||
}
|
||||
|
||||
} // namespace p2p
|
||||
@@ -36,9 +36,17 @@ std::string_view flatbuff_bytes_to_sv(const uint8_t *data, flatbuffers::uoffset_
|
||||
|
||||
std::string_view flatbuff_bytes_to_sv(const flatbuffers::Vector<uint8_t> *buffer);
|
||||
|
||||
const std::unordered_set<std::string> flatbuf_bytearrayvector_to_stringlist(const flatbuffers::Vector<flatbuffers::Offset<ByteArray>> *fbvec);
|
||||
const std::unordered_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);
|
||||
const std::unordered_map<std::string, const std::string>
|
||||
flatbuf_pairvector_to_stringmap(const flatbuffers::Vector<flatbuffers::Offset<BytesKeyValuePair>> *fbvec);
|
||||
|
||||
const std::unordered_map<std::string, const std::vector<util::hash_buffer>>
|
||||
flatbuf_rawinputs_to_hashbuffermap(const flatbuffers::Vector<flatbuffers::Offset<RawInputList>> *fbvec);
|
||||
|
||||
const std::unordered_map<std::string, util::hash_buffer>
|
||||
flatbuf_rawoutputs_to_hashbuffermap(const flatbuffers::Vector<flatbuffers::Offset<RawOutput>> *fbvec);
|
||||
|
||||
//---Conversion helpers from std data types to flatbuffers data types---//
|
||||
|
||||
@@ -51,6 +59,12 @@ stringlist_to_flatbuf_bytearrayvector(flatbuffers::FlatBufferBuilder &builder, c
|
||||
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);
|
||||
|
||||
const flatbuffers::Offset<flatbuffers::Vector<flatbuffers::Offset<RawInputList>>>
|
||||
hashbuffermap_to_flatbuf_rawinputs(flatbuffers::FlatBufferBuilder &builder, const std::unordered_map<std::string, const std::vector<util::hash_buffer>> &map);
|
||||
|
||||
const flatbuffers::Offset<flatbuffers::Vector<flatbuffers::Offset<RawOutput>>>
|
||||
hashbuffermap_to_flatbuf_rawoutputs(flatbuffers::FlatBufferBuilder &builder, const std::unordered_map<std::string, util::hash_buffer> &map);
|
||||
|
||||
} // namespace p2p
|
||||
|
||||
#endif
|
||||
63
src/proc.cpp
63
src/proc.cpp
@@ -30,10 +30,10 @@ enum FDTYPE
|
||||
};
|
||||
|
||||
// Map of user pipe fds (map key: user public key)
|
||||
contract_fdmap userfds;
|
||||
contract_fdmap_t userfds;
|
||||
|
||||
// Map of NPL pipe fds (map key: user public key)
|
||||
contract_fdmap nplfds;
|
||||
contract_fdmap_t nplfds;
|
||||
|
||||
// Pipe fds for HP <--> messages.
|
||||
std::vector<int> hpscfds;
|
||||
@@ -242,10 +242,9 @@ int write_contract_args(const ContractExecArgs &args)
|
||||
*/
|
||||
int write_contract_hp_inputs(const ContractExecArgs &args)
|
||||
{
|
||||
if (create_and_write_iopipes(hpscfds, args.hpscbufs.first) != 0) // hpscbufs.first is the input buffer.
|
||||
if (create_and_write_iopipes(hpscfds, args.hpscbufs.inputs) != 0)
|
||||
{
|
||||
LOG_ERR << "Error writing HP input to SC (" << args.hpscbufs.first.length()
|
||||
<< " bytes)";
|
||||
LOG_ERR << "Error writing HP inputs to SC";
|
||||
return -1;
|
||||
}
|
||||
return 0;
|
||||
@@ -259,11 +258,11 @@ int write_contract_hp_inputs(const ContractExecArgs &args)
|
||||
*/
|
||||
int read_contract_hp_outputs(const ContractExecArgs &args)
|
||||
{
|
||||
// Clear the input buffer because we are sure the contract has finished reading from
|
||||
// Clear the input buffers because we are sure the contract has finished reading from
|
||||
// that mapped memory portion.
|
||||
args.hpscbufs.first.clear(); //bufpair.first is the input buffer.
|
||||
args.hpscbufs.inputs.clear();
|
||||
|
||||
if (read_iopipe(hpscfds, args.hpscbufs.second) != 0) // hpscbufs.second is the output buffer.
|
||||
if (read_iopipe(hpscfds, args.hpscbufs.output) != 0) // hpscbufs.second is the output buffer.
|
||||
return -1;
|
||||
|
||||
return 0;
|
||||
@@ -274,7 +273,7 @@ int read_contract_hp_outputs(const ContractExecArgs &args)
|
||||
* @param fdmap Any pubkey->fdlist map. (eg. userfds, nplfds)
|
||||
* @param os An output stream.
|
||||
*/
|
||||
void fdmap_json_to_stream(const contract_fdmap &fdmap, std::ostringstream &os)
|
||||
void fdmap_json_to_stream(const contract_fdmap_t &fdmap, std::ostringstream &os)
|
||||
{
|
||||
for (auto itr = fdmap.begin(); itr != fdmap.end(); itr++)
|
||||
{
|
||||
@@ -302,16 +301,16 @@ void fdmap_json_to_stream(const contract_fdmap &fdmap, std::ostringstream &os)
|
||||
* modified (eg. fd close, buffer clear).
|
||||
*
|
||||
* @param fdmap A map which has public key and a vector<int> as fd list for that public key.
|
||||
* @param bufmap A map which has a public key and input/output buffer pair for that public key.
|
||||
* @param bufmap A map which has a public key and input/output buffer lists for that public key.
|
||||
* @return 0 on success. -1 on failure.
|
||||
*/
|
||||
int write_contract_fdmap_inputs(contract_fdmap &fdmap, contract_bufmap &bufmap)
|
||||
int write_contract_fdmap_inputs(contract_fdmap_t &fdmap, contract_bufmap_t &bufmap)
|
||||
{
|
||||
// Loop through input buffer for each pubkey.
|
||||
for (auto &[pubkey, bufpair] : bufmap)
|
||||
// Loop through input buffers for each pubkey.
|
||||
for (auto &[pubkey, buflist] : bufmap)
|
||||
{
|
||||
std::vector<int> fds = std::vector<int>();
|
||||
if (create_and_write_iopipes(fds, bufpair.first) != 0) // bufpair.first is the input buffer.
|
||||
if (create_and_write_iopipes(fds, buflist.inputs) != 0)
|
||||
return -1;
|
||||
|
||||
fdmap.emplace(pubkey, std::move(fds));
|
||||
@@ -328,18 +327,18 @@ int write_contract_fdmap_inputs(contract_fdmap &fdmap, contract_bufmap &bufmap)
|
||||
* @param bufmap A map which has a public key and input/output buffer pair for that public key.
|
||||
* @return 0 on success. -1 on failure.
|
||||
*/
|
||||
int read_contract_fdmap_outputs(contract_fdmap &fdmap, contract_bufmap &bufmap)
|
||||
int read_contract_fdmap_outputs(contract_fdmap_t &fdmap, contract_bufmap_t &bufmap)
|
||||
{
|
||||
for (auto &[pubkey, bufpair] : bufmap)
|
||||
{
|
||||
// Clear the input buffer because we are sure the contract has finished reading from
|
||||
// that mapped memory portion.
|
||||
bufpair.first.clear(); //bufpair.first is the input buffer.
|
||||
// the inputs' mapped memory portion.
|
||||
bufpair.inputs.clear();
|
||||
|
||||
// Get fds for the pubkey.
|
||||
std::vector<int> &fds = fdmap[pubkey];
|
||||
|
||||
if (read_iopipe(fds, bufpair.second) != 0) // bufpair.second is the output buffer.
|
||||
if (read_iopipe(fds, bufpair.output) != 0) // bufpair.second is the output buffer.
|
||||
return -1;
|
||||
}
|
||||
|
||||
@@ -350,7 +349,7 @@ int read_contract_fdmap_outputs(contract_fdmap &fdmap, contract_bufmap &bufmap)
|
||||
* Common function to close any open fds in the map after an error.
|
||||
* @param fdmap Any pubkey->fdlist map. (eg. userfds, nplfds)
|
||||
*/
|
||||
void cleanup_fdmap(contract_fdmap &fdmap)
|
||||
void cleanup_fdmap(contract_fdmap_t &fdmap)
|
||||
{
|
||||
for (auto &[pubkey, fds] : fdmap)
|
||||
{
|
||||
@@ -370,7 +369,7 @@ void cleanup_fdmap(contract_fdmap &fdmap)
|
||||
* @param fds Vector to populate fd list.
|
||||
* @param inputbuffer Buffer to write into the HP write fd.
|
||||
*/
|
||||
int create_and_write_iopipes(std::vector<int> &fds, std::string &inputbuffer)
|
||||
int create_and_write_iopipes(std::vector<int> &fds, std::list<std::string> &inputs)
|
||||
{
|
||||
int inpipe[2];
|
||||
if (pipe(inpipe) != 0)
|
||||
@@ -392,17 +391,17 @@ int create_and_write_iopipes(std::vector<int> &fds, std::string &inputbuffer)
|
||||
fds.push_back(outpipe[0]); //HPREAD
|
||||
fds.push_back(outpipe[1]); //SCWRITE
|
||||
|
||||
// Write the input (if any) into the contract and close the writefd.
|
||||
// Write the inputs (if any) into the contract and close the writefd.
|
||||
|
||||
int writefd = fds[FDTYPE::HPWRITE];
|
||||
bool vmsplice_error = false;
|
||||
|
||||
if (!inputbuffer.empty())
|
||||
for (std::string &input : inputs)
|
||||
{
|
||||
// We use vmsplice to map (zero-copy) the input into the fd.
|
||||
iovec memsegs[1];
|
||||
memsegs[0].iov_base = inputbuffer.data();
|
||||
memsegs[0].iov_len = inputbuffer.length();
|
||||
memsegs[0].iov_base = input.data();
|
||||
memsegs[0].iov_len = input.length();
|
||||
|
||||
if (vmsplice(writefd, memsegs, 1, 0) == -1)
|
||||
vmsplice_error = true;
|
||||
@@ -421,15 +420,15 @@ int create_and_write_iopipes(std::vector<int> &fds, std::string &inputbuffer)
|
||||
}
|
||||
|
||||
/**
|
||||
* Common function to read and close SC output from the pipe and populate a given buffer.
|
||||
* Common function to read and close SC output from the pipe and populate the output list.
|
||||
* @param fds Vector representing the pipes fd list.
|
||||
* @param The buffer to place the read output.
|
||||
* @param output The buffer to place the read output.
|
||||
*/
|
||||
int read_iopipe(std::vector<int> &fds, std::string &outputbuffer)
|
||||
int read_iopipe(std::vector<int> &fds, std::string &output)
|
||||
{
|
||||
// Read any outputs that have been written by the contract process
|
||||
// from the HP outpipe and store in the outbuffer.
|
||||
// outbuffer will be read by the consensus process later when it wishes so.
|
||||
// Read any data that have been written by the contract process
|
||||
// from the output pipe and store in the output buffer.
|
||||
// Outputs will be read by the consensus process later when it wishes so.
|
||||
|
||||
int readfd = fds[FDTYPE::HPREAD];
|
||||
int bytes_available = 0;
|
||||
@@ -438,12 +437,12 @@ int read_iopipe(std::vector<int> &fds, std::string &outputbuffer)
|
||||
|
||||
if (bytes_available > 0)
|
||||
{
|
||||
outputbuffer.resize(bytes_available); // args.hpscbufs.second is the output buffer.
|
||||
output.resize(bytes_available);
|
||||
|
||||
// Populate the user output buffer with new data from the pipe.
|
||||
// We use vmsplice to map (zero-copy) the output from the fd into output bbuffer.
|
||||
iovec memsegs[1];
|
||||
memsegs[0].iov_base = outputbuffer.data();
|
||||
memsegs[0].iov_base = output.data();
|
||||
memsegs[0].iov_len = bytes_available;
|
||||
|
||||
if (vmsplice(readfd, memsegs, 1, 0) == -1)
|
||||
|
||||
52
src/proc.hpp
52
src/proc.hpp
@@ -5,6 +5,7 @@
|
||||
#include <iostream>
|
||||
#include <unordered_map>
|
||||
#include <vector>
|
||||
#include <list>
|
||||
#include "usr/usr.hpp"
|
||||
#include "util.hpp"
|
||||
|
||||
@@ -14,13 +15,26 @@
|
||||
namespace proc
|
||||
{
|
||||
|
||||
/**
|
||||
* Represents list of inputs to the contract and the accumilated contract output for those inputs.
|
||||
*/
|
||||
struct contract_iobuf_pair
|
||||
{
|
||||
// List of inputs to be fed into the contract.
|
||||
std::list<std::string> inputs;
|
||||
|
||||
// Output emitted by contract after execution. (Because we are reading output at the end, there's no way to
|
||||
// get a "list" of outputs. So it's always a one contingous output.)
|
||||
std::string output;
|
||||
};
|
||||
|
||||
// Common typedef for a map of pubkey->fdlist.
|
||||
// This is used to keep track of fdlist quadruplet with a public key (eg. user, npl).
|
||||
typedef std::unordered_map<std::string, std::vector<int>> contract_fdmap;
|
||||
typedef std::unordered_map<std::string, std::vector<int>> contract_fdmap_t;
|
||||
|
||||
// Common typedef for a map of pubkey->buf-pair (input buffer and output buffer).
|
||||
// This is used to keep track of input/output buffer pair with a public key (eg. user, npl)
|
||||
typedef std::unordered_map<std::string, std::pair<std::string, std::string>> contract_bufmap;
|
||||
// Common typedef for a map of pubkey->I/O list pair (input list and output list).
|
||||
// This is used to keep track of input/output buffers for a given public key (eg. user, npl)
|
||||
typedef std::unordered_map<std::string, contract_iobuf_pair> contract_bufmap_t;
|
||||
|
||||
/**
|
||||
* Holds information that should be passed into the contract process.
|
||||
@@ -28,25 +42,25 @@ typedef std::unordered_map<std::string, std::pair<std::string, std::string>> con
|
||||
struct ContractExecArgs
|
||||
{
|
||||
// Map of user I/O buffers (map key: user binary public key).
|
||||
// The value is a pair holding consensus-verified input and contract-generated output.
|
||||
contract_bufmap &userbufs;
|
||||
// The value is a pair holding consensus-verified inputs and contract-generated outputs.
|
||||
contract_bufmap_t &userbufs;
|
||||
|
||||
// Map of NPL I/O buffers (map key: Peer binary public key).
|
||||
// The value is a pair holding NPL input and contract-generated output.
|
||||
contract_bufmap &nplbufs;
|
||||
// The value is a pair holding NPL inputs and contract-generated outputs.
|
||||
contract_bufmap_t &nplbufs;
|
||||
|
||||
// Pair of HP<->SC JSON message buffers (mainly used for control messages).
|
||||
// Input buffer for HP->SC messages, Output buffer for SC->HP messages.
|
||||
std::pair<std::string, std::string> &hpscbufs;
|
||||
// Input buffers for HP->SC messages, Output buffers for SC->HP messages.
|
||||
contract_iobuf_pair &hpscbufs;
|
||||
|
||||
// Current HotPocket timestamp.
|
||||
int64_t timestamp;
|
||||
|
||||
ContractExecArgs(
|
||||
int64_t _timestamp,
|
||||
contract_bufmap &_userbufs,
|
||||
contract_bufmap &_nplbufs,
|
||||
std::pair<std::string, std::string> &_hpscbufs) :
|
||||
contract_bufmap_t &_userbufs,
|
||||
contract_bufmap_t &_nplbufs,
|
||||
contract_iobuf_pair &_hpscbufs) :
|
||||
userbufs(_userbufs),
|
||||
nplbufs(_nplbufs),
|
||||
hpscbufs(_hpscbufs)
|
||||
@@ -69,17 +83,17 @@ int read_contract_hp_outputs(const ContractExecArgs &args);
|
||||
|
||||
// Common helper functions
|
||||
|
||||
void fdmap_json_to_stream(const contract_fdmap &fdmap, std::ostringstream &os);
|
||||
void fdmap_json_to_stream(const contract_fdmap_t &fdmap, std::ostringstream &os);
|
||||
|
||||
int write_contract_fdmap_inputs(contract_fdmap &fdmap, contract_bufmap &bufmap);
|
||||
int write_contract_fdmap_inputs(contract_fdmap_t &fdmap, contract_bufmap_t &bufmap);
|
||||
|
||||
int read_contract_fdmap_outputs(contract_fdmap &fdmap, contract_bufmap &bufmap);
|
||||
int read_contract_fdmap_outputs(contract_fdmap_t &fdmap, contract_bufmap_t &bufmap);
|
||||
|
||||
void cleanup_fdmap(contract_fdmap &fdmap);
|
||||
void cleanup_fdmap(contract_fdmap_t &fdmap);
|
||||
|
||||
int create_and_write_iopipes(std::vector<int> &fds, std::string &inputbuffer);
|
||||
int create_and_write_iopipes(std::vector<int> &fds, std::list<std::string> &inputs);
|
||||
|
||||
int read_iopipe(std::vector<int> &fds, std::string &outputbuffer);
|
||||
int read_iopipe(std::vector<int> &fds, std::string &output);
|
||||
|
||||
void close_unused_fds(bool is_hp);
|
||||
|
||||
|
||||
@@ -48,7 +48,7 @@ void user_session_handler::on_connect(sock::socket_session<user_outbound_message
|
||||
session->init_uniqueid();
|
||||
|
||||
// Create an entry in pending_challenges for later tracking upon challenge response.
|
||||
usr::pending_challenges[session->uniqueid] = challengehex;
|
||||
usr::pending_challenges.try_emplace(session->uniqueid, challengehex);
|
||||
|
||||
user_outbound_message outmsg(std::move(msgstr));
|
||||
session->send(std::move(outmsg));
|
||||
@@ -95,7 +95,7 @@ void user_session_handler::on_message(
|
||||
|
||||
session->flags.reset(util::SESSION_FLAG::USER_CHALLENGE_ISSUED); // Clear challenge-issued flag
|
||||
session->flags.set(util::SESSION_FLAG::USER_AUTHED); // Set the user-authed flag
|
||||
usr::add_user(session, userpubkey); // Add the user to the global authed user list
|
||||
usr::add_user(session, userpubkey); // Add the user to the global authed user list
|
||||
usr::pending_challenges.erase(session->uniqueid); // Remove the stored challenge
|
||||
|
||||
LOG_INFO << "User connection " << session->uniqueid << " authenticated. Public key "
|
||||
@@ -125,10 +125,13 @@ void user_session_handler::on_message(
|
||||
// This is an authed user.
|
||||
usr::connected_user &user = itr->second;
|
||||
|
||||
//Append the bytes into connected user input buffer.
|
||||
user.inbuffer.append(message);
|
||||
{
|
||||
std::lock_guard<std::mutex> lock(users_mutex);
|
||||
//Add to the hashed input buffer list.
|
||||
user.inputs.push_back(util::hash_buffer(message, user.pubkey));
|
||||
}
|
||||
|
||||
LOG_DBG << "Collected " << user.inbuffer.length() << " bytes from user";
|
||||
LOG_DBG << "Collected " << message.length() << " bytes from user";
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -31,13 +31,13 @@ std::mutex users_mutex; // Mutex for users access race conditions.
|
||||
* This is used for pubkey duplicate checks as well.
|
||||
* Map key: User binary pubkey
|
||||
*/
|
||||
std::unordered_map<std::string, std::string> sessionids;
|
||||
std::unordered_map<std::string, const std::string> sessionids;
|
||||
|
||||
/**
|
||||
* Keep track of verification-pending challenges issued to newly connected users.
|
||||
* Map key: User socket session id (<ip:port>)
|
||||
*/
|
||||
std::unordered_map<std::string, std::string> pending_challenges;
|
||||
std::unordered_map<std::string, const std::string> pending_challenges;
|
||||
|
||||
/**
|
||||
* User session handler instance. This instance's methods will be fired for any user socket activity.
|
||||
@@ -152,7 +152,10 @@ int verify_user_challenge_response(std::string &extracted_pubkeyhex, std::string
|
||||
{
|
||||
// We load response raw bytes into json document.
|
||||
rapidjson::Document d;
|
||||
d.Parse(response.data());
|
||||
|
||||
// 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>(response.data());
|
||||
if (d.HasParseError())
|
||||
{
|
||||
LOG_INFO << "Challenge response json parsing failed.";
|
||||
@@ -226,7 +229,7 @@ int add_user(sock::socket_session<user_outbound_message> *session, const std::st
|
||||
}
|
||||
|
||||
// Populate sessionid map so we can lookup by user pubkey.
|
||||
sessionids[pubkey] = sessionid;
|
||||
sessionids.try_emplace(pubkey, sessionid);
|
||||
|
||||
return 0;
|
||||
}
|
||||
@@ -254,7 +257,7 @@ int remove_user(const std::string &sessionid)
|
||||
std::lock_guard<std::mutex> lock(users_mutex);
|
||||
sessionids.erase(user.pubkey);
|
||||
}
|
||||
|
||||
|
||||
users.erase(itr);
|
||||
return 0;
|
||||
}
|
||||
@@ -268,7 +271,6 @@ void start_listening()
|
||||
auto address = net::ip::make_address(conf::cfg.listenip);
|
||||
sess_opts.max_message_size = conf::cfg.pubmaxsize;
|
||||
|
||||
|
||||
std::make_shared<sock::socket_server<user_outbound_message>>(
|
||||
ioc,
|
||||
ctx,
|
||||
|
||||
@@ -4,6 +4,7 @@
|
||||
#include <cstdio>
|
||||
#include <string_view>
|
||||
#include <unordered_map>
|
||||
#include <list>
|
||||
#include <mutex>
|
||||
#include "../util.hpp"
|
||||
#include "../sock/socket_session.hpp"
|
||||
@@ -22,10 +23,10 @@ namespace usr
|
||||
struct connected_user
|
||||
{
|
||||
// User binary public key
|
||||
std::string pubkey;
|
||||
const std::string pubkey;
|
||||
|
||||
// Holds the unprocessed user input collected from websocket.
|
||||
std::string inbuffer;
|
||||
// Holds the unprocessed user inputs (and the hashes) collected from websocket.
|
||||
std::list<util::hash_buffer> inputs;
|
||||
|
||||
// Holds the websocket session of this user.
|
||||
// We don't need to own the session object since the lifetime of user and session are coupled.
|
||||
@@ -35,9 +36,9 @@ struct connected_user
|
||||
* @param _pubkey The public key of the user in binary format.
|
||||
*/
|
||||
connected_user(sock::socket_session<user_outbound_message> *_session, std::string_view _pubkey)
|
||||
: pubkey(_pubkey)
|
||||
{
|
||||
session = _session;
|
||||
pubkey = _pubkey;
|
||||
}
|
||||
};
|
||||
|
||||
@@ -52,12 +53,12 @@ extern std::mutex users_mutex; // Mutex for users access race conditions.
|
||||
* Keep track of verification-pending challenges issued to newly connected users.
|
||||
* Map key: User socket session id (<ip:port>)
|
||||
*/
|
||||
extern std::unordered_map<std::string, std::string> sessionids;
|
||||
extern std::unordered_map<std::string, const std::string> sessionids;
|
||||
|
||||
/**
|
||||
* Keep track of verification-pending challenges issued to newly connected users.
|
||||
*/
|
||||
extern std::unordered_map<std::string, std::string> pending_challenges;
|
||||
extern std::unordered_map<std::string, const std::string> pending_challenges;
|
||||
|
||||
int init();
|
||||
|
||||
|
||||
30
src/util.hpp
30
src/util.hpp
@@ -4,6 +4,7 @@
|
||||
#include <string>
|
||||
#include <vector>
|
||||
#include <rapidjson/document.h>
|
||||
#include "crypto.hpp"
|
||||
|
||||
/**
|
||||
* Contains helper functions and data structures used by multiple other subsystems.
|
||||
@@ -46,6 +47,35 @@ int version_compare(const std::string &x, const std::string &y);
|
||||
|
||||
std::string_view getsv(const rapidjson::Value &v);
|
||||
|
||||
/**
|
||||
* Represents a data buffer which calculates the hash of the buffer.
|
||||
*/
|
||||
struct hash_buffer
|
||||
{
|
||||
std::string hash;
|
||||
std::string buffer;
|
||||
|
||||
hash_buffer(std::string_view data)
|
||||
{
|
||||
buffer = data;
|
||||
}
|
||||
|
||||
hash_buffer(std::string_view data, std::string_view hashprefix)
|
||||
{
|
||||
buffer = data;
|
||||
|
||||
std::string timestr = std::to_string(get_epoch_milliseconds());
|
||||
|
||||
std::string stringtohash;
|
||||
stringtohash.reserve(hashprefix.length() + buffer.length() + timestr.length());
|
||||
stringtohash.append(hashprefix);
|
||||
stringtohash.append(buffer);
|
||||
stringtohash.append(timestr);
|
||||
|
||||
hash = crypto::sha_512_hash(stringtohash);
|
||||
}
|
||||
};
|
||||
|
||||
} // namespace util
|
||||
|
||||
#endif
|
||||
Reference in New Issue
Block a user