wtclient

package
v0.6.0 Latest Latest
Warning

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

Go to latest
Published: Feb 22, 2024 License: MIT Imports: 27 Imported by: 0

Documentation

Index

Constants

View Source
const (
	// DefaultReadTimeout specifies the default duration we will wait during
	// a read before breaking out of a blocking read.
	DefaultReadTimeout = 15 * time.Second

	// DefaultWriteTimeout specifies the default duration we will wait during
	// a write before breaking out of a blocking write.
	DefaultWriteTimeout = 15 * time.Second

	// DefaultStatInterval specifies the default interval between logging
	// metrics about the client's operation.
	DefaultStatInterval = time.Minute

	// DefaultForceQuitDelay specifies the default duration after which the
	// client should abandon any pending updates or session negotiations
	// before terminating.
	DefaultForceQuitDelay = 10 * time.Second
)

Variables

View Source
var (
	// ErrClientExiting signals that the watchtower client is shutting down.
	ErrClientExiting = errors.New("watchtower client shutting down")

	// ErrTowerCandidatesExhausted signals that a TowerCandidateIterator has
	// cycled through all available candidates.
	ErrTowerCandidatesExhausted = errors.New("exhausted all tower " +
		"candidates")

	// ErrPermanentTowerFailure signals that the tower has reported that it
	// has permanently failed or the client believes this has happened based
	// on the tower's behavior.
	ErrPermanentTowerFailure = errors.New("permanent tower failure")

	// ErrNegotiatorExiting signals that the SessionNegotiator is shutting
	// down.
	ErrNegotiatorExiting = errors.New("negotiator exiting")

	// ErrNoTowerAddrs signals that the client could not be created because
	// we have no addresses with which we can reach a tower.
	ErrNoTowerAddrs = errors.New("no tower addresses")

	// ErrFailedNegotiation signals that the session negotiator could not
	// acquire a new session as requested.
	ErrFailedNegotiation = errors.New("session negotiation unsuccessful")

	// ErrUnregisteredChannel signals that the client was unable to backup a
	// revoked state because the channel had not been previously registered
	// with the client.
	ErrUnregisteredChannel = errors.New("channel is not registered")
)

Functions

func DisableLog

func DisableLog()

DisableLog disables all library log output. Logging output is disabled by default until UseLogger is called.

func UseLogger

