peer: prevent last block height going backwards
This modifies the UpdateLastBlockHeight function to ensure the new height is after the existing height before updating it in order to prevent it from going backwards so it properly matches the intent of the function which is to report the latest known block height for the peer. Without this change, the value will properly start out at the latest known block height reported by the peer during version negotiation, however, it will be set to lower values when syncing from the peer due to requesting old blocks and blindly updating the height. It also adds a test to ensure proper functionality. This is a backport of https://github.com/decred/dcrd/pull/1747
This commit is contained in:
parent
efae8e9967
commit
7d69fb9ba6
2 changed files with 70 additions and 0 deletions
|
@ -495,6 +495,10 @@ func (p *Peer) String() string {
|
||||||
// This function is safe for concurrent access.
|
// This function is safe for concurrent access.
|
||||||
func (p *Peer) UpdateLastBlockHeight(newHeight int32) {
|
func (p *Peer) UpdateLastBlockHeight(newHeight int32) {
|
||||||
p.statsMtx.Lock()
|
p.statsMtx.Lock()
|
||||||
|
if newHeight <= p.lastBlock {
|
||||||
|
p.statsMtx.Unlock()
|
||||||
|
return
|
||||||
|
}
|
||||||
log.Tracef("Updating last block height of peer %v from %v to %v",
|
log.Tracef("Updating last block height of peer %v from %v to %v",
|
||||||
p.addr, p.lastBlock, newHeight)
|
p.addr, p.lastBlock, newHeight)
|
||||||
p.lastBlock = newHeight
|
p.lastBlock = newHeight
|
||||||
|
|
|
@ -917,6 +917,72 @@ func TestDuplicateVersionMsg(t *testing.T) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// TestUpdateLastBlockHeight ensures the last block height is set properly
|
||||||
|
// during the initial version negotiation and is only allowed to advance to
|
||||||
|
// higher values via the associated update function.
|
||||||
|
func TestUpdateLastBlockHeight(t *testing.T) {
|
||||||
|
// Create a pair of peers that are connected to each other using a fake
|
||||||
|
// connection and the remote peer starting at height 100.
|
||||||
|
const remotePeerHeight = 100
|
||||||
|
verack := make(chan struct{})
|
||||||
|
peerCfg := peer.Config{
|
||||||
|
Listeners: peer.MessageListeners{
|
||||||
|
OnVerAck: func(p *peer.Peer, msg *wire.MsgVerAck) {
|
||||||
|
verack <- struct{}{}
|
||||||
|
},
|
||||||
|
},
|
||||||
|
UserAgentName: "peer",
|
||||||
|
UserAgentVersion: "1.0",
|
||||||
|
ChainParams: &chaincfg.MainNetParams,
|
||||||
|
Services: 0,
|
||||||
|
}
|
||||||
|
remotePeerCfg := peerCfg
|
||||||
|
remotePeerCfg.NewestBlock = func() (*chainhash.Hash, int32, error) {
|
||||||
|
return &chainhash.Hash{}, remotePeerHeight, nil
|
||||||
|
}
|
||||||
|
inConn, outConn := pipe(
|
||||||
|
&conn{laddr: "10.0.0.1:9108", raddr: "10.0.0.2:9108"},
|
||||||
|
&conn{laddr: "10.0.0.2:9108", raddr: "10.0.0.1:9108"},
|
||||||
|
)
|
||||||
|
localPeer, err := peer.NewOutboundPeer(&peerCfg, inConn.laddr)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("NewOutboundPeer: unexpected err: %v\n", err)
|
||||||
|
}
|
||||||
|
localPeer.AssociateConnection(outConn)
|
||||||
|
inPeer := peer.NewInboundPeer(&remotePeerCfg)
|
||||||
|
inPeer.AssociateConnection(inConn)
|
||||||
|
|
||||||
|
// Wait for the veracks from the initial protocol version negotiation.
|
||||||
|
for i := 0; i < 2; i++ {
|
||||||
|
select {
|
||||||
|
case <-verack:
|
||||||
|
case <-time.After(time.Second):
|
||||||
|
t.Fatal("verack timeout")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Ensure the latest block height starts at the value reported by the remote
|
||||||
|
// peer via its version message.
|
||||||
|
if height := localPeer.LastBlock(); height != remotePeerHeight {
|
||||||
|
t.Fatalf("wrong starting height - got %d, want %d", height,
|
||||||
|
remotePeerHeight)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Ensure the latest block height is not allowed to go backwards.
|
||||||
|
localPeer.UpdateLastBlockHeight(remotePeerHeight - 1)
|
||||||
|
if height := localPeer.LastBlock(); height != remotePeerHeight {
|
||||||
|
t.Fatalf("height allowed to go backwards - got %d, want %d", height,
|
||||||
|
remotePeerHeight)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Ensure the latest block height is allowed to advance.
|
||||||
|
localPeer.UpdateLastBlockHeight(remotePeerHeight + 1)
|
||||||
|
if height := localPeer.LastBlock(); height != remotePeerHeight+1 {
|
||||||
|
t.Fatalf("height not allowed to advance - got %d, want %d", height,
|
||||||
|
remotePeerHeight+1)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
func init() {
|
func init() {
|
||||||
// Allow self connection when running the tests.
|
// Allow self connection when running the tests.
|
||||||
peer.TstAllowSelfConns()
|
peer.TstAllowSelfConns()
|
||||||
|
|
Loading…
Reference in a new issue