diff --git a/netsync/manager.go b/netsync/manager.go index 44c5fac66b..73260c56fb 100644 --- a/netsync/manager.go +++ b/netsync/manager.go @@ -6,7 +6,6 @@ package netsync import ( "math/rand" - "net" "sync" "sync/atomic" "time" @@ -364,19 +363,12 @@ func (sm *SyncManager) isSyncCandidate(peer *peerpkg.Peer) bool { // Typically a peer is not a candidate for sync if it's not a full node, // however regression test is special in that the regression tool is // not a full node and still needs to be considered a sync candidate. - if sm.chainParams == &chaincfg.RegressionNetParams { - // The peer is not a candidate if it's not coming from localhost - // or the hostname can't be determined for some reason. - host, _, err := net.SplitHostPort(peer.Addr()) - if err != nil { - return false - } - - if host != "127.0.0.1" && host != "localhost" { - return false - } - - // Candidate if all checks passed. + switch sm.chainParams.Name { + case chaincfg.RegressionNetParams.Name, chaincfg.SimNetParams.Name: + // In regtest/simnet mode, any peer is a valid sync candidate + // regardless of its address or service flags. This allows + // syncing from peers on non-localhost networks such as Docker + // bridge networks. return true } @@ -715,7 +707,7 @@ func (sm *SyncManager) handleBlockMsg(bmsg *blockMsg) { // the peer or ignore the block when we're in regression test // mode in this case so the chain code is actually fed the // duplicate blocks. - if sm.chainParams != &chaincfg.RegressionNetParams { + if sm.chainParams.Name != chaincfg.RegressionNetParams.Name { log.Warnf("Got unrequested block %v from %s -- "+ "disconnecting", blockHash, peer.Addr()) peer.Disconnect() diff --git a/netsync/manager_test.go b/netsync/manager_test.go index becf1a7e99..73eb0d51a8 100644 --- a/netsync/manager_test.go +++ b/netsync/manager_test.go @@ -1213,3 +1213,52 @@ func TestStartSyncChainCurrent(t *testing.T) { require.False(t, sm.ibdMode, "ibdMode should not be activated when chain is already current") } + +// TestIsSyncCandidateRegtest verifies that isSyncCandidate accepts any peer +// on regtest regardless of address, including non-localhost Docker bridge +// addresses. +func TestIsSyncCandidateRegtest(t *testing.T) { + t.Parallel() + + params := chaincfg.RegressionNetParams + sm, tearDown := makeMockSyncManager(t, ¶ms) + defer tearDown() + + tests := []struct { + name string + addr string + want bool + }{ + { + name: "localhost", + addr: "127.0.0.1:18444", + want: true, + }, + { + name: "docker bridge ip", + addr: "172.18.0.2:18444", + want: true, + }, + { + name: "remote ip", + addr: "93.184.216.34:18444", + want: true, + }, + { + name: "ipv6 loopback", + addr: "[::1]:18444", + want: true, + }, + } + + for _, tc := range tests { + t.Run(tc.name, func(t *testing.T) { + p := peer.NewInboundPeer(&peer.Config{ + ChainParams: sm.chainParams, + }) + + got := sm.isSyncCandidate(p) + require.Equal(t, tc.want, got) + }) + } +}