@@ -4,14 +4,17 @@ import (
44 "encoding/binary"
55 "fmt"
66 "math/rand"
7+ "reflect"
78 "strings"
89 "testing"
910 "time"
1011
12+ "github.com/btcsuite/btcd/blockchain"
1113 "github.com/btcsuite/btcd/btcutil/gcs"
1214 "github.com/btcsuite/btcd/btcutil/gcs/builder"
1315 "github.com/btcsuite/btcd/chaincfg"
1416 "github.com/btcsuite/btcd/chaincfg/chainhash"
17+ "github.com/btcsuite/btcd/integration/rpctest"
1518 "github.com/btcsuite/btcd/peer"
1619 "github.com/btcsuite/btcd/txscript"
1720 "github.com/btcsuite/btcd/wire"
@@ -90,6 +93,7 @@ func setupBlockManager(t *testing.T) (*blockManager, headerfs.BlockHeaderStore,
9093 BlockHeaders : hdrStore ,
9194 RegFilterHeaders : cfStore ,
9295 QueryDispatcher : & mockDispatcher {},
96+ TimeSource : blockchain .NewMedianTime (),
9397 BanPeer : func (string , banman.Reason ) error {
9498 return nil
9599 },
@@ -865,3 +869,79 @@ func TestBlockManagerDetectBadPeers(t *testing.T) {
865869 require .NoError (t , err )
866870 }
867871}
872+
873+ // TestHandleHeaders checks that we handle headers correctly, and that we
874+ // disconnect peers that serve us bad headers (headers that don't connect to
875+ // each other properly).
876+ func TestHandleHeaders (t * testing.T ) {
877+ t .Parallel ()
878+
879+ // First, we set up a block manager and a fake peer that will act as the
880+ // test's remote peer.
881+ bm , _ , _ , err := setupBlockManager (t )
882+ require .NoError (t , err )
883+
884+ fakePeer , err := peer .NewOutboundPeer (& peer.Config {}, "fake:123" )
885+ require .NoError (t , err )
886+
887+ assertPeerDisconnected := func (shouldBeDisconnected bool ) {
888+ // This is quite hacky but works: We expect the peer to be
889+ // disconnected, which sets the unexported "disconnected" field
890+ // to 1.
891+ refValue := reflect .ValueOf (fakePeer ).Elem ()
892+ foo := refValue .FieldByName ("disconnect" ).Int ()
893+
894+ if shouldBeDisconnected {
895+ require .EqualValues (t , 1 , foo )
896+ } else {
897+ require .EqualValues (t , 0 , foo )
898+ }
899+ }
900+
901+ // We'll want to use actual, real blocks, so we take a miner harness
902+ // that we can use to generate some.
903+ harness , err := rpctest .New (
904+ & chaincfg .SimNetParams , nil , []string {"--txindex" }, "" ,
905+ )
906+ require .NoError (t , err )
907+ t .Cleanup (func () {
908+ require .NoError (t , harness .TearDown ())
909+ })
910+
911+ err = harness .SetUp (false , 0 )
912+ require .NoError (t , err )
913+
914+ // Generate 200 valid blocks that we then feed to the block manager.
915+ blockHashes , err := harness .Client .Generate (200 )
916+ require .NoError (t , err )
917+
918+ hmsg := & headersMsg {
919+ headers : & wire.MsgHeaders {
920+ Headers : make ([]* wire.BlockHeader , len (blockHashes )),
921+ },
922+ peer : & ServerPeer {
923+ Peer : fakePeer ,
924+ },
925+ }
926+
927+ for i := range blockHashes {
928+ header , err := harness .Client .GetBlockHeader (blockHashes [i ])
929+ require .NoError (t , err )
930+
931+ hmsg .headers .Headers [i ] = header
932+ }
933+
934+ // Let's feed in the correct headers. This should work fine and the peer
935+ // should not be disconnected.
936+ bm .handleHeadersMsg (hmsg )
937+ assertPeerDisconnected (false )
938+
939+ // Now scramble the headers and feed them in again. This should cause
940+ // the peer to be disconnected.
941+ rand .Shuffle (len (hmsg .headers .Headers ), func (i , j int ) {
942+ hmsg .headers .Headers [i ], hmsg .headers .Headers [j ] =
943+ hmsg .headers .Headers [j ], hmsg .headers .Headers [i ]
944+ })
945+ bm .handleHeadersMsg (hmsg )
946+ assertPeerDisconnected (true )
947+ }
0 commit comments