loopin

package
v0.29.0-beta.rc2 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Dec 16, 2024 License: MIT Imports: 47 Imported by: 0

Documentation

Index

Constants

View Source
const (
	DefaultPaymentTimeoutSeconds = 60
)
View Source
const Subsystem = "SADDR"

Subsystem defines the sub system name of this package.

View Source
const (
	// SwapNotFinishedMsg is the message that is sent to the server if a
	// swap is not considered finished yet.
	SwapNotFinishedMsg = "swap not finished yet"
)

Variables

View Source
var (
	// ErrFeeTooHigh is returned if the server sets a fee rate for the htlc
	// tx that is too high. We prevent here against a low htlc timeout sweep
	// amount.
	ErrFeeTooHigh = errors.New("server htlc tx fee is higher than the " +
		"configured allowed maximum")

	// ErrBackupFeeTooHigh is returned if the server sets a fee rate for the
	// htlc backup tx that is too high. We prevent here against a low htlc
	// timeout sweep amount.
	ErrBackupFeeTooHigh = errors.New("server htlc backup tx fee is " +
		"higher than the configured allowed maximum")
)
View Source
var (
	// InitHtlcTx initiates the htlc tx creation with the server.
	InitHtlcTx = fsm.StateType("InitHtlcTx")

	// SignHtlcTx partially signs the htlc transaction with the received
	// server nonces. The client doesn't hold a final signature hence can't
	// publish the htlc.
	SignHtlcTx = fsm.StateType("SignHtlcTx")

	// MonitorInvoiceAndHtlcTx monitors the swap invoice payment and the
	// htlc transaction confirmation.
	// Since the client provided its partial signature to spend to the htlc
	// pkScript, the server could publish the htlc transaction prematurely.
	// We need to monitor the htlc transaction to sweep our timeout path in
	// this case.
	// If the server pays the swap invoice as expected we can stop to
	// monitor the htlc timeout path.
	MonitorInvoiceAndHtlcTx = fsm.StateType("MonitorInvoiceAndHtlcTx")

	// PaymentReceived is the state where the swap invoice was paid by the
	// server. The client can now sign the sweepless sweep transaction.
	PaymentReceived = fsm.StateType("PaymentReceived")

	// SweepHtlcTimeout is the state where the htlc timeout path is
	// published because the server did not pay the invoice on time.
	SweepHtlcTimeout = fsm.StateType("SweepHtlcTimeout")

	// MonitorHtlcTimeoutSweep monitors the htlc timeout sweep transaction
	// confirmation.
	MonitorHtlcTimeoutSweep = fsm.StateType("MonitorHtlcTimeoutSweep")

	// HtlcTimeoutSwept is the state where the htlc timeout sweep
	// transaction was sufficiently confirmed.
	HtlcTimeoutSwept = fsm.StateType("HtlcTimeoutSwept")

	// Succeeded is the state the swap is in if it was successful.
	Succeeded = fsm.StateType("Succeeded")

	// SucceededTransitioningFailed is the state the swap is in if the swap
	// payment was received but the client was not able to transition
	// the deposits to the looped-in state.
	SucceededTransitioningFailed = fsm.StateType("SucceededTransitioningFailed") //nolint:lll

	// UnlockDeposits is the state where the deposits are reset. This
	// happens when the state machine encountered an error and the swap
	// process needs to start from the beginning.
	UnlockDeposits = fsm.StateType("UnlockDeposits")

	// Failed is the state the swap is in if it failed.
	Failed = fsm.StateType("Failed")
)

States that the loop-in fsm can transition to.

View Source
var (
	OnInitHtlc                  = fsm.EventType("OnInitHtlc")
	OnHtlcInitiated             = fsm.EventType("OnHtlcInitiated")
	OnHtlcTxSigned              = fsm.EventType("OnHtlcTxSigned")
	OnSweepHtlcTimeout          = fsm.EventType("OnSweepHtlcTimeout")
	OnHtlcTimeoutSweepPublished = fsm.EventType("OnHtlcTimeoutSweepPublished")
	OnHtlcTimeoutSwept          = fsm.EventType("OnHtlcTimeoutSwept")
	OnPaymentReceived           = fsm.EventType("OnPaymentReceived")
	OnPaymentDeadlineExceeded   = fsm.EventType("OnPaymentDeadlineExceeded")
	OnSwapTimedOut              = fsm.EventType("OnSwapTimedOut")
	OnSucceeded                 = fsm.EventType("OnSucceeded")
	OnRecover                   = fsm.EventType("OnRecover")
)

