chainntnfs

package
v0.18.4-beta.rc1 Latest Latest
Warning

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

Go to latest
Published: Nov 21, 2024 License: MIT Imports: 18 Imported by: 311

README

chainntnfs

Build Status MIT licensed GoDoc

The chainntnfs package implements a set of interfaces which allow callers to receive notifications in response to specific on-chain events. The set of notifications available include:

  • Notifications for each new block connected to the current best chain.
  • Notifications once a txid has reached a specified number of confirmations.
  • Notifications once a target outpoint (txid:index) has been spent.

These notifications are used within lnd in order to properly handle the workflows for: channel funding, cooperative channel closures, forced channel closures, channel contract breaches, sweeping time-locked outputs, and finally pruning the channel graph.

This package is intentionally general enough to be applicable outside the specific use cases within lnd outlined above. The current sole concrete implementation of the ChainNotifier interface depends on btcd.

Installation and Updating

$  go get -u github.com/lightningnetwork/lnd/chainntnfs

Documentation

Index

Constants

View Source
const (
	// ReorgSafetyLimit is the chain depth beyond which it is assumed a
	// block will not be reorganized out of the chain. This is used to
	// determine when to prune old confirmation requests so that reorgs are
	// handled correctly. The average number of blocks in a day is a
	// reasonable value to use.
	ReorgSafetyLimit = 144

	// MaxNumConfs is the maximum number of confirmations that can be
	// requested on a transaction.
	MaxNumConfs = ReorgSafetyLimit
)

Variables

View Source
var (
	// ErrCorruptedHeightHintCache indicates that the on-disk representation
	// has altered since the height hint cache instance was initialized.
	ErrCorruptedHeightHintCache = errors.New("height hint cache has been " +
		"corrupted")

	// ErrSpendHintNotFound is an error returned when a spend hint for an
	// outpoint was not found.
	ErrSpendHintNotFound = errors.New("spend hint not found")

	// ErrConfirmHintNotFound is an error returned when a confirm hint for a
	// transaction was not found.
	ErrConfirmHintNotFound = errors.New("confirm hint not found")
)
View Source
var (
	// ZeroHash is the value that should be used as the txid when
	// registering for the confirmation of a script on-chain. This allows
	// the notifier to match _and_ dispatch upon the inclusion of the script
	// on-chain, rather than the txid.
	ZeroHash chainhash.Hash

	// ZeroOutPoint is the value that should be used as the outpoint when
	// registering for the spend of a script on-chain. This allows the
	// notifier to match _and_ dispatch upon detecting the spend of the
	// script on-chain, rather than the outpoint.
	ZeroOutPoint wire.OutPoint

	// ZeroTaprootPkScript is the parsed txscript.PkScript of an empty
	// Taproot SegWit v1 key being pushed to the stack. This allows the
	// notifier to match _and_ dispatch upon detecting the spend of the
	// outpoint on-chain, rather than the pkScript (which cannot be derived
	// from the witness alone in the SegWit v1 case).
	ZeroTaprootPkScript, _ = txscript.ParsePkScript(zeroV1KeyPush[:])
)
View Source
var (
	// ErrTxNotifierExiting is an error returned when attempting to interact
	// with the TxNotifier but it been shut down.
	ErrTxNotifierExiting = errors.New("TxNotifier is exiting")

	// ErrNoScript is an error returned when a confirmation/spend
	// registration is attempted without providing an accompanying output
	// script.
	ErrNoScript = errors.New("an output script must be provided")

	// ErrNoHeightHint is an error returned when a confirmation/spend
	// registration is attempted without providing an accompanying height
	// hint.
	ErrNoHeightHint = errors.New("a height hint greater than 0 must be " +
		"provided")

	// ErrNumConfsOutOfRange is an error returned when a confirmation/spend
	// registration is attempted and the number of confirmations provided is
	// out of range.
	ErrNumConfsOutOfRange = fmt.Errorf("number of confirmations must be "+
		"between %d and %d", 1, MaxNumConfs)

	// ErrEmptyWitnessStack is returned when a spending transaction has an
	// empty witness stack. More details in,
	// - https://github.com/bitcoin/bitcoin/issues/28730
	ErrEmptyWitnessStack = errors.New("witness stack is empty")
)
View Source
var (
	// ErrChainNotifierShuttingDown is used when we are trying to
	// measure a spend notification when notifier is already stopped.
	ErrChainNotifierShuttingDown = errors.New("chain notifier shutting down")
)

Log is a logger that is initialized with no output filters. This means the package will not perform any logging by default until the caller requests it.

Functions

func ConfDetailsFromTxIndex

func ConfDetailsFromTxIndex(chainConn TxIndexConn, r ConfRequest,
	txNotFoundErr string) (*TxConfirmation, TxConfStatus, error)

ConfDetailsFromTxIndex looks up whether a transaction is already included in a block in the active chain by using the backend node's transaction index. If the transaction is found its TxConfStatus is returned. If it was found in the mempool this will be TxFoundMempool, if it is found in a block this will be TxFoundIndex. Otherwise TxNotFoundIndex is returned. If the tx is found in a block its confirmation details are also returned.

func DisableLog

func DisableLog()

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

func GetCommonBlockAncestorHeight