func UseLogger(logger slog.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 AuthDialer

type AuthDialer func(localKey keychain.SingleKeyECDH,
	netAddr *lnwire.NetAddress,
	dialer tor.DialFunc) (wtserver.Peer, error)

AuthDialer connects to a remote node using an authenticated transport, such as brontide. The dialer argument is used to specify a resolver, which allows this method to be used over Tor or clear net connections.

type Client

type Client interface {
	// AddTower adds a new watchtower reachable at the given address and
	// considers it for new sessions. If the watchtower already exists, then
	// any new addresses included will be considered when dialing it for
	// session negotiations and backups.
	AddTower(*lnwire.NetAddress) error

	// RemoveTower removes a watchtower from being considered for future
	// session negotiations and from being used for any subsequent backups
	// until it's added again. If an address is provided, then this call
	// only serves as a way of removing the address from the watchtower
	// instead.
	RemoveTower(*secp256k1.PublicKey, net.Addr) error

	// RegisteredTowers retrieves the list of watchtowers registered with
	// the client.
	RegisteredTowers() ([]*RegisteredTower, error)

	// LookupTower retrieves a registered watchtower through its public key.
	LookupTower(*secp256k1.PublicKey) (*RegisteredTower, error)

	// Stats returns the in-memory statistics of the client since startup.
	Stats() ClientStats

	// Policy returns the active client policy configuration.
	Policy() wtpolicy.Policy

	// RegisterChannel persistently initializes any channel-dependent
	// parameters within the client. This should be called during link
	// startup to ensure that the client is able to support the link during
	// operation.
	RegisterChannel(lnwire.ChannelID) error

	// BackupState initiates a request to back up a particular revoked
	// state. If the method returns nil, the backup is guaranteed to be
	// successful unless the client is force quit, or the justice
	// transaction would create dust outputs when trying to abide by the
	// negotiated policy. If the channel we're trying to back up doesn't
	// have a tweak for the remote party's output, then isTweakless should
	// be true.
	BackupState(*lnwire.ChannelID, *lnwallet.BreachRetribution,
		channeldb.ChannelType) error

	// Start initializes the watchtower client, allowing it process requests
	// to backup revoked channel states.
	Start() error

	// Stop attempts a graceful shutdown of the watchtower client. In doing
	// so, it will attempt to flush the pipeline and deliver any queued
	// states to the tower before exiting.
	Stop() error

	// ForceQuit will forcibly shutdown the watchtower client. Calling this
	// may lead to queued states being dropped.
	ForceQuit()
}

Client is the primary interface used by the daemon to control a client's lifecycle and backup revoked states.

type ClientStats

type ClientStats struct {

	// NumTasksPending is the total number of backups that are pending to
	// be acknowledged by all active and exhausted watchtower sessions.
	NumTasksPending int

	// NumTasksAccepted is the total number of backups made to all active
	// and exhausted watchtower sessions.
	NumTasksAccepted int

	// NumTasksIneligible is the total number of backups that all active and
	// exhausted watchtower sessions have failed to acknowledge.
	NumTasksIneligible int

	// NumSessionsAcquired is the total number of new sessions made to
	// watchtowers.
	NumSessionsAcquired int

	// NumSessionsExhausted is the total number of watchtower sessions that
	// have been exhausted.
	NumSessionsExhausted int
	// contains filtered or unexported fields
}

ClientStats is a collection of in-memory statistics of the actions the client has performed since its creation.

func (*ClientStats) Copy

func (s *ClientStats) Copy() ClientStats

Copy returns a copy of the current stats.

func (*ClientStats) String

func (s *ClientStats) String() string

String returns a human readable summary of the client's metrics.

type Config

type Config struct {
	// Signer provides access to the wallet so that the client can sign
	// justice transactions that spend from a remote party's commitment
	// transaction.
	Signer input.Signer

	// NewAddress generates a new on-chain sweep pkscript.
	NewAddress func() ([]byte, error)

	// SecretKeyRing is used to derive the session keys used to communicate
	// with the tower. The client only stores the KeyLocators internally so
	// that we never store private keys on disk.
	SecretKeyRing ECDHKeyRing

	// Dial connects to an addr using the specified net and returns the
	// connection object.
	Dial tor.DialFunc

	// AuthDialer establishes a brontide connection over an onion or clear
	// network.
	AuthDial AuthDialer

	// DB provides access to the client's stable storage medium.
	DB DB

	// Policy is the session policy the client will propose when creating
	// new sessions with the tower. If the policy differs from any active
	// sessions recorded in the database, those sessions will be ignored and
	// new sessions will be requested immediately.
	Policy wtpolicy.Policy

	// ChainHash identifies the chain that the client is on and for which
	// the tower must be watching to monitor for breaches.
	ChainHash chainhash.Hash

	// ChainParams stores the parameters of the chain that the client is
	// on.
	ChainParams *chaincfg.Params

	// ForceQuitDelay is the duration after attempting to shutdown that the
	// client will automatically abort any pending backups if an unclean
	// shutdown is detected. If the value is less than or equal to zero, a
	// call to Stop may block indefinitely. The client can always be
	// ForceQuit externally irrespective of the chosen parameter.
	ForceQuitDelay time.Duration

	// ReadTimeout is the duration we will wait during a read before
	// breaking out of a blocking read. If the value is less than or equal
	// to zero, the default will be used instead.
	ReadTimeout time.Duration

	// WriteTimeout is the duration we will wait during a write before
	// breaking out of a blocking write. If the value is less than or equal
	// to zero, the default will be used instead.
	WriteTimeout time.Duration

	// MinBackoff defines the initial backoff applied to connections with
	// watchtowers. Subsequent backoff durations will grow exponentially up
	// until MaxBackoff.
	MinBackoff time.Duration

	// MaxBackoff defines the maximum backoff applied to connections with
	// watchtowers. If the exponential backoff produces a timeout greater
	// than this value, the backoff will be clamped to MaxBackoff.
	MaxBackoff time.Duration
}

Config provides the TowerClient with access to the resources it requires to perform its duty. All nillable fields must be non-nil for the tower to be initialized properly.

type DB

type DB interface {
	// CreateTower initialize an address record used to communicate with a
	// watchtower. Each Tower is assigned a unique ID, that is used to
	// amortize storage costs of the public key when used by multiple
	// sessions. If the tower already exists, the address is appended to the
	// list of all addresses used to that tower previously and its
	// corresponding sessions are marked as active.
	CreateTower(*lnwire.NetAddress) (*wtdb.Tower, error)

	// RemoveTower modifies a tower's record within the database. If an
	// address is provided, then _only_ the address record should be removed
	// from the tower's persisted state. Otherwise, we'll attempt to mark
	// the tower as inactive by marking all of its sessions inactive. If any
	// of its sessions has unacked updates, then ErrTowerUnackedUpdates is
	// returned. If the tower doesn't have any sessions at all, it'll be
	// completely removed from the database.
	//
	// NOTE: An error is not returned if the tower doesn't exist.
	RemoveTower(*secp256k1.PublicKey, net.Addr) error

	// LoadTower retrieves a tower by its public key.
	LoadTower(*secp256k1.PublicKey) (*wtdb.Tower, error)

	// LoadTowerByID retrieves a tower by its tower ID.
	LoadTowerByID(wtdb.TowerID) (*wtdb.Tower, error)

	// ListTowers retrieves the list of towers available within the
	// database.
	ListTowers() ([]*wtdb.Tower, error)

	// NextSessionKeyIndex reserves a new session key derivation index for a
	// particular tower id and blob type. The index is reserved for that
	// (tower, blob type) pair until CreateClientSession is invoked for that
	// tower and index, at which point a new index for that tower can be
	// reserved. Multiple calls to this method before CreateClientSession is
	// invoked should return the same index.
	NextSessionKeyIndex(wtdb.TowerID, blob.Type) (uint32, error)

	// CreateClientSession saves a newly negotiated client session to the
	// client's database. This enables the session to be used across
	// restarts.
	CreateClientSession(*wtdb.ClientSession) error

	// ListClientSessions returns all sessions that have not yet been
	// exhausted. This is used on startup to find any sessions which may
	// still be able to accept state updates. An optional tower ID can be
	// used to filter out any client sessions in the response that do not
	// correspond to this tower.
	ListClientSessions(*wtdb.TowerID) (map[wtdb.SessionID]*wtdb.ClientSession, error)

	// FetchChanSummaries loads a mapping from all registered channels to
	// their channel summaries.
	FetchChanSummaries() (wtdb.ChannelSummaries, error)

	// RegisterChannel registers a channel for use within the client
	// database. For now, all that is stored in the channel summary is the
	// sweep pkscript that we'd like any tower sweeps to pay into. In the
	// future, this will be extended to contain more info to allow the
	// client efficiently request historical states to be backed up under
	// the client's active policy.
	RegisterChannel(lnwire.ChannelID, []byte) error

	// MarkBackupIneligible records that the state identified by the
	// (channel id, commit height) tuple was ineligible for being backed up
	// under the current policy. This state can be retried later under a
	// different policy.
	MarkBackupIneligible(chanID lnwire.ChannelID, commitHeight uint64) error

	// CommitUpdate writes the next state update for a particular
	// session, so that we can be sure to resend it after a restart if it
	// hasn't been ACK'd by the tower. The sequence number of the update
	// should be exactly one greater than the existing entry, and less that
	// or equal to the session's MaxUpdates.
	CommitUpdate(id *wtdb.SessionID,
		update *wtdb.CommittedUpdate) (uint16, error)

	// AckUpdate records an acknowledgment from the watchtower that the
	// update identified by seqNum was received and saved. The returned
	// lastApplied will be recorded.
	AckUpdate(id *wtdb.SessionID, seqNum, lastApplied uint16) error
}

DB abstracts the required database operations required by the watchtower client.

type ECDHKeyRing added in v0.3.0

type ECDHKeyRing interface {
	keychain.ECDHRing

	// DeriveKey attempts to derive an arbitrary key specified by the
	// passed KeyLocator. This may be used in several recovery scenarios,
	// or when manually rotating something like our current default node
	// key.
	DeriveKey(keyLoc keychain.KeyLocator) (keychain.KeyDescriptor, error)
}

ECDHKeyRing abstracts the ability to derive shared ECDH keys given a description of the derivation path of a private key.

type NegotiatorConfig

type NegotiatorConfig struct {
	// DB provides access to a persistent storage medium used by the tower
	// to properly allocate session ephemeral keys and record successfully
	// negotiated sessions.
	DB DB

	// SecretKeyRing allows the client to derive new session private keys
	// when attempting to negotiate session with a tower.
	SecretKeyRing ECDHKeyRing

	// Candidates is an abstract set of tower candidates that the negotiator
	// will traverse serially when attempting to negotiate a new session.
	Candidates TowerCandidateIterator

	// Policy defines the session policy that will be proposed to towers
	// when attempting to negotiate a new session. This policy will be used
	// across all negotiation proposals for the lifetime of the negotiator.
	Policy wtpolicy.Policy

	// Dial initiates an outbound brontide connection to the given address
	// using a specified private key. The peer is returned in the event of a
	// successful connection.
	Dial func(keychain.SingleKeyECDH, *lnwire.NetAddress) (wtserver.Peer,
		error)

	// SendMessage writes a wtwire message to remote peer.
	SendMessage func(wtserver.Peer, wtwire.Message) error

	// ReadMessage reads a message from a remote peer and returns the
	// decoded wtwire message.
	ReadMessage func(wtserver.Peer) (wtwire.Message, error)

	// ChainHash the genesis hash identifying the chain for any negotiated
	// sessions. Any state updates sent to that session should also
	// originate from this chain.
	ChainHash chainhash.Hash

	// MinBackoff defines the initial backoff applied by the session
	// negotiator after all tower candidates have been exhausted and
	// reattempting negotiation with the same set of candidates. Subsequent
	// backoff durations will grow exponentially.
	MinBackoff time.Duration

	// MaxBackoff defines the maximum backoff applied by the session
	// negotiator after all tower candidates have been exhausted and
	// reattempting negotiation with the same set of candidates. If the
	// exponential backoff produces a timeout greater than this value, the
	// backoff duration will be clamped to MaxBackoff.
	MaxBackoff time.Duration

	// Log specifies the desired log output, which should be prefixed by the
	// client type, e.g. anchor or legacy.
	Log slog.Logger
}

NegotiatorConfig provides access to the resources required by a SessionNegotiator to faithfully carry out its duties. All nil-able field must be initialized.

type RegisteredTower

type RegisteredTower struct {
	*wtdb.Tower

	// Sessions is the set of sessions corresponding to the watchtower.
	Sessions map[wtdb.SessionID]*wtdb.ClientSession

	// ActiveSessionCandidate determines whether the watchtower is currently
	// being considered for new sessions.
	ActiveSessionCandidate bool
}

RegisteredTower encompasses information about a registered watchtower with the client.

type SessionNegotiator

type SessionNegotiator interface {
	// RequestSession signals to the session negotiator that the client
	// needs another session. Once the session is negotiated, it should be
	// returned via NewSessions.
	RequestSession()

	// NewSessions is a read-only channel where newly negotiated sessions
	// will be delivered.
	NewSessions() <-chan *wtdb.ClientSession

	// Start safely initializes the session negotiator.
	Start() error

	// Stop safely shuts down the session negotiator.
	Stop() error
}

SessionNegotiator is an interface for asynchronously requesting new sessions.

type TowerCandidateIterator

type TowerCandidateIterator interface {
	// AddCandidate adds a new candidate tower to the iterator. If the
	// candidate already exists, then any new addresses are added to it.
	AddCandidate(*wtdb.Tower)

	// RemoveCandidate removes an existing candidate tower from the
	// iterator. An optional address can be provided to indicate a stale
	// tower address to remove it. If it isn't provided, then the tower is
	// completely removed from the iterator.
	RemoveCandidate(wtdb.TowerID, net.Addr) error

	// IsActive determines whether a given tower is exists within the
	// iterator.
	IsActive(wtdb.TowerID) bool

	// Reset clears any internal iterator state, making previously taken
	// candidates available as long as they remain in the set.
	Reset() error

	// Next returns the next candidate tower. The iterator is not required
	// to return results in any particular order.  If no more candidates are
	// available, ErrTowerCandidatesExhausted is returned.
	Next() (*wtdb.Tower, error)
}

TowerCandidateIterator provides an abstraction for iterating through possible watchtower addresses when attempting to create a new session.

type TowerClient

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

TowerClient is a concrete implementation of the Client interface, offering a non-blocking, reliable subsystem for backing up revoked states to a specified private tower.

func New

func New(config *Config) (*TowerClient, error)

New initializes a new TowerClient from the provide Config. An error is returned if the client could not initialized.

func (*TowerClient) AddTower

func (c *TowerClient) AddTower(addr *lnwire.NetAddress) error

AddTower adds a new watchtower reachable at the given address and considers it for new sessions. If the watchtower already exists, then any new addresses included will be considered when dialing it for session negotiations and backups.

func (*TowerClient) BackupState

func (c *TowerClient) BackupState(chanID *lnwire.ChannelID,
	breachInfo *lnwallet.BreachRetribution,
	chanType channeldb.ChannelType) error

BackupState initiates a request to back up a particular revoked state. If the method returns nil, the backup is guaranteed to be successful unless the:

  • client is force quit,
  • justice transaction would create dust outputs when trying to abide by the negotiated policy, or
  • breached outputs contain too little value to sweep at the target sweep fee rate.

func (*TowerClient) ForceQuit

func (c *TowerClient) ForceQuit()

ForceQuit idempotently initiates an unclean shutdown of the watchtower client. This should only be executed if Stop is unable to exit cleanly.

func (*TowerClient) LookupTower

func (c *TowerClient) LookupTower(pubKey *secp256k1.PublicKey) (*RegisteredTower, error)

LookupTower retrieves a registered watchtower through its public key.

func (*TowerClient) Policy

func (c *TowerClient) Policy() wtpolicy.Policy

Policy returns the active client policy configuration.

func (*TowerClient) RegisterChannel

func (c *TowerClient) RegisterChannel(chanID lnwire.ChannelID) error

RegisterChannel persistently initializes any channel-dependent parameters within the client. This should be called during link startup to ensure that the client is able to support the link during operation.

func (*TowerClient) RegisteredTowers

func (c *TowerClient) RegisteredTowers() ([]*RegisteredTower, error)

RegisteredTowers retrieves the list of watchtowers registered with the client.

func (*TowerClient) RemoveTower

func (c *TowerClient) RemoveTower(pubKey *secp256k1.PublicKey, addr net.Addr) error

RemoveTower removes a watchtower from being considered for future session negotiations and from being used for any subsequent backups until it's added again. If an address is provided, then this call only serves as a way of removing the address from the watchtower instead.

func (*TowerClient) Start

func (c *TowerClient) Start() error

Start initializes the watchtower client by loading or negotiating an active session and then begins processing backup tasks from the request pipeline.

func (*TowerClient) Stats

func (c *TowerClient) Stats() ClientStats

Stats returns the in-memory statistics of the client since startup.

func (*TowerClient) Stop

func (c *TowerClient) Stop() error

Stop idempotently initiates a graceful shutdown of the watchtower client.

Jump to

Keyboard shortcuts

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