Events.

View Source
var (
	// ErrInvalidOutpoint is returned when an outpoint contains the outpoint
	// separator.
	ErrInvalidOutpoint = errors.New("outpoint contains outpoint separator")
)

Functions

func UseLogger

func UseLogger(logger btclog.Logger)

UseLogger uses a specified Logger to output package logging info. This should be used in preference to SetLogWriter if the caller is also using btclog.

Types

type AddressManager

type AddressManager interface {
	// GetStaticAddressParameters returns the static address parameters.
	GetStaticAddressParameters(ctx context.Context) (*address.Parameters,
		error)

	// GetStaticAddress returns the deposit address for the given client and
	// server public keys.
	GetStaticAddress(ctx context.Context) (*script.StaticAddress, error)
}

AddressManager handles fetching of address parameters.

type BaseDB

type BaseDB interface {
	Querier

	// ExecTx allows for executing a function in the context of a database
	// transaction.
	ExecTx(ctx context.Context, txOptions loopdb.TxOptions,
		txBody func(Querier) error) error
}

BaseDB is the interface that contains all the queries generated by sqlc for the static_address_swaps table and transaction functionality.

type Config

type Config struct {
	// Server is the client that is used to communicate with the static
	// address server.
	Server looprpc.StaticAddressServerClient

	// AddressManager gives the withdrawal manager access to static address
	// parameters.
	AddressManager AddressManager

	// DepositManager gives the withdrawal manager access to the deposits
	// enabling it to create and manage loop-ins.
	DepositManager DepositManager

	// LndClient is used to add invoices and select hop hints.
	LndClient lndclient.LightningClient

	// InvoicesClient is used to subscribe to invoice settlements and
	// cancel invoices.
	InvoicesClient lndclient.InvoicesClient

	// SwapClient is used to get loop in quotes.
	QuoteGetter QuoteGetter

	// NodePubKey is used to get a loo-in quote.
	NodePubkey route.Vertex

	// WalletKit is the wallet client that is used to derive new keys from
	// lnd's wallet.
	WalletKit lndclient.WalletKitClient

	// ChainParams is the chain configuration(mainnet, testnet...) this
	// manager uses.
	ChainParams *chaincfg.Params

	// Chain is the chain notifier that is used to listen for new
	// blocks.
	ChainNotifier lndclient.ChainNotifierClient

	// Signer is the signer client that is used to sign transactions.
	Signer lndclient.SignerClient

	// Store is the database store that is used to store static address
	// loop-in related records.
	Store StaticAddressLoopInStore

	// NotificationManager is the manager that handles the notification
	// subscriptions.
	NotificationManager NotificationManager

	// ValidateLoopInContract validates the contract parameters against our
	// request.
	ValidateLoopInContract ValidateLoopInContract

	// MaxStaticAddrHtlcFeePercentage is the percentage of the swap amount
	// that we allow the server to charge for the htlc transaction.
	// Although highly unlikely, this is a defense against the server
	// publishing the htlc without paying the swap invoice, forcing us to
	// sweep the timeout path.
	MaxStaticAddrHtlcFeePercentage float64

	// MaxStaticAddrHtlcBackupFeePercentage is the percentage of the swap
	// amount that we allow the server to charge for the htlc backup
	// transactions. This is a defense against the server publishing the
	// htlc backup without paying the swap invoice, forcing us to sweep the
	// timeout path. This value is elevated compared to
	// MaxStaticAddrHtlcFeePercentage since it serves the server as backup
	// transaction in case of fee spikes.
	MaxStaticAddrHtlcBackupFeePercentage float64
}

Config contains the services required for the loop-in manager.

type DepositManager

