chainbackends

package
v0.1.1-rc2 Latest Latest
Warning

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

Go to latest
Published: Jul 31, 2026 License: MIT Imports: 18 Imported by: 0

Documentation

Overview

Package chainbackends provides concrete implementations of the chainsource.ChainBackend interface.

The ChainBackend interface is defined in the chainsource package and provides a blockchain data abstraction layer for the Ark actor system. This package contains pluggable backend implementations that can be used depending on deployment requirements.

Available Backends

LNDBackend: Full-node backend that wraps lnd's chain notification and fee estimation interfaces. Suitable for production deployments where lnd is available. Provides real-time notifications via lnd's chainntnfs package.

Usage

Backends are instantiated and passed to the ChainSource actor during initialization. For in-process lnd:

backend := chainbackends.NewLNDBackend(
	notifier, feeEstimator, broadcaster,
)
chainSource := chainsource.NewChainSourceActor(
	backend, system, ctx,
)

For remote lnd via lndclient:

backend := chainbackends.NewLNDBackendFromLndClient(lndServices)
chainSource := chainsource.NewChainSourceActor(
	backend, system, ctx,
)

Architecture

The separation between interface (chainsource) and implementations (chainbackends) provides several benefits:

  1. Pluggability: Easy to swap backends without changing actor code
  2. Testing: Mock backends can be created for testing
  3. Dependencies: The actor system doesn't depend on lnd or HTTP libraries
  4. Extensibility: New backends can be added without modifying core code

Implementation Requirements

Backend implementations must:

  • Implement all methods of chainsource.ChainBackend
  • Be safe for concurrent use
  • Handle context cancellation properly
  • Clean up resources in Stop()
  • Document any limitations or unsupported operations

Backend Selection Criteria

LNDBackend is recommended when:

  • Running a full node with lnd
  • Real-time notifications are required
  • Low latency is critical
  • Full Bitcoin protocol support is needed

Index

Constants

View Source
const (
	// Subsystem defines the logging subsystem code for the chainbackends
	// package.
	Subsystem = "CBKD"

	// LndClientSubsystem defines the logging subsystem code for the
	// lndclient adapter components.
	LndClientSubsystem = "LNDC"
)

Variables

This section is empty.

Functions

func WalkPackageTxErrors

func WalkPackageTxErrors(err error, fn func(*PackageTxError))

WalkPackageTxErrors invokes `fn` for every `*PackageTxError` reachable from `err` by walking both the `Unwrap() error` and `Unwrap() []error` shapes. It is safe to call with `nil`.

Used by callers (e.g. `txconfirm.isParentKnownChildFailed`) that need to inspect every per-tx entry in a joined `SubmitPackage` error. `errors.As` alone only surfaces the first match, which is insufficient when distinct classifications must be observed for the parent and the child.

Implementation note: this walks the error tree directly rather than using `errors.As(&pte)`, because `errors.As` short-circuits on the first match and would miss sibling per-tx entries — the whole point of the walker. The lint disables below are intentional for that reason.

Types

type LNDBackend

type LNDBackend struct {

	// Log is an optional logger for this backend. If None, the backend
	// falls back to extracting a logger from context.
	Log fn.Option[btclog.Logger]
	// contains filtered or unexported fields
}

LNDBackend implements the chainsource.ChainBackend interface by wrapping lnd's chain notification and fee estimation interfaces. This backend provides full-node functionality and is suitable for production deployments where lnd is available.

The backend delegates all operations to the underlying lnd components: chainntnfs for notifications and chainfee for fee estimation.

func NewLNDBackend

func NewLNDBackend(notifier chainntnfs.ChainNotifier,
	feeEstimator chainfee.Estimator,
	broadcaster TxBroadcaster) *LNDBackend

NewLNDBackend creates a new LNDBackend instance with the given lnd components. All parameters must be non-nil.

func NewLNDBackendFromLndClient

