codec_test.go raw

   1  package btcwire
   2  
   3  import (
   4  	"bytes"
   5  	"errors"
   6  	"io"
   7  	"math"
   8  	"testing"
   9  
  10  	"git.smesh.lol/nostrino/pkg/crypto/chainhash"
  11  )
  12  
  13  func TestCompactSize(t *testing.T) {
  14  	tests := []struct {
  15  		value   uint64
  16  		encoded []byte
  17  	}{
  18  		{0, []byte{0x00}},
  19  		{1, []byte{0x01}},
  20  		{0xfc, []byte{0xfc}},
  21  		{0xfd, []byte{0xfd, 0xfd, 0x00}},
  22  		{0xffff, []byte{0xfd, 0xff, 0xff}},
  23  		{0x10000, []byte{0xfe, 0x00, 0x00, 0x01, 0x00}},
  24  		{0xffffffff, []byte{0xfe, 0xff, 0xff, 0xff, 0xff}},
  25  		{0x100000000, []byte{0xff, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00}},
  26  		{math.MaxUint64, []byte{0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff}},
  27  	}
  28  	for _, tc := range tests {
  29  		var e Encoder
  30  		e.CompactSize(tc.value)
  31  		if !bytes.Equal(e.Bytes(), tc.encoded) {
  32  			t.Fatalf("CompactSize(%d) = %x, want %x", tc.value, e.Bytes(), tc.encoded)
  33  		}
  34  		if e.Len() != len(tc.encoded) {
  35  			t.Fatalf("Len() = %d, want %d", e.Len(), len(tc.encoded))
  36  		}
  37  		d := NewDecoder(tc.encoded)
  38  		got, err := d.CompactSize()
  39  		if err != nil {
  40  			t.Fatalf("decoding %x: %v", tc.encoded, err)
  41  		}
  42  		if got != tc.value {
  43  			t.Fatalf("decoded %d, want %d", got, tc.value)
  44  		}
  45  		if d.Remaining() != 0 {
  46  			t.Fatalf("%d bytes left after decoding %d", d.Remaining(), tc.value)
  47  		}
  48  	}
  49  }
  50  
  51  func TestCompactSizeNonCanonical(t *testing.T) {
  52  	tests := []struct {
  53  		name    string
  54  		encoded []byte
  55  	}{
  56  		{"small value with 0xfd prefix", []byte{0xfd, 0xfc, 0x00}},
  57  		{"zero with 0xfd prefix", []byte{0xfd, 0x00, 0x00}},
  58  		{"0xffff with 0xfe prefix", []byte{0xfe, 0xff, 0xff, 0x00, 0x00}},
  59  		{"0xffffffff with 0xff prefix", []byte{0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00}},
  60  	}
  61  	for _, tc := range tests {
  62  		t.Run(tc.name, func(t *testing.T) {
  63  			if _, err := NewDecoder(tc.encoded).CompactSize(); !errors.Is(err, ErrNonCanonicalCompactSize) {
  64  				t.Fatalf("error = %v, want ErrNonCanonicalCompactSize", err)
  65  			}
  66  		})
  67  	}
  68  }
  69  
  70  func TestCompactSizeTruncated(t *testing.T) {
  71  	tests := [][]byte{
  72  		nil,
  73  		{0xfd},
  74  		{0xfd, 0x01},
  75  		{0xfe},
  76  		{0xfe, 0x01, 0x02},
  77  		{0xff},
  78  		{0xff, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07},
  79  	}
  80  	for _, encoded := range tests {
  81  		if _, err := NewDecoder(encoded).CompactSize(); !errors.Is(err, io.ErrUnexpectedEOF) {
  82  			t.Fatalf("decoding %x: error = %v, want io.ErrUnexpectedEOF", encoded, err)
  83  		}
  84  	}
  85  }
  86  
  87  func TestVarBytes(t *testing.T) {
  88  	values := [][]byte{
  89  		nil,
  90  		{},
  91  		[]byte("a"),
  92  		[]byte("compact filters"),
  93  		bytes.Repeat([]byte{0x5a}, 0xfc),
  94  		bytes.Repeat([]byte{0x5a}, 0xfd),
  95  		bytes.Repeat([]byte{0x5a}, 0x10000),
  96  	}
  97  	for _, value := range values {
  98  		var e Encoder
  99  		if err := WriteVarBytes(&e, value); err != nil {
 100  			t.Fatalf("WriteVarBytes(%d bytes): %v", len(value), err)
 101  		}
 102  		d := NewDecoder(e.Bytes())
 103  		got, err := ReadVarBytes(d, MaxPayload)
 104  		if err != nil {
 105  			t.Fatalf("ReadVarBytes(%d bytes): %v", len(value), err)
 106  		}
 107  		if !bytes.Equal(got, value) {
 108  			t.Fatalf("decoded %x, want %x", got, value)
 109  		}
 110  		if d.Remaining() != 0 {
 111  			t.Fatalf("%d bytes left after decoding", d.Remaining())
 112  		}
 113  	}
 114  }
 115  
 116  func TestVarBytesErrors(t *testing.T) {
 117  	t.Run("too large for limit", func(t *testing.T) {
 118  		var e Encoder
 119  		if err := WriteVarBytes(&e, []byte("0123456789")); err != nil {
 120  			t.Fatalf("WriteVarBytes: %v", err)
 121  		}
 122  		if _, err := ReadVarBytes(NewDecoder(e.Bytes()), 9); !errors.Is(err, ErrVarBytesTooLarge) {
 123  			t.Fatalf("error = %v, want ErrVarBytesTooLarge", err)
 124  		}
 125  	})
 126  	t.Run("negative limit", func(t *testing.T) {
 127  		if _, err := ReadVarBytes(NewDecoder(nil), -1); !errors.Is(err, ErrInvalidLength) {
 128  			t.Fatalf("error = %v, want ErrInvalidLength", err)
 129  		}
 130  	})
 131  	t.Run("length above limit", func(t *testing.T) {
 132  		if _, err := ReadVarBytes(NewDecoder([]byte{0x05}), 4); !errors.Is(err, ErrVarBytesTooLarge) {
 133  			t.Fatalf("error = %v, want ErrVarBytesTooLarge", err)
 134  		}
 135  	})
 136  	t.Run("truncated data", func(t *testing.T) {
 137  		if _, err := ReadVarBytes(NewDecoder([]byte{0x05, 0x01, 0x02}), 100); !errors.Is(err, io.ErrUnexpectedEOF) {
 138  			t.Fatalf("error = %v, want io.ErrUnexpectedEOF", err)
 139  		}
 140  	})
 141  	t.Run("truncated length", func(t *testing.T) {
 142  		if _, err := ReadVarBytes(NewDecoder([]byte{0xfd, 0x01}), 100); !errors.Is(err, io.ErrUnexpectedEOF) {
 143  			t.Fatalf("error = %v, want io.ErrUnexpectedEOF", err)
 144  		}
 145  	})
 146  	t.Run("oversize write", func(t *testing.T) {
 147  		var e Encoder
 148  		err := WriteVarBytes(&e, make([]byte, MaxPayload+1))
 149  		if !errors.Is(err, ErrVarBytesTooLarge) {
 150  			t.Fatalf("error = %v, want ErrVarBytesTooLarge", err)
 151  		}
 152  	})
 153  }
 154  
 155  func TestPrimitives(t *testing.T) {
 156  	var e Encoder
 157  	e.Uint8(0x12)
 158  	e.Uint16(0x3456)
 159  	e.Uint16BE(0x789a)
 160  	e.Uint32(0x01020304)
 161  	e.Uint64(0x0102030405060708)
 162  	e.Int32(-2)
 163  	e.Int64(-2)
 164  	e.Hash(chainhash.Hash{0xaa, 0xbb})
 165  	want := []byte{
 166  		0x12,
 167  		0x56, 0x34,
 168  		0x78, 0x9a,
 169  		0x04, 0x03, 0x02, 0x01,
 170  		0x08, 0x07, 0x06, 0x05, 0x04, 0x03, 0x02, 0x01,
 171  		0xfe, 0xff, 0xff, 0xff,
 172  		0xfe, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
 173  		0xaa, 0xbb, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
 174  		0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
 175  		0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
 176  		0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
 177  	}
 178  	if !bytes.Equal(e.Bytes(), want) {
 179  		t.Fatalf("encoded = %x, want %x", e.Bytes(), want)
 180  	}
 181  
 182  	d := NewDecoder(want)
 183  	if v, err := d.Uint8(); err != nil || v != 0x12 {
 184  		t.Fatalf("Uint8 = %x, %v", v, err)
 185  	}
 186  	if v, err := d.Uint16(); err != nil || v != 0x3456 {
 187  		t.Fatalf("Uint16 = %x, %v", v, err)
 188  	}
 189  	if v, err := d.Uint16BE(); err != nil || v != 0x789a {
 190  		t.Fatalf("Uint16BE = %x, %v", v, err)
 191  	}
 192  	if v, err := d.Uint32(); err != nil || v != 0x01020304 {
 193  		t.Fatalf("Uint32 = %x, %v", v, err)
 194  	}
 195  	if v, err := d.Uint64(); err != nil || v != 0x0102030405060708 {
 196  		t.Fatalf("Uint64 = %x, %v", v, err)
 197  	}
 198  	if v, err := d.Int32(); err != nil || v != -2 {
 199  		t.Fatalf("Int32 = %d, %v", v, err)
 200  	}
 201  	if v, err := d.Int64(); err != nil || v != -2 {
 202  		t.Fatalf("Int64 = %d, %v", v, err)
 203  	}
 204  	h, err := d.Hash()
 205  	if err != nil {
 206  		t.Fatalf("Hash: %v", err)
 207  	}
 208  	if h[0] != 0xaa || h[1] != 0xbb {
 209  		t.Fatalf("Hash = %x", h)
 210  	}
 211  	if d.Remaining() != 0 {
 212  		t.Fatalf("Remaining = %d, want 0", d.Remaining())
 213  	}
 214  	if d.Offset() != len(want) {
 215  		t.Fatalf("Offset = %d, want %d", d.Offset(), len(want))
 216  	}
 217  }
 218  
 219  func TestDecoderTruncated(t *testing.T) {
 220  	tests := []struct {
 221  		name string
 222  		read func(*Decoder) error
 223  		data []byte
 224  	}{
 225  		{"Uint8", func(d *Decoder) error { _, err := d.Uint8(); return err }, nil},
 226  		{"Uint16", func(d *Decoder) error { _, err := d.Uint16(); return err }, []byte{0x01}},
 227  		{"Uint16BE", func(d *Decoder) error { _, err := d.Uint16BE(); return err }, []byte{0x01}},
 228  		{"Uint32", func(d *Decoder) error { _, err := d.Uint32(); return err }, []byte{1, 2, 3}},
 229  		{"Uint64", func(d *Decoder) error { _, err := d.Uint64(); return err }, []byte{1, 2, 3, 4, 5, 6, 7}},
 230  		{"Int32", func(d *Decoder) error { _, err := d.Int32(); return err }, []byte{1}},
 231  		{"Int64", func(d *Decoder) error { _, err := d.Int64(); return err }, []byte{1}},
 232  		{"Hash", func(d *Decoder) error { _, err := d.Hash(); return err }, make([]byte, chainhash.HashSize-1)},
 233  		{"Bytes", func(d *Decoder) error { _, err := d.Bytes(5); return err }, []byte{1, 2}},
 234  	}
 235  	for _, tc := range tests {
 236  		t.Run(tc.name, func(t *testing.T) {
 237  			if err := tc.read(NewDecoder(tc.data)); !errors.Is(err, io.ErrUnexpectedEOF) {
 238  				t.Fatalf("error = %v, want io.ErrUnexpectedEOF", err)
 239  			}
 240  		})
 241  	}
 242  	if _, err := NewDecoder(nil).Bytes(-1); !errors.Is(err, ErrInvalidLength) {
 243  		t.Fatalf("negative Bytes error = %v, want ErrInvalidLength", err)
 244  	}
 245  }
 246  
 247  func TestEncoderBytesAlias(t *testing.T) {
 248  	var e Encoder
 249  	e.Uint8(0x01)
 250  	b := e.Bytes()
 251  	if len(b) != 1 || b[0] != 0x01 {
 252  		t.Fatalf("Bytes() = %x", b)
 253  	}
 254  }
 255