type DepositManager interface {
	// GetAllDeposits returns all known deposits from the database store.
	GetAllDeposits(ctx context.Context) ([]*deposit.Deposit, error)

	// AllStringOutpointsActiveDeposits returns all deposits that have the
	// given outpoints and are in the given state. If any of the outpoints
	// does not correspond to an active deposit, the function returns false.
	AllStringOutpointsActiveDeposits(outpoints []string,
		stateFilter fsm.StateType) ([]*deposit.Deposit, bool)

	// TransitionDeposits transitions the given deposits to the next state
	// based on the given event. It returns an error if the transition is
	// invalid.
	TransitionDeposits(ctx context.Context, deposits []*deposit.Deposit,
		event fsm.EventType, expectedFinalState fsm.StateType) error
}

DepositManager handles the interaction of loop-ins with deposits.

type FSM

type FSM struct {
	*fsm.StateMachine
	// contains filtered or unexported fields
}

FSM embeds an FSM and extends it with a static address loop-in and a config.

func NewFSM

func NewFSM(ctx context.Context, loopIn *StaticAddressLoopIn, cfg *Config,
	recoverStateMachine bool) (*FSM, error)

NewFSM creates a new loop-in state machine.

func (*FSM) Debugf

func (f *FSM) Debugf(format string, args ...interface{})

Debugf logs a debug message with the loop-in swap hash.

func (*FSM) Errorf

func (f *FSM) Errorf(format string, args ...interface{})

Errorf logs an error message with the loop-in swap hash.

func (*FSM) Infof

func (f *FSM) Infof(format string, args ...interface{})

Infof logs an info message with the loop-in swap hash.

func (*FSM) InitHtlcAction

func (f *FSM) InitHtlcAction(ctx context.Context,
	_ fsm.EventContext) fsm.EventType

InitHtlcAction is executed if all loop-in information has been validated. We assemble a loop-in request and send it to the server.

func (*FSM) LoopInStatesV0

func (f *FSM) LoopInStatesV0() fsm.States

LoopInStatesV0 returns the state and transition map for the loop-in state machine.

func (*FSM) MonitorHtlcTimeoutSweepAction

func (f *FSM) MonitorHtlcTimeoutSweepAction(ctx context.Context,
	_ fsm.EventContext) fsm.EventType

MonitorHtlcTimeoutSweepAction is called after the htlc timeout sweep tx has been published. We monitor the confirmation of the htlc timeout sweep tx and finalize the deposits once swept.

func (*FSM) MonitorInvoiceAndHtlcTxAction

func (f *FSM) MonitorInvoiceAndHtlcTxAction(ctx context.Context,
	_ fsm.EventContext) fsm.EventType

MonitorInvoiceAndHtlcTxAction is called after the htlc tx has been signed by us. The server from here on has the ability to publish the htlc tx. If the server publishes the htlc tx without paying the invoice, we have to monitor for the timeout path and sweep the funds back to us. If, while waiting for the htlc timeout, our invoice gets paid, the swap is considered successful, and we can stop monitoring the htlc confirmation and continue to sign the sweepless sweep.

func (*FSM) PaymentReceivedAction

func (f *FSM) PaymentReceivedAction(ctx context.Context,
	_ fsm.EventContext) fsm.EventType

PaymentReceivedAction is called if the invoice was settled. We finalize the deposits by transitioning them to the LoopedIn state.

func (*FSM) SignHtlcTxAction

func (f *FSM) SignHtlcTxAction(ctx context.Context,
	_ fsm.EventContext) fsm.EventType

SignHtlcTxAction is called if the htlc was initialized and the server provided the necessary information to construct the htlc tx. We sign the htlc tx and send the signatures to the server.

func (*FSM) SweepHtlcTimeoutAction

func (f *FSM) SweepHtlcTimeoutAction(ctx context.Context,
	_ fsm.EventContext) fsm.EventType

SweepHtlcTimeoutAction is called if the server published the htlc tx without paying the invoice. We wait for the timeout path to open up and sweep the funds back to us.

func (*FSM) UnlockDepositsAction

func (f *FSM) UnlockDepositsAction(ctx context.Context,
	_ fsm.EventContext) fsm.EventType

