Skip to content

Commit

Permalink
channeldb: add encoding for ChannelEdgePolicy2
Browse files Browse the repository at this point in the history
Similarly to the previous commit, here we add the encoding for the new
ChannelEdgePolicy2. This is done in the same was as for
ChannelEdgeInfo2:
- a 0xff prefix
- followed by a type-byte
- followed by the TLV encoding of the ChannelEdgePolicy2.
  • Loading branch information
ellemouton committed Aug 23, 2024
1 parent 8162c52 commit ca4ff25
Show file tree
Hide file tree
Showing 3 changed files with 392 additions and 10 deletions.
205 changes: 198 additions & 7 deletions channeldb/edge_policy.go
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package channeldb

import (
"bufio"
"bytes"
"encoding/binary"
"fmt"
Expand All @@ -11,6 +12,30 @@ import (
"github.com/lightningnetwork/lnd/channeldb/models"
"github.com/lightningnetwork/lnd/kvdb"
"github.com/lightningnetwork/lnd/lnwire"
"github.com/lightningnetwork/lnd/tlv"
)

const (
EdgePolicy2MsgType = tlv.Type(0)
EdgePolicy2ToNode = tlv.Type(1)

// chanEdgePolicyNewEncodingPrefix is a byte used in the channel edge
// policy encoding to signal that the new style encoding which is
// prefixed with a type byte is being used instead of the legacy
// encoding which would start with 0x02 due to the fact that the
// encoding would start with a DER encoded ecdsa signature.
chanEdgePolicyNewEncodingPrefix = 0xff
)

// edgePolicyEncoding indicates how the bytes for a channel edge policy have
// been serialised.
type edgePolicyEncodingType uint8

const (
// edgePolicy2EncodingType will be used as a prefix for edge policies
// advertised using the ChannelUpdate2 message. The type indicates how
// the bytes following should be deserialized.
edgePolicy2EncodingType edgePolicyEncodingType = 0
)

func putChanEdgePolicy(edges kvdb.RwBucket, edge *models.ChannelEdgePolicy1,
Expand Down Expand Up @@ -60,7 +85,14 @@ func putChanEdgePolicy(edges kvdb.RwBucket, edge *models.ChannelEdgePolicy1,
return err
}

oldUpdateTime := uint64(oldEdgePolicy.LastUpdate.Unix())
oldPol, ok := oldEdgePolicy.(*models.ChannelEdgePolicy1)
if !ok {
return fmt.Errorf("expected "+
"*models.ChannelEdgePolicy1, got: %T",
oldEdgePolicy)
}

oldUpdateTime := uint64(oldPol.LastUpdate.Unix())

var oldIndexKey [8 + 8]byte
byteOrder.PutUint64(oldIndexKey[:8], oldUpdateTime)
Expand Down Expand Up @@ -163,7 +195,13 @@ func fetchChanEdgePolicy(edges kvdb.RBucket, chanID []byte,
return nil, err
}

return ep, nil
pol, ok := ep.(*models.ChannelEdgePolicy1)
if !ok {
return nil, fmt.Errorf("expected *models.ChannelEdgePolicy1, "+
"got: %T", ep)
}

return pol, nil
}

func fetchChanEdgePolicies(edgeIndex kvdb.RBucket, edges kvdb.RBucket,
Expand Down Expand Up @@ -198,8 +236,56 @@ func fetchChanEdgePolicies(edgeIndex kvdb.RBucket, edges kvdb.RBucket,
return edge1, edge2, nil
}

func serializeChanEdgePolicy(w io.Writer, edge *models.ChannelEdgePolicy1,
to []byte) error {
func serializeChanEdgePolicy(w io.Writer,
edgePolicy models.ChannelEdgePolicy, toNode []byte) error {

var (
withTypeByte bool
typeByte edgePolicyEncodingType
serialize func(w io.Writer) error
)

switch policy := edgePolicy.(type) {
case *models.ChannelEdgePolicy1:
serialize = func(w io.Writer) error {
copy(policy.ToNode[:], toNode)

return serializeChanEdgePolicy1(w, policy)
}
case *models.ChannelEdgePolicy2:
withTypeByte = true
typeByte = edgePolicy2EncodingType

serialize = func(w io.Writer) error {
copy(policy.ToNode[:], toNode)

return serializeChanEdgePolicy2(w, policy)
}
default:
return fmt.Errorf("unhandled implementation of "+
"ChannelEdgePolicy: %T", edgePolicy)
}

if withTypeByte {
// First, write the identifying encoding byte to signal that
// this is not using the legacy encoding.
_, err := w.Write([]byte{chanEdgePolicyNewEncodingPrefix})
if err != nil {
return err
}

// Now, write the encoding type.
_, err = w.Write([]byte{byte(typeByte)})
if err != nil {
return err
}
}

return serialize(w)
}

func serializeChanEdgePolicy1(w io.Writer,
edge *models.ChannelEdgePolicy1) error {

err := wire.WriteVarBytes(w, 0, edge.SigBytes)
if err != nil {
Expand Down Expand Up @@ -236,7 +322,7 @@ func serializeChanEdgePolicy(w io.Writer, edge *models.ChannelEdgePolicy1,
return err
}

if _, err := w.Write(to); err != nil {
if _, err := w.Write(edge.ToNode[:]); err != nil {
return err
}

Expand Down Expand Up @@ -265,7 +351,36 @@ func serializeChanEdgePolicy(w io.Writer, edge *models.ChannelEdgePolicy1,
return nil
}

func deserializeChanEdgePolicy(r io.Reader) (*models.ChannelEdgePolicy1, error) {
func serializeChanEdgePolicy2(w io.Writer,
edge *models.ChannelEdgePolicy2) error {

if len(edge.ExtraOpaqueData) > MaxAllowedExtraOpaqueBytes {
return ErrTooManyExtraOpaqueBytes(len(edge.ExtraOpaqueData))
}

var b bytes.Buffer
if err := edge.Encode(&b, 0); err != nil {
return err
}

msg := b.Bytes()

records := []tlv.Record{
tlv.MakePrimitiveRecord(EdgePolicy2MsgType, &msg),
tlv.MakePrimitiveRecord(EdgePolicy2ToNode, &edge.ToNode),
}

stream, err := tlv.NewStream(records...)
if err != nil {
return err
}

return stream.Encode(w)
}

func deserializeChanEdgePolicy(r io.Reader) (models.ChannelEdgePolicy,
error) {

// Deserialize the policy. Note that in case an optional field is not
// found, both an error and a populated policy object are returned.
edge, deserializeErr := deserializeChanEdgePolicyRaw(r)
Expand All @@ -278,7 +393,45 @@ func deserializeChanEdgePolicy(r io.Reader) (*models.ChannelEdgePolicy1, error)
return edge, deserializeErr
}

func deserializeChanEdgePolicyRaw(r io.Reader) (*models.ChannelEdgePolicy1,
func deserializeChanEdgePolicyRaw(reader io.Reader) (models.ChannelEdgePolicy,
error) {

// Wrap the io.Reader in a bufio.Reader so that we can peak the first
// byte of the stream without actually consuming from the stream.
r := bufio.NewReader(reader)

firstByte, err := r.Peek(1)
if err != nil {
return nil, err
}

if firstByte[0] != chanEdgePolicyNewEncodingPrefix {
return deserializeChanEdgePolicy1Raw(r)
}

// Pop the encoding type byte.
var scratch [1]byte
if _, err = r.Read(scratch[:]); err != nil {
return nil, err
}

// Now, read the encoding type byte.
if _, err = r.Read(scratch[:]); err != nil {
return nil, err
}

encoding := edgePolicyEncodingType(scratch[0])
switch encoding {
case edgePolicy2EncodingType:
return deserializeChanEdgePolicy2Raw(r)

default:
return nil, fmt.Errorf("unknown edge policy encoding type: %d",
encoding)
}
}

func deserializeChanEdgePolicy1Raw(r io.Reader) (*models.ChannelEdgePolicy1,
error) {

edge := &models.ChannelEdgePolicy1{}
Expand Down Expand Up @@ -364,3 +517,41 @@ func deserializeChanEdgePolicyRaw(r io.Reader) (*models.ChannelEdgePolicy1,

return edge, nil
}

func deserializeChanEdgePolicy2Raw(r io.Reader) (*models.ChannelEdgePolicy2,
error) {

var (
msgBytes []byte
toNode [33]byte
)

records := []tlv.Record{
tlv.MakePrimitiveRecord(EdgePolicy2MsgType, &msgBytes),
tlv.MakePrimitiveRecord(EdgePolicy2ToNode, &toNode),
}

stream, err := tlv.NewStream(records...)
if err != nil {
return nil, err
}

err = stream.Decode(r)
if err != nil {
return nil, err
}

var (
chanUpdate lnwire.ChannelUpdate2
reader = bytes.NewReader(msgBytes)
)
err = chanUpdate.Decode(reader, 0)
if err != nil {
return nil, err
}

return &models.ChannelEdgePolicy2{
ChannelUpdate2: chanUpdate,
ToNode: toNode,
}, nil
}
Loading

0 comments on commit ca4ff25

Please sign in to comment.