Merge pull request #3466 from cfromknecht/htlcswitch-hop

htlcswitch/hop: new package for hop payload parsing/encapsulation
This commit is contained in:
Joost Jager 2019-09-05 12:31:23 +02:00 committed by GitHub
commit 6638e1ddde
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
12 changed files with 217 additions and 156 deletions

@ -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"
)
@ -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
}
@ -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
}

@ -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
htlcswitch/hop/network.go Normal file

@ -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
htlcswitch/hop/payload.go Normal file

@ -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),
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
htlcswitch/hop/type.go Normal file

@ -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
)

@ -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
@ -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
@ -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)
}
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).

@ -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"
@ -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,
@ -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.
{

@ -16,6 +16,7 @@ import (
"github.com/lightningnetwork/lnd/channeldb"
"github.com/lightningnetwork/lnd/contractcourt"
"github.com/lightningnetwork/lnd/htlcswitch/hodl"
"github.com/lightningnetwork/lnd/htlcswitch/hop"
"github.com/lightningnetwork/lnd/input"
"github.com/lightningnetwork/lnd/invoices"
"github.com/lightningnetwork/lnd/lnpeer"
@ -436,8 +437,8 @@ func (l *channelLink) Start() error {
// off point, since all indexes below that are committed. This action
// is only performed if the link's final short channel ID has been
// assigned, otherwise we would try to trim the htlcs belonging to the
// all-zero, sourceHop ID.
if l.ShortChanID() != sourceHop {
// all-zero, hop.Source ID.
if l.ShortChanID() != hop.Source {
localHtlcIndex, err := l.channel.NextLocalHtlcIndex()
if err != nil {
return fmt.Errorf("unable to retrieve next local "+
@ -535,7 +536,7 @@ func (l *channelLink) WaitForShutdown() {
// the all-zero source ID, meaning that the channel has had its ID finalized.
func (l *channelLink) EligibleToForward() bool {
return l.channel.RemoteNextRevocation() != nil &&
l.ShortChanID() != sourceHop
l.ShortChanID() != hop.Source
}
// sampleNetworkFee samples the current fee rate on the network to get into the
@ -961,7 +962,7 @@ func (l *channelLink) htlcManager() {
// only attempt to resolve packages if our short chan id indicates that
// the channel is not pending, otherwise we should have no htlcs to
// reforward.
if l.ShortChanID() != sourceHop {
if l.ShortChanID() != hop.Source {
if err := l.resolveFwdPkgs(); err != nil {
l.fail(LinkFailureError{code: ErrInternalError},
"unable to resolve fwd pkgs: %v", err)
@ -2075,7 +2076,7 @@ func (l *channelLink) UpdateShortChanID() (lnwire.ShortChannelID, error) {
if err != nil {
l.errorf("unable to refresh short_chan_id for chan_id=%v: %v",
chanID, err)
return sourceHop, err
return hop.Source, err
}
sid := l.channel.ShortChanID()
@ -2674,7 +2675,7 @@ func (l *channelLink) processRemoteAdds(fwdPkg *channeldb.FwdPkg,
}
switch fwdInfo.NextHop {
case exitHop:
case hop.Exit:
updated, err := l.processExitHop(
pd, obfuscator, fwdInfo, heightNow,
chanIterator.ExtraOnionBlob(),
@ -2849,7 +2850,7 @@ func (l *channelLink) processRemoteAdds(fwdPkg *channeldb.FwdPkg,
// processExitHop handles an htlc for which this link is the exit hop. It
// returns a boolean indicating whether the commitment tx needs an update.
func (l *channelLink) processExitHop(pd *lnwallet.PaymentDescriptor,
obfuscator ErrorEncrypter, fwdInfo ForwardingInfo,
obfuscator ErrorEncrypter, fwdInfo hop.ForwardingInfo,
heightNow uint32, eob []byte) (bool, error) {
// If hodl.ExitSettle is requested, we will not validate the final hop's

@ -26,6 +26,7 @@ import (
"github.com/lightningnetwork/lnd/channeldb"
"github.com/lightningnetwork/lnd/contractcourt"
"github.com/lightningnetwork/lnd/htlcswitch/hodl"
"github.com/lightningnetwork/lnd/htlcswitch/hop"
"github.com/lightningnetwork/lnd/input"
"github.com/lightningnetwork/lnd/lnpeer"
"github.com/lightningnetwork/lnd/lntypes"
@ -1936,7 +1937,7 @@ func TestChannelLinkBandwidthConsistency(t *testing.T) {
}
addPkt := htlcPacket{
htlc: htlc,
incomingChanID: sourceHop,
incomingChanID: hop.Source,
incomingHTLCID: 0,
obfuscator: NewMockObfuscator(),
}
@ -2016,7 +2017,7 @@ func TestChannelLinkBandwidthConsistency(t *testing.T) {
}
addPkt = htlcPacket{
htlc: htlc,
incomingChanID: sourceHop,
incomingChanID: hop.Source,
incomingHTLCID: 1,
obfuscator: NewMockObfuscator(),
}
@ -2534,7 +2535,7 @@ func genAddsAndCircuits(numHtlcs int, htlc *lnwire.UpdateAddHTLC) (
for i := 0; i < numHtlcs; i++ {
addPkt := htlcPacket{
htlc: htlc,
incomingChanID: sourceHop,
incomingChanID: hop.Source,
incomingHTLCID: uint64(i),
obfuscator: NewMockObfuscator(),
}
@ -4307,10 +4308,10 @@ func generateHtlcAndInvoice(t *testing.T,
htlcAmt := lnwire.NewMSatFromSatoshis(10000)
htlcExpiry := testStartingHeight + testInvoiceCltvExpiry
hops := []ForwardingInfo{
hops := []hop.ForwardingInfo{
{
Network: BitcoinHop,
NextHop: exitHop,
Network: hop.BitcoinNetwork,
NextHop: hop.Exit,
AmountToForward: htlcAmt,
OutgoingCTLV: uint32(htlcExpiry),
},

@ -23,6 +23,7 @@ import (
"github.com/lightningnetwork/lnd/chainntnfs"
"github.com/lightningnetwork/lnd/channeldb"
"github.com/lightningnetwork/lnd/contractcourt"
"github.com/lightningnetwork/lnd/htlcswitch/hop"
"github.com/lightningnetwork/lnd/input"
"github.com/lightningnetwork/lnd/invoices"
"github.com/lightningnetwork/lnd/lnpeer"
@ -268,14 +269,16 @@ func (s *mockServer) QuitSignal() <-chan struct{} {
// mockHopIterator represents the test version of hop iterator which instead
// of encrypting the path in onion blob just stores the path as a list of hops.
type mockHopIterator struct {
hops []ForwardingInfo
hops []hop.ForwardingInfo
}
func newMockHopIterator(hops ...ForwardingInfo) HopIterator {
func newMockHopIterator(hops ...hop.ForwardingInfo) HopIterator {
return &mockHopIterator{hops: hops}
}
func (r *mockHopIterator) ForwardingInstructions() (ForwardingInfo, error) {
func (r *mockHopIterator) ForwardingInstructions() (
hop.ForwardingInfo, error) {
h := r.hops[0]
r.hops = r.hops[1:]
return h, nil
@ -300,7 +303,7 @@ func (r *mockHopIterator) EncodeNextHop(w io.Writer) error {
}
for _, hop := range r.hops {
if err := hop.encode(w); err != nil {
if err := encodeFwdInfo(w, &hop); err != nil {
return err
}
}
@ -308,7 +311,7 @@ func (r *mockHopIterator) EncodeNextHop(w io.Writer) error {
return nil
}
func (f *ForwardingInfo) encode(w io.Writer) error {
func encodeFwdInfo(w io.Writer, f *hop.ForwardingInfo) error {
if _, err := w.Write([]byte{byte(f.Network)}); err != nil {
return err
}
@ -429,10 +432,10 @@ func (p *mockIteratorDecoder) DecodeHopIterator(r io.Reader, rHash []byte,
}
hopLength := binary.BigEndian.Uint32(b[:])
hops := make([]ForwardingInfo, hopLength)
hops := make([]hop.ForwardingInfo, hopLength)
for i := uint32(0); i < hopLength; i++ {
f := &ForwardingInfo{}
if err := f.decode(r); err != nil {
f := &hop.ForwardingInfo{}
if err := decodeFwdInfo(r, f); err != nil {
return nil, lnwire.CodeTemporaryChannelFailure
}
@ -480,12 +483,12 @@ func (p *mockIteratorDecoder) DecodeHopIterators(id []byte,
return resps, nil
}
func (f *ForwardingInfo) decode(r io.Reader) error {
func decodeFwdInfo(r io.Reader, f *hop.ForwardingInfo) error {
var net [1]byte
if _, err := r.Read(net[:]); err != nil {
return err
}
f.Network = NetworkHop(net[0])
f.Network = hop.Network(net[0])
if err := binary.Read(r, binary.BigEndian, &f.NextHop); err != nil {
return err

@ -16,6 +16,7 @@ import (
"github.com/lightningnetwork/lnd/chainntnfs"
"github.com/lightningnetwork/lnd/channeldb"
"github.com/lightningnetwork/lnd/contractcourt"
"github.com/lightningnetwork/lnd/htlcswitch/hop"
"github.com/lightningnetwork/lnd/lntypes"
"github.com/lightningnetwork/lnd/lnwallet"
"github.com/lightningnetwork/lnd/lnwire"
@ -354,7 +355,7 @@ func (s *Switch) GetPaymentResult(paymentID uint64, paymentHash lntypes.Hash,
nChan <-chan *networkResult
err error
outKey = CircuitKey{
ChanID: sourceHop,
ChanID: hop.Source,
HtlcID: paymentID,
}
)
@ -428,7 +429,7 @@ func (s *Switch) SendHTLC(firstHop lnwire.ShortChannelID, paymentID uint64,
// this stage it means that packet haven't left boundaries of our
// system and something wrong happened.
packet := &htlcPacket{
incomingChanID: sourceHop,
incomingChanID: hop.Source,
incomingHTLCID: paymentID,
outgoingChanID: firstHop,
htlc: htlc,
@ -513,7 +514,7 @@ func (s *Switch) forward(packet *htlcPacket) error {
return ErrDuplicateAdd
case len(actions.Fails) == 1:
if packet.incomingChanID == sourceHop {
if packet.incomingChanID == hop.Source {
return err
}
@ -1031,14 +1032,14 @@ func (s *Switch) handlePacketForward(packet *htlcPacket) error {
case *lnwire.UpdateAddHTLC:
// Check if the node is set to reject all onward HTLCs and also make
// sure that HTLC is not from the source node.
if s.cfg.RejectHTLC && packet.incomingChanID != sourceHop {
if s.cfg.RejectHTLC && packet.incomingChanID != hop.Source {
failure := &lnwire.FailChannelDisabled{}
addErr := fmt.Errorf("unable to forward any htlcs")
return s.failAddPacket(packet, failure, addErr)
}
if packet.incomingChanID == sourceHop {
if packet.incomingChanID == hop.Source {
// A blank incomingChanID indicates that this is
// a pending user-initiated payment.
return s.handleLocalDispatch(packet)
@ -1080,7 +1081,7 @@ func (s *Switch) handlePacketForward(packet *htlcPacket) error {
// If the link doesn't yet have a source chan ID, then
// we'll skip it as well.
case link.ShortChanID() == sourceHop:
case link.ShortChanID() == hop.Source:
continue
}
@ -1222,7 +1223,7 @@ func (s *Switch) handlePacketForward(packet *htlcPacket) error {
//
// TODO(roasbeef): only do this once link actually
// fully settles?
localHTLC := packet.incomingChanID == sourceHop
localHTLC := packet.incomingChanID == hop.Source
if !localHTLC {
s.fwdEventMtx.Lock()
s.pendingFwdingEvents = append(
@ -1241,7 +1242,7 @@ func (s *Switch) handlePacketForward(packet *htlcPacket) error {
// A blank IncomingChanID in a circuit indicates that it is a pending
// user-initiated payment.
if packet.incomingChanID == sourceHop {
if packet.incomingChanID == hop.Source {
return s.handleLocalDispatch(packet)
}
@ -1798,7 +1799,7 @@ func (s *Switch) reforwardResponses() error {
shortChanID := openChannel.ShortChanID()
// Locally-initiated payments never need reforwarding.
if shortChanID == sourceHop {
if shortChanID == hop.Source {
continue
}
@ -1994,7 +1995,7 @@ func (s *Switch) AddLink(link ChannelLink) error {
}
shortChanID := link.ShortChanID()
if shortChanID == sourceHop {
if shortChanID == hop.Source {
log.Infof("Adding pending link chan_id=%v, short_chan_id=%v",
chanID, shortChanID)
@ -2157,7 +2158,7 @@ func (s *Switch) UpdateShortChanID(chanID lnwire.ChannelID) error {
}
// Reject any blank short channel ids.
if shortChanID == sourceHop {
if shortChanID == hop.Source {
return fmt.Errorf("refusing trivial short_chan_id for chan_id=%v"+
"live link", chanID)
}

@ -25,6 +25,7 @@ import (
"github.com/go-errors/errors"
"github.com/lightningnetwork/lnd/channeldb"
"github.com/lightningnetwork/lnd/contractcourt"
"github.com/lightningnetwork/lnd/htlcswitch/hop"
"github.com/lightningnetwork/lnd/input"
"github.com/lightningnetwork/lnd/keychain"
"github.com/lightningnetwork/lnd/lnpeer"
@ -596,7 +597,9 @@ func generatePayment(invoiceAmt, htlcAmt lnwire.MilliSatoshi, timelock uint32,
}
// generateRoute generates the path blob by given array of peers.
func generateRoute(hops ...ForwardingInfo) ([lnwire.OnionPacketSize]byte, error) {
func generateRoute(hops ...hop.ForwardingInfo) (
[lnwire.OnionPacketSize]byte, error) {
var blob [lnwire.OnionPacketSize]byte
if len(hops) == 0 {
return blob, errors.New("empty path")
@ -635,16 +638,17 @@ type threeHopNetwork struct {
// also the time lock value needed to route an HTLC with the target amount over
// the specified path.
func generateHops(payAmt lnwire.MilliSatoshi, startingHeight uint32,
path ...*channelLink) (lnwire.MilliSatoshi, uint32, []ForwardingInfo) {
path ...*channelLink) (lnwire.MilliSatoshi, uint32,
[]hop.ForwardingInfo) {
totalTimelock := startingHeight
runningAmt := payAmt
hops := make([]ForwardingInfo, len(path))
hops := make([]hop.ForwardingInfo, len(path))
for i := len(path) - 1; i >= 0; i-- {
// If this is the last hop, then the next hop is the special
// "exit node". Otherwise, we look to the "prior" hop.
nextHop := exitHop
nextHop := hop.Exit
if i != len(path)-1 {
nextHop = path[i+1].channel.ShortChanID()
}
@ -679,8 +683,8 @@ func generateHops(payAmt lnwire.MilliSatoshi, startingHeight uint32,
amount = runningAmt - fee
}
hops[i] = ForwardingInfo{
Network: BitcoinHop,
hops[i] = hop.ForwardingInfo{
Network: hop.BitcoinNetwork,
NextHop: nextHop,
AmountToForward: amount,
OutgoingCTLV: timeLock,
@ -731,7 +735,7 @@ func waitForPayFuncResult(payFunc func() error, d time.Duration) error {
// * from Alice to Carol through the Bob
// * from Alice to some another peer through the Bob
func makePayment(sendingPeer, receivingPeer lnpeer.Peer,
firstHop lnwire.ShortChannelID, hops []ForwardingInfo,
firstHop lnwire.ShortChannelID, hops []hop.ForwardingInfo,
invoiceAmt, htlcAmt lnwire.MilliSatoshi,
timelock uint32) *paymentResponse {
@ -765,7 +769,7 @@ func makePayment(sendingPeer, receivingPeer lnpeer.Peer,
// preparePayment creates an invoice at the receivingPeer and returns a function
// that, when called, launches the payment from the sendingPeer.
func preparePayment(sendingPeer, receivingPeer lnpeer.Peer,
firstHop lnwire.ShortChannelID, hops []ForwardingInfo,
firstHop lnwire.ShortChannelID, hops []hop.ForwardingInfo,
invoiceAmt, htlcAmt lnwire.MilliSatoshi,
timelock uint32) (*channeldb.Invoice, func() error, error) {
@ -1246,7 +1250,7 @@ func (n *twoHopNetwork) stop() {
}
func (n *twoHopNetwork) makeHoldPayment(sendingPeer, receivingPeer lnpeer.Peer,
firstHop lnwire.ShortChannelID, hops []ForwardingInfo,
firstHop lnwire.ShortChannelID, hops []hop.ForwardingInfo,
invoiceAmt, htlcAmt lnwire.MilliSatoshi,
timelock uint32, preimage lntypes.Preimage) chan error {