From 474ddc98ed9e9d25119ffa675751fef5803f4608 Mon Sep 17 00:00:00 2001 From: Conner Fromknecht Date: Wed, 7 Aug 2019 19:32:28 -0700 Subject: [PATCH 1/2] tlv/primitive_test: add basic encode/decode tests for primitives --- tlv/primitive_test.go | 242 ++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 242 insertions(+) create mode 100644 tlv/primitive_test.go diff --git a/tlv/primitive_test.go b/tlv/primitive_test.go new file mode 100644 index 00000000..dc4d7009 --- /dev/null +++ b/tlv/primitive_test.go @@ -0,0 +1,242 @@ +package tlv_test + +import ( + "bytes" + "reflect" + "testing" + + "github.com/btcsuite/btcd/btcec" + "github.com/lightningnetwork/lnd/tlv" +) + +var testPK, _ = btcec.ParsePubKey([]byte{0x02, + 0x3d, 0xa0, 0x92, 0xf6, 0x98, 0x0e, 0x58, 0xd2, + 0xc0, 0x37, 0x17, 0x31, 0x80, 0xe9, 0xa4, 0x65, + 0x47, 0x60, 0x26, 0xee, 0x50, 0xf9, 0x66, 0x95, + 0x96, 0x3e, 0x8e, 0xfe, 0x43, 0x6f, 0x54, 0xeb, +}, btcec.S256()) + +type primitive struct { + u8 byte + u16 uint16 + u32 uint32 + u64 uint64 + b32 [32]byte + b33 [33]byte + b64 [64]byte + pk *btcec.PublicKey + bytes []byte +} + +// TestWrongEncodingType asserts that all primitives encoders will fail with a +// ErrTypeForEncoding when an incorrect type is provided. +func TestWrongEncodingType(t *testing.T) { + encoders := []tlv.Encoder{ + tlv.EUint8, + tlv.EUint16, + tlv.EUint32, + tlv.EUint64, + tlv.EBytes32, + tlv.EBytes33, + tlv.EBytes64, + tlv.EPubKey, + tlv.EVarBytes, + } + + // We'll use an int32 since it is not a primitive type, which should + // cause the primitive encoders to fail with an ErrTypeForEncoding + // failure. + var ( + value int32 + buf [8]byte + b bytes.Buffer + ) + for _, encoder := range encoders { + err := encoder(&b, &value, &buf) + if _, ok := err.(tlv.ErrTypeForEncoding); !ok { + t.Fatalf("expected error of type ErrTypeForEncoding, "+ + "got %T", err) + } + } +} + +// TestWrongDecodingType asserts that all primitives decoders will fail with a +// ErrTypeForDecoding when an incorrect type is provided. +func TestWrongDecodingType(t *testing.T) { + decoders := []tlv.Decoder{ + tlv.DUint8, + tlv.DUint16, + tlv.DUint32, + tlv.DUint64, + tlv.DBytes32, + tlv.DBytes33, + tlv.DBytes64, + tlv.DPubKey, + tlv.DVarBytes, + } + + // We'll use an int32 since it is not a primitive type, which should + // cause the primitive decoders to fail with an ErrTypeForDecoding + // failure. + var ( + value int32 + buf [8]byte + b bytes.Buffer + ) + for _, decoder := range decoders { + err := decoder(&b, &value, &buf, 0) + if _, ok := err.(tlv.ErrTypeForDecoding); !ok { + t.Fatalf("expected error of type ErrTypeForDecoding, "+ + "got %T", err) + } + } +} + +type fieldEncoder struct { + val interface{} + encoder tlv.Encoder +} + +type fieldDecoder struct { + val interface{} + decoder tlv.Decoder + size uint64 +} + +// TestPrimitiveEncodings tests that we are able to serialize all known +// primitive field types. After successfully encoding, we check that we are able +// to decode the output and arrive at the same fields. +func TestPrimitiveEncodings(t *testing.T) { + prim := primitive{ + u8: 0x01, + u16: 0x0201, + u32: 0x02000001, + u64: 0x0200000000000001, + b32: [32]byte{0x02, 0x01}, + b33: [33]byte{0x03, 0x01}, + b64: [64]byte{0x02, 0x01}, + pk: testPK, + bytes: []byte{0xaa, 0xbb}, + } + + encoders := []fieldEncoder{ + { + val: &prim.u8, + encoder: tlv.EUint8, + }, + { + val: &prim.u16, + encoder: tlv.EUint16, + }, + { + val: &prim.u32, + encoder: tlv.EUint32, + }, + { + val: &prim.u64, + encoder: tlv.EUint64, + }, + { + val: &prim.b32, + encoder: tlv.EBytes32, + }, + { + val: &prim.b33, + encoder: tlv.EBytes33, + }, + { + val: &prim.b64, + encoder: tlv.EBytes64, + }, + { + val: &prim.pk, + encoder: tlv.EPubKey, + }, + { + val: &prim.bytes, + encoder: tlv.EVarBytes, + }, + } + + // First we'll encode the primitive fields into a buffer. + var ( + b bytes.Buffer + buf [8]byte + ) + for _, field := range encoders { + err := field.encoder(&b, field.val, &buf) + if err != nil { + t.Fatalf("unable to encode %T: %v", + field.val, err) + } + } + + // Next, we'll attempt to decode the primitive fields into a separate + // primitive struct. + r := bytes.NewReader(b.Bytes()) + var prim2 primitive + + decoders := []fieldDecoder{ + { + val: &prim2.u8, + decoder: tlv.DUint8, + size: 1, + }, + { + val: &prim2.u16, + decoder: tlv.DUint16, + size: 2, + }, + { + val: &prim2.u32, + decoder: tlv.DUint32, + size: 4, + }, + { + val: &prim2.u64, + decoder: tlv.DUint64, + size: 8, + }, + { + val: &prim2.b32, + decoder: tlv.DBytes32, + size: 32, + }, + { + val: &prim2.b33, + decoder: tlv.DBytes33, + size: 33, + }, + { + val: &prim2.b64, + decoder: tlv.DBytes64, + size: 64, + }, + { + val: &prim2.pk, + decoder: tlv.DPubKey, + size: 33, + }, + { + val: &prim2.bytes, + decoder: tlv.DVarBytes, + size: 2, + }, + } + + for _, field := range decoders { + err := field.decoder(r, field.val, &buf, field.size) + if err != nil { + t.Fatalf("unable to decode %T: %v", + field.val, err) + } + } + + // Finally, we'll compare that the original and the decode structs are + // equal. + if !reflect.DeepEqual(prim, prim2) { + t.Fatalf("primitive mismatch, "+ + "expected: %v, got: %v", + prim, prim2) + } +} From da7cb2d42a479ed9a7c1d5e7dbc82ceaa7c365e9 Mon Sep 17 00:00:00 2001 From: Conner Fromknecht Date: Wed, 7 Aug 2019 21:27:40 -0700 Subject: [PATCH 2/2] tlv/primitive: use constructor for encoding/decoding type err --- tlv/primitive.go | 36 ++++++++++++++++++------------------ 1 file changed, 18 insertions(+), 18 deletions(-) diff --git a/tlv/primitive.go b/tlv/primitive.go index 3d1f0a06..e064e73a 100644 --- a/tlv/primitive.go +++ b/tlv/primitive.go @@ -71,7 +71,7 @@ func EUint8(w io.Writer, val interface{}, buf *[8]byte) error { _, err := w.Write(buf[:1]) return err } - return ErrTypeForEncoding{val, "uint8"} + return NewTypeForEncodingErr(val, "uint8") } // EUint8T encodes a uint8 val to the provided io.Writer. This method is exposed @@ -91,7 +91,7 @@ func EUint16(w io.Writer, val interface{}, buf *[8]byte) error { _, err := w.Write(buf[:2]) return err } - return ErrTypeForEncoding{val, "uint16"} + return NewTypeForEncodingErr(val, "uint16") } // EUint16T encodes a uint16 val to the provided io.Writer. This method is @@ -111,7 +111,7 @@ func EUint32(w io.Writer, val interface{}, buf *[8]byte) error { _, err := w.Write(buf[:4]) return err } - return ErrTypeForEncoding{val, "uint32"} + return NewTypeForEncodingErr(val, "uint32") } // EUint32T encodes a uint32 val to the provided io.Writer. This method is @@ -131,7 +131,7 @@ func EUint64(w io.Writer, val interface{}, buf *[8]byte) error { _, err := w.Write(buf[:]) return err } - return ErrTypeForEncoding{val, "uint64"} + return NewTypeForEncodingErr(val, "uint64") } // EUint64T encodes a uint64 val to the provided io.Writer. This method is @@ -153,7 +153,7 @@ func DUint8(r io.Reader, val interface{}, buf *[8]byte, l uint64) error { *i = buf[0] return nil } - return ErrTypeForDecoding{val, "uint8", l, 1} + return NewTypeForDecodingErr(val, "uint8", l, 1) } // DUint16 is a Decoder for uint16 values. An error is returned if val is not a @@ -166,7 +166,7 @@ func DUint16(r io.Reader, val interface{}, buf *[8]byte, l uint64) error { *i = byteOrder.Uint16(buf[:2]) return nil } - return ErrTypeForDecoding{val, "uint16", l, 2} + return NewTypeForDecodingErr(val, "uint16", l, 2) } // DUint32 is a Decoder for uint32 values. An error is returned if val is not a @@ -179,7 +179,7 @@ func DUint32(r io.Reader, val interface{}, buf *[8]byte, l uint64) error { *i = byteOrder.Uint32(buf[:4]) return nil } - return ErrTypeForDecoding{val, "uint32", l, 4} + return NewTypeForDecodingErr(val, "uint32", l, 4) } // DUint64 is a Decoder for uint64 values. An error is returned if val is not a @@ -192,7 +192,7 @@ func DUint64(r io.Reader, val interface{}, buf *[8]byte, l uint64) error { *i = byteOrder.Uint64(buf[:]) return nil } - return ErrTypeForDecoding{val, "uint64", l, 8} + return NewTypeForDecodingErr(val, "uint64", l, 8) } // EBytes32 is an Encoder for 32-byte arrays. An error is returned if val is not @@ -202,7 +202,7 @@ func EBytes32(w io.Writer, val interface{}, _ *[8]byte) error { _, err := w.Write(b[:]) return err } - return ErrTypeForEncoding{val, "[32]byte"} + return NewTypeForEncodingErr(val, "[32]byte") } // DBytes32 is a Decoder for 32-byte arrays. An error is returned if val is not @@ -212,7 +212,7 @@ func DBytes32(r io.Reader, val interface{}, _ *[8]byte, l uint64) error { _, err := io.ReadFull(r, b[:]) return err } - return ErrTypeForDecoding{val, "[32]byte", l, 32} + return NewTypeForDecodingErr(val, "[32]byte", l, 32) } // EBytes33 is an Encoder for 33-byte arrays. An error is returned if val is not @@ -222,7 +222,7 @@ func EBytes33(w io.Writer, val interface{}, _ *[8]byte) error { _, err := w.Write(b[:]) return err } - return ErrTypeForEncoding{val, "[33]byte"} + return NewTypeForEncodingErr(val, "[33]byte") } // DBytes33 is a Decoder for 33-byte arrays. An error is returned if val is not @@ -232,7 +232,7 @@ func DBytes33(r io.Reader, val interface{}, _ *[8]byte, l uint64) error { _, err := io.ReadFull(r, b[:]) return err } - return ErrTypeForDecoding{val, "[33]byte", l, 33} + return NewTypeForDecodingErr(val, "[33]byte", l, 33) } // EBytes64 is an Encoder for 64-byte arrays. An error is returned if val is not @@ -242,7 +242,7 @@ func EBytes64(w io.Writer, val interface{}, _ *[8]byte) error { _, err := w.Write(b[:]) return err } - return ErrTypeForEncoding{val, "[64]byte"} + return NewTypeForEncodingErr(val, "[64]byte") } // DBytes64 is an Decoder for 64-byte arrays. An error is returned if val is not @@ -252,7 +252,7 @@ func DBytes64(r io.Reader, val interface{}, _ *[8]byte, l uint64) error { _, err := io.ReadFull(r, b[:]) return err } - return ErrTypeForDecoding{val, "[64]byte", l, 64} + return NewTypeForDecodingErr(val, "[64]byte", l, 64) } // EPubKey is an Encoder for *btcec.PublicKey values. An error is returned if @@ -262,7 +262,7 @@ func EPubKey(w io.Writer, val interface{}, _ *[8]byte) error { _, err := w.Write((*pk).SerializeCompressed()) return err } - return ErrTypeForEncoding{val, "*btcec.PublicKey"} + return NewTypeForEncodingErr(val, "*btcec.PublicKey") } // DPubKey is a Decoder for *btcec.PublicKey values. An error is returned if val @@ -284,7 +284,7 @@ func DPubKey(r io.Reader, val interface{}, _ *[8]byte, l uint64) error { return nil } - return ErrTypeForDecoding{val, "*btcec.PublicKey", l, 33} + return NewTypeForDecodingErr(val, "*btcec.PublicKey", l, 33) } // EVarBytes is an Encoder for variable byte slices. An error is returned if val @@ -294,7 +294,7 @@ func EVarBytes(w io.Writer, val interface{}, _ *[8]byte) error { _, err := w.Write(*b) return err } - return ErrTypeForEncoding{val, "[]byte"} + return NewTypeForEncodingErr(val, "[]byte") } // DVarBytes is a Decoder for variable byte slices. An error is returned if val @@ -305,5 +305,5 @@ func DVarBytes(r io.Reader, val interface{}, _ *[8]byte, l uint64) error { _, err := io.ReadFull(r, *b) return err } - return ErrTypeForDecoding{val, "[]byte", l, l} + return NewTypeForDecodingErr(val, "[]byte", l, l) }