Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
20 commits
Select commit Hold shift + click to select a range
92d8b0a
Replace exclusive mutex acquisition with std::atomic<uint32_t> for
heifner Feb 14, 2026
8dd59a3
Use hashed_unique index
heifner Feb 14, 2026
9dfa97f
Since peer_connections() takes a lock, move it out of for_each_connec…
heifner Feb 14, 2026
fa3d870
Convert queued_buffer::_write_queue_size to std::atomic<uint32_t> to …
heifner Feb 14, 2026
3670de7
Run integrate_received_qc_to_block synchronously instead of posting to
heifner Feb 15, 2026
09a6392
Use atomic to avoid a mutex lock
heifner Feb 15, 2026
64eaaaa
Eliminate std::function heap allocation in queued_write for every enq…
heifner Feb 16, 2026
bfda0db
Replace peer_connections() heap-allocating unordered_flat_set copy wi…
heifner Feb 16, 2026
3bdd294
Eliminate per-peer boost::asio::post lambda heap allocations in broad…
heifner Feb 16, 2026
5f99839
Zero-allocation early dedup for duplicate inbound transactions.
heifner Feb 16, 2026
6214ce4
Revert "Zero-allocation early dedup for duplicate inbound transactions."
heifner Feb 17, 2026
bade46c
peer_xlog can only be called from connection strand. Change to fc_xlo…
heifner Feb 17, 2026
8991732
Wire-level transaction ID prefix for zero-allocation duplicate dedup.
heifner Feb 17, 2026
4e3cf82
Wire-level vote ID prefix for zero-allocation duplicate vote dedup.
heifner Feb 17, 2026
771a46a
Cache vote_id in vote_buffer_factory to avoid redundant SHA-256 in br…
heifner Feb 17, 2026
c8c7d6f
Update trx_generator to use new transaction_message structure.
heifner Feb 17, 2026
7706fc9
Use small_vector to avoid heap allocation
heifner Feb 17, 2026
5ac8669
Update _write_drain_pending in reset.
heifner Feb 19, 2026
1440a21
Ensures the early-duplicate fast path still records that this peer …
heifner Feb 19, 2026
f454daf
Remove pre-validation vote dedup caching to prevent cache poisoning.
heifner Feb 19, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions libraries/chain/controller.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2967,15 +2967,15 @@ struct controller_impl {
if (qc) {
verify_qc_future.get();
}
integrate_received_qc_to_block(bsp); // Save the received QC as soon as possible, no matter whether the block itself is valid or not

if (async_voting == async_t::yes) {
boost::asio::post(thread_pool.get_executor(), [this, bsp=bsp]() {
try {
integrate_received_qc_to_block(bsp); // Save the received QC as soon as possible, no matter whether the block itself is valid or not
consider_voting(bsp, use_thread_pool_t::no);
} FC_LOG_AND_DROP()
});
} else {
integrate_received_qc_to_block(bsp);
consider_voting(bsp, use_thread_pool_t::no);
}

Expand Down
63 changes: 59 additions & 4 deletions plugins/net_plugin/include/sysio/net_plugin/buffer_factory.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -134,11 +134,66 @@ namespace sysio {
private:

static send_buffer_type create_send_buffer( const packed_transaction_ptr& trx ) {
constexpr uint32_t packed_transaction_which = to_index(msg_type_t::packed_transaction);
constexpr uint32_t transaction_message_which = to_index(msg_type_t::transaction_message);

// this implementation is to avoid copy of packed_transaction to net_message
// matches which of net_message for packed_transaction
return buffer_factory::create_send_buffer( packed_transaction_which, *trx );
// Build bytes as [size][which][trx_id][packed_transaction]
// Avoids constructing a temporary net_transaction object.
const uint32_t which_size = fc::raw::pack_size( unsigned_int( transaction_message_which ) );
const uint32_t id_size = fc::raw::pack_size( trx->id() );
const uint32_t trx_size = fc::raw::pack_size( *trx );
const uint32_t payload_size = which_size + id_size + trx_size;

const char* const header = reinterpret_cast<const char* const>(&payload_size);
const size_t buffer_size = message_header_size + payload_size;

auto send_buffer = std::make_shared<vector<char>>( buffer_size );
fc::datastream<char*> ds( send_buffer->data(), buffer_size );
ds.write( header, message_header_size );
fc::raw::pack( ds, unsigned_int( transaction_message_which ) );
fc::raw::pack( ds, trx->id() );
fc::raw::pack( ds, *trx );

return send_buffer;
}
};

struct vote_buffer_factory : public buffer_factory {

/// caches result for subsequent calls, only provide same vote_message instance for each invocation.
const send_buffer_type& get_send_buffer( const vote_message& msg ) {
if( !send_buffer ) {
send_buffer = create_send_buffer( msg );
}
return send_buffer;
}

/// returns the vote_id computed during create_send_buffer; only valid after get_send_buffer called
const vote_id_type& get_vote_id() const { return last_vote_id_; }

private:
vote_id_type last_vote_id_;

send_buffer_type create_send_buffer( const vote_message& msg ) {
constexpr uint32_t vote_which = to_index(msg_type_t::vote_message);
last_vote_id_ = compute_vote_id(msg);

// Build wire bytes: [size][which][vote_id][vote_message]
const uint32_t which_size = fc::raw::pack_size( unsigned_int( vote_which ) );
const uint32_t id_size = fc::raw::pack_size( last_vote_id_ );
const uint32_t msg_size = fc::raw::pack_size( msg );
const uint32_t payload_size = which_size + id_size + msg_size;

const char* const header = reinterpret_cast<const char* const>(&payload_size);
const size_t buffer_size = message_header_size + payload_size;

auto send_buffer = std::make_shared<vector<char>>( buffer_size );
fc::datastream<char*> ds( send_buffer->data(), buffer_size );
ds.write( header, message_header_size );
fc::raw::pack( ds, unsigned_int( vote_which ) );
fc::raw::pack( ds, last_vote_id_ );
fc::raw::pack( ds, msg );

return send_buffer;
}
};

Expand Down
23 changes: 21 additions & 2 deletions plugins/net_plugin/include/sysio/net_plugin/protocol.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -2,13 +2,26 @@
#include <sysio/chain/block.hpp>
#include <sysio/chain/vote_message.hpp>
#include <sysio/chain/types.hpp>
#include <fc/io/raw.hpp>

namespace sysio {
using namespace chain;
using namespace fc;

constexpr auto message_header_size = sizeof(uint32_t);

using vote_id_type = fc::sha256;

/// Compute a deterministic vote ID from the non-signature fields of a vote_message.
/// vote_id = SHA-256(block_id || strong || serialized_finalizer_key)
inline vote_id_type compute_vote_id(const vote_message& v) {
auto enc = fc::sha256::encoder();
fc::raw::pack(enc, v.block_id);
fc::raw::pack(enc, v.strong);
fc::raw::pack(enc, v.finalizer_key);
return enc.result();
}

struct chain_size_message {
uint32_t last_irreversible_block_num = 0;
block_id_type last_irreversible_block_id;
Expand Down Expand Up @@ -144,6 +157,11 @@ namespace sysio {
block_id_type id;
};

struct transaction_message {
transaction_id_type id;
packed_transaction trx;
};

struct transaction_notice_message {
transaction_id_type id;
};
Expand Down Expand Up @@ -183,7 +201,7 @@ namespace sysio {
request_message,
sync_request_message,
signed_block,
packed_transaction,
transaction_message,
vote_message,
block_nack_message,
block_notice_message,
Expand All @@ -200,7 +218,7 @@ namespace sysio {
request_message = fc::get_index<net_message, request_message>(),
sync_request_message = fc::get_index<net_message, sync_request_message>(),
signed_block = fc::get_index<net_message, signed_block>(),
packed_transaction = fc::get_index<net_message, packed_transaction>(),
transaction_message = fc::get_index<net_message, transaction_message>(),
vote_message = fc::get_index<net_message, vote_message>(),
block_nack_message = fc::get_index<net_message, block_nack_message>(),
block_notice_message = fc::get_index<net_message, block_notice_message>(),
Expand Down Expand Up @@ -239,6 +257,7 @@ FC_REFLECT( sysio::request_message, (req_trx)(req_blocks) )
FC_REFLECT( sysio::sync_request_message, (start_block)(end_block) )
FC_REFLECT( sysio::block_nack_message, (id) )
FC_REFLECT( sysio::block_notice_message, (previous)(id) )
FC_REFLECT( sysio::transaction_message, (id)(trx) )
FC_REFLECT( sysio::transaction_notice_message, (id) )
FC_REFLECT( sysio::gossip_bp_peers_message::bp_peer_info_v1, (server_endpoint)(outbound_ip_address)(expiration) )
FC_REFLECT( sysio::gossip_bp_peers_message::bp_peer, (version)(producer_name)(bp_peer_info) )
Expand Down
Loading