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