dnsseeder/zcash/client_test.go

300 lines
6.5 KiB
Go

package zcash
import (
"fmt"
"net"
"os"
"sync"
"sync/atomic"
"testing"
"time"
"github.com/btcsuite/btcd/peer"
"github.com/btcsuite/btcd/wire"
"github.com/btcsuite/btclog"
"github.com/zcashfoundation/dnsseeder/zcash/network"
)
// useAddrV2 specifies if startMockLoop() should send addrv2 messages or regular addr.
// It's an uint32 since it's used with the atomic package.
var useAddrV2 uint32
func TestMain(m *testing.M) {
err := startMockLoop()
if err != nil {
fmt.Printf("Failed to start mock loop!")
os.Exit(1)
}
exitCode := m.Run()
os.Exit(exitCode)
}
func startMockLoop() error {
// Configure peer to act as a regtest node that offers no services.
config, err := newSeederPeerConfig(network.Regtest, defaultPeerConfig)
if err != nil {
return err
}
config.AllowSelfConns = true
backendLogger := btclog.NewBackend(os.Stdout)
mockPeerLogger := backendLogger.Logger("mockPeer")
//mockPeerLogger.SetLevel(btclog.LevelTrace)
peer.UseLogger(mockPeerLogger)
config.Listeners.OnGetAddr = func(p *peer.Peer, msg *wire.MsgGetAddr) {
// This will an unusable peer (testnet port)
addr := wire.NewNetAddressTimestamp(
time.Now(),
0,
net.ParseIP("127.0.0.1"),
uint16(18233),
)
// This will be an unusable peer (bs port)
addr2 := wire.NewNetAddressTimestamp(
time.Now(),
0,
net.ParseIP("127.0.0.1"),
uint16(31337),
)
// This will be a usable peer, corresponding to our second listener.
addr3 := wire.NewNetAddressTimestamp(
time.Now(),
0,
net.ParseIP("127.0.0.1"),
uint16(12345),
)
if atomic.LoadUint32(&useAddrV2) != 0 {
cache := make([]*wire.NetAddressV2, 0, 1)
addrv2_1 := wire.NewNetAddressV2NetAddress(addr)
addrv2_2 := wire.NewNetAddressV2NetAddress(addr2)
addrv2_3 := wire.NewNetAddressV2NetAddress(addr3)
cache = append(cache, addrv2_1, addrv2_2, addrv2_3)
_, err := p.PushAddrV2Msg(cache)
if err != nil {
mockPeerLogger.Error(err)
}
} else {
cache := make([]*wire.NetAddress, 0, 1)
cache = append(cache, addr, addr2, addr3)
_, err := p.PushAddrMsg(cache)
if err != nil {
mockPeerLogger.Error(err)
}
}
}
listener1, err := net.Listen("tcp", net.JoinHostPort("127.0.0.1", config.ChainParams.DefaultPort))
if err != nil {
return err
}
listener2, err := net.Listen("tcp", net.JoinHostPort("127.0.0.1", "12345"))
if err != nil {
return err
}
go func() {
for {
conn, err := listener1.Accept()
if err != nil {
return
}
mockPeer := peer.NewInboundPeer(config)
mockPeer.AssociateConnection(conn)
}
}()
go func() {
for {
conn, err := listener2.Accept()
if err != nil {
return
}
defaultConfig, _ := newSeederPeerConfig(network.Regtest, defaultPeerConfig)
defaultConfig.AllowSelfConns = true
mockPeer := peer.NewInboundPeer(defaultConfig)
mockPeer.AssociateConnection(conn)
}
}()
return nil
}
func TestOutboundPeerSync(t *testing.T) {
regSeeder, err := newTestSeeder(network.Regtest)
if err != nil {
t.Error(err)
return
}
err = regSeeder.ConnectOnDefaultPort("127.0.0.1")
if err != nil {
t.Error(err)
return
}
// Can we address that peer if we want to?
p, err := regSeeder.GetPeer("127.0.0.1:18344")
if err != nil {
t.Error(err)
return
}
if p.Connected() {
regSeeder.DisconnectPeer("127.0.0.1:18344")
} else {
t.Error("Peer never connected")
}
// Can we STILL address a flushed peer?
p, err = regSeeder.GetPeer("127.0.0.1:18344")
if err != ErrNoSuchPeer {
t.Error("Peer should have been cleared on disconnect")
}
}
func TestOutboundPeerAsync(t *testing.T) {
regSeeder, err := newTestSeeder(network.Regtest)
if err != nil {
t.Fatal(err)
}
var wg sync.WaitGroup
for i := 0; i < 4; i++ {
wg.Add(1)
go func() {
err := regSeeder.ConnectOnDefaultPort("127.0.0.1")
if err != nil && err != ErrRepeatConnection {
t.Error(err)
}
wg.Done()
}()
}
wg.Wait()
// Can we address that peer if we want to?
p, err := regSeeder.GetPeer("127.0.0.1:18344")
if err != nil {
t.Error(err)
return
}
if p.Connected() {
// Shouldn't try to connect to a live peer again
err := regSeeder.ConnectOnDefaultPort("127.0.0.1")
if err != ErrRepeatConnection {
t.Error("should have caught repeat connection attempt")
}
} else {
t.Error("Peer never connected")
}
regSeeder.DisconnectAllPeers()
}
func TestRequestAddresses(t *testing.T) {
regSeeder, err := newTestSeeder(network.Regtest)
if err != nil {
t.Error(err)
return
}
err = regSeeder.ConnectOnDefaultPort("127.0.0.1")
if err != nil {
t.Fatal(err)
}
go regSeeder.RequestAddresses()
err = regSeeder.WaitForAddresses(1, 1*time.Second)
if err != nil {
t.Errorf("Error getting one mocked address: %v", err)
}
err = regSeeder.WaitForAddresses(500, 1*time.Second)
if err != ErrAddressTimeout {
t.Errorf("Should have timed out, instead got: %v", err)
}
}
func TestRequestAddressesV2(t *testing.T) {
atomic.StoreUint32(&useAddrV2, 1)
defer atomic.StoreUint32(&useAddrV2, 0)
regSeeder, err := newTestSeeder(network.Regtest)
if err != nil {
t.Error(err)
return
}
// Wrap the listener to allow checking it was called
originalFn := regSeeder.config.Listeners.OnAddrV2
var receivedAddrV2 uint32
regSeeder.config.Listeners.OnAddrV2 = func(p *peer.Peer, msg *wire.MsgAddrV2) {
atomic.StoreUint32(&receivedAddrV2, 1)
originalFn(p, msg)
}
err = regSeeder.ConnectOnDefaultPort("127.0.0.1")
if err != nil {
t.Fatal(err)
}
go regSeeder.RequestAddresses()
err = regSeeder.WaitForAddresses(1, 1*time.Second)
if err != nil {
t.Errorf("Error getting one mocked address: %v", err)
}
err = regSeeder.WaitForAddresses(500, 1*time.Second)
if err != ErrAddressTimeout {
t.Errorf("Should have timed out, instead got: %v", err)
}
if atomic.LoadUint32(&receivedAddrV2) != 1 {
t.Error("OnAddrV2 was not called")
}
}
func TestBlacklist(t *testing.T) {
regSeeder, err := newTestSeeder(network.Regtest)
if err != nil {
t.Error(err)
return
}
err = regSeeder.ConnectOnDefaultPort("127.0.0.1")
if err != nil {
t.Fatal(err)
}
go regSeeder.RequestAddresses()
err = regSeeder.WaitForAddresses(1, 1*time.Second)
if err != nil {
t.Errorf("Error getting one mocked address: %v", err)
}
workingTestPeer := PeerKey("127.0.0.1:12345")
regSeeder.testBlacklist(workingTestPeer)
_, err = regSeeder.Connect("127.0.0.1", "12345")
if err != ErrBlacklistedPeer {
t.Errorf("Blacklist did not prevent connection")
}
regSeeder.DisconnectPeer(workingTestPeer)
regSeeder.testRedeem(workingTestPeer)
_, err = regSeeder.Connect("127.0.0.1", "12345")
if err != nil {
t.Errorf("Redeem didn't allow reconnecting")
}
}