func GetCommonBlockAncestorHeight(chainConn ChainConn, reorgHash,
	chainHash chainhash.Hash) (int32, error)

GetCommonBlockAncestorHeight takes in: (1) the hash of a block that has been reorged out of the main chain (2) the hash of the block of the same height from the main chain It returns the height of the nearest common ancestor between the two hashes, or an error

func HandleMissedBlocks

func HandleMissedBlocks(chainConn ChainConn, txNotifier *TxNotifier,
	currBestBlock BlockEpoch, newHeight int32,
	backendStoresReorgs bool) (BlockEpoch, []BlockEpoch, error)

HandleMissedBlocks is called when the chain backend for a notifier misses a series of blocks, handling a reorg if necessary. Its backendStoresReorgs parameter tells it whether or not the notifier's chainConn stores information about blocks that have been reorged out of the chain, which allows HandleMissedBlocks to check whether the notifier's best block has been reorged out, and rewind the chain accordingly. It returns the best block for the notifier and a slice of the missed blocks. The new best block needs to be returned in case a chain rewind occurs and partially completes before erroring. In the case where there is no rewind, the notifier's current best block is returned.

func RegisterNotifier

func RegisterNotifier(driver *NotifierDriver) error

RegisterNotifier registers a NotifierDriver which is capable of driving a concrete ChainNotifier interface. In the case that this driver has already been registered, an error is returned.

NOTE: This function is safe for concurrent access.

func SupportedNotifiers

func SupportedNotifiers() []string

SupportedNotifiers returns a slice of strings that represent the database drivers that have been registered and are therefore supported.

NOTE: This function is safe for concurrent access.

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 BestBlockTracker

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

BestBlockTracker is a tiny subsystem that tracks the blockchain tip and saves the most recent tip information in memory for querying. It is a valid implementation of BestBlockView and additionally includes methods for starting and stopping the system.

func NewBestBlockTracker

func NewBestBlockTracker(chainNotifier ChainNotifier) *BestBlockTracker

NewBestBlockTracker creates a new BestBlockTracker that isn't running yet. It will not provide up to date information unless it has been started. The ChainNotifier parameter must also be started prior to starting the BestBlockTracker.

func (*BestBlockTracker) BestBlockHeader

func (t *BestBlockTracker) BestBlockHeader() (*wire.BlockHeader, error)

BestBlockHeader gets the most recent block header known to the BestBlockTracker.

func (*BestBlockTracker) BestHeight

func (t *BestBlockTracker) BestHeight() (uint32, error)

BestHeight gets the most recent block height known to the BestBlockTracker.

func (*BestBlockTracker) Start

func (t *BestBlockTracker) Start() error

Start starts the BestBlockTracker. It is an error to start it if it is already started.

func (*BestBlockTracker) Stop

func (t *BestBlockTracker) Stop() error

Stop stops the BestBlockTracker. It is an error to stop it if it has not been started or if it has already been stopped.

type BestBlockView

type BestBlockView interface {
	// BestHeight gets the most recent block height known to the view.
	BestHeight() (uint32, error)

	// BestBlockHeader gets the most recent block header known to the view.
	BestBlockHeader() (*wire.BlockHeader, error)
}

BestBlockView is an interface that allows the querying of the most up-to-date blockchain state with low overhead. Valid implementations of this interface must track the latest chain state.

type BlockEpoch

type BlockEpoch struct {
	// Hash is the block hash of the latest block to be added to the tip of
	// the main chain.
	Hash *chainhash.Hash

	// Height is the height of the latest block to be added to the tip of
	// the main chain.
	Height int32

	// BlockHeader is the block header of this new height.
	BlockHeader *wire.BlockHeader
}

BlockEpoch represents metadata concerning each new block connected to the main chain.

func GetClientMissedBlocks

func GetClientMissedBlocks(chainConn ChainConn, clientBestBlock *BlockEpoch,
	notifierBestHeight int32, backendStoresReorgs bool) ([]BlockEpoch, error)

GetClientMissedBlocks uses a client's best block to determine what blocks it missed being notified about, and returns them in a slice. Its backendStoresReorgs parameter tells it whether or not the notifier's chainConn stores information about blocks that have been reorged out of the chain, which allows GetClientMissedBlocks to find out whether the client's best block has been reorged out of the chain, rewind to the common ancestor and return blocks starting right after the common ancestor.

func RewindChain

func RewindChain(chainConn ChainConn, txNotifier *TxNotifier,
	currBestBlock BlockEpoch, targetHeight int32) (BlockEpoch, error)

RewindChain handles internal state updates for the notifier's TxNotifier. It has no effect if given a height greater than or equal to our current best known height. It returns the new best block for the notifier.

type BlockEpochEvent

type BlockEpochEvent struct {
	// Epochs is a receive only channel that will be sent upon each time a
	// new block is connected to the end of the main chain.
	//
	// NOTE: This channel must be buffered.
	Epochs <-chan *BlockEpoch

	// Cancel is a closure that should be executed by the caller in the case
	// that they wish to abandon their registered block epochs notification.
	Cancel func()
}

BlockEpochEvent encapsulates an on-going stream of block epoch notifications. Its only field 'Epochs' will be sent upon for each new block connected to the main-chain.

