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.
This commit is contained in:
Carla Kirk-Cohen 2024-04-08 10:22:56 -04:00
parent 776c889267
commit 9f038c6191
No known key found for this signature in database
GPG Key ID: 4CA7FE54A6213C91
2 changed files with 82 additions and 1 deletions

View File

@ -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)
}

View File

@ -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)
}