UnlockDepositsAction is called if the loop-in failed and its deposits should be available in a future loop-in request.

func (*FSM) Warnf

func (f *FSM) Warnf(format string, args ...interface{})

Warnf logs a warning message with the loop-in swap hash.

type Manager

type Manager struct {
	// contains filtered or unexported fields
}

Manager manages the address state machines.

func NewManager

func NewManager(cfg *Config) *Manager

NewManager creates a new deposit withdrawal manager.

func (*Manager) DeliverLoopInRequest

func (m *Manager) DeliverLoopInRequest(ctx context.Context,
	req *loop.StaticAddressLoopInRequest) (*StaticAddressLoopIn, error)

DeliverLoopInRequest forwards a loop-in request from the server to the manager run loop to initiate a new loop-in swap.

func (*Manager) GetAllSwaps

func (m *Manager) GetAllSwaps(ctx context.Context) ([]*StaticAddressLoopIn,
	error)

GetAllSwaps returns all static address loop-in swaps from the database store.

func (*Manager) Run

func (m *Manager) Run(ctx context.Context, currentHeight uint32) error

Run runs the static address loop-in manager.

func (*Manager) WaitInitComplete

func (m *Manager) WaitInitComplete()

WaitInitComplete waits until the static address loop-in manager has completed its setup.

type NotificationManager

type NotificationManager interface {
	// SubscribeStaticLoopInSweepRequests subscribes to the static loop in
	// sweep requests. These are sent by the server to the client to request
	// a sweep of a static loop in that has been finished.
	SubscribeStaticLoopInSweepRequests(ctx context.Context,
	) <-chan *swapserverrpc.ServerStaticLoopInSweepNotification
}

type Querier

type Querier interface {
	// InsertSwap inserts a new base swap.
	InsertSwap(ctx context.Context, arg sqlc.InsertSwapParams) error

	// InsertHtlcKeys inserts the htlc keys for a swap.
	InsertHtlcKeys(ctx context.Context, arg sqlc.InsertHtlcKeysParams) error

	// InsertStaticAddressLoopIn inserts a new static address loop-in swap.
	InsertStaticAddressLoopIn(ctx context.Context,
		arg sqlc.InsertStaticAddressLoopInParams) error

	// InsertStaticAddressMetaUpdate inserts metadata about loop-in
	// updates.
	InsertStaticAddressMetaUpdate(ctx context.Context,
		arg sqlc.InsertStaticAddressMetaUpdateParams) error

	// UpdateStaticAddressLoopIn updates a loop-in swap.
	UpdateStaticAddressLoopIn(ctx context.Context,
		arg sqlc.UpdateStaticAddressLoopInParams) error

	// GetStaticAddressLoopInSwap retrieves a loop-in swap by its swap hash.
	GetStaticAddressLoopInSwap(ctx context.Context,
		swapHash []byte) (sqlc.GetStaticAddressLoopInSwapRow, error)

	// GetStaticAddressLoopInSwapsByStates retrieves all swaps with the
	// given states. The states string is an input for the IN primitive in
	// sqlite, hence the format needs to be '{State1,State2,...}'.
	GetStaticAddressLoopInSwapsByStates(ctx context.Context,
		states sql.NullString) ([]sqlc.GetStaticAddressLoopInSwapsByStatesRow,
		error)

	// GetLoopInSwapUpdates retrieves all updates for a loop-in swap.
	GetLoopInSwapUpdates(ctx context.Context,
		swapHash []byte) ([]sqlc.StaticAddressSwapUpdate, error)

	// IsStored returns true if a swap with the given hash is stored in the
	// database, false otherwise.
	IsStored(ctx context.Context, swapHash []byte) (bool, error)
}

Querier is the interface that contains all the queries generated by sqlc for the static_address_swaps table.

type QuoteGetter

type QuoteGetter interface {
	// GetLoopInQuote returns a quote for a loop-in swap.
	GetLoopInQuote(ctx context.Context, amt btcutil.Amount,
		pubKey route.Vertex, lastHop *route.Vertex,
		routeHints [][]zpay32.HopHint,
		initiator string, numDeposits uint32) (*loop.LoopInQuote, error)
}

