Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

route-blinding: recover blinding point from forwarding packages #37

12 changes: 12 additions & 0 deletions channeldb/channel.go
Original file line number Diff line number Diff line change
Expand Up @@ -2783,6 +2783,17 @@ func (c *OpenChannel) AppendRemoteCommitChain(diff *CommitDiff) error {
// prevents the same fails and settles from being retransmitted
// after restarts. The actual fail or settle we need to
// propagate to the remote party is now in the commit diff.
//
// NOTE(1/20/23): We don't actually do any internal acknowlegment
// to the outgoing link here anymore! Ever since we moved to
// pipeline (ie: immediately send without waiting for commitment
// tx update) settles/fails, this is often (always?) called with empty
// SettleFailReferences. Instead settles/fails are acked in
// batches periodically by the Switch. I guess the Settle/Fail
// will be resent internally until that batch internal
// acknowledgement occurs.
// https://github.com/lightningnetwork/lnd/pull/3143#discussion_r304190259
fmt.Println("[AppendRemoteCommitChain]: AckSettleFails...")
err = c.Packager.AckSettleFails(tx, diff.SettleFailAcks...)
if err != nil {
return err
Expand Down Expand Up @@ -3216,6 +3227,7 @@ func (c *OpenChannel) AckAddHtlcs(addRefs ...AddRef) error {
func (c *OpenChannel) AckSettleFails(settleFailRefs ...SettleFailRef) error {
c.Lock()
defer c.Unlock()
fmt.Println("[OpenChannel.AckSettleFails]")

return kvdb.Update(c.Db.backend, func(tx kvdb.RwTx) error {
return c.Packager.AckSettleFails(tx, settleFailRefs...)
Expand Down
18 changes: 18 additions & 0 deletions channeldb/forwarding_package.go
Original file line number Diff line number Diff line change
Expand Up @@ -752,6 +752,15 @@ func (p *ChannelPackager) AckAddHtlcs(tx kvdb.RwTx, addRefs ...AddRef) error {
if len(addRefs) == 0 {
return nil
}
fmt.Printf("[ChannelPackager.AckAddHtlcs(%s)]: marking ADDs as acknowledged in forwarding package\n",
p.source,
)

if len(addRefs) == 1 {
fmt.Printf("[ChannelPackager.AckAddHtlcs(%s)]: marking ADDs at height=%d, index=%d as acknowledged in forwarding package\n",
p.source, addRefs[0].Height, addRefs[0].Index,
)
}

fwdPkgBkt := tx.ReadWriteBucket(fwdPackagesKey)
if fwdPkgBkt == nil {
Expand All @@ -777,6 +786,11 @@ func (p *ChannelPackager) AckAddHtlcs(tx kvdb.RwTx, addRefs ...AddRef) error {
// Load each height bucket once and remove all acked htlcs at that
// height.
for height, indexes := range heightDiffs {
fmt.Printf("[AckAddHtlcs(%s)]: height diff: %d, %+v!\n",
p.source,
height,
indexes,
)
err := ackAddHtlcsAtHeight(sourceBkt, height, indexes)
if err != nil {
return err
Expand Down Expand Up @@ -832,6 +846,10 @@ func ackAddHtlcsAtHeight(sourceBkt kvdb.RwBucket, height uint64,
// the settle/fail, or it becomes otherwise safe to forgo retransmitting the
// settle/fail after a restart.
func (p *ChannelPackager) AckSettleFails(tx kvdb.RwTx, settleFailRefs ...SettleFailRef) error {
fmt.Printf("[Packager.AckSettleFails(%s)]: settle/fail refs: %+v!\n",
p.source,
settleFailRefs,
)
return ackSettleFails(tx, settleFailRefs)
}

Expand Down
13 changes: 13 additions & 0 deletions htlcswitch/circuit.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ package htlcswitch

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

"github.com/lightningnetwork/lnd/channeldb"
Expand Down Expand Up @@ -76,6 +77,12 @@ func newPaymentCircuit(hash *[32]byte, pkt *htlcPacket) *PaymentCircuit {
if pkt.sourceRef != nil {
addRef = *pkt.sourceRef
}
fmt.Printf("[newPaymentCircuit(%s)]: forwarding package (processed update) add reference: %+v!\n",
pkt.incomingChanID, pkt.sourceRef,
)
fmt.Printf("[newPaymentCircuit(%s)]: htlcPacket: %+v!\n",
pkt.incomingChanID, pkt,
)

return &PaymentCircuit{
AddRef: addRef,
Expand All @@ -97,6 +104,12 @@ func makePaymentCircuit(hash *[32]byte, pkt *htlcPacket) PaymentCircuit {
if pkt.sourceRef != nil {
addRef = *pkt.sourceRef
}
fmt.Printf("[makePaymentCircuit(%s)]: forwarding package (processed update) add reference: %+v!\n",
pkt.incomingChanID, pkt.sourceRef,
)
fmt.Printf("[makePaymentCircuit(%s)]: htlcPacket: %+v!\n",
pkt.incomingChanID, pkt,
)

return PaymentCircuit{
AddRef: addRef,
Expand Down
18 changes: 18 additions & 0 deletions htlcswitch/circuit_map.go
Original file line number Diff line number Diff line change
Expand Up @@ -795,6 +795,8 @@ func (cm *circuitMap) LookupByPaymentHash(hash [32]byte) []*PaymentCircuit {
func (cm *circuitMap) CommitCircuits(circuits ...*PaymentCircuit) (
*CircuitFwdActions, error) {

fmt.Println("[switch.CommitCiruits]: committing circuits!")

inKeys := make([]CircuitKey, 0, len(circuits))
for _, circuit := range circuits {
inKeys = append(inKeys, circuit.Incoming)
Expand All @@ -803,6 +805,9 @@ func (cm *circuitMap) CommitCircuits(circuits ...*PaymentCircuit) (
log.Tracef("Committing fresh circuits: %v", newLogClosure(func() string {
return spew.Sdump(inKeys)
}))
fmt.Printf("Committing fresh circuits: %v", newLogClosure(func() string {
return spew.Sdump(inKeys)
}))

actions := &CircuitFwdActions{}

Expand All @@ -825,12 +830,14 @@ func (cm *circuitMap) CommitCircuits(circuits ...*PaymentCircuit) (
for _, circuit := range circuits {
inKey := circuit.InKey()
if foundCircuit, ok := cm.pending[inKey]; ok {
fmt.Printf("[switch.CommitCiruits]: found circuit=%s in our map!\n", inKey)
switch {

// This circuit has a keystone, it's waiting for a
// response from the remote peer on the outgoing link.
// Drop it like it's hot, ensure duplicates get caught.
case foundCircuit.HasKeystone():
fmt.Printf("[switch.CommitCiruits]: circuit=%s has a keystone! which means...\n", inKey)
drops = append(drops, circuit)

// If no keystone is set and the switch has not been
Expand All @@ -842,13 +849,16 @@ func (cm *circuitMap) CommitCircuits(circuits ...*PaymentCircuit) (
// link from failing a duplicate add while it is still
// in the server's memory mailboxes.
case !foundCircuit.LoadedFromDisk:
fmt.Printf("[switch.CommitCiruits]: circuit=%s has has not been loaded from disk!\n", inKey)
drops = append(drops, circuit)

// Otherwise, the in-mem packet has been lost due to a
// restart. It is now safe to send back a failure along
// the incoming link. The incoming link should be able
// detect and ignore duplicate packets of this type.
default:
fmt.Printf("[switch.CommitCiruits]: ADD for circuit=%s is being failed!\n", inKey)
fmt.Printf("[switch.CommitCiruits]: loaded circuit=%s from disk: %t\n", inKey, foundCircuit.LoadedFromDisk)
fails = append(fails, circuit)
addFails = append(addFails, circuit)
}
Expand All @@ -864,6 +874,7 @@ func (cm *circuitMap) CommitCircuits(circuits ...*PaymentCircuit) (

// If all circuits are dropped or failed, we are done.
if len(adds) == 0 {
fmt.Println("[switch.CommitCiruits]: no ADDs to commit. all must have been duplicates!")
actions.Drops = drops
actions.Fails = fails
return actions, nil
Expand Down Expand Up @@ -906,6 +917,7 @@ func (cm *circuitMap) CommitCircuits(circuits ...*PaymentCircuit) (
actions.Adds = adds
actions.Drops = drops
actions.Fails = fails
fmt.Println("[switch.CommitCiruits]: committing circuits succeeded!")
return actions, nil
}

Expand All @@ -922,6 +934,7 @@ func (cm *circuitMap) CommitCircuits(circuits ...*PaymentCircuit) (
actions.Drops = drops
actions.Fails = addFails

fmt.Println("[switch.CommitCiruits]: failed to commit circuits!")
return actions, err
}

Expand All @@ -948,9 +961,14 @@ func (cm *circuitMap) OpenCircuits(keystones ...Keystone) error {
return nil
}

fmt.Println("[switch.OpenCiruits]: opening circuits!")

log.Tracef("Opening finalized circuits: %v", newLogClosure(func() string {
return spew.Sdump(keystones)
}))
fmt.Printf("[switch.OpenCiruits]: Opening finalized circuits: %v", newLogClosure(func() string {
return spew.Sdump(keystones)
}))

// Check that all keystones correspond to committed-but-unopened
// circuits.
Expand Down
11 changes: 9 additions & 2 deletions htlcswitch/hodl/flags.go
Original file line number Diff line number Diff line change
Expand Up @@ -34,8 +34,6 @@ const (
// not the exit node.
FailIncoming

// TODO(conner): add modes for switch breakpoints

// AddOutgoing drops an outgoing ADD before it is added to the
// in-memory commitment state of the link.
AddOutgoing
Expand All @@ -55,6 +53,11 @@ const (
// BogusSettle attempts to settle back any incoming HTLC for which we
// are the exit node with a bogus preimage.
BogusSettle

// TODO(conner): add modes for switch breakpoints

// AddForward ...
AddForward
)

// String returns a human-readable identifier for a given Flag.
Expand All @@ -78,6 +81,8 @@ func (f Flag) String() string {
return "Commit"
case BogusSettle:
return "BogusSettle"
case AddForward:
return "AddForward"
default:
return "UnknownHodlFlag"
}
Expand Down Expand Up @@ -106,6 +111,8 @@ func (f Flag) Warning() string {
msg = "will not commit pending channel updates"
case BogusSettle:
msg = "will settle HTLC with bogus preimage"
case AddForward:
msg = "will not update switch circuit map for forwarded ADD"
default:
msg = "incorrect hodl flag usage"
}
Expand Down
13 changes: 13 additions & 0 deletions htlcswitch/hop/iterator.go
Original file line number Diff line number Diff line change
Expand Up @@ -188,6 +188,7 @@ func MakeBlindingKit(processor BlindingProcessor,
ErrDecodeFailed, err)
}

fmt.Println("MakeBlindingKit")
if err := ValidateBlindedRouteData(
routeData, incomingAmount, incomingCltv,
); err != nil {
Expand Down Expand Up @@ -420,6 +421,8 @@ func (p *OnionProcessor) DecodeHopIterators(id []byte,
resps = make([]DecodeHopIteratorResponse, batchSize)
)

fmt.Println("[DecodeHopIterators()]: Decrypting onion packets")

tx := p.router.BeginTxn(id, batchSize)

decode := func(seqNum uint16, onionPkt *sphinx.OnionPacket,
Expand Down Expand Up @@ -474,6 +477,13 @@ func (p *OnionProcessor) DecodeHopIterators(id []byte,
// Execute cpu-heavy onion decoding in parallel.
var wg sync.WaitGroup
for i := range reqs {
fmt.Printf("[DecodeHopIterators()]: Decrypting onion packet for HTLC ADD, "+
"amt=%s, cltv=%d, r_hash=%v, blinding_point=%x\n",
reqs[i].IncomingAmount.String(),
reqs[i].IncomingCltv,
reqs[i].RHash,
reqs[i].BlindingPoint.SerializeCompressed()[:10],
)
wg.Add(1)
go func(seqNum uint16) {
defer wg.Done()
Expand Down Expand Up @@ -544,6 +554,9 @@ func (p *OnionProcessor) DecodeHopIterators(id []byte,
// failure code for replays, we reuse one of the
// failure codes that has BADONION.
resp.FailCode = lnwire.CodeInvalidOnionVersion
fmt.Printf("unable to process onion packet: %v\n",
sphinx.ErrReplayedPacket)

continue
}

Expand Down
29 changes: 29 additions & 0 deletions htlcswitch/hop/payload.go
Original file line number Diff line number Diff line change
Expand Up @@ -133,6 +133,24 @@ func NewLegacyPayload(f *sphinx.HopData) *Payload {
}
}

// NOTE(10/26/22): This function is currently only used to get around
// the fact that customRecords is unexported and is required to be set.
// I don't think a function like this would have much utility otherwise.
// Given that we use TLV en/decoding I am a bit unsure how this function
// will behave/get access to the information it would need.
// The data included in a TLV payload is highly variable. That is why it makes
// sense to define a struct and then TLV encode each of the structs types
// that the user sets.
func NewTLVPayload() *Payload {

// Set the unexported customRecords field so that we can carry
// on with our Link testing.
return &Payload{
FwdInfo: ForwardingInfo{},
customRecords: make(record.CustomSet),
}
}

// NewPayloadFromReader builds a new Hop from the passed io.Reader. The reader
// should correspond to the bytes encapsulated in a TLV onion payload. The
// final hop bool signals that this payload was the final packet parsed by
Expand Down Expand Up @@ -452,6 +470,12 @@ func (h *Payload) EncryptedData() []byte {
return h.encryptedData
}

// EncryptedData returns the route blinding encrypted data parsed from the
// onion payload.
func (h *Payload) SetEncryptedData(data []byte) {
h.encryptedData = data
}

// BlindingPoint returns the route blinding point parsed from the onion payload.
func (h *Payload) BlindingPoint() *btcec.PublicKey {
return h.blindingPoint
Expand Down Expand Up @@ -512,6 +536,9 @@ func getMinRequiredViolation(set tlv.TypeMap) *tlv.Type {
func ValidateBlindedRouteData(blindedData *record.BlindedRouteData,
incomingAmount lnwire.MilliSatoshi, incomingTimelock uint32) error {

fmt.Printf("payload.go: ValidateBlindedRouteData() - validating blinded_data=%+v!\n",
blindedData)

// Bolt 04 notes that we should enforce payment constraints _if_ they
// are present, so we do not fail if not provided.
if blindedData.Constraints != nil {
Expand Down Expand Up @@ -566,6 +593,8 @@ func ValidateBlindedRouteData(blindedData *record.BlindedRouteData,
}
}

fmt.Println("payload.go: ValidateBlindedRouteData() - still validating!")

// No need to check anything else if features are not provided (bolt 4
// indicates that omitted features should be treated like an empty
// vector).
Expand Down
Loading