From 5b2869b0ecb7aa4d00ca34d12b9b0918cd1a8a0f Mon Sep 17 00:00:00 2001 From: Olaoluwa Osuntokun Date: Sun, 17 Mar 2024 15:51:09 -0400 Subject: [PATCH 1/3] tlv: add new Blob type alias In this commit, we add a new type alias for a blob type. This type can be used in areas where a byte slice is used to store a TLV value, which may be a fully opaque nested TLV. --- tlv/go.mod | 12 ++++++------ tlv/go.sum | 31 ++++++++++++------------------- tlv/record.go | 4 ++++ 3 files changed, 22 insertions(+), 25 deletions(-) diff --git a/tlv/go.mod b/tlv/go.mod index f61284752a..bfc3922c61 100644 --- a/tlv/go.mod +++ b/tlv/go.mod @@ -1,23 +1,23 @@ module github.com/lightningnetwork/lnd/tlv require ( - github.com/btcsuite/btcd v0.23.3 - github.com/btcsuite/btcd/btcec/v2 v2.1.3 + github.com/btcsuite/btcd v0.24.1-0.20240301210420-1a2b599bf1af + github.com/btcsuite/btcd/btcec/v2 v2.3.2 github.com/davecgh/go-spew v1.1.1 github.com/decred/dcrd/dcrec/secp256k1/v4 v4.0.1 github.com/lightningnetwork/lnd/fn v1.0.4 - github.com/stretchr/testify v1.8.2 + github.com/stretchr/testify v1.8.4 golang.org/x/exp v0.0.0-20231226003508-02704c960a9b ) require ( - github.com/btcsuite/btcd/chaincfg/chainhash v1.0.1 // indirect + github.com/btcsuite/btcd/chaincfg/chainhash v1.1.0 // indirect github.com/kr/pretty v0.3.0 // indirect github.com/lightninglabs/neutrino/cache v1.1.2 // indirect github.com/pmezard/go-difflib v1.0.0 // indirect github.com/rogpeppe/go-internal v1.9.0 // indirect - golang.org/x/crypto v0.7.0 // indirect - golang.org/x/sys v0.13.0 // indirect + golang.org/x/crypto v0.16.0 // indirect + golang.org/x/sys v0.15.0 // indirect gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c // indirect gopkg.in/yaml.v3 v3.0.1 // indirect ) diff --git a/tlv/go.sum b/tlv/go.sum index 25b1c26c21..fb4166322b 100644 --- a/tlv/go.sum +++ b/tlv/go.sum @@ -1,11 +1,10 @@ -github.com/btcsuite/btcd v0.23.3 h1:4KH/JKy9WiCd+iUS9Mu0Zp7Dnj17TGdKrg9xc/FGj24= -github.com/btcsuite/btcd v0.23.3/go.mod h1:0QJIIN1wwIXF/3G/m87gIwGniDMDQqjVn4SZgnFpsYY= -github.com/btcsuite/btcd/btcec/v2 v2.1.3 h1:xM/n3yIhHAhHy04z4i43C8p4ehixJZMsnrVJkgl+MTE= -github.com/btcsuite/btcd/btcec/v2 v2.1.3/go.mod h1:ctjw4H1kknNJmRN4iP1R7bTQ+v3GJkZBd6mui8ZsAZE= -github.com/btcsuite/btcd/chaincfg/chainhash v1.0.1 h1:q0rUy8C/TYNBQS1+CGKw68tLOFYSNEs0TFnxxnS9+4U= -github.com/btcsuite/btcd/chaincfg/chainhash v1.0.1/go.mod h1:7SFka0XMvUgj3hfZtydOrQY2mwhPclbT2snogU7SQQc= +github.com/btcsuite/btcd v0.24.1-0.20240301210420-1a2b599bf1af h1:F60A3wst4/fy9Yr1Vn8MYmFlfn7DNLxp8o8UTvhqgBE= +github.com/btcsuite/btcd v0.24.1-0.20240301210420-1a2b599bf1af/go.mod h1:5C8ChTkl5ejr3WHj8tkQSCmydiMEPB0ZhQhehpq7Dgg= +github.com/btcsuite/btcd/btcec/v2 v2.3.2 h1:5n0X6hX0Zk+6omWcihdYvdAlGf2DfasC0GMf7DClJ3U= +github.com/btcsuite/btcd/btcec/v2 v2.3.2/go.mod h1:zYzJ8etWJQIv1Ogk7OzpWjowwOdXY1W/17j2MW85J04= +github.com/btcsuite/btcd/chaincfg/chainhash v1.1.0 h1:59Kx4K6lzOW5w6nFlA0v5+lk/6sjybR934QNHSJZPTQ= +github.com/btcsuite/btcd/chaincfg/chainhash v1.1.0/go.mod h1:7SFka0XMvUgj3hfZtydOrQY2mwhPclbT2snogU7SQQc= github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E= -github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/decred/dcrd/crypto/blake256 v1.0.0/go.mod h1:sQl2p6Y26YV+ZOcSTP6thNdn47hh8kt6rqSlvmrXFAc= @@ -28,24 +27,18 @@ github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZN github.com/rogpeppe/go-internal v1.6.1/go.mod h1:xXDCJY+GAPziupqXw64V24skbSoqbTEfhy4qGm1nDQc= github.com/rogpeppe/go-internal v1.9.0 h1:73kH8U+JUqXU8lRuOHeVHaa/SZPifC7BkcraZVejAe8= github.com/rogpeppe/go-internal v1.9.0/go.mod h1:WtVeX8xhTBvf0smdhujwtBcq4Qrzq/fJaraNFVN+nFs= -github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= -github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw= -github.com/stretchr/objx v0.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpEOglKo= -github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= -github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU= -github.com/stretchr/testify v1.8.2 h1:+h33VjcLVPDHtOdpUCuF+7gSuG3yGIftsP1YvFihtJ8= -github.com/stretchr/testify v1.8.2/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4= -golang.org/x/crypto v0.7.0 h1:AvwMYaRytfdeVt3u6mLaxYtErKYjxA2OXjJ1HHq6t3A= -golang.org/x/crypto v0.7.0/go.mod h1:pYwdfH91IfpZVANVyUOhSIPZaFoJGxTFbZhFTx+dXZU= +github.com/stretchr/testify v1.8.4 h1:CcVxjf3Q8PM0mHUKJCdn+eZZtm5yQwehR5yeSVQQcUk= +github.com/stretchr/testify v1.8.4/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo= +golang.org/x/crypto v0.16.0 h1:mMMrFzRSCF0GvB7Ne27XVtVAaXLrPmgPC7/v0tkwHaY= +golang.org/x/crypto v0.16.0/go.mod h1:gCAAfMLgwOJRpTjQ2zCCt2OcSfYMTeZVSRtQlPC7Nq4= golang.org/x/exp v0.0.0-20231226003508-02704c960a9b h1:kLiC65FbiHWFAOu+lxwNPujcsl8VYyTYYEZnsOO1WK4= golang.org/x/exp v0.0.0-20231226003508-02704c960a9b/go.mod h1:iRJReGqOEeBhDZGkGbynYwcHlctCvnjTYIamk7uXpHI= -golang.org/x/sys v0.13.0 h1:Af8nKPmuFypiUBjVoU9V20FiaFXOcuZI21p0ycVYYGE= -golang.org/x/sys v0.13.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.15.0 h1:h48lPFYpsTvQJZF4EKyI4aLHaev3CxivZmv7yZig9pc= +golang.org/x/sys v0.15.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk= gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q= gopkg.in/errgo.v2 v2.1.0/go.mod h1:hNsd1EY+bozCKY1Ytp96fpM3vjJbqLJn88ws8XvfDNI= -gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= diff --git a/tlv/record.go b/tlv/record.go index a872e60048..7813ee771e 100644 --- a/tlv/record.go +++ b/tlv/record.go @@ -17,6 +17,10 @@ type Type uint64 // slice containing the encoded data. type TypeMap map[Type][]byte +// Blob is a type alias for a byte slice. It's used to indicate that a slice of +// bytes is actually an encoded TLV stream. +type Blob = []byte + // Encoder is a signature for methods that can encode TLV values. An error // should be returned if the Encoder cannot support the underlying type of val. // The provided scratch buffer must be non-nil. From 956b00b5993f987190d7c2d002c203dbe1cbd95e Mon Sep 17 00:00:00 2001 From: Olaoluwa Osuntokun Date: Sat, 30 Mar 2024 17:24:38 -0700 Subject: [PATCH 2/3] tlv: add in new BigSizeT type This type is useful when one wants to encode an integer as an underlying BigSize record. It wraps any integer, then handles the transformation into and out of the BigSize encoding on disk. --- tlv/record_type.go | 27 +++++++++++++++++++++++++++ 1 file changed, 27 insertions(+) diff --git a/tlv/record_type.go b/tlv/record_type.go index 297617d5a8..46c68a3236 100644 --- a/tlv/record_type.go +++ b/tlv/record_type.go @@ -159,3 +159,30 @@ func ZeroRecordT[T TlvType, V any]() RecordT[T, V] { Val: v, } } + +// BigSizeT is a high-order type that represents a TLV record that encodes an +// integer as a BigSize value in the stream. +type BigSizeT[T constraints.Integer] struct { + // We'll store the base value in the struct as a uin64, but then expose + // a public method to cast to the specified type. + v uint64 +} + +// NewBigSizeT creates a new BigSizeT type from a given integer type. +func NewBigSizeT[T constraints.Integer](val T) BigSizeT[T] { + return BigSizeT[T]{ + v: uint64(val), + } +} + +// Int returns the underlying integer value of the BigSize record. +func (b BigSizeT[T]) Int() T { + return T(b.v) +} + +// Record returns the underlying record interface for the record type. +func (t *BigSizeT[T]) Record() Record { + // We use a zero value for the type here as this should be used with + // the higher order RecordT type. + return MakeBigSizeRecord(0, &t.v) +} From c6dae6c3c0056518cd8b1b1ab6bd748fc252383e Mon Sep 17 00:00:00 2001 From: Oliver Gugger Date: Thu, 25 Apr 2024 16:51:12 +0200 Subject: [PATCH 3/3] tlv: rename receivers, add ValOpt ValOpt returns an Option of the underlying value. --- tlv/record_type.go | 23 ++++++++++++++++------- 1 file changed, 16 insertions(+), 7 deletions(-) diff --git a/tlv/record_type.go b/tlv/record_type.go index 46c68a3236..9bfcd1aaac 100644 --- a/tlv/record_type.go +++ b/tlv/record_type.go @@ -104,15 +104,15 @@ type OptionalRecordT[T TlvType, V any] struct { // TlvType returns the type of the record. This is the value used to identify // this type on the wire. This value is bound to the specified TlvType type // param. -func (t *OptionalRecordT[T, V]) TlvType() Type { +func (o *OptionalRecordT[T, V]) TlvType() Type { zeroRecord := ZeroRecordT[T, V]() return zeroRecord.TlvType() } // WhenSomeV executes the given function if the optional record is present. // This operates on the inner most type, V, which is the value of the record. -func (t *OptionalRecordT[T, V]) WhenSomeV(f func(V)) { - t.Option.WhenSome(func(r RecordT[T, V]) { +func (o *OptionalRecordT[T, V]) WhenSomeV(f func(V)) { + o.Option.WhenSome(func(r RecordT[T, V]) { f(r.Val) }) } @@ -126,7 +126,7 @@ func (o *OptionalRecordT[T, V]) UnwrapOrFailV(t *testing.T) V { return inner.Val } -// UnwrapOrErr is used to extract a value from an option, if the option is +// UnwrapOrErrV is used to extract a value from an option, if the option is // empty, then the specified error is returned directly. This gives the // underlying value of the record, instead of the record itself. func (o *OptionalRecordT[T, V]) UnwrapOrErrV(err error) (V, error) { @@ -141,10 +141,19 @@ func (o *OptionalRecordT[T, V]) UnwrapOrErrV(err error) (V, error) { } // Zero returns a zero value of the record type. -func (t *OptionalRecordT[T, V]) Zero() RecordT[T, V] { +func (o *OptionalRecordT[T, V]) Zero() RecordT[T, V] { return ZeroRecordT[T, V]() } +// ValOpt returns an Option of the underlying value. This can be used to chain +// other option related methods to avoid needing to first go through the outer +// record. +func (o *OptionalRecordT[T, V]) ValOpt() fn.Option[V] { + return fn.MapOption(func(record RecordT[T, V]) V { + return record.Val + })(o.Option) +} + // SomeRecordT creates a new OptionalRecordT type from a given RecordT type. func SomeRecordT[T TlvType, V any](record RecordT[T, V]) OptionalRecordT[T, V] { return OptionalRecordT[T, V]{ @@ -181,8 +190,8 @@ func (b BigSizeT[T]) Int() T { } // Record returns the underlying record interface for the record type. -func (t *BigSizeT[T]) Record() Record { +func (b *BigSizeT[T]) Record() Record { // We use a zero value for the type here as this should be used with // the higher order RecordT type. - return MakeBigSizeRecord(0, &t.v) + return MakeBigSizeRecord(0, &b.v) }