Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 4 additions & 3 deletions htlcswitch/circuit_map.go
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ import (
"github.com/davecgh/go-spew/spew"
"github.com/go-errors/errors"
"github.com/lightningnetwork/lnd/channeldb"
"github.com/lightningnetwork/lnd/htlcswitch/hop"
"github.com/lightningnetwork/lnd/lnwire"
)

Expand Down Expand Up @@ -311,7 +312,7 @@ func (cm *circuitMap) restoreMemState() error {
// documented case of stray keystones emerges for
// forwarded payments, this check should be removed, but
// with extreme caution.
if strayKeystone.OutKey.ChanID != sourceHop {
if strayKeystone.OutKey.ChanID != hop.Source {
continue
}

Expand Down Expand Up @@ -396,9 +397,9 @@ func (cm *circuitMap) trimAllOpenCircuits() error {

// First, skip any channels that have not been assigned their
// final channel identifier, otherwise we would try to trim
// htlcs belonging to the all-zero, sourceHop ID.
// htlcs belonging to the all-zero, hop.Source ID.
chanID := activeChannel.ShortChanID()
if chanID == sourceHop {
if chanID == hop.Source {
continue
}

Expand Down
29 changes: 29 additions & 0 deletions htlcswitch/hop/forwarding_info.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
package hop

import (
"github.com/lightningnetwork/lnd/lnwire"
)

// ForwardingInfo contains all the information that is necessary to forward and
// incoming HTLC to the next hop encoded within a valid HopIterator instance.
// Forwarding links are to use this information to authenticate the information
// received within the incoming HTLC, to ensure that the prior hop didn't
// tamper with the end-to-end routing information at all.
type ForwardingInfo struct {
// Network is the target blockchain network that the HTLC will travel
// over next.
Network Network

// NextHop is the channel ID of the next hop. The received HTLC should
// be forwarded to this particular channel in order to continue the
// end-to-end route.
NextHop lnwire.ShortChannelID

// AmountToForward is the amount of milli-satoshis that the receiving
// node should forward to the next hop.
AmountToForward lnwire.MilliSatoshi

// OutgoingCTLV is the specified value of the CTLV timelock to be used
// in the outgoing HTLC.
OutgoingCTLV uint32
}
28 changes: 28 additions & 0 deletions htlcswitch/hop/network.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
package hop

// Network indicates the blockchain network that is intended to be the next hop
// for a forwarded HTLC. The existence of this field within the ForwardingInfo
// struct enables the ability for HTLC to cross chain-boundaries at will.
type Network uint8

const (
// BitcoinNetwork denotes that an HTLC is to be forwarded along the
// Bitcoin link with the specified short channel ID.
BitcoinNetwork Network = iota

// LitecoinNetwork denotes that an HTLC is to be forwarded along the
// Litecoin link with the specified short channel ID.
LitecoinNetwork
)

// String returns the string representation of the target Network.
func (c Network) String() string {
switch c {
case BitcoinNetwork:
return "Bitcoin"
case LitecoinNetwork:
return "Litecoin"
default:
return "Kekcoin"
}
}
75 changes: 75 additions & 0 deletions htlcswitch/hop/payload.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,75 @@
package hop

import (
"encoding/binary"
"io"

"github.com/lightningnetwork/lightning-onion"
"github.com/lightningnetwork/lnd/lnwire"
"github.com/lightningnetwork/lnd/record"
"github.com/lightningnetwork/lnd/tlv"
)

// Payload encapsulates all information delivered to a hop in an onion payload.
// A Hop can represent either a TLV or legacy payload. The primary forwarding
// instruction can be accessed via ForwardingInfo, and additional records can be
// accessed by other member functions.
type Payload struct {
// FwdInfo holds the basic parameters required for HTLC forwarding, e.g.
// amount, cltv, and next hop.
FwdInfo ForwardingInfo
}

// NewLegacyPayload builds a Payload from the amount, cltv, and next hop
// parameters provided by leegacy onion payloads.
func NewLegacyPayload(f *sphinx.HopData) *Payload {
nextHop := binary.BigEndian.Uint64(f.NextAddress[:])

return &Payload{
FwdInfo: ForwardingInfo{
Network: BitcoinNetwork,
NextHop: lnwire.NewShortChanIDFromInt(nextHop),
AmountToForward: lnwire.MilliSatoshi(f.ForwardAmount),
OutgoingCTLV: f.OutgoingCltv,
},
}
}

// NewPayloadFromReader builds a new Hop from the passed io.Reader. The reader
// should correspond to the bytes encapsulated in a TLV onion payload.
func NewPayloadFromReader(r io.Reader) (*Payload, error) {
var (
cid uint64
amt uint64
cltv uint32
)

tlvStream, err := tlv.NewStream(
record.NewAmtToFwdRecord(&amt),
record.NewLockTimeRecord(&cltv),
record.NewNextHopIDRecord(&cid),
)
if err != nil {
return nil, err
}

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

return &Payload{
FwdInfo: ForwardingInfo{
Network: BitcoinNetwork,
NextHop: lnwire.NewShortChanIDFromInt(cid),
Comment thread
joostjager marked this conversation as resolved.
Outdated
AmountToForward: lnwire.MilliSatoshi(amt),
OutgoingCTLV: cltv,
},
}, nil
}

// ForwardingInfo returns the basic parameters required for HTLC forwarding,
// e.g. amount, cltv, and next hop.
func (h *Payload) ForwardingInfo() ForwardingInfo {
return h.FwdInfo
}
13 changes: 13 additions & 0 deletions htlcswitch/hop/type.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
package hop

import "github.com/lightningnetwork/lnd/lnwire"

var (
// Exit is a special "hop" denoting that an incoming HTLC is meant to
// pay finally to the receiving node.
Exit lnwire.ShortChannelID

// Source is a sentinel "hop" denoting that an incoming HTLC is
// initiated by our own switch.
Source lnwire.ShortChannelID
)
120 changes: 12 additions & 108 deletions htlcswitch/iterator.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,82 +2,15 @@ package htlcswitch

import (
"bytes"
"encoding/binary"
"fmt"
"io"

"github.com/btcsuite/btcd/btcec"
"github.com/lightningnetwork/lightning-onion"
"github.com/lightningnetwork/lnd/htlcswitch/hop"
"github.com/lightningnetwork/lnd/lnwire"
"github.com/lightningnetwork/lnd/record"
"github.com/lightningnetwork/lnd/tlv"
)

// NetworkHop indicates the blockchain network that is intended to be the next
// hop for a forwarded HTLC. The existence of this field within the
// ForwardingInfo struct enables the ability for HTLC to cross chain-boundaries
// at will.
type NetworkHop uint8

const (
// BitcoinHop denotes that an HTLC is to be forwarded along the Bitcoin
// link with the specified short channel ID.
BitcoinHop NetworkHop = iota

// LitecoinHop denotes that an HTLC is to be forwarded along the
// Litecoin link with the specified short channel ID.
LitecoinHop
)

// String returns the string representation of the target NetworkHop.
func (c NetworkHop) String() string {
switch c {
case BitcoinHop:
return "Bitcoin"
case LitecoinHop:
return "Litecoin"
default:
return "Kekcoin"
}
}

var (
// exitHop is a special "hop" which denotes that an incoming HTLC is
// meant to pay finally to the receiving node.
exitHop lnwire.ShortChannelID

// sourceHop is a sentinel value denoting that an incoming HTLC is
// initiated by our own switch.
sourceHop lnwire.ShortChannelID
)

// ForwardingInfo contains all the information that is necessary to forward and
// incoming HTLC to the next hop encoded within a valid HopIterator instance.
// Forwarding links are to use this information to authenticate the information
// received within the incoming HTLC, to ensure that the prior hop didn't
// tamper with the end-to-end routing information at all.
type ForwardingInfo struct {
// Network is the target blockchain network that the HTLC will travel
// over next.
Network NetworkHop

// NextHop is the channel ID of the next hop. The received HTLC should
// be forwarded to this particular channel in order to continue the
// end-to-end route.
NextHop lnwire.ShortChannelID

// AmountToForward is the amount of milli-satoshis that the receiving
// node should forward to the next hop.
AmountToForward lnwire.MilliSatoshi

// OutgoingCTLV is the specified value of the CTLV timelock to be used
// in the outgoing HTLC.
OutgoingCTLV uint32

// TODO(roasbeef): modify sphinx logic to not just discard the
// remaining bytes, instead should include the rest as excess
}

// HopIterator is an interface that abstracts away the routing information
// included in HTLC's which includes the entirety of the payment path of an
// HTLC. This interface provides two basic method which carry out: how to
Expand All @@ -89,7 +22,7 @@ type HopIterator interface {
// Additionally, the information encoded within the returned
// ForwardingInfo is to be used by each hop to authenticate the
// information given to it by the prior hop.
ForwardingInstructions() (ForwardingInfo, error)
ForwardingInstructions() (hop.ForwardingInfo, error)

// ExtraOnionBlob returns the additional EOB data (if available).
ExtraOnionBlob() []byte
Expand Down Expand Up @@ -146,64 +79,35 @@ func (r *sphinxHopIterator) EncodeNextHop(w io.Writer) error {
// hop to authenticate the information given to it by the prior hop.
//
// NOTE: Part of the HopIterator interface.
func (r *sphinxHopIterator) ForwardingInstructions() (ForwardingInfo, error) {
var (
nextHop lnwire.ShortChannelID
amt uint64
cltv uint32
)
func (r *sphinxHopIterator) ForwardingInstructions() (
hop.ForwardingInfo, error) {

switch r.processedPacket.Payload.Type {
// If this is the legacy payload, then we'll extract the information
// directly from the pre-populated ForwardingInstructions field.
case sphinx.PayloadLegacy:
fwdInst := r.processedPacket.ForwardingInstructions
p := hop.NewLegacyPayload(fwdInst)

switch r.processedPacket.Action {
case sphinx.ExitNode:
nextHop = exitHop
case sphinx.MoreHops:
s := binary.BigEndian.Uint64(fwdInst.NextAddress[:])
nextHop = lnwire.NewShortChanIDFromInt(s)
}
Comment thread
joostjager marked this conversation as resolved.
Outdated

amt = fwdInst.ForwardAmount
cltv = fwdInst.OutgoingCltv
return p.ForwardingInfo(), nil

// Otherwise, if this is the TLV payload, then we'll make a new stream
// to decode only what we need to make routing decisions.
case sphinx.PayloadTLV:
var cid uint64

tlvStream, err := tlv.NewStream(
record.NewAmtToFwdRecord(&amt),
record.NewLockTimeRecord(&cltv),
record.NewNextHopIDRecord(&cid),
)
if err != nil {
return ForwardingInfo{}, err
}

err = tlvStream.Decode(bytes.NewReader(
p, err := hop.NewPayloadFromReader(bytes.NewReader(
r.processedPacket.Payload.Payload,
))
if err != nil {
return ForwardingInfo{}, err
return hop.ForwardingInfo{}, err
}

nextHop = lnwire.NewShortChanIDFromInt(cid)
return p.ForwardingInfo(), nil

default:
return ForwardingInfo{}, fmt.Errorf("unknown sphinx payload "+
"type: %v", r.processedPacket.Payload.Type)
return hop.ForwardingInfo{}, fmt.Errorf("unknown "+
"sphinx payload type: %v",
r.processedPacket.Payload.Type)
}

return ForwardingInfo{
Network: BitcoinHop,
NextHop: nextHop,
AmountToForward: lnwire.MilliSatoshi(amt),
OutgoingCTLV: cltv,
}, nil
}

// ExtraOnionBlob returns the additional EOB data (if available).
Expand Down
5 changes: 3 additions & 2 deletions htlcswitch/iterator_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import (

"github.com/davecgh/go-spew/spew"
sphinx "github.com/lightningnetwork/lightning-onion"
"github.com/lightningnetwork/lnd/htlcswitch/hop"
"github.com/lightningnetwork/lnd/lnwire"
"github.com/lightningnetwork/lnd/record"
"github.com/lightningnetwork/lnd/tlv"
Expand All @@ -29,7 +30,7 @@ func TestSphinxHopIteratorForwardingInstructions(t *testing.T) {
// Next, we'll make the hop forwarding information that we should
// extract each type, no matter the payload type.
nextAddrInt := binary.BigEndian.Uint64(hopData.NextAddress[:])
expectedFwdInfo := ForwardingInfo{
expectedFwdInfo := hop.ForwardingInfo{
NextHop: lnwire.NewShortChanIDFromInt(nextAddrInt),
AmountToForward: lnwire.MilliSatoshi(hopData.ForwardAmount),
OutgoingCTLV: hopData.OutgoingCltv,
Expand All @@ -53,7 +54,7 @@ func TestSphinxHopIteratorForwardingInstructions(t *testing.T) {

var testCases = []struct {
sphinxPacket *sphinx.ProcessedPacket
expectedFwdInfo ForwardingInfo
expectedFwdInfo hop.ForwardingInfo
}{
// A regular legacy payload that signals more hops.
{
Expand Down
Loading