From 9f038c6191ee90a19fbf863a01a67d0ee5a3fd10 Mon Sep 17 00:00:00 2001 From: Carla Kirk-Cohen Date: Mon, 8 Apr 2024 10:22:56 -0400 Subject: [PATCH] htlcswitch: introduce wrapper type error encrypter to identify blinded Introduce two wrapper types for our existing SphinxErrorEncrypter that are used to represent error encrypters where we're a part of a blinded route. These encrypters are functionally the same as a sphinx encrypter, and are just used as "markers" so that we know that we need to handle our error differently due to our different role. We need to persist this information to account for restart cases where we've resovled the outgoing HTLC, then restart and need to handle the error for the incoming link. Specifically, this is relevant for: - On chain resolution messages received after restart - Forwarding packages that are re-forwarded after restart This is also generally helpful, because we can store this information in one place (the circuit) rather than trying to reconstruct it in various places when forwarding the failure back over the switch. --- htlcswitch/circuit.go | 6 +++ htlcswitch/hop/error_encryptor.go | 77 ++++++++++++++++++++++++++++++- 2 files changed, 82 insertions(+), 1 deletion(-) diff --git a/htlcswitch/circuit.go b/htlcswitch/circuit.go index efb2a4779..700b087f5 100644 --- a/htlcswitch/circuit.go +++ b/htlcswitch/circuit.go @@ -205,6 +205,12 @@ func (c *PaymentCircuit) Decode(r io.Reader) error { // Test encrypter. c.ErrorEncrypter = NewMockObfuscator() + case hop.EncrypterTypeIntroduction: + c.ErrorEncrypter = hop.NewIntroductionErrorEncrypter() + + case hop.EncrypterTypeRelaying: + c.ErrorEncrypter = hop.NewRelayingErrorEncrypter() + default: return UnknownEncrypterType(encrypterType) } diff --git a/htlcswitch/hop/error_encryptor.go b/htlcswitch/hop/error_encryptor.go index 7b6a3dd1a..127370e4d 100644 --- a/htlcswitch/hop/error_encryptor.go +++ b/htlcswitch/hop/error_encryptor.go @@ -25,6 +25,18 @@ const ( // EncrypterTypeMock is used to identify a mock obfuscator instance. EncrypterTypeMock = 2 + + // EncrypterTypeIntroduction is used to identify a sphinx onion error + // encrypter where we are the introduction node in a blinded route. It + // has the same functionality as EncrypterTypeSphinx, but is used to + // mark our special-case error handling. + EncrypterTypeIntroduction = 3 + + // EncrypterTypeRelaying is used to identify a sphinx onion error + // encryper where we are a relaying node in a blinded route. It has + // the same functionality as a EncrypterTypeSphinx, but is used to mark + // our special-case error handling. + EncrypterTypeRelaying = 4 ) // ErrorEncrypterExtracter defines a function signature that extracts an @@ -197,9 +209,72 @@ func (s *SphinxErrorEncrypter) Reextract( s.OnionErrorEncrypter = sphinxEncrypter.OnionErrorEncrypter return nil - } // A compile time check to ensure SphinxErrorEncrypter implements the // ErrorEncrypter interface. var _ ErrorEncrypter = (*SphinxErrorEncrypter)(nil) + +// A compile time check to ensure that IntroductionErrorEncrypter implements +// the ErrorEncrypter interface. +var _ ErrorEncrypter = (*IntroductionErrorEncrypter)(nil) + +// IntroductionErrorEncrypter is a wrapper type on SphinxErrorEncrypter which +// is used to signal that we have special HTLC error handling for this hop. +type IntroductionErrorEncrypter struct { + // ErrorEncrypter is the underlying error encrypter, embedded + // directly in the struct so that we don't have to re-implement the + // ErrorEncrypter interface. + ErrorEncrypter +} + +// NewIntroductionErrorEncrypter returns a blank IntroductionErrorEncrypter. +func NewIntroductionErrorEncrypter() *IntroductionErrorEncrypter { + return &IntroductionErrorEncrypter{ + ErrorEncrypter: NewSphinxErrorEncrypter(), + } +} + +// Type returns the identifier for an introduction error encrypter. +func (i *IntroductionErrorEncrypter) Type() EncrypterType { + return EncrypterTypeIntroduction +} + +// Reextract rederives the error encrypter from the currently held EphemeralKey, +// relying on the logic in the underlying SphinxErrorEncrypter. +func (i *IntroductionErrorEncrypter) Reextract( + extract ErrorEncrypterExtracter) error { + + return i.ErrorEncrypter.Reextract(extract) +} + +// A compile time check to ensure that RelayingErrorEncrypte implements +// the ErrorEncrypter interface. +var _ ErrorEncrypter = (*RelayingErrorEncrypter)(nil) + +// RelayingErrorEncrypter is a wrapper type on SphinxErrorEncrypter which +// is used to signal that we have special HTLC error handling for this hop. +type RelayingErrorEncrypter struct { + ErrorEncrypter +} + +// NewRelayingErrorEncrypter returns a blank RelayingErrorEncrypter with +// an underlying SphinxErrorEncrypter. +func NewRelayingErrorEncrypter() *RelayingErrorEncrypter { + return &RelayingErrorEncrypter{ + ErrorEncrypter: NewSphinxErrorEncrypter(), + } +} + +// Type returns the identifier for a relaying error encrypter. +func (r *RelayingErrorEncrypter) Type() EncrypterType { + return EncrypterTypeRelaying +} + +// Reextract rederives the error encrypter from the currently held EphemeralKey, +// relying on the logic in the underlying SphinxErrorEncrypter. +func (r *RelayingErrorEncrypter) Reextract( + extract ErrorEncrypterExtracter) error { + + return r.ErrorEncrypter.Reextract(extract) +}