NOTE: If the caller wishes to cancel their registered block epoch notification, the Cancel closure MUST be called.

type ChainConn

type ChainConn interface {
	// GetBlockHeader returns the block header for a hash.
	GetBlockHeader(blockHash *chainhash.Hash) (*wire.BlockHeader, error)

	// GetBlockHeaderVerbose returns the verbose block header for a hash.
	GetBlockHeaderVerbose(blockHash *chainhash.Hash) (
		*btcjson.GetBlockHeaderVerboseResult, error)

	// GetBlockHash returns the hash from a block height.
	GetBlockHash(blockHeight int64) (*chainhash.Hash, error)
}

ChainConn enables notifiers to pass in their chain backend to interface functions that require it.

type ChainNotifier

type ChainNotifier interface {
	// RegisterConfirmationsNtfn registers an intent to be notified once
	// txid reaches numConfs confirmations. We also pass in the pkScript as
	// the default light client instead needs to match on scripts created in
	// the block. If a nil txid is passed in, then not only should we match
	// on the script, but we should also dispatch once the transaction
	// containing the script reaches numConfs confirmations. This can be
	// useful in instances where we only know the script in advance, but not
	// the transaction containing it.
	//
	// The returned ConfirmationEvent should properly notify the client once
	// the specified number of confirmations has been reached for the txid,
	// as well as if the original tx gets re-org'd out of the mainchain. The
	// heightHint parameter is provided as a convenience to light clients.
	// It heightHint denotes the earliest height in the blockchain in which
	// the target txid _could_ have been included in the chain. This can be
	// used to bound the search space when checking to see if a notification
	// can immediately be dispatched due to historical data.
	//
	// NOTE: Dispatching notifications to multiple clients subscribed to
	// the same (txid, numConfs) tuple MUST be supported.
	RegisterConfirmationsNtfn(txid *chainhash.Hash, pkScript []byte,
		numConfs, heightHint uint32,
		opts ...NotifierOption) (*ConfirmationEvent, error)

	// RegisterSpendNtfn registers an intent to be notified once the target
	// outpoint is successfully spent within a transaction. The script that
	// the outpoint creates must also be specified. This allows this
	// interface to be implemented by BIP 158-like filtering. If a nil
	// outpoint is passed in, then not only should we match on the script,
	// but we should also dispatch once a transaction spends the output
	// containing said script. This can be useful in instances where we only
	// know the script in advance, but not the outpoint itself.
	//
	// The returned SpendEvent will receive a send on the 'Spend'
	// transaction once a transaction spending the input is detected on the
	// blockchain. The heightHint parameter is provided as a convenience to
	// light clients. It denotes the earliest height in the blockchain in
	// which the target output could have been spent.
	//
	// NOTE: The notification should only be triggered when the spending
	// transaction receives a single confirmation.
	//
	// NOTE: Dispatching notifications to multiple clients subscribed to a
	// spend of the same outpoint MUST be supported.
	RegisterSpendNtfn(outpoint *wire.OutPoint, pkScript []byte,
		heightHint uint32) (*SpendEvent, error)

	// RegisterBlockEpochNtfn registers an intent to be notified of each
	// new block connected to the tip of the main chain. The returned
	// BlockEpochEvent struct contains a channel which will be sent upon
	// for each new block discovered.
	//
	// Clients have the option of passing in their best known block.
	// If they specify a block, the ChainNotifier checks whether the client
	// is behind on blocks. If they are, the ChainNotifier sends a backlog
	// of block notifications for the missed blocks. If they do not provide
	// one, then a notification will be dispatched immediately for the
	// current tip of the chain upon a successful registration.
	RegisterBlockEpochNtfn(*BlockEpoch) (*BlockEpochEvent, error)

	// Start the ChainNotifier. Once started, the implementation should be
	// ready, and able to receive notification registrations from clients.
	Start() error

	// Started returns true if this instance has been started, and false otherwise.
	Started() bool

	// Stops the concrete ChainNotifier. Once stopped, the ChainNotifier
	// should disallow any future requests from potential clients.
	// Additionally, all pending client notifications will be canceled
	// by closing the related channels on the *Event's.
	Stop() error
}

ChainNotifier represents a trusted source to receive notifications concerning targeted events on the Bitcoin blockchain. The interface specification is intentionally general in order to support a wide array of chain notification implementations such as: btcd's websockets notifications, Bitcoin Core's ZeroMQ notifications, various Bitcoin API services, Electrum servers, etc.

Concrete implementations of ChainNotifier should be able to support multiple concurrent client requests, as well as multiple concurrent notification events.

type ConfNtfn

type ConfNtfn struct {
	// ConfID uniquely identifies the confirmation notification request for
	// the specified transaction/output script.
	ConfID uint64

	// ConfRequest represents either the txid or script we should detect
	// inclusion of within the chain.
	ConfRequest

	// NumConfirmations is the number of confirmations after which the
	// notification is to be sent.
	NumConfirmations uint32

	// Event contains references to the channels that the notifications are to
	// be sent over.
	Event *ConfirmationEvent

	// HeightHint is the minimum height in the chain that we expect to find
	// this txid.
	HeightHint uint32
	// contains filtered or unexported fields
}

