peer: always send latest block header as part of ping messages

In this commit, we implement a long discussed mechanism to use the
Lightning Network as a redundant block header source. By sending our
latest block header with each ping message, we give peers another source
(outside of the Bitcoin P2P network) they can use to spot check their
chain state. Peers can also use this information to detect if they've
been eclipsed from the traditional Bitcoin P2P network itself.

As is, we only send this data in Ping messages (which are periodically
sent), in the future we could also move to send them as the partial
payload for our pong messages, and also randomize the payload size
requested as well.
This commit is contained in:
Olaoluwa Osuntokun
2021-08-11 16:08:30 -07:00
parent 0d8ffd95dd
commit d566e51a52

View File

@@ -1368,6 +1368,8 @@ out:
atomic.StoreInt64(&p.pingTime, delay)
case *lnwire.Ping:
// TODO(roasbeef): get from buffer pool somewhere? ends
// up w/ lots of small allocations
pongBytes := make([]byte, msg.NumPongBytes)
p.queueMsg(lnwire.NewPong(pongBytes), nil)
@@ -1983,13 +1985,44 @@ func (p *Brontide) pingHandler() {
defer pingTicker.Stop()
// TODO(roasbeef): make dynamic in order to create fake cover traffic
const numPingBytes = 16
const numPongBytes = 16
blockEpochs, err := p.cfg.ChainNotifier.RegisterBlockEpochNtfn(nil)
if err != nil {
peerLog.Errorf("unable to establish block epoch "+
"subscription: %v", err)
}
var (
pingPayload [wire.MaxBlockHeaderPayload]byte
blockHeader *wire.BlockHeader
)
out:
for {
select {
// Each time a new block comes in, we'll copy the raw header
// contents over to our ping payload declared above. Over time,
// we'll use this to disseminate the latest block header
// between all our peers, which can later be used to
// cross-check our own view of the network to mitigate various
// types of eclipse attacks.
case epoch := <-blockEpochs.Epochs:
blockHeader = epoch.BlockHeader
headerBuf := bytes.NewBuffer(pingPayload[0:0])
err := blockHeader.Serialize(headerBuf)
if err != nil {
peerLog.Errorf("unable to encode header: %v",
err)
}
case <-pingTicker.C:
p.queueMsg(lnwire.NewPing(numPingBytes), nil)
pingMsg := &lnwire.Ping{
NumPongBytes: numPongBytes,
PaddingBytes: pingPayload[:],
}
p.queueMsg(pingMsg, nil)
case <-p.quit:
break out
}