func NewLNDBackendFromLndClient(cfg LNDBackendFromLndClientConfig) (*LNDBackend,
	error)

NewLNDBackendFromLndClient creates a new LNDBackend using lndclient services. This is a convenience function for creating a backend from a remote lnd connection. The config must include LND; use WithLogger() to inject a specific logger.

func (*LNDBackend) BestBlock

func (b *LNDBackend) BestBlock(ctx context.Context) (int32, chainhash.Hash,
	error)

BestBlock returns the current best block height and hash from lnd's view of the blockchain. We register for a single block notification to get the current tip.

func (*LNDBackend) BroadcastTx

func (b *LNDBackend) BroadcastTx(ctx context.Context, tx *wire.MsgTx,
	label string) error

BroadcastTx broadcasts a transaction to the network using the configured broadcaster.

func (*LNDBackend) EstimateFee

func (b *LNDBackend) EstimateFee(ctx context.Context, targetConf uint32) (
	btcutil.Amount, error)

EstimateFee returns the estimated fee rate in satoshis per vbyte for the given confirmation target. The fee estimator will provide the rate needed to confirm within the target number of blocks.

func (*LNDBackend) RegisterBlocks

func (b *LNDBackend) RegisterBlocks(ctx context.Context) (
	*chainsource.BlockRegistration, error)

RegisterBlocks registers for new block notifications using lnd's chain notifier. The registration returns a BlockRegistration with a channel for receiving block events.

func (*LNDBackend) RegisterConf

func (b *LNDBackend) RegisterConf(ctx context.Context, txid *chainhash.Hash,
	pkScript []byte, numConfs uint32, heightHint uint32,
	includeBlock bool) (*chainsource.ConfRegistration, error)

RegisterConf registers for confirmation notifications using lnd's chain notifier. The registration returns a ConfRegistration with channels for receiving confirmation events.

func (*LNDBackend) RegisterSpend

func (b *LNDBackend) RegisterSpend(ctx context.Context, outpoint *wire.OutPoint,
	pkScript []byte, heightHint uint32) (*chainsource.SpendRegistration,
	error)

RegisterSpend registers for spend notifications using lnd's chain notifier. The registration returns a SpendRegistration with channels for receiving spend events.

func (*LNDBackend) SetPackageSubmitter

func (b *LNDBackend) SetPackageSubmitter(packageSubmitter PackageSubmitter)

SetPackageSubmitter attaches optional package relay support to the backend.

func (*LNDBackend) Start

func (b *LNDBackend) Start() error

Start initializes the LND backend by starting the notifier and fee estimator.

func (*LNDBackend) Stop

func (b *LNDBackend) Stop() error

Stop shuts down the LND backend by stopping the notifier and fee estimator.

func (*LNDBackend) SubmitPackage

func (b *LNDBackend) SubmitPackage(ctx context.Context, parents []*wire.MsgTx,
	child *wire.MsgTx) error

SubmitPackage submits a parent+child package through the configured PackageSubmitter. This is required for v3 package relay when a fee-paying child must accompany otherwise non-relayable parents.

func (*LNDBackend) TestMempoolAccept

func (b *LNDBackend) TestMempoolAccept(_ context.Context, _ ...*wire.MsgTx) (
	[]chainsource.MempoolAcceptResult, error)

TestMempoolAccept tests whether one or more transactions would be accepted by the mempool. LND's WalletController does not expose a testmempoolaccept equivalent, so every call returns "not supported" here — callers that treat preflight as best-effort should log and continue.

type LNDBackendFromLndClientConfig

type LNDBackendFromLndClientConfig struct {
	// LND is the lndclient services connection.
	LND *lndclient.LndServices

	// Log is an optional logger for the backend components. If None, the
	// backend falls back to extracting a logger from context or uses
	// btclog.Disabled.
	Log fn.Option[btclog.Logger]

	// PackageSubmitter is an optional package submitter for atomic
	// parent+child package submission. When nil, SubmitPackage
	// returns an "unsupported" error. Typically backed by a direct
	// bitcoind RPC client.
	PackageSubmitter PackageSubmitter
}

