Merge pull request #3466 from cfromknecht/htlcswitch-hop
htlcswitch/hop: new package for hop payload parsing/encapsulation
This commit is contained in:
commit
6638e1ddde
@ -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
|
||||
}
|
||||
|
||||
|
29
htlcswitch/hop/forwarding_info.go
Normal file
29
htlcswitch/hop/forwarding_info.go
Normal file
@ -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
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
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
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 {
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user