diff --git a/go.mod b/go.mod index ce8536e..3ff22cb 100644 --- a/go.mod +++ b/go.mod @@ -103,7 +103,7 @@ require ( github.com/lightningnetwork/lnd/kvdb v1.3.1 // indirect github.com/lightningnetwork/lnd/ticker v1.1.0 // indirect github.com/lightningnetwork/lnd/tlv v1.0.3 // indirect - github.com/lightningnetwork/lnd/tor v1.0.1 // indirect + github.com/lightningnetwork/lnd/tor v1.1.0 // indirect github.com/ltcsuite/ltcd v0.20.1-beta // indirect github.com/mailru/easyjson v0.7.6 // indirect github.com/matttproud/golang_protobuf_extensions v1.0.1 // indirect @@ -182,3 +182,5 @@ require ( ) replace github.com/bottlepay/lnmux/lnmuxrpc => ./lnmuxrpc + +replace github.com/lightningnetwork/lnd => /users/Joost.Jager/lightninglabs/lnd diff --git a/go.sum b/go.sum index c7ac949..198090e 100644 --- a/go.sum +++ b/go.sum @@ -507,8 +507,6 @@ github.com/lightninglabs/neutrino v0.14.2 h1:yrnZUCYMZ5ECtXhgDrzqPq2oX8awoAN2D/c github.com/lightninglabs/neutrino v0.14.2/go.mod h1:OICUeTCn+4Tu27YRJIpWvvqySxx4oH4vgdP33Sw9RDc= github.com/lightningnetwork/lightning-onion v1.0.2-0.20220211021909-bb84a1ccb0c5 h1:TkKwqFcQTGYoI+VEqyxA8rxpCin8qDaYX0AfVRinT3k= github.com/lightningnetwork/lightning-onion v1.0.2-0.20220211021909-bb84a1ccb0c5/go.mod h1:7dDx73ApjEZA0kcknI799m2O5kkpfg4/gr7N092ojNo= -github.com/lightningnetwork/lnd v0.15.4-beta h1:vO+UZjuA8RqJdDlfwQeS0h2PCocYwwqv5HkX2IXf5/M= -github.com/lightningnetwork/lnd v0.15.4-beta/go.mod h1:6aoOkifcI9tuk8UV5l2rVZSq0681obuP4zvfK+2ZrT0= github.com/lightningnetwork/lnd/clock v1.0.1/go.mod h1:KnQudQ6w0IAMZi1SgvecLZQZ43ra2vpDNj7H/aasemg= github.com/lightningnetwork/lnd/clock v1.1.0 h1:/yfVAwtPmdx45aQBoXQImeY7sOIEr7IXlImRMBOZ7GQ= github.com/lightningnetwork/lnd/clock v1.1.0/go.mod h1:KnQudQ6w0IAMZi1SgvecLZQZ43ra2vpDNj7H/aasemg= @@ -527,8 +525,8 @@ github.com/lightningnetwork/lnd/tlv v1.0.2/go.mod h1:fICAfsqk1IOsC1J7G9IdsWX1EqW github.com/lightningnetwork/lnd/tlv v1.0.3 h1:0xBZcPuXagP6f7TY/RnLNR4igE21ov6qUdTr5NyvhhI= github.com/lightningnetwork/lnd/tlv v1.0.3/go.mod h1:dzR/aZetBri+ZY/fHbwV06fNn/3UID6htQzbHfREFdo= github.com/lightningnetwork/lnd/tor v1.0.0/go.mod h1:RDtaAdwfAm+ONuPYwUhNIH1RAvKPv+75lHPOegUcz64= -github.com/lightningnetwork/lnd/tor v1.0.1 h1:A11FrpU0Y//g+fA827W4VnjOeoIvExONdchlLX8wYkA= -github.com/lightningnetwork/lnd/tor v1.0.1/go.mod h1:RDtaAdwfAm+ONuPYwUhNIH1RAvKPv+75lHPOegUcz64= +github.com/lightningnetwork/lnd/tor v1.1.0 h1:iXO7fSzjxTI+p88KmtpbuyuRJeNfgtpl9QeaAliILXE= +github.com/lightningnetwork/lnd/tor v1.1.0/go.mod h1:RDtaAdwfAm+ONuPYwUhNIH1RAvKPv+75lHPOegUcz64= github.com/ltcsuite/ltcd v0.20.1-beta h1:ka9ZwUG7oUPppl+7ptuh5VDxGD7TWEJXu/IOOOz1yfY= github.com/ltcsuite/ltcd v0.20.1-beta/go.mod h1:ZFQaYdYULIuTQiWqs7AUiHD2XhDFeeHW1IH+UYMdABU= github.com/ltcsuite/ltcutil v0.0.0-20191227053721-6bec450ea6ad/go.mod h1:8Vg/LTOO0KYa/vlHWJ6XZAevPQThGH5sufO0Hrou/lA= diff --git a/interceptor.go b/interceptor.go index ac12736..14884df 100644 --- a/interceptor.go +++ b/interceptor.go @@ -156,10 +156,11 @@ func (i *interceptor) start(ctx context.Context) error { ChanId: item.incomingKey.ChanID, HtlcId: item.incomingKey.HtlcID, }, - Action: item.resp.action, - Preimage: item.resp.preimage[:], - FailureMessage: item.resp.failureMessage, - FailureCode: item.resp.failureCode, + Action: item.resp.action, + Preimage: item.resp.preimage[:], + FailureMessage: item.resp.failureMessage, + FailureCode: item.resp.failureCode, + FailureMessageUnencrypted: item.resp.failureMessageUnencrypted, } if err := send(rpcResp); err != nil { @@ -226,7 +227,6 @@ func (i *interceptor) htlcReceiveLoop(ctx context.Context, select { case i.htlcChan <- &interceptedHtlc{ - source: i.pubKey, circuitKey: circuitKey, hash: hash, onionBlob: htlc.OnionBlob, diff --git a/mux.go b/mux.go index 8ac3970..14d8211 100644 --- a/mux.go +++ b/mux.go @@ -5,6 +5,7 @@ import ( "context" "fmt" "sync" + "time" "github.com/bottlepay/lnmux/common" "github.com/bottlepay/lnmux/lnd" @@ -29,6 +30,10 @@ type Mux struct { settledHandler *SettledHandler routingPolicy RoutingPolicy + + virtualChannel uint64 + muxKey common.PubKey + nodeKey common.PubKey } type MuxConfig struct { @@ -51,9 +56,7 @@ type RoutingPolicy struct { FeeRatePpm int64 } -func New(cfg *MuxConfig) (*Mux, - error) { - +func New(cfg *MuxConfig) (*Mux, error) { idKeyDesc, err := cfg.KeyRing.DeriveKey( keychain.KeyLocator{ Family: keychain.KeyFamilyNodeKey, @@ -66,6 +69,17 @@ func New(cfg *MuxConfig) (*Mux, nodeKeyECDH := keychain.NewPubKeyECDH(idKeyDesc, cfg.KeyRing) + muxKubKey, err := cfg.KeyRing.DeriveKey(keychain.KeyLocator{}) + if err != nil { + return nil, err + } + muxKey, err := common.NewPubKeyFromBytes( + muxKubKey.PubKey.SerializeCompressed(), + ) + if err != nil { + return nil, err + } + replayLog := &replayLog{} sphinxRouter := sphinx.NewRouter( @@ -74,18 +88,25 @@ func New(cfg *MuxConfig) (*Mux, sphinx := hop.NewOnionProcessor(sphinxRouter) + connectedNode := cfg.Lnd.PubKey() + logger := cfg.Logger.With("node", connectedNode) + + virtualChannel := virtualChannelFromNode(connectedNode) + return &Mux{ registry: cfg.Registry, sphinx: sphinx, lnd: cfg.Lnd, - logger: cfg.Logger, + logger: logger, settledHandler: cfg.SettledHandler, routingPolicy: cfg.RoutingPolicy, + virtualChannel: virtualChannel, + muxKey: muxKey, + nodeKey: cfg.Lnd.PubKey(), }, nil } type interceptedHtlc struct { - source common.PubKey circuitKey types.CircuitKey hash lntypes.Hash onionBlob []byte @@ -99,10 +120,11 @@ type interceptedHtlc struct { } type interceptedHtlcResponse struct { - action routerrpc.ResolveHoldForwardAction - preimage lntypes.Preimage - failureMessage []byte - failureCode lnrpc.Failure_FailureCode + action routerrpc.ResolveHoldForwardAction + preimage lntypes.Preimage + failureMessage []byte + failureCode lnrpc.Failure_FailureCode + failureMessageUnencrypted bool } func (p *Mux) Run(mainCtx context.Context) error { @@ -153,10 +175,8 @@ func (p *Mux) Run(mainCtx context.Context) error { } case htlc := <-htlcChan: - virtualChannel := virtualChannelFromNode(htlc.source) - // Only intercept htlcs for the virtual channel. - if htlc.outgoingChanID != virtualChannel { + if htlc.outgoingChanID != p.virtualChannel { err := htlc.reply(&interceptedHtlcResponse{ action: routerrpc.ResolveHoldForwardAction_RESUME, }) @@ -209,7 +229,6 @@ func (p *Mux) ProcessHtlc( logger := p.logger.With( "hash", htlc.hash, - "source", htlc.source, "circuitKey", htlc.circuitKey, ) @@ -218,6 +237,35 @@ func (p *Mux) ProcessHtlc( fail := func(code lnwire.FailCode) error { logger.Debugw("Failing htlc", "code", code) + if code == lnwire.CodeFeeInsufficient { + var channelFlags lnwire.ChanUpdateChanFlags + + if bytes.Compare(p.muxKey[:], p.nodeKey[:]) == 1 { + channelFlags |= lnwire.ChanUpdateDirection + } + + wireMsg := lnwire.NewFeeInsufficient(0, lnwire.ChannelUpdate{ + ChainHash: *p.lnd.Network().GenesisHash, + ShortChannelID: lnwire.NewShortChanIDFromInt(p.virtualChannel), + Timestamp: uint32(time.Now().Unix()), + ChannelFlags: channelFlags, + TimeLockDelta: uint16(p.routingPolicy.CltvDelta), + BaseFee: uint32(p.routingPolicy.FeeBaseMsat), + FeeRate: uint32(p.routingPolicy.FeeRatePpm), + }) + var w bytes.Buffer + err := lnwire.EncodeFailureMessage(&w, wireMsg, 0) + if err != nil { + return err + } + + return htlc.reply(&interceptedHtlcResponse{ + action: routerrpc.ResolveHoldForwardAction_FAIL, + failureMessage: w.Bytes(), + failureMessageUnencrypted: true, + }) + } + rpcCode, err := marshallFailureCode(code) if err != nil { return err @@ -354,7 +402,7 @@ func (p *Mux) ProcessHtlc( htlcKey := types.HtlcKey{ ChanID: htlc.circuitKey.ChanID, HtlcID: htlc.circuitKey.HtlcID, - Node: htlc.source, + Node: p.lnd.PubKey(), } p.registry.NotifyExitHopHtlc(