I understand that in selfish mining a malicious node can "send its entire hidden chain". Exactly how is this done? I know that usually a single block is broadcast-ed right after it is mined, but how does it relay an entire chain?
Forks appear naturally, when two miners produce competing blocks approximately simultaneously. Such forks may have arbitrary length (thankfully, with exponentially decreasing probability under reasonable assumptions), which may need to be resolved. Doing so involves having a mechanism of synchronizing chains where the receiver is missing multiple blocks. So there isn't anything special here, it's just the normal protocol for relaying blocks that is used.
What that protocol is depends on the software used.
The basic approach involves sending an
inv for the new tip. The receiver will then fetch the block using
getdata, notice it is missing its parent, and ask for that parent using another
getdata and so forth, until it reaches a parent that the receiver already has.
Since Bitcoin Core 0.10, nodes will respond to an
inv with a
getheaders, to retrieve all block headers between a point the receiver already has and the announced tip. The request contains a list of recent block hashes the receiver has to avoid duplicating things. Only when the receiver has all the headers, and has validated them, it will start asking for the full blocks that are missing along the way. This permits fetching blocks from multiple peers in parallel.
Since the adding support for BIP130 ("sendheaders") in Bitcoin Core 0.12, announcements of new blocks themselves are done by immediately sending the headers, avoiding an
Since adding support for BIP152 ("compact blocks") in Bitcoin Core 0.13, blocks can also be announced (in negotiated cases) without any
headers message at all, instead sending a compact block directly (which uses an encoding that avoids transactions the receiver is assumed to already have). In case there are missing transactions, or parent blocks, those are requested using the normal means (
Note that all mechanisms are still available for all nodes on the network. The more modern ones are generally superior, but older or simpler software implementations can still use the
getdata approach if desired.