ConfNtfn represents a notifier client's request to receive a notification once the target transaction/output script gets sufficient confirmations. The client is asynchronously notified via the ConfirmationEvent channels.

type ConfRegistration

type ConfRegistration struct {
	// Event contains references to the channels that the notifications are
	// to be sent over.
	Event *ConfirmationEvent

	// HistoricalDispatch, if non-nil, signals to the client who registered
	// the notification that they are responsible for attempting to manually
	// rescan blocks for the txid/output script between the start and end
	// heights.
	HistoricalDispatch *HistoricalConfDispatch

	// Height is the height of the TxNotifier at the time the confirmation
	// notification was registered. This can be used so that backends can
	// request to be notified of confirmations from this point forwards.
	Height uint32
}

ConfRegistration encompasses all of the information required for callers to retrieve details about a confirmation event.

type ConfRequest

type ConfRequest struct {
	// TxID is the hash of the transaction for which confirmation
	// notifications are requested. If set to a zero hash, then a
	// confirmation notification will be dispatched upon inclusion of the
	// _script_, rather than the txid.
	TxID chainhash.Hash

	// PkScript is the public key script of an outpoint created in this
	// transaction.
	PkScript txscript.PkScript
}

ConfRequest encapsulates a request for a confirmation notification of either a txid or output script.

func NewConfRequest

func NewConfRequest(txid *chainhash.Hash, pkScript []byte) (ConfRequest, error)

NewConfRequest creates a request for a confirmation notification of either a txid or output script. A nil txid or an allocated ZeroHash can be used to dispatch the confirmation notification on the script.

func (ConfRequest) MatchesTx

func (r ConfRequest) MatchesTx(tx *wire.MsgTx) bool

MatchesTx determines whether the given transaction satisfies the confirmation request. If the confirmation request is for a script, then we'll check all of the outputs of the transaction to determine if it matches. Otherwise, we'll match on the txid.

func (ConfRequest) String

func (r ConfRequest) String() string

String returns the string representation of the ConfRequest.

type ConfirmHintCache

type ConfirmHintCache interface {
	// CommitConfirmHint commits a confirm hint for the transactions to the
	// cache.
	CommitConfirmHint(height uint32, confRequests ...ConfRequest) error

	// QueryConfirmHint returns the latest confirm hint for a transaction
	// hash. ErrConfirmHintNotFound is returned if a confirm hint does not
	// exist within the cache for the transaction hash.
	QueryConfirmHint(confRequest ConfRequest) (uint32, error)

	// PurgeConfirmHint removes the confirm hint for the transactions from
	// the cache.
	PurgeConfirmHint(confRequests ...ConfRequest) error
}

ConfirmHintCache is an interface whose duty is to cache confirm hints for transactions. A confirm hint is defined as the earliest height in the chain at which a transaction could have been included in a block.

type ConfirmationEvent

type ConfirmationEvent struct {
	// Confirmed is a channel that will be sent upon once the transaction
	// has been fully confirmed. The struct sent will contain all the
	// details of the channel's confirmation.
	//
	// NOTE: This channel must be buffered.
	Confirmed chan *TxConfirmation

	// Updates is a channel that will sent upon, at every incremental
	// confirmation, how many confirmations are left to declare the
	// transaction as fully confirmed.
	//
	// NOTE: This channel must be buffered with the number of required
	// confirmations.
	Updates chan uint32

	// NegativeConf is a channel that will be sent upon if the transaction
	// confirms, but is later reorged out of the chain. The integer sent
	// through the channel represents the reorg depth.
	//
	// NOTE: This channel must be buffered.
	NegativeConf chan int32

	// Done is a channel that gets sent upon once the confirmation request
	// is no longer under the risk of being reorged out of the chain.
	//
	// NOTE: This channel must be buffered.
	Done chan struct{}

	// Cancel is a closure that should be executed by the caller in the case
	// that they wish to prematurely abandon their registered confirmation
	// notification.
	Cancel func()
}

ConfirmationEvent encapsulates a confirmation notification. With this struct, callers can be notified of: the instance the target txid reaches the targeted number of confirmations, how many confirmations are left for the target txid to be fully confirmed at every new block height, and also in the event that the original txid becomes disconnected from the blockchain as a result of a re-org.

Once the txid reaches the specified number of confirmations, the 'Confirmed' channel will be sent upon fulfilling the notification.

If the event that the original transaction becomes re-org'd out of the main chain, the 'NegativeConf' will be sent upon with a value representing the depth of the re-org.

NOTE: If the caller wishes to cancel their registered spend notification, the Cancel closure MUST be called.

func NewConfirmationEvent

func NewConfirmationEvent(numConfs uint32, cancel func()) *ConfirmationEvent

NewConfirmationEvent constructs a new ConfirmationEvent with newly opened channels.

type HistoricalConfDispatch

type HistoricalConfDispatch struct {
	// ConfRequest represents either the txid or script we should detect
	// inclusion of within the chain.
	ConfRequest

	// StartHeight specifies the block height at which to begin the
	// historical rescan.
	StartHeight uint32

	// EndHeight specifies the last block height (inclusive) that the
	// historical scan should consider.
	EndHeight uint32
}

