diff --git a/channeldb/error.go b/channeldb/error.go index 15cfa840..c9ddfb49 100644 --- a/channeldb/error.go +++ b/channeldb/error.go @@ -97,6 +97,12 @@ var ( // ErrNoForwardingEvents is returned in the case that a query fails due // to the log not having any recorded events. ErrNoForwardingEvents = fmt.Errorf("no recorded forwarding events") + + // ErrEdgePolicyOptionalFieldNotFound is an error returned if a channel + // policy field is not found in the db even though its message flags + // indicate it should be. + ErrEdgePolicyOptionalFieldNotFound = fmt.Errorf("optional field not " + + "present") ) // ErrTooManyExtraOpaqueBytes creates an error which should be returned if the diff --git a/channeldb/graph.go b/channeldb/graph.go index 947561a1..085d46e7 100644 --- a/channeldb/graph.go +++ b/channeldb/graph.go @@ -2439,6 +2439,10 @@ type ChannelEdgePolicy struct { // in millisatoshi. MinHTLC lnwire.MilliSatoshi + // MaxHTLC is the largest value HTLC this node will accept, expressed + // in millisatoshi. + MaxHTLC lnwire.MilliSatoshi + // FeeBaseMSat is the base HTLC fee that will be charged for forwarding // ANY HTLC, expressed in mSAT's. FeeBaseMSat lnwire.MilliSatoshi @@ -3348,11 +3352,26 @@ func serializeChanEdgePolicy(w io.Writer, edge *ChannelEdgePolicy, return err } + // If the max_htlc field is present, we write it. To be compatible with + // older versions that wasn't aware of this field, we write it as part + // of the opaque data. + // TODO(halseth): clean up when moving to TLV. + var opaqueBuf bytes.Buffer + if edge.MessageFlags&lnwire.ChanUpdateOptionMaxHtlc != 0 { + err := binary.Write(&opaqueBuf, byteOrder, uint64(edge.MaxHTLC)) + if err != nil { + return err + } + } + if len(edge.ExtraOpaqueData) > MaxAllowedExtraOpaqueBytes { return ErrTooManyExtraOpaqueBytes(len(edge.ExtraOpaqueData)) } + if _, err := opaqueBuf.Write(edge.ExtraOpaqueData); err != nil { + return err + } - if err := wire.WriteVarBytes(w, 0, edge.ExtraOpaqueData); err != nil { + if err := wire.WriteVarBytes(w, 0, opaqueBuf.Bytes()); err != nil { return err } return nil @@ -3416,6 +3435,7 @@ func deserializeChanEdgePolicy(r io.Reader, return nil, fmt.Errorf("unable to fetch node: %x, %v", pub[:], err) } + edge.Node = &node // We'll try and see if there are any opaque bytes left, if not, then // we'll ignore the EOF error and return the edge as is. @@ -3429,6 +3449,25 @@ func deserializeChanEdgePolicy(r io.Reader, return nil, err } - edge.Node = &node + // See if optional fields are present. + if edge.MessageFlags&lnwire.ChanUpdateOptionMaxHtlc != 0 { + // The max_htlc field should be at the beginning of the opaque + // bytes. + opq := edge.ExtraOpaqueData + + // If the max_htlc field is not present, it might be old data + // stored before this field was validated. We'll return the + // edge along with an error. + if len(opq) < 8 { + return edge, ErrEdgePolicyOptionalFieldNotFound + } + + maxHtlc := byteOrder.Uint64(opq[:8]) + edge.MaxHTLC = lnwire.MilliSatoshi(maxHtlc) + + // Exclude the parsed field from the rest of the opaque data. + edge.ExtraOpaqueData = opq[8:] + } + return edge, nil }