Merge pull request #775 from cfromknecht/sphinx-replay
Switch Persistence [1/4]: Infra for Sphinx Batched Decoding and Replay Protection
This commit is contained in:
commit
649be5ee0b
6
glide.lock
generated
6
glide.lock
generated
@ -1,5 +1,5 @@
|
|||||||
hash: e0cbbf733425814948ced513c5921d8a4920f179d059f39eeafbf337c32b4ead
|
hash: 607d774162a30647479b037b9291e372c92d1ab6b60808837b22c205ac58981f
|
||||||
updated: 2018-03-08T20:06:04.267833-05:00
|
updated: 2018-03-08T21:10:50.953704-05:00
|
||||||
imports:
|
imports:
|
||||||
- name: git.schwanenlied.me/yawning/bsaes.git
|
- name: git.schwanenlied.me/yawning/bsaes.git
|
||||||
version: e06297f34865a50b8e473105e52cb64ad1b55da8
|
version: e06297f34865a50b8e473105e52cb64ad1b55da8
|
||||||
@ -84,7 +84,7 @@ imports:
|
|||||||
- filterdb
|
- filterdb
|
||||||
- headerfs
|
- headerfs
|
||||||
- name: github.com/lightningnetwork/lightning-onion
|
- name: github.com/lightningnetwork/lightning-onion
|
||||||
version: dbb6dc0eaf32a043c9bc3cfed0fd5fd8db08e3b9
|
version: 9e4b184daf3e32e0c2e523b92ec1b2d6c51ad77f
|
||||||
- name: github.com/ltcsuite/ltcd
|
- name: github.com/ltcsuite/ltcd
|
||||||
version: 5f654d5faab99ee2b3488fabba98e5f7a5257ee3
|
version: 5f654d5faab99ee2b3488fabba98e5f7a5257ee3
|
||||||
subpackages:
|
subpackages:
|
||||||
|
@ -59,7 +59,7 @@ import:
|
|||||||
- package: google.golang.org/grpc
|
- package: google.golang.org/grpc
|
||||||
version: b3ddf786825de56a4178401b7e174ee332173b66
|
version: b3ddf786825de56a4178401b7e174ee332173b66
|
||||||
- package: github.com/lightningnetwork/lightning-onion
|
- package: github.com/lightningnetwork/lightning-onion
|
||||||
version: dbb6dc0eaf32a043c9bc3cfed0fd5fd8db08e3b9
|
version: 9e4b184daf3e32e0c2e523b92ec1b2d6c51ad77f
|
||||||
- package: github.com/grpc-ecosystem/grpc-gateway
|
- package: github.com/grpc-ecosystem/grpc-gateway
|
||||||
version: f2862b476edcef83412c7af8687c9cd8e4097c0f
|
version: f2862b476edcef83412c7af8687c9cd8e4097c0f
|
||||||
- package: github.com/go-errors/errors
|
- package: github.com/go-errors/errors
|
||||||
|
@ -3,6 +3,7 @@ package htlcswitch
|
|||||||
import (
|
import (
|
||||||
"bytes"
|
"bytes"
|
||||||
"fmt"
|
"fmt"
|
||||||
|
"io"
|
||||||
|
|
||||||
"github.com/lightningnetwork/lightning-onion"
|
"github.com/lightningnetwork/lightning-onion"
|
||||||
"github.com/lightningnetwork/lnd/lnwire"
|
"github.com/lightningnetwork/lnd/lnwire"
|
||||||
@ -45,6 +46,37 @@ type ErrorDecrypter interface {
|
|||||||
DecryptError(lnwire.OpaqueReason) (*ForwardingError, error)
|
DecryptError(lnwire.OpaqueReason) (*ForwardingError, error)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// EncrypterType establishes an enum used in serialization to indicate how to
|
||||||
|
// decode a concrete instance of the ErrorEncrypter interface.
|
||||||
|
type EncrypterType byte
|
||||||
|
|
||||||
|
const (
|
||||||
|
// EncrypterTypeNone signals that no error encyrpter is present, this
|
||||||
|
// can happen if the htlc is originates in the switch.
|
||||||
|
EncrypterTypeNone EncrypterType = 0
|
||||||
|
|
||||||
|
// EncrypterTypeSphinx is used to identify a sphinx onion error
|
||||||
|
// encrypter instance.
|
||||||
|
EncrypterTypeSphinx = 1
|
||||||
|
|
||||||
|
// EncrypterTypeMock is used to identify a mock obfuscator instance.
|
||||||
|
EncrypterTypeMock = 2
|
||||||
|
)
|
||||||
|
|
||||||
|
// UnknownEncrypterType is an error message used to signal that an unexpected
|
||||||
|
// EncrypterType was encountered during decoding.
|
||||||
|
type UnknownEncrypterType EncrypterType
|
||||||
|
|
||||||
|
// Error returns a formatted error indicating the invalid EncrypterType.
|
||||||
|
func (e UnknownEncrypterType) Error() string {
|
||||||
|
return fmt.Sprintf("unknown error encrypter type: %d", e)
|
||||||
|
}
|
||||||
|
|
||||||
|
// ErrorEncrypterExtracter defines a function signature that extracts an
|
||||||
|
// ErrorEncrypter from an sphinx OnionPacket.
|
||||||
|
type ErrorEncrypterExtracter func(*sphinx.OnionPacket) (ErrorEncrypter,
|
||||||
|
lnwire.FailCode)
|
||||||
|
|
||||||
// ErrorEncrypter is an interface that is used to encrypt HTLC related errors
|
// ErrorEncrypter is an interface that is used to encrypt HTLC related errors
|
||||||
// at the source of the error, and also at each intermediate hop all the way
|
// at the source of the error, and also at each intermediate hop all the way
|
||||||
// back to the source of the payment.
|
// back to the source of the payment.
|
||||||
@ -59,6 +91,16 @@ type ErrorEncrypter interface {
|
|||||||
// in an additional layer of onion encryption. This process repeats
|
// in an additional layer of onion encryption. This process repeats
|
||||||
// until the error arrives at the source of the payment.
|
// until the error arrives at the source of the payment.
|
||||||
IntermediateEncrypt(lnwire.OpaqueReason) lnwire.OpaqueReason
|
IntermediateEncrypt(lnwire.OpaqueReason) lnwire.OpaqueReason
|
||||||
|
|
||||||
|
// Type returns an enum indicating the underlying concrete instance
|
||||||
|
// backing this interface.
|
||||||
|
Type() EncrypterType
|
||||||
|
|
||||||
|
// Encode serializes the encrypter to the given io.Writer.
|
||||||
|
Encode(io.Writer) error
|
||||||
|
|
||||||
|
// Decode deserializes the encrypter from the given io.Reader.
|
||||||
|
Decode(io.Reader) error
|
||||||
}
|
}
|
||||||
|
|
||||||
// SphinxErrorEncrypter is a concrete implementation of both the ErrorEncrypter
|
// SphinxErrorEncrypter is a concrete implementation of both the ErrorEncrypter
|
||||||
@ -67,6 +109,16 @@ type ErrorEncrypter interface {
|
|||||||
// encryption and must be treated as such accordingly.
|
// encryption and must be treated as such accordingly.
|
||||||
type SphinxErrorEncrypter struct {
|
type SphinxErrorEncrypter struct {
|
||||||
*sphinx.OnionErrorEncrypter
|
*sphinx.OnionErrorEncrypter
|
||||||
|
|
||||||
|
ogPacket *sphinx.OnionPacket
|
||||||
|
}
|
||||||
|
|
||||||
|
// NewSphinxErrorEncrypter initializes a new sphinx error encrypter as well as
|
||||||
|
// the embedded onion error encrypter.
|
||||||
|
func NewSphinxErrorEncrypter() *SphinxErrorEncrypter {
|
||||||
|
return &SphinxErrorEncrypter{
|
||||||
|
OnionErrorEncrypter: &sphinx.OnionErrorEncrypter{},
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// EncryptFirstHop transforms a concrete failure message into an encrypted
|
// EncryptFirstHop transforms a concrete failure message into an encrypted
|
||||||
@ -97,6 +149,24 @@ func (s *SphinxErrorEncrypter) IntermediateEncrypt(reason lnwire.OpaqueReason) l
|
|||||||
return s.EncryptError(false, reason)
|
return s.EncryptError(false, reason)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Type returns the identifier for a sphinx error encrypter.
|
||||||
|
func (s *SphinxErrorEncrypter) Type() EncrypterType {
|
||||||
|
return EncrypterTypeSphinx
|
||||||
|
}
|
||||||
|
|
||||||
|
// Encode serializes the error encrypter to the provided io.Writer.
|
||||||
|
func (s *SphinxErrorEncrypter) Encode(w io.Writer) error {
|
||||||
|
return s.OnionErrorEncrypter.Encode(w)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Decode reconstructs the error encrypter from the provided io.Reader.
|
||||||
|
func (s *SphinxErrorEncrypter) Decode(r io.Reader) error {
|
||||||
|
if s.OnionErrorEncrypter == nil {
|
||||||
|
s.OnionErrorEncrypter = &sphinx.OnionErrorEncrypter{}
|
||||||
|
}
|
||||||
|
return s.OnionErrorEncrypter.Decode(r)
|
||||||
|
}
|
||||||
|
|
||||||
// A compile time check to ensure SphinxErrorEncrypter implements the
|
// A compile time check to ensure SphinxErrorEncrypter implements the
|
||||||
// ErrorEncrypter interface.
|
// ErrorEncrypter interface.
|
||||||
var _ ErrorEncrypter = (*SphinxErrorEncrypter)(nil)
|
var _ ErrorEncrypter = (*SphinxErrorEncrypter)(nil)
|
||||||
|
@ -40,6 +40,10 @@ var (
|
|||||||
// exitHop is a special "hop" which denotes that an incoming HTLC is
|
// exitHop is a special "hop" which denotes that an incoming HTLC is
|
||||||
// meant to pay finally to the receiving node.
|
// meant to pay finally to the receiving node.
|
||||||
exitHop lnwire.ShortChannelID
|
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
|
// ForwardingInfo contains all the information that is necessary to forward and
|
||||||
@ -85,14 +89,20 @@ type HopIterator interface {
|
|||||||
// EncodeNextHop encodes the onion packet destined for the next hop
|
// EncodeNextHop encodes the onion packet destined for the next hop
|
||||||
// into the passed io.Writer.
|
// into the passed io.Writer.
|
||||||
EncodeNextHop(w io.Writer) error
|
EncodeNextHop(w io.Writer) error
|
||||||
|
|
||||||
|
// ExtractErrorEncrypter returns the ErrorEncrypter needed for this hop,
|
||||||
|
// along with a failure code to signal if the decoding was successful.
|
||||||
|
ExtractErrorEncrypter(ErrorEncrypterExtracter) (ErrorEncrypter,
|
||||||
|
lnwire.FailCode)
|
||||||
}
|
}
|
||||||
|
|
||||||
// sphinxHopIterator is the Sphinx implementation of hop iterator which uses
|
// sphinxHopIterator is the Sphinx implementation of hop iterator which uses
|
||||||
// onion routing to encode the payment route in such a way so that node might
|
// onion routing to encode the payment route in such a way so that node might
|
||||||
// see only the next hop in the route..
|
// see only the next hop in the route..
|
||||||
type sphinxHopIterator struct {
|
type sphinxHopIterator struct {
|
||||||
// nextPacket is the decoded onion packet for the _next_ hop.
|
// ogPacket is the original packet from which the processed packet is
|
||||||
nextPacket *sphinx.OnionPacket
|
// derived.
|
||||||
|
ogPacket *sphinx.OnionPacket
|
||||||
|
|
||||||
// processedPacket is the outcome of processing an onion packet. It
|
// processedPacket is the outcome of processing an onion packet. It
|
||||||
// includes the information required to properly forward the packet to
|
// includes the information required to properly forward the packet to
|
||||||
@ -100,6 +110,17 @@ type sphinxHopIterator struct {
|
|||||||
processedPacket *sphinx.ProcessedPacket
|
processedPacket *sphinx.ProcessedPacket
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// makeSphinxHopIterator converts a processed packet returned from a sphinx
|
||||||
|
// router and converts it into an hop iterator for usage in the link.
|
||||||
|
func makeSphinxHopIterator(ogPacket *sphinx.OnionPacket,
|
||||||
|
packet *sphinx.ProcessedPacket) *sphinxHopIterator {
|
||||||
|
|
||||||
|
return &sphinxHopIterator{
|
||||||
|
ogPacket: ogPacket,
|
||||||
|
processedPacket: packet,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// A compile time check to ensure sphinxHopIterator implements the HopIterator
|
// A compile time check to ensure sphinxHopIterator implements the HopIterator
|
||||||
// interface.
|
// interface.
|
||||||
var _ HopIterator = (*sphinxHopIterator)(nil)
|
var _ HopIterator = (*sphinxHopIterator)(nil)
|
||||||
@ -108,7 +129,7 @@ var _ HopIterator = (*sphinxHopIterator)(nil)
|
|||||||
//
|
//
|
||||||
// NOTE: Part of the HopIterator interface.
|
// NOTE: Part of the HopIterator interface.
|
||||||
func (r *sphinxHopIterator) EncodeNextHop(w io.Writer) error {
|
func (r *sphinxHopIterator) EncodeNextHop(w io.Writer) error {
|
||||||
return r.nextPacket.Encode(w)
|
return r.processedPacket.NextPacket.Encode(w)
|
||||||
}
|
}
|
||||||
|
|
||||||
// ForwardingInstructions returns the set of fields that detail exactly _how_
|
// ForwardingInstructions returns the set of fields that detail exactly _how_
|
||||||
@ -137,6 +158,18 @@ func (r *sphinxHopIterator) ForwardingInstructions() ForwardingInfo {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// ExtractErrorEncrypter decodes and returns the ErrorEncrypter for this hop,
|
||||||
|
// along with a failure code to signal if the decoding was successful. The
|
||||||
|
// ErrorEncrypter is used to encrypt errors back to the sender in the event that
|
||||||
|
// a payment fails.
|
||||||
|
//
|
||||||
|
// NOTE: Part of the HopIterator interface.
|
||||||
|
func (r *sphinxHopIterator) ExtractErrorEncrypter(
|
||||||
|
extracter ErrorEncrypterExtracter) (ErrorEncrypter, lnwire.FailCode) {
|
||||||
|
|
||||||
|
return extracter(r.ogPacket)
|
||||||
|
}
|
||||||
|
|
||||||
// OnionProcessor is responsible for keeping all sphinx dependent parts inside
|
// OnionProcessor is responsible for keeping all sphinx dependent parts inside
|
||||||
// and expose only decoding function. With such approach we give freedom for
|
// and expose only decoding function. With such approach we give freedom for
|
||||||
// subsystems which wants to decode sphinx path to not be dependable from
|
// subsystems which wants to decode sphinx path to not be dependable from
|
||||||
@ -155,11 +188,22 @@ func NewOnionProcessor(router *sphinx.Router) *OnionProcessor {
|
|||||||
return &OnionProcessor{router}
|
return &OnionProcessor{router}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Start spins up the onion processor's sphinx router.
|
||||||
|
func (p *OnionProcessor) Start() error {
|
||||||
|
return p.router.Start()
|
||||||
|
}
|
||||||
|
|
||||||
|
// Stop shutsdown the onion processor's sphinx router.
|
||||||
|
func (p *OnionProcessor) Stop() error {
|
||||||
|
p.router.Stop()
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
// DecodeHopIterator attempts to decode a valid sphinx packet from the passed io.Reader
|
// DecodeHopIterator attempts to decode a valid sphinx packet from the passed io.Reader
|
||||||
// instance using the rHash as the associated data when checking the relevant
|
// instance using the rHash as the associated data when checking the relevant
|
||||||
// MACs during the decoding process.
|
// MACs during the decoding process.
|
||||||
func (p *OnionProcessor) DecodeHopIterator(r io.Reader, rHash []byte) (HopIterator,
|
func (p *OnionProcessor) DecodeHopIterator(r io.Reader, rHash []byte,
|
||||||
lnwire.FailCode) {
|
incomingCltv uint32) (HopIterator, lnwire.FailCode) {
|
||||||
|
|
||||||
onionPkt := &sphinx.OnionPacket{}
|
onionPkt := &sphinx.OnionPacket{}
|
||||||
if err := onionPkt.Decode(r); err != nil {
|
if err := onionPkt.Decode(r); err != nil {
|
||||||
@ -179,7 +223,9 @@ func (p *OnionProcessor) DecodeHopIterator(r io.Reader, rHash []byte) (HopIterat
|
|||||||
// associated data in order to thwart attempts a replay attacks. In the
|
// associated data in order to thwart attempts a replay attacks. In the
|
||||||
// case of a replay, an attacker is *forced* to use the same payment
|
// case of a replay, an attacker is *forced* to use the same payment
|
||||||
// hash twice, thereby losing their money entirely.
|
// hash twice, thereby losing their money entirely.
|
||||||
sphinxPacket, err := p.router.ProcessOnionPacket(onionPkt, rHash)
|
sphinxPacket, err := p.router.ProcessOnionPacket(
|
||||||
|
onionPkt, rHash, incomingCltv,
|
||||||
|
)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
switch err {
|
switch err {
|
||||||
case sphinx.ErrInvalidOnionVersion:
|
case sphinx.ErrInvalidOnionVersion:
|
||||||
@ -194,10 +240,160 @@ func (p *OnionProcessor) DecodeHopIterator(r io.Reader, rHash []byte) (HopIterat
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return &sphinxHopIterator{
|
return makeSphinxHopIterator(onionPkt, sphinxPacket), lnwire.CodeNone
|
||||||
nextPacket: sphinxPacket.NextPacket,
|
}
|
||||||
processedPacket: sphinxPacket,
|
|
||||||
}, lnwire.CodeNone
|
// DecodeHopIteratorRequest encapsulates all date necessary to process an onion
|
||||||
|
// packet, perform sphinx replay detection, and schedule the entry for garbage
|
||||||
|
// collection.
|
||||||
|
type DecodeHopIteratorRequest struct {
|
||||||
|
OnionReader io.Reader
|
||||||
|
RHash []byte
|
||||||
|
IncomingCltv uint32
|
||||||
|
}
|
||||||
|
|
||||||
|
// DecodeHopIteratorResponse encapsulates the outcome of a batched sphinx onion
|
||||||
|
// processing.
|
||||||
|
type DecodeHopIteratorResponse struct {
|
||||||
|
HopIterator HopIterator
|
||||||
|
FailCode lnwire.FailCode
|
||||||
|
}
|
||||||
|
|
||||||
|
// Result returns the (HopIterator, lnwire.FailCode) tuple, which should
|
||||||
|
// correspond to the index of a particular DecodeHopIteratorRequest.
|
||||||
|
//
|
||||||
|
// NOTE: The HopIterator should be considered invalid if the fail code is
|
||||||
|
// anything but lnwire.CodeNone.
|
||||||
|
func (r *DecodeHopIteratorResponse) Result() (HopIterator, lnwire.FailCode) {
|
||||||
|
return r.HopIterator, r.FailCode
|
||||||
|
}
|
||||||
|
|
||||||
|
// DecodeHopIterators performs batched decoding and validation of incoming
|
||||||
|
// sphinx packets. For the same `id`, this method will return the same iterators
|
||||||
|
// and failcodes upon subsequent invocations.
|
||||||
|
//
|
||||||
|
// NOTE: In order for the responses to be valid, the caller must guarantee that
|
||||||
|
// the presented readers and rhashes *NEVER* deviate across invocations for the
|
||||||
|
// same id.
|
||||||
|
func (p *OnionProcessor) DecodeHopIterators(id []byte,
|
||||||
|
reqs []DecodeHopIteratorRequest) ([]DecodeHopIteratorResponse, error) {
|
||||||
|
|
||||||
|
var (
|
||||||
|
batchSize = len(reqs)
|
||||||
|
onionPkts = make([]sphinx.OnionPacket, batchSize)
|
||||||
|
resps = make([]DecodeHopIteratorResponse, batchSize)
|
||||||
|
)
|
||||||
|
|
||||||
|
tx := p.router.BeginTxn(id, batchSize)
|
||||||
|
|
||||||
|
for i, req := range reqs {
|
||||||
|
onionPkt := &onionPkts[i]
|
||||||
|
resp := &resps[i]
|
||||||
|
|
||||||
|
err := onionPkt.Decode(req.OnionReader)
|
||||||
|
switch err {
|
||||||
|
case nil:
|
||||||
|
// success
|
||||||
|
|
||||||
|
case sphinx.ErrInvalidOnionVersion:
|
||||||
|
resp.FailCode = lnwire.CodeInvalidOnionVersion
|
||||||
|
continue
|
||||||
|
|
||||||
|
case sphinx.ErrInvalidOnionKey:
|
||||||
|
resp.FailCode = lnwire.CodeInvalidOnionKey
|
||||||
|
continue
|
||||||
|
|
||||||
|
default:
|
||||||
|
log.Errorf("unable to decode onion packet: %v", err)
|
||||||
|
resp.FailCode = lnwire.CodeInvalidOnionKey
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
err = tx.ProcessOnionPacket(
|
||||||
|
uint16(i), onionPkt, req.RHash, req.IncomingCltv,
|
||||||
|
)
|
||||||
|
switch err {
|
||||||
|
case nil:
|
||||||
|
// success
|
||||||
|
|
||||||
|
case sphinx.ErrInvalidOnionVersion:
|
||||||
|
resp.FailCode = lnwire.CodeInvalidOnionVersion
|
||||||
|
continue
|
||||||
|
|
||||||
|
case sphinx.ErrInvalidOnionHMAC:
|
||||||
|
resp.FailCode = lnwire.CodeInvalidOnionHmac
|
||||||
|
continue
|
||||||
|
|
||||||
|
case sphinx.ErrInvalidOnionKey:
|
||||||
|
resp.FailCode = lnwire.CodeInvalidOnionKey
|
||||||
|
continue
|
||||||
|
|
||||||
|
default:
|
||||||
|
log.Errorf("unable to process onion packet: %v", err)
|
||||||
|
resp.FailCode = lnwire.CodeInvalidOnionKey
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// With that batch created, we will now attempt to write the shared
|
||||||
|
// secrets to disk. This operation will returns the set of indices that
|
||||||
|
// were detected as replays, and the computed sphinx packets for all
|
||||||
|
// indices that did not fail the above loop. Only indices that are not
|
||||||
|
// in the replay set should be considered valid, as they are
|
||||||
|
// opportunistically computed.
|
||||||
|
packets, replays, err := tx.Commit()
|
||||||
|
if err != nil {
|
||||||
|
log.Errorf("unable to process onion packet batch %x: %v",
|
||||||
|
id, err)
|
||||||
|
|
||||||
|
// If we failed to commit the batch to the secret share log, we
|
||||||
|
// will mark all not-yet-failed channels with a temporary
|
||||||
|
// channel failure and exit since we cannot proceed.
|
||||||
|
for i := range resps {
|
||||||
|
resp := &resps[i]
|
||||||
|
|
||||||
|
// Skip any indexes that already failed onion decoding.
|
||||||
|
if resp.FailCode != lnwire.CodeNone {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
log.Errorf("unable to process onion packet %x-%v",
|
||||||
|
id, i)
|
||||||
|
resp.FailCode = lnwire.CodeTemporaryChannelFailure
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO(conner): return real errors to caller so link can fail?
|
||||||
|
return resps, err
|
||||||
|
}
|
||||||
|
|
||||||
|
// Otherwise, the commit was successful. Now we will post process any
|
||||||
|
// remaining packets, additionally failing any that were included in the
|
||||||
|
// replay set.
|
||||||
|
for i := range resps {
|
||||||
|
resp := &resps[i]
|
||||||
|
|
||||||
|
// Skip any indexes that already failed onion decoding.
|
||||||
|
if resp.FailCode != lnwire.CodeNone {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
// If this index is contained in the replay set, mark it with a
|
||||||
|
// temporary channel failure error code. We infer that the
|
||||||
|
// offending error was due to a replayed packet because this
|
||||||
|
// index was found in the replay set.
|
||||||
|
if replays.Contains(uint16(i)) {
|
||||||
|
log.Errorf("unable to process onion packet: %v",
|
||||||
|
sphinx.ErrReplayedPacket)
|
||||||
|
resp.FailCode = lnwire.CodeTemporaryChannelFailure
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
// Finally, construct a hop iterator from our processed sphinx
|
||||||
|
// packet, simultaneously caching the original onion packet.
|
||||||
|
resp.HopIterator = makeSphinxHopIterator(&onionPkts[i], &packets[i])
|
||||||
|
}
|
||||||
|
|
||||||
|
return resps, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// ExtractErrorEncrypter takes an io.Reader which should contain the onion
|
// ExtractErrorEncrypter takes an io.Reader which should contain the onion
|
||||||
@ -205,20 +401,8 @@ func (p *OnionProcessor) DecodeHopIterator(r io.Reader, rHash []byte) (HopIterat
|
|||||||
// ErrorEncrypter instance using the derived shared secret. In the case that en
|
// ErrorEncrypter instance using the derived shared secret. In the case that en
|
||||||
// error occurs, a lnwire failure code detailing the parsing failure will be
|
// error occurs, a lnwire failure code detailing the parsing failure will be
|
||||||
// returned.
|
// returned.
|
||||||
func (p *OnionProcessor) ExtractErrorEncrypter(r io.Reader) (ErrorEncrypter, lnwire.FailCode) {
|
func (p *OnionProcessor) ExtractErrorEncrypter(onionPkt *sphinx.OnionPacket) (
|
||||||
|
ErrorEncrypter, lnwire.FailCode) {
|
||||||
onionPkt := &sphinx.OnionPacket{}
|
|
||||||
if err := onionPkt.Decode(r); err != nil {
|
|
||||||
switch err {
|
|
||||||
case sphinx.ErrInvalidOnionVersion:
|
|
||||||
return nil, lnwire.CodeInvalidOnionVersion
|
|
||||||
case sphinx.ErrInvalidOnionKey:
|
|
||||||
return nil, lnwire.CodeInvalidOnionKey
|
|
||||||
default:
|
|
||||||
log.Errorf("unable to decode onion packet: %v", err)
|
|
||||||
return nil, lnwire.CodeInvalidOnionKey
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
onionObfuscator, err := sphinx.NewOnionErrorEncrypter(p.router,
|
onionObfuscator, err := sphinx.NewOnionErrorEncrypter(p.router,
|
||||||
onionPkt.EphemeralKey)
|
onionPkt.EphemeralKey)
|
||||||
@ -238,5 +422,6 @@ func (p *OnionProcessor) ExtractErrorEncrypter(r io.Reader) (ErrorEncrypter, lnw
|
|||||||
|
|
||||||
return &SphinxErrorEncrypter{
|
return &SphinxErrorEncrypter{
|
||||||
OnionErrorEncrypter: onionObfuscator,
|
OnionErrorEncrypter: onionObfuscator,
|
||||||
|
ogPacket: onionPkt,
|
||||||
}, lnwire.CodeNone
|
}, lnwire.CodeNone
|
||||||
}
|
}
|
||||||
|
@ -3,12 +3,11 @@ package htlcswitch
|
|||||||
import (
|
import (
|
||||||
"bytes"
|
"bytes"
|
||||||
"fmt"
|
"fmt"
|
||||||
|
"io"
|
||||||
"sync"
|
"sync"
|
||||||
"sync/atomic"
|
"sync/atomic"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"io"
|
|
||||||
|
|
||||||
"crypto/sha256"
|
"crypto/sha256"
|
||||||
|
|
||||||
"github.com/go-errors/errors"
|
"github.com/go-errors/errors"
|
||||||
@ -130,11 +129,19 @@ type ChannelLinkConfig struct {
|
|||||||
// DecodeHopIterator function is responsible for decoding HTLC Sphinx
|
// DecodeHopIterator function is responsible for decoding HTLC Sphinx
|
||||||
// onion blob, and creating hop iterator which will give us next
|
// onion blob, and creating hop iterator which will give us next
|
||||||
// destination of HTLC.
|
// destination of HTLC.
|
||||||
DecodeHopIterator func(r io.Reader, rHash []byte) (HopIterator, lnwire.FailCode)
|
DecodeHopIterator func(r io.Reader, rHash []byte,
|
||||||
|
cltv uint32) (HopIterator, lnwire.FailCode)
|
||||||
|
|
||||||
|
// DecodeHopIterators facilitates batched decoding of HTLC Sphinx onion
|
||||||
|
// blobs, which are then used to inform how to forward an HTLC.
|
||||||
|
// NOTE: This function assumes the same set of readers and preimages are
|
||||||
|
// always presented for the same identifier.
|
||||||
|
DecodeHopIterators func([]byte, []DecodeHopIteratorRequest) (
|
||||||
|
[]DecodeHopIteratorResponse, error)
|
||||||
|
|
||||||
// DecodeOnionObfuscator function is responsible for decoding HTLC
|
// DecodeOnionObfuscator function is responsible for decoding HTLC
|
||||||
// Sphinx onion blob, and creating onion failure obfuscator.
|
// Sphinx onion blob, and creating onion failure obfuscator.
|
||||||
DecodeOnionObfuscator func(r io.Reader) (ErrorEncrypter, lnwire.FailCode)
|
DecodeOnionObfuscator ErrorEncrypterExtracter
|
||||||
|
|
||||||
// GetLastChannelUpdate retrieves the latest routing policy for this
|
// GetLastChannelUpdate retrieves the latest routing policy for this
|
||||||
// particular channel. This will be used to provide payment senders our
|
// particular channel. This will be used to provide payment senders our
|
||||||
@ -1448,26 +1455,6 @@ func (l *channelLink) processLockedInHtlcs(
|
|||||||
var onionBlob [lnwire.OnionPacketSize]byte
|
var onionBlob [lnwire.OnionPacketSize]byte
|
||||||
copy(onionBlob[:], pd.OnionBlob)
|
copy(onionBlob[:], pd.OnionBlob)
|
||||||
|
|
||||||
// Retrieve onion obfuscator from onion blob in order
|
|
||||||
// to produce initial obfuscation of the onion
|
|
||||||
// failureCode.
|
|
||||||
onionReader := bytes.NewReader(onionBlob[:])
|
|
||||||
obfuscator, failureCode := l.cfg.DecodeOnionObfuscator(
|
|
||||||
onionReader,
|
|
||||||
)
|
|
||||||
if failureCode != lnwire.CodeNone {
|
|
||||||
// If we're unable to process the onion blob
|
|
||||||
// than we should send the malformed htlc error
|
|
||||||
// to payment sender.
|
|
||||||
l.sendMalformedHTLCError(pd.HtlcIndex, failureCode,
|
|
||||||
onionBlob[:])
|
|
||||||
needUpdate = true
|
|
||||||
|
|
||||||
log.Errorf("unable to decode onion "+
|
|
||||||
"obfuscator: %v", failureCode)
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
|
|
||||||
// Before adding the new htlc to the state machine,
|
// Before adding the new htlc to the state machine,
|
||||||
// parse the onion object in order to obtain the
|
// parse the onion object in order to obtain the
|
||||||
// routing information with DecodeHopIterator function
|
// routing information with DecodeHopIterator function
|
||||||
@ -1479,9 +1466,9 @@ func (l *channelLink) processLockedInHtlcs(
|
|||||||
// attacks. In the case of a replay, an attacker is
|
// attacks. In the case of a replay, an attacker is
|
||||||
// *forced* to use the same payment hash twice, thereby
|
// *forced* to use the same payment hash twice, thereby
|
||||||
// losing their money entirely.
|
// losing their money entirely.
|
||||||
onionReader = bytes.NewReader(onionBlob[:])
|
onionReader := bytes.NewReader(onionBlob[:])
|
||||||
chanIterator, failureCode := l.cfg.DecodeHopIterator(
|
chanIterator, failureCode := l.cfg.DecodeHopIterator(
|
||||||
onionReader, pd.RHash[:],
|
onionReader, pd.RHash[:], pd.Timeout,
|
||||||
)
|
)
|
||||||
if failureCode != lnwire.CodeNone {
|
if failureCode != lnwire.CodeNone {
|
||||||
// If we're unable to process the onion blob
|
// If we're unable to process the onion blob
|
||||||
@ -1496,6 +1483,25 @@ func (l *channelLink) processLockedInHtlcs(
|
|||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Retrieve onion obfuscator from onion blob in order
|
||||||
|
// to produce initial obfuscation of the onion
|
||||||
|
// failureCode.
|
||||||
|
obfuscator, failureCode := chanIterator.ExtractErrorEncrypter(
|
||||||
|
l.cfg.DecodeOnionObfuscator,
|
||||||
|
)
|
||||||
|
if failureCode != lnwire.CodeNone {
|
||||||
|
// If we're unable to process the onion blob
|
||||||
|
// than we should send the malformed htlc error
|
||||||
|
// to payment sender.
|
||||||
|
l.sendMalformedHTLCError(pd.HtlcIndex, failureCode,
|
||||||
|
onionBlob[:])
|
||||||
|
needUpdate = true
|
||||||
|
|
||||||
|
log.Errorf("unable to decode onion "+
|
||||||
|
"obfuscator: %v", failureCode)
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
heightNow := l.bestHeight
|
heightNow := l.bestHeight
|
||||||
|
|
||||||
fwdInfo := chanIterator.ForwardingInstructions()
|
fwdInfo := chanIterator.ForwardingInstructions()
|
||||||
|
@ -9,12 +9,11 @@ import (
|
|||||||
"testing"
|
"testing"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"io"
|
|
||||||
|
|
||||||
"math"
|
"math"
|
||||||
|
|
||||||
"github.com/davecgh/go-spew/spew"
|
"github.com/davecgh/go-spew/spew"
|
||||||
"github.com/go-errors/errors"
|
"github.com/go-errors/errors"
|
||||||
|
"github.com/lightningnetwork/lightning-onion"
|
||||||
"github.com/lightningnetwork/lnd/chainntnfs"
|
"github.com/lightningnetwork/lnd/chainntnfs"
|
||||||
"github.com/lightningnetwork/lnd/channeldb"
|
"github.com/lightningnetwork/lnd/channeldb"
|
||||||
"github.com/lightningnetwork/lnd/contractcourt"
|
"github.com/lightningnetwork/lnd/contractcourt"
|
||||||
@ -1119,7 +1118,7 @@ func TestChannelLinkMultiHopDecodeError(t *testing.T) {
|
|||||||
|
|
||||||
// Replace decode function with another which throws an error.
|
// Replace decode function with another which throws an error.
|
||||||
n.carolChannelLink.cfg.DecodeOnionObfuscator = func(
|
n.carolChannelLink.cfg.DecodeOnionObfuscator = func(
|
||||||
r io.Reader) (ErrorEncrypter, lnwire.FailCode) {
|
*sphinx.OnionPacket) (ErrorEncrypter, lnwire.FailCode) {
|
||||||
return nil, lnwire.CodeInvalidOnionVersion
|
return nil, lnwire.CodeInvalidOnionVersion
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1450,7 +1449,7 @@ func newSingleLinkTestHarness(chanAmt, chanReserve btcutil.Amount) (
|
|||||||
Peer: alicePeer,
|
Peer: alicePeer,
|
||||||
Switch: New(Config{}),
|
Switch: New(Config{}),
|
||||||
DecodeHopIterator: decoder.DecodeHopIterator,
|
DecodeHopIterator: decoder.DecodeHopIterator,
|
||||||
DecodeOnionObfuscator: func(io.Reader) (ErrorEncrypter, lnwire.FailCode) {
|
DecodeOnionObfuscator: func(*sphinx.OnionPacket) (ErrorEncrypter, lnwire.FailCode) {
|
||||||
return obfuscator, lnwire.CodeNone
|
return obfuscator, lnwire.CodeNone
|
||||||
},
|
},
|
||||||
GetLastChannelUpdate: mockGetChanUpdateMessage,
|
GetLastChannelUpdate: mockGetChanUpdateMessage,
|
||||||
|
@ -15,6 +15,7 @@ import (
|
|||||||
|
|
||||||
"github.com/btcsuite/fastsha256"
|
"github.com/btcsuite/fastsha256"
|
||||||
"github.com/go-errors/errors"
|
"github.com/go-errors/errors"
|
||||||
|
"github.com/lightningnetwork/lightning-onion"
|
||||||
"github.com/lightningnetwork/lnd/chainntnfs"
|
"github.com/lightningnetwork/lnd/chainntnfs"
|
||||||
"github.com/lightningnetwork/lnd/channeldb"
|
"github.com/lightningnetwork/lnd/channeldb"
|
||||||
"github.com/lightningnetwork/lnd/contractcourt"
|
"github.com/lightningnetwork/lnd/contractcourt"
|
||||||
@ -195,6 +196,10 @@ type mockHopIterator struct {
|
|||||||
hops []ForwardingInfo
|
hops []ForwardingInfo
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (r *mockHopIterator) OnionPacket() *sphinx.OnionPacket {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
func newMockHopIterator(hops ...ForwardingInfo) HopIterator {
|
func newMockHopIterator(hops ...ForwardingInfo) HopIterator {
|
||||||
return &mockHopIterator{hops: hops}
|
return &mockHopIterator{hops: hops}
|
||||||
}
|
}
|
||||||
@ -205,6 +210,12 @@ func (r *mockHopIterator) ForwardingInstructions() ForwardingInfo {
|
|||||||
return h
|
return h
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (r *mockHopIterator) ExtractErrorEncrypter(
|
||||||
|
extracter ErrorEncrypterExtracter) (ErrorEncrypter, lnwire.FailCode) {
|
||||||
|
|
||||||
|
return extracter(nil)
|
||||||
|
}
|
||||||
|
|
||||||
func (r *mockHopIterator) EncodeNextHop(w io.Writer) error {
|
func (r *mockHopIterator) EncodeNextHop(w io.Writer) error {
|
||||||
var hopLength [4]byte
|
var hopLength [4]byte
|
||||||
binary.BigEndian.PutUint32(hopLength[:], uint32(len(r.hops)))
|
binary.BigEndian.PutUint32(hopLength[:], uint32(len(r.hops)))
|
||||||
@ -246,12 +257,30 @@ var _ HopIterator = (*mockHopIterator)(nil)
|
|||||||
|
|
||||||
// mockObfuscator mock implementation of the failure obfuscator which only
|
// mockObfuscator mock implementation of the failure obfuscator which only
|
||||||
// encodes the failure and do not makes any onion obfuscation.
|
// encodes the failure and do not makes any onion obfuscation.
|
||||||
type mockObfuscator struct{}
|
type mockObfuscator struct {
|
||||||
|
ogPacket *sphinx.OnionPacket
|
||||||
|
}
|
||||||
|
|
||||||
func newMockObfuscator() ErrorEncrypter {
|
func newMockObfuscator() ErrorEncrypter {
|
||||||
return &mockObfuscator{}
|
return &mockObfuscator{}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (o *mockObfuscator) OnionPacket() *sphinx.OnionPacket {
|
||||||
|
return o.ogPacket
|
||||||
|
}
|
||||||
|
|
||||||
|
func (o *mockObfuscator) Type() EncrypterType {
|
||||||
|
return EncrypterTypeMock
|
||||||
|
}
|
||||||
|
|
||||||
|
func (o *mockObfuscator) Encode(w io.Writer) error {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (o *mockObfuscator) Decode(r io.Reader) error {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
func (o *mockObfuscator) EncryptFirstHop(failure lnwire.FailureMessage) (
|
func (o *mockObfuscator) EncryptFirstHop(failure lnwire.FailureMessage) (
|
||||||
lnwire.OpaqueReason, error) {
|
lnwire.OpaqueReason, error) {
|
||||||
|
|
||||||
@ -292,10 +321,20 @@ var _ ErrorDecrypter = (*mockDeobfuscator)(nil)
|
|||||||
|
|
||||||
// mockIteratorDecoder test version of hop iterator decoder which decodes the
|
// mockIteratorDecoder test version of hop iterator decoder which decodes the
|
||||||
// encoded array of hops.
|
// encoded array of hops.
|
||||||
type mockIteratorDecoder struct{}
|
type mockIteratorDecoder struct {
|
||||||
|
mu sync.RWMutex
|
||||||
|
|
||||||
func (p *mockIteratorDecoder) DecodeHopIterator(r io.Reader, meta []byte) (
|
responses map[[32]byte][]DecodeHopIteratorResponse
|
||||||
HopIterator, lnwire.FailCode) {
|
}
|
||||||
|
|
||||||
|
func newMockIteratorDecoder() *mockIteratorDecoder {
|
||||||
|
return &mockIteratorDecoder{
|
||||||
|
responses: make(map[[32]byte][]DecodeHopIteratorResponse),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (p *mockIteratorDecoder) DecodeHopIterator(r io.Reader, rHash []byte,
|
||||||
|
cltv uint32) (HopIterator, lnwire.FailCode) {
|
||||||
|
|
||||||
var b [4]byte
|
var b [4]byte
|
||||||
_, err := r.Read(b[:])
|
_, err := r.Read(b[:])
|
||||||
@ -317,6 +356,40 @@ func (p *mockIteratorDecoder) DecodeHopIterator(r io.Reader, meta []byte) (
|
|||||||
return newMockHopIterator(hops...), lnwire.CodeNone
|
return newMockHopIterator(hops...), lnwire.CodeNone
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (p *mockIteratorDecoder) DecodeHopIterators(id []byte,
|
||||||
|
reqs []DecodeHopIteratorRequest) ([]DecodeHopIteratorResponse, error) {
|
||||||
|
|
||||||
|
idHash := sha256.Sum256(id)
|
||||||
|
|
||||||
|
p.mu.RLock()
|
||||||
|
if resps, ok := p.responses[idHash]; ok {
|
||||||
|
p.mu.RUnlock()
|
||||||
|
return resps, nil
|
||||||
|
}
|
||||||
|
p.mu.RUnlock()
|
||||||
|
|
||||||
|
batchSize := len(reqs)
|
||||||
|
|
||||||
|
resps := make([]DecodeHopIteratorResponse, 0, batchSize)
|
||||||
|
for _, req := range reqs {
|
||||||
|
iterator, failcode := p.DecodeHopIterator(
|
||||||
|
req.OnionReader, req.RHash, req.IncomingCltv,
|
||||||
|
)
|
||||||
|
|
||||||
|
resp := DecodeHopIteratorResponse{
|
||||||
|
HopIterator: iterator,
|
||||||
|
FailCode: failcode,
|
||||||
|
}
|
||||||
|
resps = append(resps, resp)
|
||||||
|
}
|
||||||
|
|
||||||
|
p.mu.Lock()
|
||||||
|
p.responses[idHash] = resps
|
||||||
|
p.mu.Unlock()
|
||||||
|
|
||||||
|
return resps, nil
|
||||||
|
}
|
||||||
|
|
||||||
func (f *ForwardingInfo) decode(r io.Reader) error {
|
func (f *ForwardingInfo) decode(r io.Reader) error {
|
||||||
var net [1]byte
|
var net [1]byte
|
||||||
if _, err := r.Read(net[:]); err != nil {
|
if _, err := r.Read(net[:]); err != nil {
|
||||||
|
@ -11,14 +11,13 @@ import (
|
|||||||
"io/ioutil"
|
"io/ioutil"
|
||||||
"os"
|
"os"
|
||||||
|
|
||||||
"io"
|
|
||||||
|
|
||||||
"math/big"
|
"math/big"
|
||||||
|
|
||||||
"net"
|
"net"
|
||||||
|
|
||||||
"github.com/btcsuite/fastsha256"
|
"github.com/btcsuite/fastsha256"
|
||||||
"github.com/go-errors/errors"
|
"github.com/go-errors/errors"
|
||||||
|
"github.com/lightningnetwork/lightning-onion"
|
||||||
"github.com/lightningnetwork/lnd/chainntnfs"
|
"github.com/lightningnetwork/lnd/chainntnfs"
|
||||||
"github.com/lightningnetwork/lnd/channeldb"
|
"github.com/lightningnetwork/lnd/channeldb"
|
||||||
"github.com/lightningnetwork/lnd/contractcourt"
|
"github.com/lightningnetwork/lnd/contractcourt"
|
||||||
@ -800,7 +799,7 @@ func newThreeHopNetwork(t testing.TB, aliceChannel, firstBobChannel,
|
|||||||
Peer: bobServer,
|
Peer: bobServer,
|
||||||
Switch: aliceServer.htlcSwitch,
|
Switch: aliceServer.htlcSwitch,
|
||||||
DecodeHopIterator: decoder.DecodeHopIterator,
|
DecodeHopIterator: decoder.DecodeHopIterator,
|
||||||
DecodeOnionObfuscator: func(io.Reader) (ErrorEncrypter,
|
DecodeOnionObfuscator: func(*sphinx.OnionPacket) (ErrorEncrypter,
|
||||||
lnwire.FailCode) {
|
lnwire.FailCode) {
|
||||||
return obfuscator, lnwire.CodeNone
|
return obfuscator, lnwire.CodeNone
|
||||||
},
|
},
|
||||||
@ -846,7 +845,7 @@ func newThreeHopNetwork(t testing.TB, aliceChannel, firstBobChannel,
|
|||||||
Peer: aliceServer,
|
Peer: aliceServer,
|
||||||
Switch: bobServer.htlcSwitch,
|
Switch: bobServer.htlcSwitch,
|
||||||
DecodeHopIterator: decoder.DecodeHopIterator,
|
DecodeHopIterator: decoder.DecodeHopIterator,
|
||||||
DecodeOnionObfuscator: func(io.Reader) (ErrorEncrypter,
|
DecodeOnionObfuscator: func(*sphinx.OnionPacket) (ErrorEncrypter,
|
||||||
lnwire.FailCode) {
|
lnwire.FailCode) {
|
||||||
return obfuscator, lnwire.CodeNone
|
return obfuscator, lnwire.CodeNone
|
||||||
},
|
},
|
||||||
@ -892,7 +891,7 @@ func newThreeHopNetwork(t testing.TB, aliceChannel, firstBobChannel,
|
|||||||
Peer: carolServer,
|
Peer: carolServer,
|
||||||
Switch: bobServer.htlcSwitch,
|
Switch: bobServer.htlcSwitch,
|
||||||
DecodeHopIterator: decoder.DecodeHopIterator,
|
DecodeHopIterator: decoder.DecodeHopIterator,
|
||||||
DecodeOnionObfuscator: func(io.Reader) (ErrorEncrypter,
|
DecodeOnionObfuscator: func(*sphinx.OnionPacket) (ErrorEncrypter,
|
||||||
lnwire.FailCode) {
|
lnwire.FailCode) {
|
||||||
return obfuscator, lnwire.CodeNone
|
return obfuscator, lnwire.CodeNone
|
||||||
},
|
},
|
||||||
@ -938,7 +937,7 @@ func newThreeHopNetwork(t testing.TB, aliceChannel, firstBobChannel,
|
|||||||
Peer: bobServer,
|
Peer: bobServer,
|
||||||
Switch: carolServer.htlcSwitch,
|
Switch: carolServer.htlcSwitch,
|
||||||
DecodeHopIterator: decoder.DecodeHopIterator,
|
DecodeHopIterator: decoder.DecodeHopIterator,
|
||||||
DecodeOnionObfuscator: func(io.Reader) (ErrorEncrypter,
|
DecodeOnionObfuscator: func(*sphinx.OnionPacket) (ErrorEncrypter,
|
||||||
lnwire.FailCode) {
|
lnwire.FailCode) {
|
||||||
return obfuscator, lnwire.CodeNone
|
return obfuscator, lnwire.CodeNone
|
||||||
},
|
},
|
||||||
|
@ -5006,7 +5006,7 @@ func testBidirectionalAsyncPayments(net *lntest.NetworkHarness, t *harnessTest)
|
|||||||
|
|
||||||
// Wait for Alice and Bob receive their payments, and throw and error
|
// Wait for Alice and Bob receive their payments, and throw and error
|
||||||
// if something goes wrong.
|
// if something goes wrong.
|
||||||
maxTime := 20 * time.Second
|
maxTime := 60 * time.Second
|
||||||
for i := 0; i < 2; i++ {
|
for i := 0; i < 2; i++ {
|
||||||
select {
|
select {
|
||||||
case err := <-errChan:
|
case err := <-errChan:
|
||||||
|
18
server.go
18
server.go
@ -9,6 +9,7 @@ import (
|
|||||||
"image/color"
|
"image/color"
|
||||||
"math/big"
|
"math/big"
|
||||||
"net"
|
"net"
|
||||||
|
"path/filepath"
|
||||||
"strconv"
|
"strconv"
|
||||||
"sync"
|
"sync"
|
||||||
"sync/atomic"
|
"sync/atomic"
|
||||||
@ -151,6 +152,15 @@ func newServer(listenAddrs []string, chanDB *channeldb.DB, cc *chainControl,
|
|||||||
globalFeatures := lnwire.NewRawFeatureVector()
|
globalFeatures := lnwire.NewRawFeatureVector()
|
||||||
|
|
||||||
serializedPubKey := privKey.PubKey().SerializeCompressed()
|
serializedPubKey := privKey.PubKey().SerializeCompressed()
|
||||||
|
|
||||||
|
// Initialize the sphinx router, placing it's persistent replay log in
|
||||||
|
// the same directory as the channel graph database.
|
||||||
|
graphDir := filepath.Dir(chanDB.Path())
|
||||||
|
sharedSecretPath := filepath.Join(graphDir, "sphinxreplay.db")
|
||||||
|
sphinxRouter := sphinx.NewRouter(
|
||||||
|
sharedSecretPath, privKey, activeNetParams.Params, cc.chainNotifier,
|
||||||
|
)
|
||||||
|
|
||||||
s := &server{
|
s := &server{
|
||||||
chanDB: chanDB,
|
chanDB: chanDB,
|
||||||
cc: cc,
|
cc: cc,
|
||||||
@ -162,8 +172,7 @@ func newServer(listenAddrs []string, chanDB *channeldb.DB, cc *chainControl,
|
|||||||
|
|
||||||
// TODO(roasbeef): derive proper onion key based on rotation
|
// TODO(roasbeef): derive proper onion key based on rotation
|
||||||
// schedule
|
// schedule
|
||||||
sphinx: htlcswitch.NewOnionProcessor(
|
sphinx: htlcswitch.NewOnionProcessor(sphinxRouter),
|
||||||
sphinx.NewRouter(privKey, activeNetParams.Params)),
|
|
||||||
lightningID: sha256.Sum256(serializedPubKey),
|
lightningID: sha256.Sum256(serializedPubKey),
|
||||||
|
|
||||||
persistentPeers: make(map[string]struct{}),
|
persistentPeers: make(map[string]struct{}),
|
||||||
@ -491,7 +500,9 @@ func (s *server) Start() error {
|
|||||||
if err := s.cc.chainNotifier.Start(); err != nil {
|
if err := s.cc.chainNotifier.Start(); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
if err := s.sphinx.Start(); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
if err := s.htlcSwitch.Start(); err != nil {
|
if err := s.htlcSwitch.Start(); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
@ -554,6 +565,7 @@ func (s *server) Stop() error {
|
|||||||
s.cc.chainNotifier.Stop()
|
s.cc.chainNotifier.Stop()
|
||||||
s.chanRouter.Stop()
|
s.chanRouter.Stop()
|
||||||
s.htlcSwitch.Stop()
|
s.htlcSwitch.Stop()
|
||||||
|
s.sphinx.Stop()
|
||||||
s.utxoNursery.Stop()
|
s.utxoNursery.Stop()
|
||||||
s.breachArbiter.Stop()
|
s.breachArbiter.Stop()
|
||||||
s.authGossiper.Stop()
|
s.authGossiper.Stop()
|
||||||
|
Loading…
Reference in New Issue
Block a user