type SqlStore

type SqlStore struct {
	// contains filtered or unexported fields
}

SqlStore is the backing store for static address loop-ins.

func NewSqlStore

func NewSqlStore(db BaseDB, clock clock.Clock,
	network *chaincfg.Params) *SqlStore

NewSqlStore constructs a new SQLStore from a BaseDB. The BaseDB is agnostic to the underlying driver which can be postgres or sqlite.

func (*SqlStore) CreateLoopIn

func (s *SqlStore) CreateLoopIn(ctx context.Context,
	loopIn *StaticAddressLoopIn) error

CreateLoopIn inserts a new loop-in swap into the database. Basic loop-in parameters are stored in the swaps table, htlc key information is stored in the htlc_keys table, and loop-in specific information is stored in the static_address_swaps table.

func (*SqlStore) GetLoopInByHash

func (s *SqlStore) GetLoopInByHash(ctx context.Context,
	swapHash lntypes.Hash) (*StaticAddressLoopIn, error)

GetLoopInByHash returns the loop-in swap with the given hash.

func (*SqlStore) GetStaticAddressLoopInSwapsByStates

func (s *SqlStore) GetStaticAddressLoopInSwapsByStates(ctx context.Context,
	states []fsm.StateType) ([]*StaticAddressLoopIn, error)

GetStaticAddressLoopInSwapsByStates returns all static address loop-ins from the db that are in the given states.

func (*SqlStore) IsStored

func (s *SqlStore) IsStored(ctx context.Context, swapHash lntypes.Hash) (bool,
	error)

IsStored returns true if a swap with the given hash is stored in the database, false otherwise.

func (*SqlStore) UpdateLoopIn

func (s *SqlStore) UpdateLoopIn(ctx context.Context,
	loopIn *StaticAddressLoopIn) error

UpdateLoopIn updates the loop-in in the database.

type StaticAddressLoopIn

type StaticAddressLoopIn struct {
	// SwapHash is the hashed preimage of the swap invoice. It represents
	// the primary identifier of the swap.
	SwapHash lntypes.Hash

	// SwapPreimage is the preimage that is used for the swap.
	SwapPreimage lntypes.Preimage

	// HtlcCltvExpiry is the expiry of the swap.
	HtlcCltvExpiry int32

	// MaxSwapFee is the swap fee in sats that the user accepted when
	// initiating the swap. It is the upper limit for the QuotedSwapFee.
	MaxSwapFee btcutil.Amount

	// InitiationHeight is the height at which the swap was initiated.
	InitiationHeight uint32

	// InitiationTime is the time at which the swap was initiated.
	InitiationTime time.Time

	// ProtocolVersion is the protocol version of the static address.
	ProtocolVersion version.AddressProtocolVersion

	// Label contains an optional label for the swap.
	Label string

	// ClientPubkey is the pubkey of the client that is used for the swap.
	ClientPubkey *btcec.PublicKey

	// ServerPubkey is the pubkey of the server that is used for the swap.
	ServerPubkey *btcec.PublicKey

	// HtlcKeyLocator is the locator of the server's htlc key.
	HtlcKeyLocator keychain.KeyLocator

	// SwapInvoice is the invoice that needs to be paid by the server to
	// complete the loop-in swap.
	SwapInvoice string

	// LastHop is an optional parameter that specifies the last hop to be
	// used for a loop in swap.
	LastHop []byte

	// The swap payment timeout allows the user to specify an upper limit
	// for the amount of time the server is allowed to take to fulfill the
	// off-chain swap payment. If the timeout is reached the swap will be
	// aborted on the server side and the client can retry the swap with
	// different parameters.
	PaymentTimeoutSeconds uint32

	// QuotedSwapFee is the swap fee in sats that the server returned in the
	// swap quote.
	QuotedSwapFee btcutil.Amount

	// The outpoints in the format txid:vout that are part of the loop-in
	// swap.
	DepositOutpoints []string

	// Initiator is an optional identification string that will be appended
	// to the user agent string sent to the server to give information about
	// the usage of loop. This initiator part is meant for user interfaces
	// to add their name to give the full picture of the binary used
	// (loopd, lit) and the method used for triggering the swap
	// (loop cli, autolooper, lit ui, other 3rd party ui).
	Initiator string

	// Private indicates whether the destination node should be considered
	// private. In which case, loop will generate hop hints to assist with
	// probing and payment.
	Private bool

	// Optional route hints to reach the destination through private
	// channels.
	RouteHints [][]zpay32.HopHint

	// Deposits are the deposits that are part of the loop-in swap. They
	// implicitly carry the swap amount.
	Deposits []*deposit.Deposit

	// AddressParams are the parameters of the address that is used for the
	// swap.
	AddressParams *address.Parameters

	// Address is the address script that is used for the swap.
	Address *script.StaticAddress

	// HtlcTxFeeRate is the fee rate that is used for the htlc transaction.
	HtlcTxFeeRate chainfee.SatPerKWeight

	// HtlcTxHighFeeRate is the fee rate that is used for the htlc
	// transaction.
	HtlcTxHighFeeRate chainfee.SatPerKWeight

	// HtlcTxExtremelyHighFeeRate is the fee rate that is used for the htlc
	// transaction.
	HtlcTxExtremelyHighFeeRate chainfee.SatPerKWeight

	// HtlcTimeoutSweepTxHash is the hash of the htlc timeout sweep tx.
	HtlcTimeoutSweepTxHash *chainhash.Hash

	// HtlcTimeoutSweepAddress
	HtlcTimeoutSweepAddress btcutil.Address
	// contains filtered or unexported fields
}