LNDBackendFromLndClientConfig holds configuration for creating an LNDBackend from lndclient services.

func (LNDBackendFromLndClientConfig) WithLogger

WithLogger returns a new config with the given logger set.

type LndClientChainNotifier

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

LndClientChainNotifier implements chainntnfs.ChainNotifier using lndclient. This adapter bridges the lndclient.ChainNotifierClient interface to the chainntnfs.ChainNotifier interface expected by LNDBackend.

func NewLndClientChainNotifier

func NewLndClientChainNotifier(
	cfg LndClientChainNotifierConfig) *LndClientChainNotifier

NewLndClientChainNotifier creates a new chain notifier backed by lndclient. The config must include LND; use WithLogger() to inject a specific logger.

func (*LndClientChainNotifier) RegisterBlockEpochNtfn

func (n *LndClientChainNotifier) RegisterBlockEpochNtfn(
	bestBlock *chainntnfs.BlockEpoch) (*chainntnfs.BlockEpochEvent, error)

RegisterBlockEpochNtfn registers for block epoch notifications using lndclient's ChainNotifier.

func (*LndClientChainNotifier) RegisterConfirmationsNtfn

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

RegisterConfirmationsNtfn registers for confirmation notifications using lndclient's ChainNotifier.

func (*LndClientChainNotifier) RegisterSpendNtfn

func (n *LndClientChainNotifier) RegisterSpendNtfn(outpoint *wire.OutPoint,
	pkScript []byte, heightHint uint32) (*chainntnfs.SpendEvent, error)

RegisterSpendNtfn registers for spend notifications using lndclient's ChainNotifier.

func (*LndClientChainNotifier) Start

func (n *LndClientChainNotifier) Start() error

Start is a no-op for lndclient-backed notifiers since the connection is already established.

func (*LndClientChainNotifier) Started

func (n *LndClientChainNotifier) Started() bool

Started returns true since lndclient connections are always ready.

func (*LndClientChainNotifier) Stop

func (n *LndClientChainNotifier) Stop() error

Stop is a no-op for lndclient-backed notifiers.

type LndClientChainNotifierConfig

type LndClientChainNotifierConfig struct {
	// LND is the lndclient services connection.
	LND *lndclient.LndServices

	// Log is an optional logger for this notifier. If None, the notifier
	// falls back to extracting a logger from context via
	// LoggerFromContext, or uses btclog.Disabled if no logger is found.
	Log fn.Option[btclog.Logger]
}

LndClientChainNotifierConfig holds configuration for LndClientChainNotifier.

func (LndClientChainNotifierConfig) WithLogger

WithLogger returns a new config with the given logger set.

type LndClientFeeEstimator

type LndClientFeeEstimator = chainfees.WalletKitEstimator

LndClientFeeEstimator implements chainfee.Estimator using lndclient.

func NewLndClientFeeEstimator

func NewLndClientFeeEstimator(walletKit lndclient.WalletKitClient) (
	*LndClientFeeEstimator, error)

NewLndClientFeeEstimator creates a new fee estimator backed by lndclient. It uses last-good fallback semantics: a WalletKit error returns the last successful rate (or the relay floor before any success) rather than propagating the error, so a transient WalletKit outage does not abort fee estimation on the standalone LND backend path.

type LndClientTxBroadcaster

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

LndClientTxBroadcaster implements TxBroadcaster using lndclient.WalletKitClient.

func NewLndClientTxBroadcaster

func NewLndClientTxBroadcaster(
	walletKit lndclient.WalletKitClient) *LndClientTxBroadcaster

NewLndClientTxBroadcaster creates a new broadcaster backed by lndclient.

func (*LndClientTxBroadcaster) PublishTransaction