HistoricalConfDispatch parametrizes a manual rescan for a particular transaction/output script. The parameters include the start and end block heights specifying the range of blocks to scan.

type HistoricalSpendDispatch

type HistoricalSpendDispatch struct {
	// SpendRequest represents either the outpoint or script we should
	// detect the spend of.
	SpendRequest

	// StartHeight specified the block height at which to begin the
	// historical rescan.
	StartHeight uint32

	// EndHeight specifies the last block height (inclusive) that the
	// historical rescan should consider.
	EndHeight uint32
}

HistoricalSpendDispatch parametrizes a manual rescan to determine the spending details (if any) of an outpoint/output script. The parameters include the start and end block heights specifying the range of blocks to scan.

type MempoolNotifier

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

MempoolNotifier defines an internal mempool notifier that's used to notify the spending of given inputs. This is mounted to either `BitcoindNotifier` or `BtcdNotifier` depending on the chain backend.

func NewMempoolNotifier

func NewMempoolNotifier() *MempoolNotifier

NewMempoolNotifier takes a chain connection and returns a new mempool notifier.

func (*MempoolNotifier) ProcessRelevantSpendTx

func (m *MempoolNotifier) ProcessRelevantSpendTx(tx *btcutil.Tx) error

ProcessRelevantSpendTx takes a transaction and checks whether it spends any of the subscribed inputs. If so, spend notifications are sent to the relevant subscribers.

func (*MempoolNotifier) SubscribeInput

func (m *MempoolNotifier) SubscribeInput(
	outpoint wire.OutPoint) *MempoolSpendEvent

SubscribeInput takes an outpoint of the input and returns a channel that the subscriber can listen to for the spending event.

func (*MempoolNotifier) TearDown

func (m *MempoolNotifier) TearDown()

TearDown stops the notifier and cleans up resources.

func (*MempoolNotifier) UnsubscribeEvent

func (m *MempoolNotifier) UnsubscribeEvent(sub *MempoolSpendEvent)

UnsubscribeEvent removes a given subscriber for the given MempoolSpendEvent.

func (*MempoolNotifier) UnsubscribeInput

func (m *MempoolNotifier) UnsubscribeInput(outpoint wire.OutPoint)

UnsubscribeInput removes all the subscriptions for the given outpoint.

func (*MempoolNotifier) UnsubsribeConfirmedSpentTx

func (m *MempoolNotifier) UnsubsribeConfirmedSpentTx(tx *btcutil.Tx)

UnsubsribeConfirmedSpentTx takes a transaction and removes the subscriptions identified using its inputs.

type MempoolSpendEvent

type MempoolSpendEvent struct {
	// Spend is a receive only channel which will be sent upon once the
	// target outpoint has been spent.
	//
	// NOTE: This channel must be buffered.
	Spend <-chan *SpendDetail
	// contains filtered or unexported fields
}

MempoolSpendEvent is returned to the subscriber to watch for the spending event for the requested input.

type MempoolWatcher

type MempoolWatcher interface {
	// SubscribeMempoolSpent allows the caller to register a subscription
	// to watch for a spend of an outpoint in the mempool.The event will be
	// dispatched once the outpoint is spent in the mempool.
	SubscribeMempoolSpent(op wire.OutPoint) (*MempoolSpendEvent, error)

	// CancelMempoolSpendEvent allows the caller to cancel a subscription to
	// watch for a spend of an outpoint in the mempool.
	CancelMempoolSpendEvent(sub *MempoolSpendEvent)

	// LookupInputMempoolSpend looks up the mempool to find a spending tx
	// which spends the given outpoint. A fn.None is returned if it's not
	// found.
	LookupInputMempoolSpend(op wire.OutPoint) fn.Option[wire.MsgTx]
}

MempoolWatcher defines an interface that allows the caller to query information in the mempool.

type MockChainNotifier

type MockChainNotifier struct {
	mock.Mock
}

MockNotifier is a mock implementation of the ChainNotifier interface.

func (*MockChainNotifier) RegisterBlockEpochNtfn

func (m *MockChainNotifier) RegisterBlockEpochNtfn(epoch *BlockEpoch) (
	*BlockEpochEvent, error)

RegisterBlockEpochNtfn registers an intent to be notified of each new block connected to the tip of the main chain.

func (*MockChainNotifier) RegisterConfirmationsNtfn

func (m *MockChainNotifier) RegisterConfirmationsNtfn(txid *chainhash.Hash,
	pkScript []byte, numConfs, heightHint uint32,
	opts ...NotifierOption) (*ConfirmationEvent, error)

RegisterConfirmationsNtfn registers an intent to be notified once txid reaches numConfs confirmations.

func (*MockChainNotifier) RegisterSpendNtfn

func (m *MockChainNotifier) RegisterSpendNtfn(outpoint *wire.OutPoint,
	pkScript []byte, heightHint uint32) (*SpendEvent, error)

RegisterSpendNtfn registers an intent to be notified once the target outpoint is successfully spent within a transaction.

func (*MockChainNotifier) Start

func (m *MockChainNotifier) Start() error

Start the ChainNotifier. Once started, the implementation should be ready, and able to receive notification registrations from clients.