StaticAddressLoopIn represents the in-memory loop-in information.

func (*StaticAddressLoopIn) GetState

func (l *StaticAddressLoopIn) GetState() fsm.StateType

GetState returns the current state of the loop-in swap.

func (*StaticAddressLoopIn) IsInState

func (l *StaticAddressLoopIn) IsInState(state fsm.StateType) bool

IsInState returns true if the deposit is in the given state.

func (*StaticAddressLoopIn) Outpoints

func (l *StaticAddressLoopIn) Outpoints() []wire.OutPoint

Outpoints returns the wire outpoints of the deposits.

func (*StaticAddressLoopIn) RemainingPaymentTimeSeconds

func (l *StaticAddressLoopIn) RemainingPaymentTimeSeconds() int64

RemainingPaymentTimeSeconds returns the remaining time in seconds until the payment timeout is reached. The remaining time is calculated from the initiation time of the swap. If more than the swaps configured payment timeout has passed, the remaining time will be negative.

func (*StaticAddressLoopIn) SetState

func (l *StaticAddressLoopIn) SetState(state fsm.StateType)

SetState sets the current state of the loop-in swap.

func (*StaticAddressLoopIn) TotalDepositAmount

func (l *StaticAddressLoopIn) TotalDepositAmount() btcutil.Amount

TotalDepositAmount returns the total amount of the deposits.

type StaticAddressLoopInStore

type StaticAddressLoopInStore interface {
	// CreateLoopIn creates a loop-in record in the database.
	CreateLoopIn(ctx context.Context, loopIn *StaticAddressLoopIn) error

	// UpdateLoopIn updates a loop-in record in the database.
	UpdateLoopIn(ctx context.Context, loopIn *StaticAddressLoopIn) error

	// GetStaticAddressLoopInSwapsByStates returns all loop-ins with given
	// states.
	GetStaticAddressLoopInSwapsByStates(ctx context.Context,
		states []fsm.StateType) ([]*StaticAddressLoopIn, error)

	// IsStored checks if the loop-in is already stored in the database.
	IsStored(ctx context.Context, swapHash lntypes.Hash) (bool, error)

	// GetLoopInByHash returns the loop-in swap with the given hash.
	GetLoopInByHash(ctx context.Context, swapHash lntypes.Hash) (
		*StaticAddressLoopIn, error)
}

StaticAddressLoopInStore provides access to the static address loop-in DB.

type ValidateLoopInContract

type ValidateLoopInContract func(height int32, htlcExpiry int32) error

ValidateLoopInContract validates the contract parameters against our request.

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL