A node cannot send a block to a peer. The block is found and its size computed correctly, then zero bytes are written and the channel is dropped.
Present on master (9099a906, libbitcoin-node 2b377d16) in default configuration. This is the v1 transport; enable_privacy defaults to false.
Steps to trigger
- Run bs with inbound connections enabled.
- Connect a peer and complete the version/verack handshake.
- Send
getdata with MSG_BLOCK (or MSG_WITNESS_BLOCK) and the hash of a block the node holds.
- The peer receives zero bytes and the node closes the connection.
MSG_TX on the same channel serves normally. bitcoind answers the same request with the block and stays connected.
Observed
Recv getdata from [...] (37 bytes)
Send block to [...] (285 bytes)
Send failure block to [...] (0 bytes) bad data stream
Inbound peer channel stop [...] bad data stream
Mechanism
channel_peer::send type-erases the message and carries a registry index instead:
out.message = rpc::any_t{ system::to_shared(message) };
out.index = rpc::peer_registry::index_of<Message>();
peer_dispatch.hpp registers 35 types, all messages::peer::*; the only "block" entry is messages::peer::block. libbitcoin-node sends its own node::messages::block, which is not registered, so index_of returns unknown (= size = 35) and peer_registry::to_frame returns null. That becomes bad_stream and stops the channel.
The 285 in the log is message.size(), logged before serialization is attempted. index_of is constexpr, so nothing on the wire affects it.
Introduced by
01d95d9f "Write bip324 messages natively", which replaced serialization at the send site with the registry lookup. git log -S index_of -- channel_peer.hpp returns only this commit.
Why tests didn't catch it
Each registered message is tested here with index_of<T>() then commands().at(index), which throws for unknown. All 35 registered types have one. node::messages::block cannot have one — the test lives in the repo that has no knowledge of node's types.
libbitcoin-node's test/messages/block.cpp passes, because node::messages::block::serialize is correct in isolation; nothing calls it. Its test/protocols/protocol.cpp is BOOST_REQUIRE(true).
A node cannot send a block to a peer. The block is found and its size computed correctly, then zero bytes are written and the channel is dropped.
Present on master (
9099a906, libbitcoin-node2b377d16) in default configuration. This is the v1 transport;enable_privacydefaults tofalse.Steps to trigger
getdatawithMSG_BLOCK(orMSG_WITNESS_BLOCK) and the hash of a block the node holds.MSG_TXon the same channel serves normally. bitcoind answers the same request with the block and stays connected.Observed
Mechanism
channel_peer::sendtype-erases the message and carries a registry index instead:peer_dispatch.hppregisters 35 types, allmessages::peer::*; the only"block"entry ismessages::peer::block. libbitcoin-node sends its ownnode::messages::block, which is not registered, soindex_ofreturnsunknown(= size= 35) andpeer_registry::to_framereturns null. That becomesbad_streamand stops the channel.The
285in the log ismessage.size(), logged before serialization is attempted.index_ofisconstexpr, so nothing on the wire affects it.Introduced by
01d95d9f"Write bip324 messages natively", which replaced serialization at the send site with the registry lookup.git log -S index_of -- channel_peer.hppreturns only this commit.Why tests didn't catch it
Each registered message is tested here with
index_of<T>()thencommands().at(index), which throws forunknown. All 35 registered types have one.node::messages::blockcannot have one — the test lives in the repo that has no knowledge of node's types.libbitcoin-node's
test/messages/block.cpppasses, becausenode::messages::block::serializeis correct in isolation; nothing calls it. Itstest/protocols/protocol.cppisBOOST_REQUIRE(true).