func (*MockChainNotifier) Started

func (m *MockChainNotifier) Started() bool

Started returns true if this instance has been started, and false otherwise.

func (*MockChainNotifier) Stop

func (m *MockChainNotifier) Stop() error

Stops the concrete ChainNotifier.

type MockMempoolWatcher

type MockMempoolWatcher struct {
	mock.Mock
}

MockMempoolWatcher is a mock implementation of the MempoolWatcher interface. This is used by other subsystems to mock the behavior of the mempool watcher.

func NewMockMempoolWatcher

func NewMockMempoolWatcher() *MockMempoolWatcher

NewMockMempoolWatcher returns a new instance of a mock mempool watcher.

func (*MockMempoolWatcher) CancelMempoolSpendEvent

func (m *MockMempoolWatcher) CancelMempoolSpendEvent(
	sub *MempoolSpendEvent)

CancelMempoolSpendEvent implements the MempoolWatcher interface.

func (*MockMempoolWatcher) LookupInputMempoolSpend

func (m *MockMempoolWatcher) LookupInputMempoolSpend(
	op wire.OutPoint) fn.Option[wire.MsgTx]

LookupInputMempoolSpend looks up the mempool to find a spending tx which spends the given outpoint.

func (*MockMempoolWatcher) SubscribeMempoolSpent

func (m *MockMempoolWatcher) SubscribeMempoolSpent(
	op wire.OutPoint) (*MempoolSpendEvent, error)

SubscribeMempoolSpent implements the MempoolWatcher interface.

type NotifierDriver

type NotifierDriver struct {
	// NotifierType is a string which uniquely identifies the ChainNotifier
	// that this driver, drives.
	NotifierType string

	// New creates a new instance of a concrete ChainNotifier
	// implementation given a variadic set up arguments. The function takes
	// a variadic number of interface parameters in order to provide
	// initialization flexibility, thereby accommodating several potential
	// ChainNotifier implementations.
	New func(args ...interface{}) (ChainNotifier, error)
}

NotifierDriver represents a "driver" for a particular interface. A driver is identified by a globally unique string identifier along with a 'New()' method which is responsible for initializing a particular ChainNotifier concrete implementation.

func RegisteredNotifiers

func RegisteredNotifiers() []*NotifierDriver

RegisteredNotifiers returns a slice of all currently registered notifiers.

NOTE: This function is safe for concurrent access.

type NotifierOption

type NotifierOption func(*notifierOptions)

NotifierOption is a functional option that allows a caller to modify the events received from the notifier.

func WithIncludeBlock

func WithIncludeBlock() NotifierOption

WithIncludeBlock is an optional argument that allows the calelr to specify that the block that mined a transaction should be included in the response.

type SpendDetail

type SpendDetail struct {
	SpentOutPoint     *wire.OutPoint
	SpenderTxHash     *chainhash.Hash
	SpendingTx        *wire.MsgTx
	SpenderInputIndex uint32
	SpendingHeight    int32
}

SpendDetail contains details pertaining to a spent output. This struct itself is the spentness notification. It includes the original outpoint which triggered the notification, the hash of the transaction spending the output, the spending transaction itself, and finally the input index which spent the target output.

func (*SpendDetail) HasSpenderWitness

func (s *SpendDetail) HasSpenderWitness() bool

HasSpenderWitness returns true if the spending transaction has non-empty witness.

func (*SpendDetail) String

func (s *SpendDetail) String() string

String returns a string representation of SpendDetail.

type SpendEvent

type SpendEvent struct {
	// Spend is a receive only channel which will be sent upon once the
	// target outpoint has been spent.
	//
	// NOTE: This channel must be buffered.
	Spend chan *SpendDetail

	// Reorg is a channel that will be sent upon once we detect the spending
	// transaction of the outpoint in question has been reorged out of the
	// chain.
	//
	// NOTE: This channel must be buffered.
	Reorg chan struct{}

	// Done is a channel that gets sent upon once the confirmation request
	// is no longer under the risk of being reorged out of the chain.
	//
	// NOTE: This channel must be buffered.
	Done chan struct{}

	// Cancel is a closure that should be executed by the caller in the case
	// that they wish to prematurely abandon their registered spend
	// notification.
	Cancel func()
}

SpendEvent encapsulates a spentness notification. Its only field 'Spend' will be sent upon once the target output passed into RegisterSpendNtfn has been spent on the blockchain.

NOTE: If the caller wishes to cancel their registered spend notification, the Cancel closure MUST be called.

func NewSpendEvent

func NewSpendEvent(cancel func()) *SpendEvent

NewSpendEvent constructs a new SpendEvent with newly opened channels.

type SpendHintCache

type SpendHintCache interface {
	// CommitSpendHint commits a spend hint for the outpoints to the cache.
	CommitSpendHint(height uint32, spendRequests ...SpendRequest) error

	// QuerySpendHint returns the latest spend hint for an outpoint.
	// ErrSpendHintNotFound is returned if a spend hint does not exist
	// within the cache for the outpoint.
	QuerySpendHint(spendRequest SpendRequest) (uint32, error)

	// PurgeSpendHint removes the spend hint for the outpoints from the
	// cache.
	PurgeSpendHint(spendRequests ...SpendRequest) error
}

