mirror of
https://github.com/EvernodeXRPL/hpcore.git
synced 2026-04-29 15:37:59 +00:00
Basic consensus implementation (#45)
Consensus for user connections, user inputs, contract outputs and time.
This commit is contained in:
@@ -6,6 +6,7 @@
|
||||
#include "../hplog.hpp"
|
||||
#include "p2p.hpp"
|
||||
#include "peer_session_handler.hpp"
|
||||
#include "peer_message_handler.hpp"
|
||||
#include "message_content_generated.h"
|
||||
#include "message_container_generated.h"
|
||||
|
||||
@@ -32,70 +33,6 @@ std::string_view peer_outbound_message::buffer()
|
||||
(*fbbuilder_ptr).GetSize());
|
||||
}
|
||||
|
||||
//private method used to create a proposal message with dummy data.
|
||||
//Will be similiar to consensus proposal creation in each stage.
|
||||
const std::string create_message(flatbuffers::FlatBufferBuilder &container_builder)
|
||||
{
|
||||
//todo:get a average propsal message size and allocate builder based on that.
|
||||
/*
|
||||
* todo: create custom vector allocator for protobuff in order to avoid copying buffer to string.
|
||||
* includes overidding socket_session send method to support this as well.
|
||||
*/
|
||||
flatbuffers::FlatBufferBuilder builder(1024);
|
||||
std::time_t timestamp = std::time(nullptr);
|
||||
uint8_t stage = 0;
|
||||
|
||||
std::string pubkey = conf::cfg.pubkey;
|
||||
flatbuffers::Offset<flatbuffers::Vector<uint8_t>> pubkey_b = builder.CreateVector((uint8_t *)pubkey.data(), pubkey.size());
|
||||
|
||||
//create dummy propsal message
|
||||
flatbuffers::Offset<Proposal> proposal = CreateProposal(builder, pubkey_b, timestamp, stage, timestamp);
|
||||
flatbuffers::Offset<Content> message = CreateContent(builder, Message_Proposal, proposal.Union());
|
||||
builder.Finish(message); //finished building message content to get serialised content.
|
||||
|
||||
//Get serialized/packed message content pointer and size.
|
||||
uint8_t *buf = builder.GetBufferPointer();
|
||||
flatbuffers::uoffset_t size = builder.GetSize();
|
||||
|
||||
//Get a binary string_view for the serialised message content.
|
||||
const char *content_str = reinterpret_cast<const char *>(buf);
|
||||
std::string_view message_content(content_str, size);
|
||||
|
||||
//create container message content from serialised content from previous step.
|
||||
flatbuffers::Offset<flatbuffers::Vector<uint8_t>> content = container_builder.CreateVector(buf, size);
|
||||
|
||||
//Sign message content with node's private key.
|
||||
std::string sig = crypto::sign(message_content, conf::cfg.seckey);
|
||||
char *sig_buf = sig.data();
|
||||
flatbuffers::Offset<flatbuffers::Vector<uint8_t>> signature = container_builder.CreateVector((uint8_t *)sig_buf, sig.size()); //include signature to message
|
||||
|
||||
flatbuffers::Offset<Container> container_message = CreateContainer(container_builder, util::MIN_PEERMSG_VERSION, signature, content);
|
||||
container_builder.Finish(container_message); //finished building message container to get serialised message.
|
||||
|
||||
flatbuffers::uoffset_t buf_size = container_builder.GetSize();
|
||||
uint8_t *message_buf = container_builder.GetBufferPointer();
|
||||
|
||||
//todo: should return buffer_pointer to socket.
|
||||
return std::string((char *)message_buf, buf_size);
|
||||
}
|
||||
|
||||
/**
|
||||
* Private method to return string_view from flat buffer data pointer and length.
|
||||
*/
|
||||
std::string_view flatbuff_bytes_to_sv(const uint8_t *data, flatbuffers::uoffset_t length)
|
||||
{
|
||||
const char *signature_content_str = reinterpret_cast<const char *>(data);
|
||||
return std::string_view(signature_content_str, length);
|
||||
}
|
||||
|
||||
/**
|
||||
* Private method to return 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());
|
||||
}
|
||||
|
||||
/**
|
||||
* This gets hit every time a peer connects to HP via the peer port (configured in contract config).
|
||||
*/
|
||||
@@ -105,15 +42,20 @@ void peer_session_handler::on_connect(sock::socket_session<peer_outbound_message
|
||||
{
|
||||
// We init the session unique id to associate with the challenge.
|
||||
session->init_uniqueid();
|
||||
peer_connections.insert(std::make_pair(session->uniqueid, session));
|
||||
{
|
||||
std::lock_guard<std::mutex> lock(p2p::peer_connections_mutex);
|
||||
peer_connections.insert(std::make_pair(session->uniqueid, session));
|
||||
}
|
||||
LOG_DBG << "Adding peer to list: " << session->uniqueid;
|
||||
}
|
||||
else
|
||||
{
|
||||
// todo: set container builder defualt builder size to combination of serialized content length + signature length(which is fixed)
|
||||
peer_outbound_message msg(std::make_shared<flatbuffers::FlatBufferBuilder>(1024));
|
||||
std::string message = create_message(msg.builder());
|
||||
session->send(msg);
|
||||
// peer_outbound_message msg(std::make_shared<flatbuffers::FlatBufferBuilder>(1024));
|
||||
|
||||
// proposal p;
|
||||
// create_msg_from_proposal(msg.builder(), p);
|
||||
// session->send(msg);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -121,93 +63,66 @@ void peer_session_handler::on_connect(sock::socket_session<peer_outbound_message
|
||||
//validate and handle each type of peer messages.
|
||||
void peer_session_handler::on_message(sock::socket_session<peer_outbound_message> *session, std::string_view message)
|
||||
{
|
||||
//Accessing message buffer
|
||||
const uint8_t *container_pointer = reinterpret_cast<const uint8_t *>(message.data());
|
||||
size_t container_length = message.length();
|
||||
const Container *container;
|
||||
if (validate_and_extract_container(&container, message) != 0)
|
||||
return;
|
||||
|
||||
//Defining Flatbuffer verifier (default max depth = 64, max_tables = 1000000,)
|
||||
flatbuffers::Verifier container_verifier(container_pointer, container_length);
|
||||
//Get serialised message content.
|
||||
const flatbuffers::Vector<uint8_t> *container_content = container->content();
|
||||
|
||||
//Verify container message using flatbuffer verifier
|
||||
if (VerifyContainerBuffer(container_verifier))
|
||||
//Accessing message content and size.
|
||||
const uint8_t *content_ptr = container_content->Data();
|
||||
flatbuffers::uoffset_t content_size = container_content->size();
|
||||
|
||||
const Content *content;
|
||||
if (validate_and_extract_content(&content, content_ptr, content_size) != 0)
|
||||
return;
|
||||
|
||||
p2p::Message content_message_type = content->message_type(); //i.e - proposal, npl, state request, state response, etc
|
||||
|
||||
if (content_message_type == Message_Proposal_Message) //message is a proposal message
|
||||
{
|
||||
//Get message container
|
||||
const p2p::Container *container = GetContainer(container_pointer);
|
||||
const uint16_t version = container->version();
|
||||
const Proposal_Message *proposalmsg = content->message_as_Proposal_Message();
|
||||
|
||||
//validate message for malleability, timeliness, signature and prune recieving messages.
|
||||
bool val_result = validate_content_message(
|
||||
flatbuff_bytes_to_sv(content_ptr, content_size),
|
||||
flatbuff_bytes_to_sv(container->signature()),
|
||||
flatbuff_bytes_to_sv(proposalmsg->pubkey()),
|
||||
proposalmsg->timestamp());
|
||||
|
||||
//Get serialised message content.
|
||||
const flatbuffers::Vector<uint8_t> *container_content = container->content();
|
||||
|
||||
//Accessing message content and size.
|
||||
const uint8_t *content_pointer = container_content->Data();
|
||||
flatbuffers::uoffset_t content_size = container_content->size();
|
||||
|
||||
//Defining Flatbuffer verifier for content message verification.
|
||||
//Since content is also serialised by using Filterbuf we can verify it using Filterbuffer.
|
||||
flatbuffers::Verifier content_verifier(content_pointer, content_size);
|
||||
|
||||
//verify content message conent using flatbuffer verifier.
|
||||
if (VerifyContainerBuffer(content_verifier))
|
||||
if (val_result == 0)
|
||||
{
|
||||
//Get message content.
|
||||
const Content *content = GetContent(content_pointer);
|
||||
p2p::Message content_message_type = content->message_type(); //i.e - proposal, npl, state request, state response, etc
|
||||
|
||||
if (content_message_type == Message_Proposal) //message is a proposal message
|
||||
{
|
||||
const Proposal *proposal = content->message_as_Proposal();
|
||||
uint64_t timestamp = proposal->timestamp();
|
||||
|
||||
//Get public key of message originating node.
|
||||
std::string_view message_pubkey = flatbuff_bytes_to_sv(proposal->pubkey());
|
||||
|
||||
//Get signature from container message.
|
||||
std::string_view message_signature = flatbuff_bytes_to_sv(container->signature());
|
||||
|
||||
std::string_view message_content = flatbuff_bytes_to_sv(content_pointer, content_size);
|
||||
|
||||
//validate message for malleability, timeliness, signature and prune recieving messages.
|
||||
bool validated = p2p::validate_peer_message(message_content, message_signature, message_pubkey, timestamp, version);
|
||||
if (validated)
|
||||
{
|
||||
//if validated send message to consensus.
|
||||
//if validated broadcast message.
|
||||
}
|
||||
else
|
||||
{
|
||||
LOG_DBG << "Message validation failed";
|
||||
}
|
||||
}
|
||||
else if (content_message_type == Message_Npl) //message is a proposal message
|
||||
{
|
||||
const Npl *npl = content->message_as_Npl();
|
||||
// execute npl logic here.
|
||||
//broadcast message.
|
||||
}
|
||||
else
|
||||
{
|
||||
//warn received invalid message from peer.
|
||||
LOG_DBG << "Received invalid message type from peer";
|
||||
//remove/penalize node who sent the message.
|
||||
}
|
||||
std::lock_guard<std::mutex> lock(collected_msgs.proposals_mutex);
|
||||
collected_msgs.proposals.push_back(create_proposal_from_msg(*proposalmsg));
|
||||
}
|
||||
else
|
||||
{
|
||||
//warn bad message content.
|
||||
LOG_DBG << "Bad message content";
|
||||
LOG_DBG << "Message content field validation failed";
|
||||
}
|
||||
}
|
||||
else if (content_message_type == Message_Npl_Message) //message is a NPL message
|
||||
{
|
||||
const Npl_Message *npl = content->message_as_Npl_Message();
|
||||
// execute npl logic here.
|
||||
//broadcast message.
|
||||
}
|
||||
else
|
||||
{
|
||||
//warn bad messages from peer.
|
||||
LOG_DBG << "Bad message from peer";
|
||||
//warn received invalid message from peer.
|
||||
LOG_DBG << "Received invalid message type from peer";
|
||||
//TODO: remove/penalize node who sent the message.
|
||||
}
|
||||
}
|
||||
|
||||
//peer session on message callback method
|
||||
void peer_session_handler::on_close(sock::socket_session<peer_outbound_message> *session)
|
||||
{
|
||||
LOG_DBG << "on_closing peer :" << session->uniqueid;
|
||||
{
|
||||
std::lock_guard<std::mutex> lock(p2p::peer_connections_mutex);
|
||||
peer_connections.erase(session->uniqueid);
|
||||
}
|
||||
LOG_DBG << "Peer disonnected: " << session->uniqueid;
|
||||
}
|
||||
|
||||
} // namespace p2p
|
||||
Reference in New Issue
Block a user