Skip to content

Commit

Permalink
Merge pull request #1812 from Crypt-iQ/btcd_addrv2
Browse files Browse the repository at this point in the history
multi: implement BIP-155 addrv2 support
  • Loading branch information
Roasbeef authored Apr 13, 2022
2 parents e153fef + cb6f21b commit bf64c8b
Show file tree
Hide file tree
Showing 21 changed files with 1,967 additions and 275 deletions.
182 changes: 119 additions & 63 deletions addrmgr/addrmanager.go

Large diffs are not rendered by default.

32 changes: 19 additions & 13 deletions addrmgr/addrmanager_internal_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,12 +6,14 @@ import (
"net"
"os"
"testing"
"time"

"github.com/btcsuite/btcd/wire"
)

// randAddr generates a *wire.NetAddress backed by a random IPv4/IPv6 address.
func randAddr(t *testing.T) *wire.NetAddress {
// randAddr generates a *wire.NetAddressV2 backed by a random IPv4/IPv6
// address.
func randAddr(t *testing.T) *wire.NetAddressV2 {
t.Helper()

ipv4 := rand.Intn(2) == 0
Expand All @@ -30,22 +32,26 @@ func randAddr(t *testing.T) *wire.NetAddress {
ip = b[:]
}

return &wire.NetAddress{
Services: wire.ServiceFlag(rand.Uint64()),
IP: ip,
Port: uint16(rand.Uint32()),
}
services := wire.ServiceFlag(rand.Uint64())
port := uint16(rand.Uint32())

return wire.NetAddressV2FromBytes(
time.Now(), services, ip, port,
)
}

// assertAddr ensures that the two addresses match. The timestamp is not
// checked as it does not affect uniquely identifying a specific address.
func assertAddr(t *testing.T, got, expected *wire.NetAddress) {
func assertAddr(t *testing.T, got, expected *wire.NetAddressV2) {
if got.Services != expected.Services {
t.Fatalf("expected address services %v, got %v",
expected.Services, got.Services)
}
if !got.IP.Equal(expected.IP) {
t.Fatalf("expected address IP %v, got %v", expected.IP, got.IP)
gotAddr := got.Addr.String()
expectedAddr := expected.Addr.String()
if gotAddr != expectedAddr {
t.Fatalf("expected address IP %v, got %v", expectedAddr,
gotAddr)
}
if got.Port != expected.Port {
t.Fatalf("expected address port %d, got %d", expected.Port,
Expand All @@ -56,7 +62,7 @@ func assertAddr(t *testing.T, got, expected *wire.NetAddress) {
// assertAddrs ensures that the manager's address cache matches the given
// expected addresses.
func assertAddrs(t *testing.T, addrMgr *AddrManager,
expectedAddrs map[string]*wire.NetAddress) {
expectedAddrs map[string]*wire.NetAddressV2) {

t.Helper()

Expand Down Expand Up @@ -96,7 +102,7 @@ func TestAddrManagerSerialization(t *testing.T) {
// We'll be adding 5 random addresses to the manager.
const numAddrs = 5

expectedAddrs := make(map[string]*wire.NetAddress, numAddrs)
expectedAddrs := make(map[string]*wire.NetAddressV2, numAddrs)
for i := 0; i < numAddrs; i++ {
addr := randAddr(t)
expectedAddrs[NetAddressKey(addr)] = addr
Expand Down Expand Up @@ -141,7 +147,7 @@ func TestAddrManagerV1ToV2(t *testing.T) {
// each addresses' services will not be stored.
const numAddrs = 5

expectedAddrs := make(map[string]*wire.NetAddress, numAddrs)
expectedAddrs := make(map[string]*wire.NetAddressV2, numAddrs)
for i := 0; i < numAddrs; i++ {
addr := randAddr(t)
expectedAddrs[NetAddressKey(addr)] = addr
Expand Down
175 changes: 122 additions & 53 deletions addrmgr/addrmanager_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ import (
// naTest is used to describe a test to be performed against the NetAddressKey
// method.
type naTest struct {
in wire.NetAddress
in wire.NetAddressV2
want string
}

Expand Down Expand Up @@ -93,8 +93,10 @@ func addNaTests() {

func addNaTest(ip string, port uint16, want string) {
nip := net.ParseIP(ip)
na := *wire.NewNetAddressIPPort(nip, port, wire.SFNodeNetwork)
test := naTest{na, want}
na := wire.NetAddressV2FromBytes(
time.Now(), wire.SFNodeNetwork, nip, port,
)
test := naTest{*na, want}
naTests = append(naTests, test)
}

Expand Down Expand Up @@ -157,37 +159,49 @@ func TestAddAddressByIP(t *testing.T) {

func TestAddLocalAddress(t *testing.T) {
var tests = []struct {
address wire.NetAddress
address wire.NetAddressV2
priority addrmgr.AddressPriority
valid bool
}{
{
wire.NetAddress{IP: net.ParseIP("192.168.0.100")},
*wire.NetAddressV2FromBytes(
time.Now(), 0, net.ParseIP("192.168.0.100"), 0,
),
addrmgr.InterfacePrio,
false,
},
{
wire.NetAddress{IP: net.ParseIP("204.124.1.1")},
*wire.NetAddressV2FromBytes(
time.Now(), 0, net.ParseIP("204.124.1.1"), 0,
),
addrmgr.InterfacePrio,
true,
},
{
wire.NetAddress{IP: net.ParseIP("204.124.1.1")},
*wire.NetAddressV2FromBytes(
time.Now(), 0, net.ParseIP("204.124.1.1"), 0,
),
addrmgr.BoundPrio,
true,
},
{
wire.NetAddress{IP: net.ParseIP("::1")},
*wire.NetAddressV2FromBytes(
time.Now(), 0, net.ParseIP("::1"), 0,
),
addrmgr.InterfacePrio,
false,
},
{
wire.NetAddress{IP: net.ParseIP("fe80::1")},
*wire.NetAddressV2FromBytes(
time.Now(), 0, net.ParseIP("fe80::1"), 0,
),
addrmgr.InterfacePrio,
false,
},
{
wire.NetAddress{IP: net.ParseIP("2620:100::1")},
*wire.NetAddressV2FromBytes(
time.Now(), 0, net.ParseIP("2620:100::1"), 0,
),
addrmgr.InterfacePrio,
true,
},
Expand All @@ -197,12 +211,12 @@ func TestAddLocalAddress(t *testing.T) {
result := amgr.AddLocalAddress(&test.address, test.priority)
if result == nil && !test.valid {
t.Errorf("TestAddLocalAddress test #%d failed: %s should have "+
"been accepted", x, test.address.IP)
"been accepted", x, test.address.Addr.String())
continue
}
if result != nil && test.valid {
t.Errorf("TestAddLocalAddress test #%d failed: %s should not have "+
"been accepted", x, test.address.IP)
"been accepted", x, test.address.Addr.String())
continue
}
}
Expand Down Expand Up @@ -257,7 +271,7 @@ func TestNeedMoreAddresses(t *testing.T) {
if !b {
t.Errorf("Expected that we need more addresses")
}
addrs := make([]*wire.NetAddress, addrsToAdd)
addrs := make([]*wire.NetAddressV2, addrsToAdd)

var err error
for i := 0; i < addrsToAdd; i++ {
Expand All @@ -268,7 +282,9 @@ func TestNeedMoreAddresses(t *testing.T) {
}
}

srcAddr := wire.NewNetAddressIPPort(net.IPv4(173, 144, 173, 111), 8333, 0)
srcAddr := wire.NetAddressV2FromBytes(
time.Now(), 0, net.IPv4(173, 144, 173, 111), 8333,
)

n.AddAddresses(addrs, srcAddr)
numAddrs := n.NumAddresses()
Expand All @@ -285,7 +301,7 @@ func TestNeedMoreAddresses(t *testing.T) {
func TestGood(t *testing.T) {
n := addrmgr.New("testgood", lookupFunc)
addrsToAdd := 64 * 64
addrs := make([]*wire.NetAddress, addrsToAdd)
addrs := make([]*wire.NetAddressV2, addrsToAdd)

var err error
for i := 0; i < addrsToAdd; i++ {
Expand All @@ -296,7 +312,9 @@ func TestGood(t *testing.T) {
}
}

srcAddr := wire.NewNetAddressIPPort(net.IPv4(173, 144, 173, 111), 8333, 0)
srcAddr := wire.NetAddressV2FromBytes(
time.Now(), 0, net.IPv4(173, 144, 173, 111), 8333,
)

n.AddAddresses(addrs, srcAddr)
for _, addr := range addrs {
Expand Down Expand Up @@ -331,8 +349,8 @@ func TestGetAddress(t *testing.T) {
if ka == nil {
t.Fatalf("Did not get an address where there is one in the pool")
}
if ka.NetAddress().IP.String() != someIP {
t.Errorf("Wrong IP: got %v, want %v", ka.NetAddress().IP.String(), someIP)
if ka.NetAddress().Addr.String() != someIP {
t.Errorf("Wrong IP: got %v, want %v", ka.NetAddress().Addr.String(), someIP)
}

// Mark this as a good address and get it
Expand All @@ -341,8 +359,8 @@ func TestGetAddress(t *testing.T) {
if ka == nil {
t.Fatalf("Did not get an address where there is one in the pool")
}
if ka.NetAddress().IP.String() != someIP {
t.Errorf("Wrong IP: got %v, want %v", ka.NetAddress().IP.String(), someIP)
if ka.NetAddress().Addr.String() != someIP {
t.Errorf("Wrong IP: got %v, want %v", ka.NetAddress().Addr.String(), someIP)
}

numAddrs := n.NumAddresses()
Expand All @@ -352,43 +370,83 @@ func TestGetAddress(t *testing.T) {
}

func TestGetBestLocalAddress(t *testing.T) {
localAddrs := []wire.NetAddress{
{IP: net.ParseIP("192.168.0.100")},
{IP: net.ParseIP("::1")},
{IP: net.ParseIP("fe80::1")},
{IP: net.ParseIP("2001:470::1")},
localAddrs := []wire.NetAddressV2{
*wire.NetAddressV2FromBytes(
time.Now(), 0, net.ParseIP("192.168.0.100"), 0,
),
*wire.NetAddressV2FromBytes(
time.Now(), 0, net.ParseIP("::1"), 0,
),
*wire.NetAddressV2FromBytes(
time.Now(), 0, net.ParseIP("fe80::1"), 0,
),
*wire.NetAddressV2FromBytes(
time.Now(), 0, net.ParseIP("2001:470::1"), 0,
),
}

var tests = []struct {
remoteAddr wire.NetAddress
want0 wire.NetAddress
want1 wire.NetAddress
want2 wire.NetAddress
want3 wire.NetAddress
remoteAddr wire.NetAddressV2
want0 wire.NetAddressV2
want1 wire.NetAddressV2
want2 wire.NetAddressV2
want3 wire.NetAddressV2
}{
{
// Remote connection from public IPv4
wire.NetAddress{IP: net.ParseIP("204.124.8.1")},
wire.NetAddress{IP: net.IPv4zero},
wire.NetAddress{IP: net.IPv4zero},
wire.NetAddress{IP: net.ParseIP("204.124.8.100")},
wire.NetAddress{IP: net.ParseIP("fd87:d87e:eb43:25::1")},
*wire.NetAddressV2FromBytes(
time.Now(), 0, net.ParseIP("204.124.8.1"), 0,
),
*wire.NetAddressV2FromBytes(
time.Now(), 0, net.IPv4zero, 0,
),
*wire.NetAddressV2FromBytes(
time.Now(), 0, net.IPv4zero, 0,
),
*wire.NetAddressV2FromBytes(
time.Now(), 0, net.ParseIP("204.124.8.100"), 0,
),
*wire.NetAddressV2FromBytes(
time.Now(), 0,
net.ParseIP("fd87:d87e:eb43:25::1"), 0,
),
},
{
// Remote connection from private IPv4
wire.NetAddress{IP: net.ParseIP("172.16.0.254")},
wire.NetAddress{IP: net.IPv4zero},
wire.NetAddress{IP: net.IPv4zero},
wire.NetAddress{IP: net.IPv4zero},
wire.NetAddress{IP: net.IPv4zero},
*wire.NetAddressV2FromBytes(
time.Now(), 0, net.ParseIP("172.16.0.254"), 0,
),
*wire.NetAddressV2FromBytes(
time.Now(), 0, net.IPv4zero, 0,
),
*wire.NetAddressV2FromBytes(
time.Now(), 0, net.IPv4zero, 0,
),
*wire.NetAddressV2FromBytes(
time.Now(), 0, net.IPv4zero, 0,
),
*wire.NetAddressV2FromBytes(
time.Now(), 0, net.IPv4zero, 0,
),
},
{
// Remote connection from public IPv6
wire.NetAddress{IP: net.ParseIP("2602:100:abcd::102")},
wire.NetAddress{IP: net.IPv6zero},
wire.NetAddress{IP: net.ParseIP("2001:470::1")},
wire.NetAddress{IP: net.ParseIP("2001:470::1")},
wire.NetAddress{IP: net.ParseIP("2001:470::1")},
*wire.NetAddressV2FromBytes(
time.Now(), 0,
net.ParseIP("2602:100:abcd::102"), 0,
),
*wire.NetAddressV2FromBytes(
time.Now(), 0, net.IPv6zero, 0,
),
*wire.NetAddressV2FromBytes(
time.Now(), 0, net.ParseIP("2001:470::1"), 0,
),
*wire.NetAddressV2FromBytes(
time.Now(), 0, net.ParseIP("2001:470::1"), 0,
),
*wire.NetAddressV2FromBytes(
time.Now(), 0, net.ParseIP("2001:470::1"), 0,
),
},
/* XXX
{
Expand All @@ -406,9 +464,12 @@ func TestGetBestLocalAddress(t *testing.T) {
// Test against default when there's no address
for x, test := range tests {
got := amgr.GetBestLocalAddress(&test.remoteAddr)
if !test.want0.IP.Equal(got.IP) {
wantAddr := test.want0.Addr.String()
gotAddr := got.Addr.String()
if wantAddr != gotAddr {
remoteAddr := test.remoteAddr.Addr.String()
t.Errorf("TestGetBestLocalAddress test1 #%d failed for remote address %s: want %s got %s",
x, test.remoteAddr.IP, test.want1.IP, got.IP)
x, remoteAddr, wantAddr, gotAddr)
continue
}
}
Expand All @@ -420,23 +481,31 @@ func TestGetBestLocalAddress(t *testing.T) {
// Test against want1
for x, test := range tests {
got := amgr.GetBestLocalAddress(&test.remoteAddr)
if !test.want1.IP.Equal(got.IP) {
wantAddr := test.want1.Addr.String()
gotAddr := got.Addr.String()
if wantAddr != gotAddr {
remoteAddr := test.remoteAddr.Addr.String()
t.Errorf("TestGetBestLocalAddress test1 #%d failed for remote address %s: want %s got %s",
x, test.remoteAddr.IP, test.want1.IP, got.IP)
x, remoteAddr, wantAddr, gotAddr)
continue
}
}

// Add a public IP to the list of local addresses.
localAddr := wire.NetAddress{IP: net.ParseIP("204.124.8.100")}
amgr.AddLocalAddress(&localAddr, addrmgr.InterfacePrio)
localAddr := wire.NetAddressV2FromBytes(
time.Now(), 0, net.ParseIP("204.124.8.100"), 0,
)
amgr.AddLocalAddress(localAddr, addrmgr.InterfacePrio)

// Test against want2
for x, test := range tests {
got := amgr.GetBestLocalAddress(&test.remoteAddr)
if !test.want2.IP.Equal(got.IP) {
wantAddr := test.want2.Addr.String()
gotAddr := got.Addr.String()
if wantAddr != gotAddr {
remoteAddr := test.remoteAddr.Addr.String()
t.Errorf("TestGetBestLocalAddress test2 #%d failed for remote address %s: want %s got %s",
x, test.remoteAddr.IP, test.want2.IP, got.IP)
x, remoteAddr, wantAddr, gotAddr)
continue
}
}
Expand Down
Loading

0 comments on commit bf64c8b

Please sign in to comment.