SpendHintCache is an interface whose duty is to cache spend hints for outpoints. A spend hint is defined as the earliest height in the chain at which an outpoint could have been spent within.

type SpendNtfn

type SpendNtfn struct {
	// SpendID uniquely identies the spend notification request for the
	// specified outpoint/output script.
	SpendID uint64

	// SpendRequest represents either the outpoint or script we should
	// detect the spend of.
	SpendRequest

	// Event contains references to the channels that the notifications are
	// to be sent over.
	Event *SpendEvent

	// HeightHint is the earliest height in the chain that we expect to find
	// the spending transaction of the specified outpoint/output script.
	// This value will be overridden by the spend hint cache if it contains
	// an entry for it.
	HeightHint uint32
	// contains filtered or unexported fields
}

SpendNtfn represents a client's request to receive a notification once an outpoint/output script has been spent on-chain. The client is asynchronously notified via the SpendEvent channels.

type SpendRegistration

type SpendRegistration struct {
	// Event contains references to the channels that the notifications are
	// to be sent over.
	Event *SpendEvent

	// HistoricalDispatch, if non-nil, signals to the client who registered
	// the notification that they are responsible for attempting to manually
	// rescan blocks for the txid/output script between the start and end
	// heights.
	HistoricalDispatch *HistoricalSpendDispatch

	// Height is the height of the TxNotifier at the time the spend
	// notification was registered. This can be used so that backends can
	// request to be notified of spends from this point forwards.
	Height uint32
}

SpendRegistration encompasses all of the information required for callers to retrieve details about a spend event.

type SpendRequest

type SpendRequest struct {
	// OutPoint is the outpoint for which a client has requested a spend
	// notification for. If set to a zero outpoint, then a spend
	// notification will be dispatched upon detecting the spend of the
	// _script_, rather than the outpoint.
	OutPoint wire.OutPoint

	// PkScript is the script of the outpoint. If a zero outpoint is set,
	// then this can be an arbitrary script.
	PkScript txscript.PkScript
}

SpendRequest encapsulates a request for a spend notification of either an outpoint or output script.

func NewSpendRequest

func NewSpendRequest(op *wire.OutPoint, pkScript []byte) (SpendRequest, error)

NewSpendRequest creates a request for a spend notification of either an outpoint or output script. A nil outpoint or an allocated ZeroOutPoint can be used to dispatch the confirmation notification on the script.

func (SpendRequest) MatchesTx

func (r SpendRequest) MatchesTx(tx *wire.MsgTx) (bool, uint32, error)

MatchesTx determines whether the given transaction satisfies the spend request. If the spend request is for an outpoint, then we'll check all of the outputs being spent by the inputs of the transaction to determine if it matches. Otherwise, we'll need to match on the output script being spent, so we'll recompute it for each input of the transaction to determine if it matches.

func (SpendRequest) String

func (r SpendRequest) String() string

String returns the string representation of the SpendRequest.

type TxConfStatus

type TxConfStatus uint8

TxConfStatus denotes the status of a transaction's lookup.

const (
	// TxFoundMempool denotes that the transaction was found within the
	// backend node's mempool.
	TxFoundMempool TxConfStatus = iota

	// TxFoundIndex denotes that the transaction was found within the
	// backend node's txindex.
	TxFoundIndex

	// TxNotFoundIndex denotes that the transaction was not found within the
	// backend node's txindex.
	TxNotFoundIndex

	// TxFoundManually denotes that the transaction was found within the
	// chain by scanning for it manually.
	TxFoundManually

	// TxNotFoundManually denotes that the transaction was not found within
	// the chain by scanning for it manually.
	TxNotFoundManually
)

func (TxConfStatus) String

func (t TxConfStatus) String() string

String returns the string representation of the TxConfStatus.

type TxConfirmation

type TxConfirmation struct {
	// BlockHash is the hash of the block that confirmed the original
	// transition.
	BlockHash *chainhash.Hash

	// BlockHeight is the height of the block in which the transaction was
	// confirmed within.
	BlockHeight uint32

	// TxIndex is the index within the block of the ultimate confirmed
	// transaction.
	TxIndex uint32

	// Tx is the transaction for which the notification was requested for.
	Tx *wire.MsgTx

	// Block is the block that contains the transaction referenced above.
	//
	// NOTE: This is only specified if the confirmation request opts to
	// have the response include the block itself.
	Block *wire.MsgBlock
}

TxConfirmation carries some additional block-level details of the exact block that specified transactions was confirmed within.

type TxIndexConn

type TxIndexConn interface {
	// GetRawTransactionVerbose returns the transaction identified by the
	// passed chain hash, and returns additional information such as the
	// block that the transaction confirmed.
	GetRawTransactionVerbose(*chainhash.Hash) (*btcjson.TxRawResult, error)

	// GetBlock returns the block identified by the chain hash.
	GetBlock(*chainhash.Hash) (*wire.MsgBlock, error)
}

TxIndexConn abstracts an RPC backend with txindex enabled.

type TxNotifier

type TxNotifier struct {
	sync.Mutex
	// contains filtered or unexported fields
}

