version_test.go raw

   1  package btcwire
   2  
   3  import (
   4  	"bytes"
   5  	"errors"
   6  	"math"
   7  	"reflect"
   8  	"testing"
   9  )
  10  
  11  func TestVersionRoundTrip(t *testing.T) {
  12  	tests := []struct {
  13  		name  string
  14  		recv  string
  15  		from  string
  16  		ua    string
  17  		relay bool
  18  	}{
  19  		{"ipv4", "127.0.0.1", "10.0.0.1", "Satoshi:27.0.0", true},
  20  		{"ipv6", "2001:db8::1", "::1", "nostrino:0.1.0", false},
  21  		{"mixed", "::ffff:192.168.1.1", "192.168.1.2", "Satoshi:25.0.0/", true},
  22  		{"empty user agent", "0.0.0.0", "0.0.0.0", "", true},
  23  		{"long user agent", "127.0.0.1", "127.0.0.1", string(bytes.Repeat([]byte("x"), MaxUserAgentSize)), false},
  24  	}
  25  	for _, tc := range tests {
  26  		t.Run(tc.name, func(t *testing.T) {
  27  			want := Version{
  28  				ProtocolVersion: ProtocolVersion,
  29  				Services:        ServiceNodeNetwork | ServiceNodeWitness | ServiceNodeCompactFilters,
  30  				Timestamp:       1700000000,
  31  				AddrRecv:        mustAddress(t, tc.recv, 8333),
  32  				AddrFrom:        mustAddress(t, tc.from, 18333),
  33  				Nonce:           0x0102030405060708,
  34  				UserAgent:       tc.ua,
  35  				LastBlock:       800000,
  36  				Relay:           tc.relay,
  37  			}
  38  			payload, err := want.EncodePayload()
  39  			if err != nil {
  40  				t.Fatalf("EncodePayload: %v", err)
  41  			}
  42  			var got Version
  43  			if err := got.DecodePayload(payload); err != nil {
  44  				t.Fatalf("DecodePayload: %v", err)
  45  			}
  46  			if !reflect.DeepEqual(got, want) {
  47  				t.Fatalf("decoded = %+v, want %+v", got, want)
  48  			}
  49  		})
  50  	}
  51  }
  52  
  53  func TestVersionWireLayout(t *testing.T) {
  54  	v := Version{
  55  		ProtocolVersion: ProtocolVersion,
  56  		Services:        ServiceNodeNetwork,
  57  		Timestamp:       1700000000,
  58  		AddrRecv:        mustAddress(t, "127.0.0.1", 8333),
  59  		AddrFrom:        mustAddress(t, "1.2.3.4", 18333),
  60  		Nonce:           0x0102030405060708,
  61  		UserAgent:       "abc",
  62  		LastBlock:       100,
  63  		Relay:           true,
  64  	}
  65  	payload, err := v.EncodePayload()
  66  	if err != nil {
  67  		t.Fatalf("EncodePayload: %v", err)
  68  	}
  69  	// 4 + 8 + 8 + 26 + 26 + 8 + 1 + 3 + 4 + 1.
  70  	if got, want := len(payload), 89; got != want {
  71  		t.Fatalf("payload length = %d, want %d", got, want)
  72  	}
  73  	checks := []struct {
  74  		name string
  75  		got  []byte
  76  		want []byte
  77  	}{
  78  		{"protocol version", payload[0:4], []byte{0x80, 0x11, 0x01, 0x00}},
  79  		{"services", payload[4:12], []byte{0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}},
  80  		{"timestamp", payload[12:20], []byte{0x00, 0xf1, 0x53, 0x65, 0x00, 0x00, 0x00, 0x00}},
  81  		{"addr recv port", payload[44:46], []byte{0x20, 0x8d}},
  82  		{"addr from port", payload[70:72], []byte{0x47, 0x9d}},
  83  		{"nonce", payload[72:80], []byte{0x08, 0x07, 0x06, 0x05, 0x04, 0x03, 0x02, 0x01}},
  84  		{"user agent length", payload[80:81], []byte{0x03}},
  85  		{"user agent", payload[81:84], []byte("abc")},
  86  		{"last block", payload[84:88], []byte{0x64, 0x00, 0x00, 0x00}},
  87  		{"relay", payload[88:89], []byte{0x01}},
  88  	}
  89  	for _, c := range checks {
  90  		if !bytes.Equal(c.got, c.want) {
  91  			t.Fatalf("%s bytes = %x, want %x", c.name, c.got, c.want)
  92  		}
  93  	}
  94  	// 8333 = 0x208d and 18333 = 0x479d, big endian on the wire.
  95  	if got := payload[28:44]; !bytes.Equal(got, []byte{
  96  		0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
  97  		0x00, 0x00, 0xff, 0xff, 0x7f, 0x00, 0x00, 0x01,
  98  	}) {
  99  		t.Fatalf("addr recv IP = %x", got)
 100  	}
 101  }
 102  
 103  func TestVersionDecodeTruncated(t *testing.T) {
 104  	v := Version{
 105  		ProtocolVersion: ProtocolVersion,
 106  		Services:        ServiceNodeNetwork,
 107  		Timestamp:       1700000000,
 108  		AddrRecv:        mustAddress(t, "127.0.0.1", 8333),
 109  		AddrFrom:        mustAddress(t, "127.0.0.1", 8333),
 110  		Nonce:           7,
 111  		UserAgent:       "abc",
 112  		LastBlock:       42,
 113  		Relay:           true,
 114  	}
 115  	payload, err := v.EncodePayload()
 116  	if err != nil {
 117  		t.Fatalf("EncodePayload: %v", err)
 118  	}
 119  	// Everything before the optional relay byte is required.
 120  	required := len(payload) - 1
 121  	for n := 0; n < required; n++ {
 122  		var got Version
 123  		if err := got.DecodePayload(payload[:n]); err == nil {
 124  			t.Fatalf("decoding %d of %d bytes succeeded", n, len(payload))
 125  		}
 126  	}
 127  	// The relay byte is optional: without it the message is still valid and
 128  	// relay defaults to true.
 129  	var got Version
 130  	if err := got.DecodePayload(payload[:required]); err != nil {
 131  		t.Fatalf("decoding without relay byte: %v", err)
 132  	}
 133  	if !got.Relay {
 134  		t.Fatal("missing relay byte did not default to true")
 135  	}
 136  	if got.UserAgent != "abc" || got.LastBlock != 42 || got.Nonce != 7 {
 137  		t.Fatalf("decoded fields = %+v", got)
 138  	}
 139  }
 140  
 141  func TestVersionRelayDecoding(t *testing.T) {
 142  	v := Version{
 143  		ProtocolVersion: ProtocolVersion,
 144  		UserAgent:       "ua",
 145  		LastBlock:       1,
 146  	}
 147  	payload, err := v.EncodePayload()
 148  	if err != nil {
 149  		t.Fatalf("EncodePayload: %v", err)
 150  	}
 151  	payload[len(payload)-1] = 0
 152  	var got Version
 153  	if err := got.DecodePayload(payload); err != nil {
 154  		t.Fatalf("DecodePayload: %v", err)
 155  	}
 156  	if got.Relay {
 157  		t.Fatal("relay byte 0 decoded as true")
 158  	}
 159  	// Any non-zero byte is treated as true, matching Bitcoin Core.
 160  	payload[len(payload)-1] = 2
 161  	if err := got.DecodePayload(payload); err != nil {
 162  		t.Fatalf("DecodePayload: %v", err)
 163  	}
 164  	if !got.Relay {
 165  		t.Fatal("relay byte 2 decoded as false")
 166  	}
 167  }
 168  
 169  func TestVersionUserAgentLimit(t *testing.T) {
 170  	t.Run("encode rejects oversize", func(t *testing.T) {
 171  		v := &Version{UserAgent: string(bytes.Repeat([]byte("x"), MaxUserAgentSize+1))}
 172  		if _, err := v.EncodePayload(); !errors.Is(err, ErrInvalidPayload) {
 173  			t.Fatalf("error = %v, want ErrInvalidPayload", err)
 174  		}
 175  	})
 176  	t.Run("decode rejects oversize", func(t *testing.T) {
 177  		// Fixed fields, then a 257-byte user agent, then the last block and
 178  		// relay byte.
 179  		payload := make([]byte, 80)
 180  		payload = append(payload, 0xfd, 0x01, 0x01)
 181  		payload = append(payload, bytes.Repeat([]byte("x"), 257)...)
 182  		payload = append(payload, 0, 0, 0, 0, 0)
 183  		var got Version
 184  		if err := got.DecodePayload(payload); !errors.Is(err, ErrVarBytesTooLarge) {
 185  			t.Fatalf("error = %v, want ErrVarBytesTooLarge", err)
 186  		}
 187  	})
 188  }
 189  
 190  func TestEmptyPayloadMessages(t *testing.T) {
 191  	tests := []struct {
 192  		name  string
 193  		value Payload
 194  	}{
 195  		{"verack", &VerAck{}},
 196  		{"sendheaders", &SendHeaders{}},
 197  		{"wtxidrelay", &WtxidRelay{}},
 198  		{"sendaddrv2", &SendAddrV2{}},
 199  	}
 200  	for _, tc := range tests {
 201  		t.Run(tc.name, func(t *testing.T) {
 202  			payload, err := tc.value.EncodePayload()
 203  			if err != nil {
 204  				t.Fatalf("EncodePayload: %v", err)
 205  			}
 206  			if len(payload) != 0 {
 207  				t.Fatalf("payload = %x, want empty", payload)
 208  			}
 209  			if err := tc.value.DecodePayload(nil); err != nil {
 210  				t.Fatalf("DecodePayload(nil): %v", err)
 211  			}
 212  			if err := tc.value.DecodePayload([]byte{0x00}); !errors.Is(err, ErrInvalidPayload) {
 213  				t.Fatalf("DecodePayload([0]) error = %v, want ErrInvalidPayload", err)
 214  			}
 215  		})
 216  	}
 217  }
 218  
 219  func TestPingPong(t *testing.T) {
 220  	nonces := []uint64{0, 1, 0xffffffffffffffff}
 221  	for _, nonce := range nonces {
 222  		t.Run("ping", func(t *testing.T) {
 223  			want := &Ping{Nonce: nonce}
 224  			payload, err := want.EncodePayload()
 225  			if err != nil {
 226  				t.Fatalf("EncodePayload: %v", err)
 227  			}
 228  			if len(payload) != 8 {
 229  				t.Fatalf("payload length = %d, want 8", len(payload))
 230  			}
 231  			var got Ping
 232  			if err := got.DecodePayload(payload); err != nil {
 233  				t.Fatalf("DecodePayload: %v", err)
 234  			}
 235  			if got.Nonce != nonce {
 236  				t.Fatalf("Nonce = %d, want %d", got.Nonce, nonce)
 237  			}
 238  		})
 239  		t.Run("pong", func(t *testing.T) {
 240  			want := &Pong{Nonce: nonce}
 241  			payload, err := want.EncodePayload()
 242  			if err != nil {
 243  				t.Fatalf("EncodePayload: %v", err)
 244  			}
 245  			var got Pong
 246  			if err := got.DecodePayload(payload); err != nil {
 247  				t.Fatalf("DecodePayload: %v", err)
 248  			}
 249  			if got.Nonce != nonce {
 250  				t.Fatalf("Nonce = %d, want %d", got.Nonce, nonce)
 251  			}
 252  		})
 253  	}
 254  	for _, n := range []int{0, 7, 9} {
 255  		var p Ping
 256  		if err := p.DecodePayload(make([]byte, n)); !errors.Is(err, ErrInvalidPayload) {
 257  			t.Fatalf("ping payload of %d bytes error = %v, want ErrInvalidPayload", n, err)
 258  		}
 259  		var q Pong
 260  		if err := q.DecodePayload(make([]byte, n)); !errors.Is(err, ErrInvalidPayload) {
 261  			t.Fatalf("pong payload of %d bytes error = %v, want ErrInvalidPayload", n, err)
 262  		}
 263  	}
 264  }
 265  
 266  func TestFeeFilter(t *testing.T) {
 267  	rates := []int64{0, 1, 1000, -1, math.MaxInt64, math.MinInt64}
 268  	for _, rate := range rates {
 269  		want := &FeeFilter{FeeRate: rate}
 270  		payload, err := want.EncodePayload()
 271  		if err != nil {
 272  			t.Fatalf("EncodePayload: %v", err)
 273  		}
 274  		if len(payload) != 8 {
 275  			t.Fatalf("payload length = %d, want 8", len(payload))
 276  		}
 277  		var got FeeFilter
 278  		if err := got.DecodePayload(payload); err != nil {
 279  			t.Fatalf("DecodePayload: %v", err)
 280  		}
 281  		if got.FeeRate != rate {
 282  			t.Fatalf("FeeRate = %d, want %d", got.FeeRate, rate)
 283  		}
 284  	}
 285  	var f FeeFilter
 286  	if err := f.DecodePayload(make([]byte, 4)); !errors.Is(err, ErrInvalidPayload) {
 287  		t.Fatalf("short payload error = %v, want ErrInvalidPayload", err)
 288  	}
 289  	if err := f.DecodePayload(make([]byte, 9)); !errors.Is(err, ErrInvalidPayload) {
 290  		t.Fatalf("long payload error = %v, want ErrInvalidPayload", err)
 291  	}
 292  }
 293  
 294  func TestProtocolConstants(t *testing.T) {
 295  	if ProtocolVersion != 70016 {
 296  		t.Fatalf("ProtocolVersion = %d, want 70016", ProtocolVersion)
 297  	}
 298  	if ServiceNodeNetwork != 1 {
 299  		t.Fatalf("ServiceNodeNetwork = %d, want 1", ServiceNodeNetwork)
 300  	}
 301  	if ServiceNodeWitness != 1<<3 {
 302  		t.Fatalf("ServiceNodeWitness = %d, want %d", ServiceNodeWitness, 1<<3)
 303  	}
 304  	if ServiceNodeCompactFilters != 1<<6 {
 305  		t.Fatalf("ServiceNodeCompactFilters = %d, want %d", ServiceNodeCompactFilters, 1<<6)
 306  	}
 307  }
 308  
 309  func TestVersionFrameRoundTrip(t *testing.T) {
 310  	v := &Version{
 311  		ProtocolVersion: ProtocolVersion,
 312  		Services:        ServiceNodeCompactFilters,
 313  		Timestamp:       1,
 314  		Nonce:           2,
 315  		UserAgent:       "Satoshi:27.0.0",
 316  		LastBlock:       3,
 317  		Relay:           true,
 318  	}
 319  	frame, err := EncodeMessagePayload(MainNet, CmdVersion, v)
 320  	if err != nil {
 321  		t.Fatalf("EncodeMessagePayload: %v", err)
 322  	}
 323  	msg, err := DecodeMessage(MainNet, bytes.NewReader(frame))
 324  	if err != nil {
 325  		t.Fatalf("DecodeMessage: %v", err)
 326  	}
 327  	var got Version
 328  	if err := msg.Decode(&got); err != nil {
 329  		t.Fatalf("Decode: %v", err)
 330  	}
 331  	if !reflect.DeepEqual(got, *v) {
 332  		t.Fatalf("decoded = %+v, want %+v", got, *v)
 333  	}
 334  }
 335