func (b *LndClientTxBroadcaster) PublishTransaction(ctx context.Context,
	tx *wire.MsgTx, label string) error

PublishTransaction broadcasts the given transaction to the network via lnd.

type PackageSubmitter

type PackageSubmitter interface {
	// SubmitPackage submits the package. The maxFeeRate parameter is
	// optional and nil leaves the node default unchanged. The context
	// controls cancellation/timeout for the underlying RPC.
	SubmitPackage(ctx context.Context, parents []*wire.MsgTx,
		child *wire.MsgTx,
		maxFeeRate *float64) (*btcjson.SubmitPackageResult, error)
}

PackageSubmitter atomically submits parent+child transaction packages. Bitcoind-backed implementations can satisfy this interface to expose v3 package relay through the LND chain backend.

type PackageTxError

type PackageTxError struct {
	// Wtxid is the witness txid that bitcoind / btcd echoed for this
	// per-tx package result.
	Wtxid string

	// Txid is the legacy (non-witness) txid associated with this entry.
	Txid chainhash.Hash

	// Reason is the raw reject reason as emitted by the chain backend
	// before normalisation. Kept for diagnostics; do not rely on it for
	// classification — use `errors.Is` against the unwrapped sentinel
	// instead.
	Reason string
	// contains filtered or unexported fields
}

PackageTxError is one per-tx result error from a `SubmitPackage` response. It preserves the original wtxid / txid / reject reason for diagnostics, and unwraps to a chain-backend sentinel mapped via `rpcclient.MapRPCErr` so callers can `errors.Is` against typed sentinels (e.g. `rpcclient.ErrTxAlreadyKnown`, `rpcclient.ErrInsufficientFee`) instead of substring-matching the raw bitcoind / btcd reject string.

func NewPackageTxError

func NewPackageTxError(wtxid string, txid chainhash.Hash,
	reason string) *PackageTxError

NewPackageTxError builds a `PackageTxError` from a per-tx package result. The mapped sentinel is computed eagerly via `rpcclient.MapRPCErr` so the caller side can rely on `errors.Is` without re-parsing the reason.

func (*PackageTxError) Error

func (e *PackageTxError) Error() string

Error implements the `error` interface and preserves the legacy "wtxid=<wtxid> txid=<txid>: <reason>" diagnostic shape that joined error messages used to carry, so log output and existing string-matching fallbacks (e.g. `rejecting replacement` heuristics) keep working until they are migrated to typed checks.

func (*PackageTxError) Unwrap

func (e *PackageTxError) Unwrap() error

Unwrap surfaces the mapped chain sentinel so callers can write `errors.Is(err, rpcclient.ErrTxAlreadyKnown)` instead of substring-matching the raw reason.

type TxBroadcaster

type TxBroadcaster interface {
	// PublishTransaction broadcasts the given transaction to the network.
	// The label parameter is optional and may be used for wallet tracking.
	PublishTransaction(ctx context.Context, tx *wire.MsgTx,
		label string) error
}

TxBroadcaster is a minimal interface for broadcasting transactions. This allows LNDBackend to work with both lnwallet.WalletController (in-process lnd) and lndclient wrappers (remote lnd via gRPC).

Directories

Path Synopsis
Package bitcoindrpc provides a direct-to-bitcoind JSON-RPC implementation of chainbackends.PackageSubmitter, used by the production daemon (and by integration tests) when the LND v3 submitpackage path is not available.
Package bitcoindrpc provides a direct-to-bitcoind JSON-RPC implementation of chainbackends.PackageSubmitter, used by the production daemon (and by integration tests) when the LND v3 submitpackage path is not available.
Package lndsubmitter provides a chainbackends.PackageSubmitter backed by lnd's WalletKit.SubmitPackage RPC.
Package lndsubmitter provides a chainbackends.PackageSubmitter backed by lnd's WalletKit.SubmitPackage RPC.

Jump to

Keyboard shortcuts

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