TxNotifier is a struct responsible for delivering transaction notifications to subscribers. These notifications can be of two different types: transaction/output script confirmations and/or outpoint/output script spends. The TxNotifier will watch the blockchain as new blocks come in, in order to satisfy its client requests.

func NewTxNotifier

func NewTxNotifier(startHeight uint32, reorgSafetyLimit uint32,
	confirmHintCache ConfirmHintCache,
	spendHintCache SpendHintCache) *TxNotifier

NewTxNotifier creates a TxNotifier. The current height of the blockchain is accepted as a parameter. The different hint caches (confirm and spend) are used as an optimization in order to retrieve a better starting point when dispatching a rescan for a historical event in the chain.

func (*TxNotifier) CancelConf

func (n *TxNotifier) CancelConf(confRequest ConfRequest, confID uint64)

CancelConf cancels an existing request for a spend notification of an outpoint/output script. The request is identified by its spend ID.

func (*TxNotifier) CancelSpend

func (n *TxNotifier) CancelSpend(spendRequest SpendRequest, spendID uint64)

CancelSpend cancels an existing request for a spend notification of an outpoint/output script. The request is identified by its spend ID.

func (*TxNotifier) ConnectTip

func (n *TxNotifier) ConnectTip(block *btcutil.Block,
	blockHeight uint32) error

ConnectTip handles a new block extending the current chain. It will go through every transaction and determine if it is relevant to any of its clients. A transaction can be relevant in either of the following two ways:

  1. One of the inputs in the transaction spends an outpoint/output script for which we currently have an active spend registration for.

  2. The transaction has a txid or output script for which we currently have an active confirmation registration for.

In the event that the transaction is relevant, a confirmation/spend notification will be queued for dispatch to the relevant clients. Confirmation notifications will only be dispatched for transactions/output scripts that have met the required number of confirmations required by the client.

NOTE: In order to actually dispatch the relevant transaction notifications to clients, NotifyHeight must be called with the same block height in order to maintain correctness.

func (*TxNotifier) DisconnectTip

func (n *TxNotifier) DisconnectTip(blockHeight uint32) error

DisconnectTip handles the tip of the current chain being disconnected during a chain reorganization. If any watched requests were included in this block, internal structures are updated to ensure confirmation/spend notifications are consumed (if not already), and reorg notifications are dispatched instead. Confirmation/spend notifications will be dispatched again upon block inclusion.

func (*TxNotifier) NotifyHeight

func (n *TxNotifier) NotifyHeight(height uint32) error

NotifyHeight dispatches confirmation and spend notifications to the clients who registered for a notification which has been fulfilled at the passed height.

func (*TxNotifier) ProcessRelevantSpendTx

func (n *TxNotifier) ProcessRelevantSpendTx(tx *btcutil.Tx,
	blockHeight uint32) error

ProcessRelevantSpendTx processes a transaction provided externally. This will check whether the transaction is relevant to the notifier if it spends any outpoints/output scripts for which we currently have registered notifications for. If it is relevant, spend notifications will be dispatched to the caller.

func (*TxNotifier) RegisterConf

func (n *TxNotifier) RegisterConf(txid *chainhash.Hash, pkScript []byte,
	numConfs, heightHint uint32,
	optFuncs ...NotifierOption) (*ConfRegistration, error)

RegisterConf handles a new confirmation notification request. The client will be notified when the transaction/output script gets a sufficient number of confirmations in the blockchain.

NOTE: If the transaction/output script has already been included in a block on the chain, the confirmation details must be provided with the UpdateConfDetails method, otherwise we will wait for the transaction/output script to confirm even though it already has.

func (*TxNotifier) RegisterSpend

func (n *TxNotifier) RegisterSpend(outpoint *wire.OutPoint, pkScript []byte,
	heightHint uint32) (*SpendRegistration, error)

RegisterSpend handles a new spend notification request. The client will be notified once the outpoint/output script is detected as spent within the chain.

NOTE: If the outpoint/output script has already been spent within the chain before the notifier's current tip, the spend details must be provided with the UpdateSpendDetails method, otherwise we will wait for the outpoint/output script to be spent at tip, even though it already has.

func (*TxNotifier) TearDown

func (n *TxNotifier) TearDown()

TearDown is to be called when the owner of the TxNotifier is exiting. This closes the event channels of all registered notifications that have not been dispatched yet.

func (*TxNotifier) UpdateConfDetails

func (n *TxNotifier) UpdateConfDetails(confRequest ConfRequest,
	details *TxConfirmation) error

UpdateConfDetails attempts to update the confirmation details for an active notification within the notifier. This should only be used in the case of a transaction/output script that has confirmed before the notifier's current height.

NOTE: The notification should be registered first to ensure notifications are dispatched correctly.

func (*TxNotifier) UpdateSpendDetails

func (n *TxNotifier) UpdateSpendDetails(spendRequest SpendRequest,
	details *SpendDetail) error

UpdateSpendDetails attempts to update the spend details for all active spend notification requests for an outpoint/output script. This method should be used once a historical scan of the chain has finished. If the historical scan did not find a spending transaction for it, the spend details may be nil.

NOTE: A notification request for the outpoint/output script must be registered first to ensure notifications are delivered.

Directories

Path Synopsis

Jump to

Keyboard shortcuts

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