lntest

package
v0.18.0-beta.rc4 Latest Latest
Warning

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

Go to latest
Published: May 29, 2024 License: MIT Imports: 50 Imported by: 0

README

lntest

lntest is a package which holds the components used for the lnd’s integration tests. It is responsible for managing lnd nodes, chain backends and miners, advancing nodes’ states and providing assertions.

Quick Start

A simple example to run the integration test.

func TestFoo(t *testing.T) {
	// Get the binary path and setup the harness test.
	//
	// TODO: define the binary path to lnd and the name of the database
	// backend.
	harnessTest := lntemp.SetupHarness(t, binary, *dbBackendFlag)
	defer harnessTest.Stop()

	// Setup standby nodes, Alice and Bob, which will be alive and shared
	// among all the test cases.
	harnessTest.SetupStandbyNodes()

	// Run the subset of the test cases selected in this tranche.
	//
	// TODO: define your own testCases.
	for _, tc := range testCases {
		tc := tc

		t.Run(tc.Name, func(st *testing.T) {
			// Create a separate harness test for the testcase to
			// avoid overwriting the external harness test that is
			// tied to the parent test.
			ht := harnessTest.Subtest(st)

			// Run the test cases.
			ht.RunTestCase(tc)
		})
	}
}
Package Structure

This package has four major components, HarnessTest, HarnessMiner, node.HarnessNode and rpc.HarnessRPC, with the following architecture,

+----------------------------------------------------------+
|                                                          |
|                        HarnessTest                       |
|                                                          |
| +----------------+  +----------------+  +--------------+ |
| |   HarnessNode  |  |   HarnessNode  |  | HarnessMiner | |
| |                |  |                |  +--------------+ |
| | +------------+ |  | +------------+ |                   |
| | | HarnessRPC | |  | | HarnessRPC | |  +--------------+ |
| | +------------+ |  | +------------+ |  | HarnessMiner | |
| +----------------+  +----------------+  +--------------+ |
+----------------------------------------------------------+
  • HarnessRPC holds all the RPC clients and adds a layer over all the RPC methods to assert no error happened at the RPC level.

  • HarnessNode builds on top of the HarnessRPC. It is responsible for managing the lnd node, including start and stop pf the lnd process, authentication of the gRPC connection, topology subscription(NodeWatcher) and maintains an internal state(NodeState).

  • HarnessMiner builds on top of btcd’s rcptest.Harness and is responsible for managing blocks and the mempool.

  • HarnessTest builds on top of testing.T and can be viewed as the assertion machine. It provides multiple ways to initialize a node, such as with/without seed, backups, etc. It also handles interactions between nodes like connecting nodes and opening/closing channels so it’s easier to acquire or validate a desired test states such as node’s balance, mempool condition, etc.

Standby Nodes

Standby nodes are HarnessNodes created when initializing the integration test and stay alive across all the test cases. Creating a new node is not without a cost. With block height increasing, it takes significantly longer to initialize a new node and wait for it to be synced. Standby nodes, however, don’t have this problem as they are digesting blocks all the time. Thus it’s encouraged to use standby nodes wherever possible.

Currently there are two standby nodes, Alice and Bob. Their internal states are recorded and taken into account when HarnessTest makes assertions. When making a new test case using Subtest, there’s a cleanup function which further validates the current test case has no dangling uncleaned states, such as transactions left in mempool, open channels, etc.

Different Code Used in lntest

Since the miner in lntest uses regtest, it has a very fast block production rate, which is the greatest difference between the conditions it simulates and the real-world has. Aside from that, lnd has several places that use different code, which is triggered by the build flag integration, to speed up the tests. They are summarized as followings,

  1. funding.checkPeerChannelReadyInterval, which is used when we wait for the peer to send us ChannelReady. This value is 1 second in lnd, and 10 milliseconds in lntest.
  2. lncfg.ProtocolOptions, which is used to specify protocol flags. In lnd, anchor and script enforced lease are enabled by default, while in lntest, they are disabled by default.
  3. Reduced scrypt parameters are used in lntest. In lnd, the parameters N, R, and P are imported from snacl, while in lntest they are replaced with waddrmgr.FastScryptOptions. Both macaroon and aezeed are affected.
  4. The method, nextRevocationProducer, defined in LightningWallet is slightly different. For lnwallet, it will check a special pre-defined channel ID to test restoring channel backups created with the old revocation root derivation method.

Documentation

Overview

Package lntest provides testing utilities for the lnd repository.

This package contains infrastructure for integration tests that launch full lnd nodes in a controlled environment and interact with them via RPC. Using a NetworkHarness, a test can launch multiple lnd nodes, open channels between them, create defined network topologies, and anything else that is possible with RPC commands.

Index

Constants

View Source
const (
	// NeutrinoBackendName is the name of the neutrino backend.
	NeutrinoBackendName = "neutrino"

	DefaultTimeout = wait.DefaultTimeout
)
View Source
const (

	// DefaultFeeRateSatPerKw specifies the default fee rate used in the
	// tests.
	DefaultFeeRateSatPerKw = 12500
)

Variables

This section is empty.

Functions

func CalcStaticFee

func CalcStaticFee(c lnrpc.CommitmentType, numHTLCs int) btcutil.Amount

CalcStaticFee calculates appropriate fees for commitment transactions. This function provides a simple way to allow test balance assertions to take fee calculations into account.

func CalcStaticFeeBuffer

func CalcStaticFeeBuffer(c lnrpc.CommitmentType, numHTLCs int) btcutil.Amount

CalcStaticFeeBuffer calculates appropriate fee buffer which must be taken into account when sending htlcs.

func CalculateMaxHtlc

func CalculateMaxHtlc(chanCap btcutil.Amount) uint64

CalculateMaxHtlc re-implements the RequiredRemoteChannelReserve of the funding manager's config, which corresponds to the maximum MaxHTLC value we allow users to set when updating a channel policy.

func ChanPointFromPendingUpdate

func ChanPointFromPendingUpdate(pu *lnrpc.PendingUpdate) *lnrpc.ChannelPoint

ChanPointFromPendingUpdate constructs a channel point from a lnrpc pending update.

func CommitTypeHasAnchors

func CommitTypeHasAnchors(commitType lnrpc.CommitmentType) bool

CommitTypeHasAnchors returns whether commitType uses anchor outputs.

func CommitTypeHasTaproot

func CommitTypeHasTaproot(commitType lnrpc.CommitmentType) bool

CommitTypeHasTaproot returns whether commitType is a taproot commitment.

func CopyFile

func CopyFile(dest, src string) error

CopyFile copies the file src to dest.

func NodeArgsForCommitType

func NodeArgsForCommitType(commitType lnrpc.CommitmentType) []string

NodeArgsForCommitType returns the command line flag to supply to enable this commitment type.

func ParseDerivationPath

func ParseDerivationPath(path string) ([]uint32, error)

parseDerivationPath parses a path in the form of m/x'/y'/z'/a/b into a slice of [x, y, z, a, b], meaning that the apostrophe is ignored and 2^31 is _not_ added to the numbers.

Types

type BtcdBackendConfig

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

BtcdBackendConfig is an implementation of the BackendConfig interface backed by a btcd node.

func NewBackend

func NewBackend(miner string, netParams *chaincfg.Params) (
	*BtcdBackendConfig, func() error, error)

NewBackend starts a new rpctest.Harness and returns a BtcdBackendConfig for that node. miner should be set to the P2P address of the miner to connect to.

func (BtcdBackendConfig) ConnectMiner

func (b BtcdBackendConfig) ConnectMiner() error

ConnectMiner is called to establish a connection to the test miner.

func (BtcdBackendConfig) Credentials

func (b BtcdBackendConfig) Credentials() (string, string, string, error)

Credentials returns the rpc username, password and host for the backend.

func (BtcdBackendConfig) DisconnectMiner

func (b BtcdBackendConfig) DisconnectMiner() error

DisconnectMiner is called to disconnect the miner.

func (BtcdBackendConfig) GenArgs

func (b BtcdBackendConfig) GenArgs() []string

GenArgs returns the arguments needed to be passed to LND at startup for using this node as a chain backend.

func (BtcdBackendConfig) Name

func (b BtcdBackendConfig) Name() string

Name returns the name of the backend type.

type FeeService

type FeeService struct {
	*testing.T
	// contains filtered or unexported fields
}

FeeService runs a web service that provides fee estimation information.

func NewFeeService

func NewFeeService(t *testing.T) *FeeService

NewFeeService spins up a go-routine to serve fee estimates.

func (*FeeService) Reset

func (f *FeeService) Reset()

Reset resets the fee rate map to the default value.

func (*FeeService) SetFeeRate

func (f *FeeService) SetFeeRate(fee chainfee.SatPerKWeight, conf uint32)

SetFeeRate sets a fee for the given confirmation target.

func (*FeeService) Start

func (f *FeeService) Start() error

Start starts the web server.

func (*FeeService) Stop

func (f *FeeService) Stop() error

Stop stops the web server.

func (*FeeService) URL

func (f *FeeService) URL() string

URL returns the service endpoint.

type HarnessMiner

type HarnessMiner struct {
	*testing.T
	*rpctest.Harness
	// contains filtered or unexported fields
}

func NewMiner

func NewMiner(ctxt context.Context, t *testing.T) *HarnessMiner

NewMiner creates a new miner using btcd backend with the default log file dir and name.

func NewTempMiner

func NewTempMiner(ctxt context.Context, t *testing.T,
	tempDir, tempLogFilename string) *HarnessMiner

NewTempMiner creates a new miner using btcd backend with the specified log file dir and name.

func (*HarnessMiner) AssertMinerBlockHeightDelta

func (h *HarnessMiner) AssertMinerBlockHeightDelta(tempMiner *HarnessMiner,
	delta int32)

AssertMinerBlockHeightDelta ensures that tempMiner is 'delta' blocks ahead of miner.

func (*HarnessMiner) AssertNumTxsInMempool

func (h *HarnessMiner) AssertNumTxsInMempool(n int) []*chainhash.Hash

AssertNumTxsInMempool polls until finding the desired number of transactions in the provided miner's mempool. It will asserrt if this number is not met after the given timeout.

func (*HarnessMiner) AssertOutpointInMempool

func (h *HarnessMiner) AssertOutpointInMempool(op wire.OutPoint) *wire.MsgTx

AssertOutpointInMempool asserts a given outpoint can be found in the mempool.

func (*HarnessMiner) AssertTxInBlock

func (h *HarnessMiner) AssertTxInBlock(block *wire.MsgBlock,
	txid *chainhash.Hash)

AssertTxInBlock asserts that a given txid can be found in the passed block.

func (*HarnessMiner) AssertTxInMempool

func (h *HarnessMiner) AssertTxInMempool(txid *chainhash.Hash) *wire.MsgTx

AssertTxInMempool asserts a given transaction can be found in the mempool.

func (*HarnessMiner) AssertTxNotInMempool

func (h *HarnessMiner) AssertTxNotInMempool(txid chainhash.Hash) *wire.MsgTx

AssertTxNotInMempool asserts a given transaction cannot be found in the mempool. It assumes the mempool is not empty.

NOTE: this should be used after `AssertTxInMempool` to ensure the tx has entered the mempool before. Otherwise it might give false positive and the tx may enter the mempool after the check.

func (*HarnessMiner) ConnectMiner

func (h *HarnessMiner) ConnectMiner(tempMiner *HarnessMiner)

ConnectMiner connects the miner to a temp miner.

func (*HarnessMiner) CreateTransaction

func (h *HarnessMiner) CreateTransaction(outputs []*wire.TxOut,
	feeRate btcutil.Amount) *wire.MsgTx

CreateTransaction uses the miner to create a transaction using the given outputs using the specified fee rate and returns the transaction.

func (*HarnessMiner) DisconnectMiner

func (h *HarnessMiner) DisconnectMiner(tempMiner *HarnessMiner)

DisconnectMiner disconnects the miner from the temp miner.

func (*HarnessMiner) GenerateBlocks

func (h *HarnessMiner) GenerateBlocks(num uint32) []*chainhash.Hash

GenerateBlocks mine 'num' of blocks and returns them.

func (*HarnessMiner) GetBestBlock

func (h *HarnessMiner) GetBestBlock() (*chainhash.Hash, int32)

GetBestBlock makes a RPC request to miner and asserts.

func (*HarnessMiner) GetBlock

func (h *HarnessMiner) GetBlock(blockHash *chainhash.Hash) *wire.MsgBlock

GetBlock gets a block using its block hash.

func (*HarnessMiner) GetNumTxsFromMempool

func (h *HarnessMiner) GetNumTxsFromMempool(n int) []*wire.MsgTx

GetNumTxsFromMempool polls until finding the desired number of transactions in the miner's mempool and returns the full transactions to the caller.

func (*HarnessMiner) GetRawMempool

func (h *HarnessMiner) GetRawMempool() []*chainhash.Hash

GetRawMempool makes a RPC call to the miner's GetRawMempool and asserts.

func (*HarnessMiner) GetRawTransaction

func (h *HarnessMiner) GetRawTransaction(txid *chainhash.Hash) *btcutil.Tx

GetRawTransaction makes a RPC call to the miner's GetRawTransaction and asserts.

func (*HarnessMiner) GetRawTransactionVerbose

func (h *HarnessMiner) GetRawTransactionVerbose(
	txid *chainhash.Hash) *btcjson.TxRawResult

GetRawTransactionVerbose makes a RPC call to the miner's GetRawTransactionVerbose and asserts.

func (*HarnessMiner) MineBlockWithTx

func (h *HarnessMiner) MineBlockWithTx(tx *wire.MsgTx) *wire.MsgBlock

MineBlocksWithTx mines a single block to include the specifies tx only.

func (*HarnessMiner) MineBlockWithTxes

func (h *HarnessMiner) MineBlockWithTxes(txes []*btcutil.Tx) *wire.MsgBlock

MineBlocksWithTxes mines a single block to include the specifies transactions only.

func (*HarnessMiner) MineBlocks

func (h *HarnessMiner) MineBlocks(num uint32) []*wire.MsgBlock

MineBlocks mine 'num' of blocks and check that blocks are present in node blockchain.

func (*HarnessMiner) MineBlocksAndAssertNumTxes

func (h *HarnessMiner) MineBlocksAndAssertNumTxes(num uint32,
	numTxs int) []*wire.MsgBlock

MineBlocksAndAssertNumTxes mine 'num' of blocks and check that blocks are present in node blockchain. numTxs should be set to the number of transactions (excluding the coinbase) we expect to be included in the first mined block.

func (*HarnessMiner) MineBlocksSlow

func (h *HarnessMiner) MineBlocksSlow(num uint32) []*wire.MsgBlock

MineBlocksSlow mines 'num' of blocks. Between each mined block an artificial delay is introduced to give all network participants time to catch up.

func (*HarnessMiner) MineEmptyBlocks

func (h *HarnessMiner) MineEmptyBlocks(num int) []*wire.MsgBlock

MineEmptyBlocks mines a given number of empty blocks.

func (*HarnessMiner) NewMinerAddress

func (h *HarnessMiner) NewMinerAddress() btcutil.Address

NewMinerAddress creates a new address for the miner and asserts.

func (*HarnessMiner) SendOutput

func (h *HarnessMiner) SendOutput(newOutput *wire.TxOut,
	feeRate btcutil.Amount) *chainhash.Hash

SendOutput creates, signs, and finally broadcasts a transaction spending the harness' available mature coinbase outputs to create the new output.

func (*HarnessMiner) SendOutputsWithoutChange

func (h *HarnessMiner) SendOutputsWithoutChange(outputs []*wire.TxOut,
	feeRate btcutil.Amount) *chainhash.Hash

SendOutputsWithoutChange uses the miner to send the given outputs using the specified fee rate and returns the txid.

func (*HarnessMiner) SpawnTempMiner

func (h *HarnessMiner) SpawnTempMiner() *HarnessMiner

SpawnTempMiner creates a temp miner and syncs it with the current miner. Once miners are synced, the temp miner is disconnected from the original miner and returned.

func (*HarnessMiner) Stop

func (h *HarnessMiner) Stop()

Stop shuts down the miner and saves its logs.

type HarnessOpt

type HarnessOpt func(*harnessOpts)

HarnessOpt is a functional option that can be used to modify the behavior of harness functionality.

func WithAMP

func WithAMP() HarnessOpt

WithAMP is a functional option that can be used to enable the AMP feature for sending payments.

type HarnessTest

type HarnessTest struct {
	*testing.T

	// Miner is a reference to a running full node that can be used to
	// create new blocks on the network.
	Miner *HarnessMiner
	// contains filtered or unexported fields
}

HarnessTest builds on top of a testing.T with enhanced error detection. It is responsible for managing the interactions among different nodes, and providing easy-to-use assertions.

func NewHarnessTest

func NewHarnessTest(t *testing.T, lndBinary string, feeService WebFeeService,
	dbBackend node.DatabaseBackend, nativeSQL bool) *HarnessTest

NewHarnessTest creates a new instance of a harnessTest from a regular testing.T instance.

func SetupHarness

func SetupHarness(t *testing.T, binaryPath, dbBackendName string,
	nativeSQL bool, feeService WebFeeService) *HarnessTest

SetupHarness creates a new HarnessTest with a series of setups such that the instance is ready for usage. The setups are, 1. create the directories to hold lnd files. 2. start a btcd miner. 3. start a chain backend(btcd, bitcoind, or neutrino). 4. connect the miner and the chain backend. 5. start the HarnessTest.

func (*HarnessTest) AssertActiveHtlcs

func (h *HarnessTest) AssertActiveHtlcs(hn *node.HarnessNode,
	payHashes ...[]byte)

AssertActiveHtlcs makes sure the node has the _exact_ HTLCs matching payHashes on _all_ their channels.

func (*HarnessTest) AssertActiveNodesSynced

func (h *HarnessTest) AssertActiveNodesSynced()

AssertActiveNodesSynced asserts all active nodes have synced to the chain.

func (*HarnessTest) AssertActiveNodesSyncedTo

func (h *HarnessTest) AssertActiveNodesSyncedTo(bestBlock *wire.MsgBlock)

AssertActiveNodesSyncedTo asserts all active nodes have synced to the provided bestBlock.

func (*HarnessTest) AssertAllTxesSpendFrom

func (h *HarnessTest) AssertAllTxesSpendFrom(txes []*wire.MsgTx,
	prevTxid chainhash.Hash)

assertAllTxesSpendFrom asserts that all txes in the list spend from the given tx.

func (*HarnessTest) AssertAmountPaid

func (h *HarnessTest) AssertAmountPaid(channelName string, hn *node.HarnessNode,
	chanPoint *lnrpc.ChannelPoint, amountSent, amountReceived int64)

AssertAmountPaid checks that the ListChannels command of the provided node list the total amount sent and received as expected for the provided channel.

func (*HarnessTest) AssertChannelActive

func (h *HarnessTest) AssertChannelActive(hn *node.HarnessNode,
	cp *lnrpc.ChannelPoint) *lnrpc.Channel

AssertChannelActive checks if a channel identified by the specified channel point is active.

func (*HarnessTest) AssertChannelBalanceResp

func (h *HarnessTest) AssertChannelBalanceResp(hn *node.HarnessNode,
	expected *lnrpc.ChannelBalanceResponse)

AssertChannelBalanceResp makes a ChannelBalance request and checks the returned response matches the expected.

func (*HarnessTest) AssertChannelCommitHeight

func (h *HarnessTest) AssertChannelCommitHeight(hn *node.HarnessNode,
	cp *lnrpc.ChannelPoint, height int)

AssertChannelCommitHeight asserts the given channel for the node has the expected commit height(`NumUpdates`).

func (*HarnessTest) AssertChannelExists

func (h *HarnessTest) AssertChannelExists(hn *node.HarnessNode,
	cp *lnrpc.ChannelPoint) *lnrpc.Channel

AssertChannelExists asserts that an active channel identified by the specified channel point exists from the point-of-view of the node.

func (*HarnessTest) AssertChannelInactive

func (h *HarnessTest) AssertChannelInactive(hn *node.HarnessNode,
	cp *lnrpc.ChannelPoint) *lnrpc.Channel

AssertChannelInactive checks if a channel identified by the specified channel point is inactive.

func (*HarnessTest) AssertChannelLocalBalance

func (h *HarnessTest) AssertChannelLocalBalance(hn *node.HarnessNode,
	cp *lnrpc.ChannelPoint, balance int64) *lnrpc.Channel

AssertChannelLocalBalance checks the local balance of the given channel is expected. The channel found using the specified channel point is returned.

func (*HarnessTest) AssertChannelNumUpdates

func (h *HarnessTest) AssertChannelNumUpdates(hn *node.HarnessNode,
	num uint64, cp *lnrpc.ChannelPoint)

AssertChannelNumUpdates checks the num of updates is expected from the given channel.

func (*HarnessTest) AssertChannelPendingForceClose

func (h *HarnessTest) AssertChannelPendingForceClose(hn *node.HarnessNode,
	chanPoint *lnrpc.ChannelPoint) PendingForceClose

AssertChannelPendingForceClose asserts that the given channel found in the node is pending force close. Returns the PendingForceClose if found.

func (*HarnessTest) AssertChannelPolicy

func (h *HarnessTest) AssertChannelPolicy(hn *node.HarnessNode,
	advertisingNode string, expectedPolicy *lnrpc.RoutingPolicy,
	chanPoint *lnrpc.ChannelPoint)

AssertChannelPolicy asserts that the passed node's known channel policy for the passed chanPoint is consistent with the expected policy values.

func (*HarnessTest) AssertChannelPolicyUpdate

func (h *HarnessTest) AssertChannelPolicyUpdate(hn *node.HarnessNode,
	advertisingNode *node.HarnessNode, policy *lnrpc.RoutingPolicy,
	chanPoint *lnrpc.ChannelPoint, includeUnannounced bool)

AssertChannelPolicyUpdate checks that the required policy update has happened on the given node.

func (*HarnessTest) AssertChannelWaitingClose

func (h *HarnessTest) AssertChannelWaitingClose(hn *node.HarnessNode,
	chanPoint *lnrpc.ChannelPoint) WaitingCloseChannel

AssertChannelWaitingClose asserts that the given channel found in the node is waiting close. Returns the WaitingCloseChannel if found.

func (*HarnessTest) AssertClosingTxInMempool

func (h *HarnessTest) AssertClosingTxInMempool(cp *lnrpc.ChannelPoint,
	c lnrpc.CommitmentType) *wire.MsgTx

AssertClosingTxInMempool assert that the closing transaction of the given channel point can be found in the mempool. If the channel has anchors, it will assert the anchor sweep tx is also in the mempool.

func (*HarnessTest) AssertConnected

func (h *HarnessTest) AssertConnected(a, b *node.HarnessNode)

AssertConnected asserts that two peers are connected.

func (*HarnessTest) AssertFeeReport

func (h *HarnessTest) AssertFeeReport(hn *node.HarnessNode,
	day, week, month int)

AssertFeeReport checks that the fee report from the given node has the desired day, week, and month sum values.

func (*HarnessTest) AssertFirstHTLCError

func (h *HarnessTest) AssertFirstHTLCError(hn *node.HarnessNode,
	code lnrpc.Failure_FailureCode)

AssertFirstHTLCError checks that the first HTLC of the last payment sent by the given node failed with the expected failure code.

func (*HarnessTest) AssertHTLCNotActive

func (h *HarnessTest) AssertHTLCNotActive(hn *node.HarnessNode,
	cp *lnrpc.ChannelPoint, payHash []byte) *lnrpc.HTLC

AssertHLTCNotActive asserts the node doesn't have a pending HTLC in the given channel, which mean either the HTLC never exists, or it was pending and now settled. Returns the HTLC if found and active.

NOTE: to check a pending HTLC becoming settled, first use AssertHLTCActive then follow this check.

func (*HarnessTest) AssertHtlcEventType

func (h *HarnessTest) AssertHtlcEventType(client rpc.HtlcEventsClient,
	userType routerrpc.HtlcEvent_EventType) *routerrpc.HtlcEvent

AssertHtlcEventType consumes one event from a client and asserts the event type is matched.

func (*HarnessTest) AssertHtlcEventTypes

func (h *HarnessTest) AssertHtlcEventTypes(client rpc.HtlcEventsClient,
	userType routerrpc.HtlcEvent_EventType,
	eventType HtlcEvent) *routerrpc.HtlcEvent

AssertHtlcEventType consumes one event from a client and asserts both the user event type the event.Event type is matched.

func (*HarnessTest) AssertHtlcEvents

func (h *HarnessTest) AssertHtlcEvents(client rpc.HtlcEventsClient,
	fwdCount, fwdFailCount, settleCount int,
	userType routerrpc.HtlcEvent_EventType) []*routerrpc.HtlcEvent

AssertHtlcEvents consumes events from a client and ensures that they are of the expected type and contain the expected number of forwards, forward failures and settles.

TODO(yy): needs refactor to reduce its complexity.

func (*HarnessTest) AssertIncomingHTLCActive

func (h *HarnessTest) AssertIncomingHTLCActive(hn *node.HarnessNode,
	cp *lnrpc.ChannelPoint, payHash []byte) *lnrpc.HTLC

AssertIncomingHTLCActive asserts the node has a pending incoming HTLC in the given channel. Returns the HTLC if found and active.

func (*HarnessTest) AssertInvoiceEqual

func (h *HarnessTest) AssertInvoiceEqual(a, b *lnrpc.Invoice)

AssertInvoiceEqual asserts that two lnrpc.Invoices are equivalent. A custom comparison function is defined for these tests, since proto message returned from unary and streaming RPCs (as of protobuf 1.23.0 and grpc 1.29.1) aren't consistent with the private fields set on the messages. As a result, we avoid using require.Equal and test only the actual data members.

func (*HarnessTest) AssertInvoiceSettled

func (h *HarnessTest) AssertInvoiceSettled(hn *node.HarnessNode, addr []byte)

AssertInvoiceSettled asserts a given invoice specified by its payment address is settled.

func (*HarnessTest) AssertInvoiceState

func (h *HarnessTest) AssertInvoiceState(stream rpc.SingleInvoiceClient,
	state lnrpc.Invoice_InvoiceState) *lnrpc.Invoice

AssertInvoiceState takes a single invoice subscription stream and asserts that a given invoice has became the desired state before timeout and returns the invoice found.

func (*HarnessTest) AssertLastHTLCError

func (h *HarnessTest) AssertLastHTLCError(hn *node.HarnessNode,
	code lnrpc.Failure_FailureCode)

AssertLastHTLCError checks that the last sent HTLC of the last payment sent by the given node failed with the expected failure code.

func (*HarnessTest) AssertNodeNumChannels

func (h *HarnessTest) AssertNodeNumChannels(hn *node.HarnessNode,
	numChannels int)

AssertNodeNumChannels polls the provided node's list channels rpc until it reaches the desired number of total channels.

func (*HarnessTest) AssertNodesNumPendingOpenChannels

func (h *HarnessTest) AssertNodesNumPendingOpenChannels(a, b *node.HarnessNode,
	expected int)

AssertNodesNumPendingOpenChannels asserts that both of the nodes have the expected number of pending open channels.

func (*HarnessTest) AssertNotConnected

func (h *HarnessTest) AssertNotConnected(a, b *node.HarnessNode)

AssertNotConnected asserts that two peers are not connected.

func (*HarnessTest) AssertNumActiveHtlcs

func (h *HarnessTest) AssertNumActiveHtlcs(hn *node.HarnessNode, num int)

AssertNumActiveHtlcs asserts that a given number of HTLCs are seen in the node's channels.

func (*HarnessTest) AssertNumChannelUpdates

func (h *HarnessTest) AssertNumChannelUpdates(hn *node.HarnessNode,
	chanPoint *lnrpc.ChannelPoint, num int)

AssertNumChannelUpdates asserts that a given number of channel updates has been seen in the specified node's network topology.

func (*HarnessTest) AssertNumEdges

func (h *HarnessTest) AssertNumEdges(hn *node.HarnessNode,
	expected int, includeUnannounced bool) []*lnrpc.ChannelEdge

AssertNumEdges checks that an expected number of edges can be found in the node specified.

func (*HarnessTest) AssertNumHTLCsAndStage

func (h *HarnessTest) AssertNumHTLCsAndStage(hn *node.HarnessNode,
	chanPoint *lnrpc.ChannelPoint, num int, stage uint32)

AssertNumHTLCsAndStage takes a pending force close channel's channel point and asserts the expected number of pending HTLCs and HTLC stage are matched.

func (*HarnessTest) AssertNumInvoices

func (h *HarnessTest) AssertNumInvoices(hn *node.HarnessNode,
	num int) []*lnrpc.Invoice

AssertNumInvoices asserts that the number of invoices made within the test scope is as expected.

func (*HarnessTest) AssertNumNodeAnns

func (h *HarnessTest) AssertNumNodeAnns(hn *node.HarnessNode,
	pubkey string, num int) []*lnrpc.NodeUpdate

AssertNumNodeAnns asserts that a given number of node announcements has been seen in the specified node.

func (*HarnessTest) AssertNumPayments

func (h *HarnessTest) AssertNumPayments(hn *node.HarnessNode,
	num int) []*lnrpc.Payment

AssertNumPayments asserts that the number of payments made within the test scope is as expected, including the incomplete ones.

func (*HarnessTest) AssertNumPendingForceClose

func (h *HarnessTest) AssertNumPendingForceClose(hn *node.HarnessNode,
	num int) []*lnrpc.PendingChannelsResponse_ForceClosedChannel

AssertNumPendingForceClose checks that a PendingChannels response from the node reports the expected number of pending force close channels.

func (*HarnessTest) AssertNumPendingOpenChannels

func (h *HarnessTest) AssertNumPendingOpenChannels(hn *node.HarnessNode,
	expected int) []*lnrpc.PendingChannelsResponse_PendingOpenChannel

AssertNumPendingOpenChannels asserts that a given node have the expected number of pending open channels.

func (*HarnessTest) AssertNumPendingSweeps

func (h *HarnessTest) AssertNumPendingSweeps(hn *node.HarnessNode,
	n int) []*walletrpc.PendingSweep

AssertNumPendingSweeps asserts the number of pending sweeps for the given node.

func (*HarnessTest) AssertNumPolicyUpdates

func (h *HarnessTest) AssertNumPolicyUpdates(hn *node.HarnessNode,
	chanPoint *lnrpc.ChannelPoint,
	advertisingNode *node.HarnessNode, num int)

AssertNumPolicyUpdates asserts that a given number of channel policy updates has been seen in the specified node.

func (*HarnessTest) AssertNumUTXOs

func (h *HarnessTest) AssertNumUTXOs(hn *node.HarnessNode,
	num int) []*lnrpc.Utxo

AssertNumUTXOs asserts the expected num of utxos are seen, including confirmed and unconfirmed outputs.

NOTE: for standby nodes(Alice and Bob), this method takes account of the previous state of the node's UTXOs. Check `AssertNumUTXOsWithConf` for details.

func (*HarnessTest) AssertNumUTXOsConfirmed

func (h *HarnessTest) AssertNumUTXOsConfirmed(hn *node.HarnessNode,
	num int) []*lnrpc.Utxo

AssertNumUTXOsConfirmed asserts the expected num of confirmed utxos are seen, which means the returned utxos have at least one confirmation.

NOTE: for standby nodes(Alice and Bob), this method takes account of the previous state of the node's UTXOs. Check `AssertNumUTXOsWithConf` for details.

func (*HarnessTest) AssertNumUTXOsUnconfirmed

func (h *HarnessTest) AssertNumUTXOsUnconfirmed(hn *node.HarnessNode,
	num int) []*lnrpc.Utxo

AssertNumUTXOsUnconfirmed asserts the expected num of unconfirmed utxos are seen.

NOTE: for standby nodes(Alice and Bob), this method takes account of the previous state of the node's UTXOs. Check `AssertNumUTXOsWithConf` for details.

func (*HarnessTest) AssertNumUTXOsWithConf

func (h *HarnessTest) AssertNumUTXOsWithConf(hn *node.HarnessNode,
	expectedUtxos int, max, min int32) []*lnrpc.Utxo

AssertNumUTXOsWithConf waits for the given number of UTXOs with the specified confirmations range to be available or fails if that isn't the case before the default timeout.

NOTE: for standby nodes(Alice and Bob), this method takes account of the previous state of the node's UTXOs. The previous state is snapshotted when finishing a previous test case via the cleanup function in `Subtest`. In other words, this assertion only checks the new changes made in the current test.

func (*HarnessTest) AssertNumWaitingClose

func (h *HarnessTest) AssertNumWaitingClose(hn *node.HarnessNode,
	num int) []*lnrpc.PendingChannelsResponse_WaitingCloseChannel

AssertNumWaitingClose checks that a PendingChannels response from the node reports the expected number of waiting close channels.

func (*HarnessTest) AssertOutgoingHTLCActive

func (h *HarnessTest) AssertOutgoingHTLCActive(hn *node.HarnessNode,
	cp *lnrpc.ChannelPoint, payHash []byte) *lnrpc.HTLC

AssertOutgoingHTLCActive asserts the node has a pending outgoing HTLC in the given channel. Returns the HTLC if found and active.

func (*HarnessTest) AssertOutputScriptClass

func (h *HarnessTest) AssertOutputScriptClass(tx *btcutil.Tx,
	outputIndex uint32, scriptClass txscript.ScriptClass)

AssertOutputScriptClass checks that the specified transaction output has the expected script class.

func (*HarnessTest) AssertPaymentStatus

func (h *HarnessTest) AssertPaymentStatus(hn *node.HarnessNode,
	preimage lntypes.Preimage,
	status lnrpc.Payment_PaymentStatus) *lnrpc.Payment

AssertPaymentStatus asserts that the given node list a payment with the given preimage has the expected status. It also checks that the payment has the expected preimage, which is empty when it's not settled and matches the given preimage when it's succeeded.

func (*HarnessTest) AssertPaymentStatusFromStream

func (h *HarnessTest) AssertPaymentStatusFromStream(stream rpc.PaymentClient,
	status lnrpc.Payment_PaymentStatus) *lnrpc.Payment

AssertPaymentStatusFromStream takes a client stream and asserts the payment is in desired status before default timeout. The payment found is returned once succeeded.

func (*HarnessTest) AssertPaymentSucceedWithTimeout

func (h *HarnessTest) AssertPaymentSucceedWithTimeout(stream rpc.PaymentClient,
	timeout time.Duration) *lnrpc.Payment

AssertPaymentSucceedWithTimeout asserts that a payment is succeeded within the specified timeout.

func (*HarnessTest) AssertPeerConnected

func (h *HarnessTest) AssertPeerConnected(a, b *node.HarnessNode)

AssertPeerConnected asserts that the given node b is connected to a.

func (*HarnessTest) AssertPeerNotConnected

func (h *HarnessTest) AssertPeerNotConnected(a, b *node.HarnessNode)

AssertPeerNotConnected asserts that the given node b is not connected to a.

func (*HarnessTest) AssertStreamChannelCoopClosed

func (h *HarnessTest) AssertStreamChannelCoopClosed(hn *node.HarnessNode,
	cp *lnrpc.ChannelPoint, anchors bool,
	stream rpc.CloseChanClient) *chainhash.Hash

AssertStreamChannelCoopClosed reads an update from the close channel client stream and asserts that the mempool state and node's topology match a coop close. In specific, - assert the channel is waiting close and has the expected ChanStatusFlags. - assert the mempool has the closing txes and anchor sweeps. - mine a block and assert the closing txid is mined. - assert the node has zero waiting close channels. - assert the node has seen the channel close update.

func (*HarnessTest) AssertStreamChannelForceClosed

func (h *HarnessTest) AssertStreamChannelForceClosed(hn *node.HarnessNode,
	cp *lnrpc.ChannelPoint, anchorSweep bool,
	stream rpc.CloseChanClient) *chainhash.Hash

AssertStreamChannelForceClosed reads an update from the close channel client stream and asserts that the mempool state and node's topology match a local force close. In specific,

  • assert the channel is waiting close and has the expected ChanStatusFlags.
  • assert the mempool has the closing txes.
  • mine a block and assert the closing txid is mined.
  • assert the channel is pending force close.
  • assert the node has seen the channel close update.
  • assert there's a pending anchor sweep request once the force close tx is confirmed.

func (*HarnessTest) AssertSweepFound

func (h *HarnessTest) AssertSweepFound(hn *node.HarnessNode,
	sweep string, verbose bool, startHeight int32)

AssertSweepFound looks up a sweep in a nodes list of broadcast sweeps and asserts it's found.

NOTE: Does not account for node's internal state.

func (*HarnessTest) AssertTopologyChannelClosed

func (h *HarnessTest) AssertTopologyChannelClosed(hn *node.HarnessNode,
	chanPoint *lnrpc.ChannelPoint) *lnrpc.ClosedChannelUpdate

AssertTopologyChannelClosed asserts a given channel is closed by checking the graph topology subscription of the specified node. Returns the closed channel update if found.

func (*HarnessTest) AssertTopologyChannelOpen

func (h *HarnessTest) AssertTopologyChannelOpen(hn *node.HarnessNode,
	chanPoint *lnrpc.ChannelPoint)

AssertTopologyChannelOpen asserts that a given channel outpoint is seen by the passed node's network topology.

func (*HarnessTest) AssertTransactionInWallet

func (h *HarnessTest) AssertTransactionInWallet(hn *node.HarnessNode,
	txid chainhash.Hash)

AssertTransactionInWallet asserts a given txid can be found in the node's wallet.

func (*HarnessTest) AssertTransactionNotInWallet

func (h *HarnessTest) AssertTransactionNotInWallet(hn *node.HarnessNode,
	txid chainhash.Hash)

AssertTransactionNotInWallet asserts a given txid can NOT be found in the node's wallet.

func (*HarnessTest) AssertTxAtHeight

func (h *HarnessTest) AssertTxAtHeight(hn *node.HarnessNode, height int32,
	txid *chainhash.Hash) *lnrpc.Transaction

AssertTxAtHeight gets all of the transactions that a node's wallet has a record of at the target height, and finds and returns the tx with the target txid, failing if it is not found.

func (*HarnessTest) AssertTxSpendFrom

func (h *HarnessTest) AssertTxSpendFrom(tx *wire.MsgTx,
	prevTxid chainhash.Hash)

AssertTxSpendFrom asserts that a given tx is spent from a previous tx.

func (*HarnessTest) AssertUTXOInWallet

func (h *HarnessTest) AssertUTXOInWallet(hn *node.HarnessNode,
	op *lnrpc.OutPoint, account string)

AssertUTXOInWallet asserts that a given UTXO can be found in the node's wallet.

func (*HarnessTest) AssertWalletAccountBalance

func (h *HarnessTest) AssertWalletAccountBalance(hn *node.HarnessNode,
	account string, confirmedBalance, unconfirmedBalance int64)

AssertWalletAccountBalance asserts that the unconfirmed and confirmed balance for the given account is satisfied by the WalletBalance and ListUnspent RPCs. The unconfirmed balance is not checked for neutrino nodes.

func (*HarnessTest) AssertWalletLockedBalance

func (h *HarnessTest) AssertWalletLockedBalance(hn *node.HarnessNode,
	balance int64)

AssertWalletLockedBalance asserts the expected amount has been marked as locked in the node's WalletBalance response.

func (*HarnessTest) AssertZombieChannel

func (h *HarnessTest) AssertZombieChannel(hn *node.HarnessNode, chanID uint64)

AssertZombieChannel asserts that a given channel found using the chanID is marked as zombie.

func (*HarnessTest) BackupDB

func (h *HarnessTest) BackupDB(hn *node.HarnessNode)

BackupDB creates a backup of the current database. It will stop the node first, copy the database files, and restart the node.

func (*HarnessTest) CalculateTxFee

func (h *HarnessTest) CalculateTxFee(tx *wire.MsgTx) btcutil.Amount

CalculateTxFee retrieves parent transactions and reconstructs the fee paid.

func (*HarnessTest) CalculateTxFeeRate

func (h *HarnessTest) CalculateTxFeeRate(
	tx *wire.MsgTx) chainfee.SatPerKWeight

CalculateTxFeeRate calculates the fee rate for a given tx.

func (*HarnessTest) CalculateTxWeight

func (h *HarnessTest) CalculateTxWeight(tx *wire.MsgTx) lntypes.WeightUnit

CalculateTxWeight calculates the weight for a given tx.

TODO(yy): use weight estimator to get more accurate result.

func (*HarnessTest) CalculateTxesFeeRate

func (h *HarnessTest) CalculateTxesFeeRate(txns []*wire.MsgTx) int64

CalculateTxesFeeRate takes a list of transactions and estimates the fee rate used to sweep them.

NOTE: only used in current test file.

func (*HarnessTest) ChainBackendName

func (h *HarnessTest) ChainBackendName() string

ChainBackendName returns the chain backend name used in the test.

func (*HarnessTest) CleanShutDown

func (h *HarnessTest) CleanShutDown()

CleanShutDown is used to quickly end a test by shutting down all non-standby nodes and mining blocks to empty the mempool.

NOTE: this method provides a faster exit for a test that involves force closures as the caller doesn't need to mine all the blocks to make sure the mempool is empty.

func (*HarnessTest) CleanupForceClose

func (h *HarnessTest) CleanupForceClose(hn *node.HarnessNode)

CleanupForceClose mines a force close commitment found in the mempool and the following sweep transaction from the force closing node.

func (*HarnessTest) CloseChannel

func (h *HarnessTest) CloseChannel(hn *node.HarnessNode,
	cp *lnrpc.ChannelPoint) *chainhash.Hash

CloseChannel attempts to coop close a non-anchored channel identified by the passed channel point owned by the passed harness node. The following items are asserted,

  1. a close pending event is sent from the close channel client.
  2. the closing tx is found in the mempool.
  3. the node reports the channel being waiting to close.
  4. a block is mined and the closing tx should be found in it.
  5. the node reports zero waiting close channels.
  6. the node receives a topology update regarding the channel close.

func (*HarnessTest) CloseChannelAssertErr

func (h *HarnessTest) CloseChannelAssertErr(hn *node.HarnessNode,
	cp *lnrpc.ChannelPoint, force bool) error

CloseChannelAssertErr closes the given channel and asserts an error returned.

func (*HarnessTest) CloseChannelAssertPending

func (h *HarnessTest) CloseChannelAssertPending(hn *node.HarnessNode,
	cp *lnrpc.ChannelPoint,
	force bool) (rpc.CloseChanClient, *chainhash.Hash)

CloseChannelAssertPending attempts to close the channel indicated by the passed channel point, initiated by the passed node. Once the CloseChannel rpc is called, it will consume one event and assert it's a close pending event. In addition, it will check that the closing tx can be found in the mempool.

func (*HarnessTest) CompletePaymentRequests

func (h *HarnessTest) CompletePaymentRequests(hn *node.HarnessNode,
	paymentRequests []string, opts ...HarnessOpt)

CompletePaymentRequests sends payments from a node to complete all payment requests. This function does not return until all payments successfully complete without errors.

func (*HarnessTest) CompletePaymentRequestsNoWait

func (h *HarnessTest) CompletePaymentRequestsNoWait(hn *node.HarnessNode,
	paymentRequests []string, chanPoint *lnrpc.ChannelPoint)

CompletePaymentRequestsNoWait sends payments from a node to complete all payment requests without waiting for the results. Instead, it checks the number of updates in the specified channel has increased.

func (*HarnessTest) ConnectMiner

func (h *HarnessTest) ConnectMiner()

ConnectMiner connects the miner with the chain backend in the network.

func (*HarnessTest) ConnectNodes

func (h *HarnessTest) ConnectNodes(a, b *node.HarnessNode)

ConnectNodes creates a connection between the two nodes and asserts the connection is succeeded.

func (*HarnessTest) ConnectNodesPerm

func (h *HarnessTest) ConnectNodesPerm(a, b *node.HarnessNode)

ConnectNodesPerm creates a persistent connection between the two nodes and asserts the connection is succeeded.

func (*HarnessTest) Context

func (h *HarnessTest) Context() context.Context

Context returns the run context used in this test. Usaually it should be managed by the test itself otherwise undefined behaviors will occur. It can be used, however, when a test needs to have its own context being managed differently. In that case, instead of using a background context, the run context should be used such that the test context scope can be fully controlled.

func (*HarnessTest) CreateBurnAddr

func (h *HarnessTest) CreateBurnAddr(addrType lnrpc.AddressType) ([]byte,
	btcutil.Address)

CreateBurnAddr creates a random burn address of the given type.

func (*HarnessTest) CreatePayReqs

func (h *HarnessTest) CreatePayReqs(hn *node.HarnessNode,
	paymentAmt btcutil.Amount, numInvoices int,
	routeHints ...*lnrpc.RouteHint) ([]string, [][]byte, []*lnrpc.Invoice)

CreatePayReqs is a helper method that will create a slice of payment requests for the given node.

func (*HarnessTest) DecodeAddress

func (h *HarnessTest) DecodeAddress(addr string) btcutil.Address

DecodeAddress decodes a given address and asserts there's no error.

func (*HarnessTest) DisconnectMiner

func (h *HarnessTest) DisconnectMiner()

DisconnectMiner removes the connection between the miner and the chain backend in the network.

func (*HarnessTest) DisconnectNodes

func (h *HarnessTest) DisconnectNodes(a, b *node.HarnessNode)

DisconnectNodes disconnects the given two nodes and asserts the disconnection is succeeded. The request is made from node a and sent to node b.

func (*HarnessTest) EnsureConnected

func (h *HarnessTest) EnsureConnected(a, b *node.HarnessNode)

EnsureConnected will try to connect to two nodes, returning no error if they are already connected. If the nodes were not connected previously, this will behave the same as ConnectNodes. If a pending connection request has already been made, the method will block until the two nodes appear in each other's peers list, or until the DefaultTimeout expires.

func (*HarnessTest) FindSweepingTxns

func (h *HarnessTest) FindSweepingTxns(txns []*wire.MsgTx,
	expectedNumSweeps int, closeTxid chainhash.Hash) []*wire.MsgTx

FindSweepingTxns asserts the expected number of sweeping txns are found in the txns specified and return them.

func (*HarnessTest) ForceCloseChannel

func (h *HarnessTest) ForceCloseChannel(hn *node.HarnessNode,
	cp *lnrpc.ChannelPoint) *chainhash.Hash

ForceCloseChannel attempts to force close a non-anchored channel identified by the passed channel point owned by the passed harness node. The following items are asserted,

  1. a close pending event is sent from the close channel client.
  2. the closing tx is found in the mempool.
  3. the node reports the channel being waiting to close.
  4. a block is mined and the closing tx should be found in it.
  5. the node reports zero waiting close channels.
  6. the node receives a topology update regarding the channel close.
  7. mine DefaultCSV-1 blocks.
  8. the node reports zero pending force close channels.

func (*HarnessTest) FundCoins

func (h *HarnessTest) FundCoins(amt btcutil.Amount, hn *node.HarnessNode)

FundCoins attempts to send amt satoshis from the internal mining node to the targeted lightning node using a P2WKH address. 2 blocks are mined after in order to confirm the transaction.

func (*HarnessTest) FundCoinsNP2WKH

func (h *HarnessTest) FundCoinsNP2WKH(amt btcutil.Amount,
	target *node.HarnessNode)

FundCoinsNP2WKH attempts to send amt satoshis from the internal mining node to the targeted lightning node using a NP2WKH address.

func (*HarnessTest) FundCoinsP2TR

func (h *HarnessTest) FundCoinsP2TR(amt btcutil.Amount,
	target *node.HarnessNode)

FundCoinsP2TR attempts to send amt satoshis from the internal mining node to the targeted lightning node using a P2TR address.

func (*HarnessTest) FundCoinsUnconfirmed

func (h *HarnessTest) FundCoinsUnconfirmed(amt btcutil.Amount,
	hn *node.HarnessNode)

FundCoinsUnconfirmed attempts to send amt satoshis from the internal mining node to the targeted lightning node using a P2WKH address. No blocks are mined after and the UTXOs are unconfirmed.

func (*HarnessTest) GetChanPointFundingTxid

func (h *HarnessTest) GetChanPointFundingTxid(
	cp *lnrpc.ChannelPoint) *chainhash.Hash

GetChanPointFundingTxid takes a channel point and converts it into a chain hash.

func (*HarnessTest) GetChannelByChanPoint

func (h *HarnessTest) GetChannelByChanPoint(hn *node.HarnessNode,
	chanPoint *lnrpc.ChannelPoint) *lnrpc.Channel

GetChannelByChanPoint tries to find a channel matching the channel point and asserts. It returns the channel found.

func (*HarnessTest) GetChannelCommitType

func (h *HarnessTest) GetChannelCommitType(hn *node.HarnessNode,
	chanPoint *lnrpc.ChannelPoint) lnrpc.CommitmentType

GetChannelCommitType retrieves the active channel commitment type for the given chan point.

func (*HarnessTest) GetOutputIndex

func (h *HarnessTest) GetOutputIndex(txid *chainhash.Hash, addr string) int

GetOutputIndex returns the output index of the given address in the given transaction.

func (*HarnessTest) GetUTXOs

func (h *HarnessTest) GetUTXOs(hn *node.HarnessNode,
	account string) []*lnrpc.Utxo

GetUTXOs returns all the UTXOs for the given node's account, including confirmed and unconfirmed.

func (*HarnessTest) GetUTXOsConfirmed

func (h *HarnessTest) GetUTXOsConfirmed(hn *node.HarnessNode,
	account string) []*lnrpc.Utxo

GetUTXOsConfirmed returns the confirmed UTXOs for the given node's account.

func (*HarnessTest) GetUTXOsUnconfirmed

func (h *HarnessTest) GetUTXOsUnconfirmed(hn *node.HarnessNode,
	account string) []*lnrpc.Utxo

GetUTXOsUnconfirmed returns the unconfirmed UTXOs for the given node's account.

func (*HarnessTest) IsNeutrinoBackend

func (h *HarnessTest) IsNeutrinoBackend() bool

IsNeutrinoBackend returns a bool indicating whether the node is using a neutrino as its backend. This is useful when we want to skip certain tests which cannot be done with a neutrino backend.

func (*HarnessTest) KillNode

func (h *HarnessTest) KillNode(hn *node.HarnessNode)

KillNode kills the node (but won't wait for the node process to stop).

func (*HarnessTest) MineBlocks

func (h *HarnessTest) MineBlocks(num uint32) []*wire.MsgBlock

MineBlocks mines blocks and asserts all active nodes have synced to the chain.

NOTE: this differs from miner's `MineBlocks` as it requires the nodes to be synced.

func (*HarnessTest) MineBlocksAndAssertNumTxes

func (h *HarnessTest) MineBlocksAndAssertNumTxes(num uint32,
	numTxs int) []*wire.MsgBlock

MineBlocksAndAssertNumTxes mines blocks and asserts the number of transactions are found in the first block. It also asserts all active nodes have synced to the chain.

NOTE: this differs from miner's `MineBlocks` as it requires the nodes to be synced.

TODO(yy): change the APIs to force callers to think about blocks and txns: - MineBlocksAndAssertNumTxes -> MineBlocks - add more APIs to mine a single tx.

func (*HarnessTest) MineClosingTx

func (h *HarnessTest) MineClosingTx(cp *lnrpc.ChannelPoint) *wire.MsgTx

AssertClosingTxInMempool assert that the closing transaction of the given channel point can be found in the mempool. If the channel has anchors, it will assert the anchor sweep tx is also in the mempool.

func (*HarnessTest) MineEmptyBlocks

func (h *HarnessTest) MineEmptyBlocks(num int) []*wire.MsgBlock

MineEmptyBlocks mines a given number of empty blocks.

NOTE: this differs from miner's `MineEmptyBlocks` as it requires the nodes to be synced.

func (*HarnessTest) NewNode

func (h *HarnessTest) NewNode(name string,
	extraArgs []string) *node.HarnessNode

NewNode creates a new node and asserts its creation. The node is guaranteed to have finished its initialization and all its subservers are started.

func (*HarnessTest) NewNodeEtcd

func (h *HarnessTest) NewNodeEtcd(name string, etcdCfg *etcd.Config,
	password []byte, cluster bool,
	leaderSessionTTL int) *node.HarnessNode

NewNodeEtcd starts a new node with seed that'll use an external etcd database as its storage. The passed cluster flag indicates that we'd like the node to join the cluster leader election. We won't wait until RPC is available (this is useful when the node is not expected to become the leader right away).

func (*HarnessTest) NewNodeRemoteSigner

func (h *HarnessTest) NewNodeRemoteSigner(name string, extraArgs []string,
	password []byte, watchOnly *lnrpc.WatchOnly) *node.HarnessNode

NewNodeRemoteSigner creates a new remote signer node and asserts its creation.

func (*HarnessTest) NewNodeWithSeed

func (h *HarnessTest) NewNodeWithSeed(name string,
	extraArgs []string, password []byte,
	statelessInit bool) (*node.HarnessNode, []string, []byte)

NewNodeWithSeed fully initializes a new HarnessNode after creating a fresh aezeed. The provided password is used as both the aezeed password and the wallet password. The generated mnemonic is returned along with the initialized harness node.

func (*HarnessTest) NewNodeWithSeedEtcd

func (h *HarnessTest) NewNodeWithSeedEtcd(name string, etcdCfg *etcd.Config,
	password []byte, statelessInit, cluster bool,
	leaderSessionTTL int) (*node.HarnessNode, []string, []byte)

NewNodeWithSeedEtcd starts a new node with seed that'll use an external etcd database as its storage. The passed cluster flag indicates that we'd like the node to join the cluster leader election.

func (*HarnessTest) OpenChannel

func (h *HarnessTest) OpenChannel(alice, bob *node.HarnessNode,
	p OpenChannelParams) *lnrpc.ChannelPoint

OpenChannel attempts to open a channel with the specified parameters extended from Alice to Bob. Additionally, for public channels, it will mine extra blocks so they are announced to the network. In specific, the following items are asserted,

  • for non-zero conf channel, 1 blocks will be mined to confirm the funding tx.
  • both nodes should see the channel edge update in their network graph.
  • both nodes can report the status of the new channel from ListChannels.
  • extra blocks are mined if it's a public channel.

func (*HarnessTest) OpenChannelAssertErr

func (h *HarnessTest) OpenChannelAssertErr(srcNode, destNode *node.HarnessNode,
	p OpenChannelParams, expectedErr error)

OpenChannelAssertErr opens a channel between node srcNode and destNode, asserts that the expected error is returned from the channel opening.

func (*HarnessTest) OpenChannelAssertPending

func (h *HarnessTest) OpenChannelAssertPending(srcNode,
	destNode *node.HarnessNode, p OpenChannelParams) *lnrpc.PendingUpdate

OpenChannelAssertPending attempts to open a channel between srcNode and destNode with the passed channel funding parameters. Once the `OpenChannel` is called, it will consume the first event it receives from the open channel client and asserts it's a channel pending event. It returns the `PendingUpdate`.

func (*HarnessTest) OpenChannelAssertStream

func (h *HarnessTest) OpenChannelAssertStream(srcNode,
	destNode *node.HarnessNode, p OpenChannelParams) rpc.OpenChanClient

OpenChannelAssertStream attempts to open a channel between srcNode and destNode with the passed channel funding parameters. Once the `OpenChannel` is called, it will consume the first event it receives from the open channel client and asserts it's a channel pending event. It returns the open channel stream.

func (*HarnessTest) OpenChannelNoAnnounce

func (h *HarnessTest) OpenChannelNoAnnounce(alice, bob *node.HarnessNode,
	p OpenChannelParams) *lnrpc.ChannelPoint

OpenChannelNoAnnounce attempts to open a channel with the specified parameters extended from Alice to Bob without mining the necessary blocks to announce the channel. Additionally, the following items are asserted,

  • for non-zero conf channel, 1 blocks will be mined to confirm the funding tx.
  • both nodes should see the channel edge update in their network graph.
  • both nodes can report the status of the new channel from ListChannels.

func (*HarnessTest) OpenChannelPsbt

func (h *HarnessTest) OpenChannelPsbt(srcNode, destNode *node.HarnessNode,
	p OpenChannelParams) (rpc.OpenChanClient, []byte)

OpenChannelPsbt attempts to open a channel between srcNode and destNode with the passed channel funding parameters. It will assert if the expected step of funding the PSBT is not received from the source node.

func (*HarnessTest) OpenMultiChannelsAsync

func (h *HarnessTest) OpenMultiChannelsAsync(
	reqs []*OpenChannelRequest) []*lnrpc.ChannelPoint

OpenMultiChannelsAsync takes a list of OpenChannelRequest and opens them in batch. The channel points are returned in same the order of the requests once all of the channel open succeeded.

NOTE: compared to open multiple channel sequentially, this method will be faster as it doesn't need to mine 6 blocks for each channel open. However, it does make debugging the logs more difficult as messages are intertwined.

func (*HarnessTest) OutPointFromChannelPoint

func (h *HarnessTest) OutPointFromChannelPoint(
	cp *lnrpc.ChannelPoint) wire.OutPoint

OutPointFromChannelPoint creates an outpoint from a given channel point.

func (*HarnessTest) PayToAddrScript

func (h *HarnessTest) PayToAddrScript(addr btcutil.Address) []byte

PayToAddrScript creates a new script from the given address and asserts there's no error.

func (*HarnessTest) QueryChannelByChanPoint

func (h *HarnessTest) QueryChannelByChanPoint(hn *node.HarnessNode,
	chanPoint *lnrpc.ChannelPoint,
	opts ...ListChannelOption) *lnrpc.Channel

QueryChannelByChanPoint tries to find a channel matching the channel point and asserts. It returns the channel found.

func (*HarnessTest) QueryRoutesAndRetry

func (h *HarnessTest) QueryRoutesAndRetry(hn *node.HarnessNode,
	req *lnrpc.QueryRoutesRequest) *lnrpc.QueryRoutesResponse

QueryRoutesAndRetry attempts to keep querying a route until timeout is reached.

NOTE: when a channel is opened, we may need to query multiple times to get it in our QueryRoutes RPC. This happens even after we check the channel is heard by the node using ht.AssertChannelOpen. Deep down, this is because our GraphTopologySubscription and QueryRoutes give different results regarding a specific channel, with the formal reporting it being open while the latter not, resulting GraphTopologySubscription acting "faster" than QueryRoutes. TODO(yy): make sure related subsystems share the same view on a given channel.

func (*HarnessTest) Random32Bytes

func (h *HarnessTest) Random32Bytes() []byte

Random32Bytes generates a random 32 bytes which can be used as a pay hash, preimage, etc.

func (*HarnessTest) RandomPreimage

func (h *HarnessTest) RandomPreimage() lntypes.Preimage

RandomPreimage generates a random preimage which can be used as a payment preimage.

func (*HarnessTest) ReceiveChannelEvent

func (h *HarnessTest) ReceiveChannelEvent(
	stream rpc.ChannelEventsClient) *lnrpc.ChannelEventUpdate

ReceiveChannelEvent waits until a message is received from the ChannelEventsClient stream or the timeout is reached.

func (*HarnessTest) ReceiveCloseChannelUpdate

func (h *HarnessTest) ReceiveCloseChannelUpdate(
	stream rpc.CloseChanClient) (*lnrpc.CloseStatusUpdate, error)

ReceiveCloseChannelUpdate waits until a message or an error is received on the subscribe channel close stream or the timeout is reached.

func (*HarnessTest) ReceiveHtlcEvent

func (h *HarnessTest) ReceiveHtlcEvent(
	stream rpc.HtlcEventsClient) *routerrpc.HtlcEvent

ReceiveHtlcEvent waits until a message is received on the subscribe htlc event stream or the timeout is reached.

func (*HarnessTest) ReceiveHtlcInterceptor

func (h *HarnessTest) ReceiveHtlcInterceptor(
	stream rpc.InterceptorClient) *routerrpc.ForwardHtlcInterceptRequest

ReceiveHtlcInterceptor waits until a message is received on the htlc interceptor stream or the timeout is reached.

func (*HarnessTest) ReceiveInvoiceUpdate

func (h *HarnessTest) ReceiveInvoiceUpdate(
	stream rpc.InvoiceUpdateClient) *lnrpc.Invoice

ReceiveInvoiceUpdate waits until a message is received on the subscribe invoice stream or the timeout is reached.

func (*HarnessTest) ReceiveOpenChannelError

func (h *HarnessTest) ReceiveOpenChannelError(
	stream rpc.OpenChanClient, expectedErr error)

ReceiveOpenChannelError waits for the expected error during the open channel flow from the peer or times out.

func (*HarnessTest) ReceiveOpenChannelUpdate

func (h *HarnessTest) ReceiveOpenChannelUpdate(
	stream rpc.OpenChanClient) *lnrpc.OpenStatusUpdate

ReceiveOpenChannelUpdate waits until a message is received on the stream or the timeout is reached.

func (*HarnessTest) ReceivePaymentUpdate

func (h *HarnessTest) ReceivePaymentUpdate(
	stream rpc.PaymentClient) (*lnrpc.Payment, error)

ReceivePaymentUpdate waits until a message is received on the payment client stream or the timeout is reached.

func (*HarnessTest) ReceiveSendToRouteUpdate

func (h *HarnessTest) ReceiveSendToRouteUpdate(
	stream rpc.SendToRouteClient) (*lnrpc.SendResponse, error)

ReceiveSendToRouteUpdate waits until a message is received on the SendToRoute client stream or the timeout is reached.

func (*HarnessTest) ReceiveSingleInvoice

func (h *HarnessTest) ReceiveSingleInvoice(
	stream rpc.SingleInvoiceClient) *lnrpc.Invoice

ReceiveSingleInvoice waits until a message is received on the subscribe single invoice stream or the timeout is reached.

func (*HarnessTest) ReceiveTrackPayment

func (h *HarnessTest) ReceiveTrackPayment(
	stream rpc.TrackPaymentClient) *lnrpc.Payment

ReceiveTrackPayment waits until a message is received on the track payment stream or the timeout is reached.

func (*HarnessTest) RestartNode

func (h *HarnessTest) RestartNode(hn *node.HarnessNode)

RestartNode restarts a given node, unlocks it and asserts it's successfully started.

func (*HarnessTest) RestartNodeAndRestoreDB

func (h *HarnessTest) RestartNodeAndRestoreDB(hn *node.HarnessNode)

RestartNodeAndRestoreDB restarts a given node with a callback to restore the db.

func (*HarnessTest) RestartNodeNoUnlock

func (h *HarnessTest) RestartNodeNoUnlock(hn *node.HarnessNode)

RestartNodeNoUnlock restarts a given node without unlocking its wallet.

func (*HarnessTest) RestartNodeWithChanBackups

func (h *HarnessTest) RestartNodeWithChanBackups(hn *node.HarnessNode,
	chanBackups ...*lnrpc.ChanBackupSnapshot)

RestartNodeWithChanBackups restarts a given node with the specified channel backups.

func (*HarnessTest) RestartNodeWithExtraArgs

func (h *HarnessTest) RestartNodeWithExtraArgs(hn *node.HarnessNode,
	extraArgs []string)

RestartNodeWithExtraArgs updates the node's config and restarts it.

func (*HarnessTest) RestoreNodeWithSeed

func (h *HarnessTest) RestoreNodeWithSeed(name string, extraArgs []string,
	password []byte, mnemonic []string, rootKey string,
	recoveryWindow int32,
	chanBackups *lnrpc.ChanBackupSnapshot) *node.HarnessNode

RestoreNodeWithSeed fully initializes a HarnessNode using a chosen mnemonic, password, recovery window, and optionally a set of static channel backups. After providing the initialization request to unlock the node, this method will finish initializing the LightningClient such that the HarnessNode can be used for regular rpc operations.

func (*HarnessTest) RunTestCase

func (h *HarnessTest) RunTestCase(testCase *TestCase)

RunTestCase executes a harness test case. Any errors or panics will be represented as fatal.

func (*HarnessTest) SendCoins

func (h *HarnessTest) SendCoins(a, b *node.HarnessNode,
	amt btcutil.Amount) *wire.MsgTx

SendCoins sends a coin from node A to node B with the given amount, returns the sending tx.

func (*HarnessTest) SendPaymentAndAssertStatus

func (h *HarnessTest) SendPaymentAndAssertStatus(hn *node.HarnessNode,
	req *routerrpc.SendPaymentRequest,
	status lnrpc.Payment_PaymentStatus) *lnrpc.Payment

SendPaymentAndAssertStatus sends a payment from the passed node and asserts the desired status is reached.

func (*HarnessTest) SendPaymentAssertFail

func (h *HarnessTest) SendPaymentAssertFail(hn *node.HarnessNode,
	req *routerrpc.SendPaymentRequest,
	reason lnrpc.PaymentFailureReason) *lnrpc.Payment

SendPaymentAssertFail sends a payment from the passed node and asserts the payment is failed with the specified failure reason .

func (*HarnessTest) SendPaymentAssertSettled

func (h *HarnessTest) SendPaymentAssertSettled(hn *node.HarnessNode,
	req *routerrpc.SendPaymentRequest) *lnrpc.Payment

SendPaymentAssertSettled sends a payment from the passed node and asserts the payment is settled.

func (*HarnessTest) SetFeeEstimate

func (h *HarnessTest) SetFeeEstimate(fee chainfee.SatPerKWeight)

SetFeeEstimate sets a fee rate to be returned from fee estimator.

NOTE: this method will set the fee rate for a conf target of 1, which is the fallback fee rate for a `WebAPIEstimator` if a higher conf target's fee rate is not set. This means if the fee rate for conf target 6 is set, the fee estimator will use that value instead.

func (*HarnessTest) SetFeeEstimateWithConf

func (h *HarnessTest) SetFeeEstimateWithConf(
	fee chainfee.SatPerKWeight, conf uint32)

SetFeeEstimateWithConf sets a fee rate of a specified conf target to be returned from fee estimator.

func (*HarnessTest) SetTestName

func (h *HarnessTest) SetTestName(name string)

SetTestName set the test case name.

func (*HarnessTest) SetupRemoteSigningStandbyNodes

func (h *HarnessTest) SetupRemoteSigningStandbyNodes()

SetupRemoteSigningStandbyNodes starts the initial seeder nodes within the test harness in a remote signing configuration. The initial node's wallets will be funded wallets with 100x1 BTC outputs each.

func (*HarnessTest) SetupStandbyNodes

func (h *HarnessTest) SetupStandbyNodes()

SetUp starts the initial seeder nodes within the test harness. The initial node's wallets will be funded wallets with 10x10 BTC outputs each.

func (*HarnessTest) Shutdown

func (h *HarnessTest) Shutdown(node *node.HarnessNode)

Shutdown shuts down the given node and asserts that no errors occur.

func (*HarnessTest) Start

func (h *HarnessTest) Start(chain node.BackendConfig, miner *HarnessMiner)

Start will assemble the chain backend and the miner for the HarnessTest. It also starts the fee service and watches lnd process error.

func (*HarnessTest) Stop

func (h *HarnessTest) Stop()

Stop stops the test harness.

func (*HarnessTest) Subtest

func (h *HarnessTest) Subtest(t *testing.T) *HarnessTest

Subtest creates a child HarnessTest, which inherits the harness net and stand by nodes created by the parent test. It will return a cleanup function which resets all the standby nodes' configs back to its original state and create snapshots of each nodes' internal state.

func (*HarnessTest) SuspendNode

func (h *HarnessTest) SuspendNode(node *node.HarnessNode) func() error

SuspendNode stops the given node and returns a callback that can be used to start it again.

func (*HarnessTest) WaitForBalanceConfirmed

func (h *HarnessTest) WaitForBalanceConfirmed(hn *node.HarnessNode,
	expected btcutil.Amount)

WaitForBalanceConfirmed waits until the node sees the expected confirmed balance in its wallet.

func (*HarnessTest) WaitForBalanceUnconfirmed

func (h *HarnessTest) WaitForBalanceUnconfirmed(hn *node.HarnessNode,
	expected btcutil.Amount)

WaitForBalanceUnconfirmed waits until the node sees the expected unconfirmed balance in its wallet.

func (*HarnessTest) WaitForBlockchainSync

func (h *HarnessTest) WaitForBlockchainSync(hn *node.HarnessNode)

WaitForBlockchainSync waits until the node is synced to chain.

func (*HarnessTest) WaitForBlockchainSyncTo

func (h *HarnessTest) WaitForBlockchainSyncTo(hn *node.HarnessNode,
	bestBlock *wire.MsgBlock)

WaitForBlockchainSyncTo waits until the node is synced to bestBlock.

func (HarnessTest) WaitForChannelCloseEvent

func (h HarnessTest) WaitForChannelCloseEvent(
	stream rpc.CloseChanClient) *chainhash.Hash

WaitForChannelCloseEvent waits for a notification that a channel is closed by consuming a message from the passed close channel stream. Returns the closing txid if found.

func (HarnessTest) WaitForChannelOpenEvent

func (h HarnessTest) WaitForChannelOpenEvent(
	stream rpc.OpenChanClient) *lnrpc.ChannelPoint

WaitForChannelOpenEvent waits for a notification that a channel is open by consuming a message from the passed open channel stream.

func (*HarnessTest) WaitForGraphSync

func (h *HarnessTest) WaitForGraphSync(hn *node.HarnessNode)

WaitForGraphSync waits until the node is synced to graph or times out.

func (*HarnessTest) WaitForNodeBlockHeight

func (h *HarnessTest) WaitForNodeBlockHeight(hn *node.HarnessNode,
	height int32)

WaitForNodeBlockHeight queries the node for its current block height until it reaches the passed height.

type HtlcEvent

type HtlcEvent int

HtlcEvent maps the series of event types used in `*routerrpc.HtlcEvent_*`.

const (
	HtlcEventForward HtlcEvent = iota
	HtlcEventForwardFail
	HtlcEventSettle
	HtlcEventLinkFail
	HtlcEventFinal
)

type ListChannelOption

type ListChannelOption func(r *lnrpc.ListChannelsRequest)

FindChannelOption is a functional type for an option that modifies a ListChannelsRequest.

func WithPeerAliasLookup

func WithPeerAliasLookup() ListChannelOption

WithPeerAliasLookup is an option for setting the peer alias lookup flag on a ListChannelsRequest.

type OpenChannelParams

type OpenChannelParams struct {
	// Amt is the local amount being put into the channel.
	Amt btcutil.Amount

	// PushAmt is the amount that should be pushed to the remote when the
	// channel is opened.
	PushAmt btcutil.Amount

	// Private is a boolan indicating whether the opened channel should be
	// private.
	Private bool

	// SpendUnconfirmed is a boolean indicating whether we can utilize
	// unconfirmed outputs to fund the channel.
	SpendUnconfirmed bool

	// MinHtlc is the htlc_minimum_msat value set when opening the channel.
	MinHtlc lnwire.MilliSatoshi

	// RemoteMaxHtlcs is the remote_max_htlcs value set when opening the
	// channel, restricting the number of concurrent HTLCs the remote party
	// can add to a commitment.
	RemoteMaxHtlcs uint16

	// FundingShim is an optional funding shim that the caller can specify
	// in order to modify the channel funding workflow.
	FundingShim *lnrpc.FundingShim

	// SatPerVByte is the amount of satoshis to spend in chain fees per
	// virtual byte of the transaction.
	SatPerVByte btcutil.Amount

	// ConfTarget is the number of blocks that the funding transaction
	// should be confirmed in.
	ConfTarget fn.Option[int32]

	// CommitmentType is the commitment type that should be used for the
	// channel to be opened.
	CommitmentType lnrpc.CommitmentType

	// ZeroConf is used to determine if the channel will be a zero-conf
	// channel. This only works if the explicit negotiation is used with
	// anchors or script enforced leases.
	ZeroConf bool

	// ScidAlias denotes whether the channel will be an option-scid-alias
	// channel type negotiation.
	ScidAlias bool

	// BaseFee is the channel base fee applied during the channel
	// announcement phase.
	BaseFee uint64

	// FeeRate is the channel fee rate in ppm applied during the channel
	// announcement phase.
	FeeRate uint64

	// UseBaseFee, if set, instructs the downstream logic to apply the
	// user-specified channel base fee to the channel update announcement.
	// If set to false it avoids applying a base fee of 0 and instead
	// activates the default configured base fee.
	UseBaseFee bool

	// UseFeeRate, if set, instructs the downstream logic to apply the
	// user-specified channel fee rate to the channel update announcement.
	// If set to false it avoids applying a fee rate of 0 and instead
	// activates the default configured fee rate.
	UseFeeRate bool

	// FundMax is a boolean indicating whether the channel should be funded
	// with the maximum possible amount from the wallet.
	FundMax bool

	// An optional note-to-self containing some useful information about the
	// channel. This is stored locally only, and is purely for reference. It
	// has no bearing on the channel's operation. Max allowed length is 500
	// characters.
	Memo string

	// Outpoints is a list of client-selected outpoints that should be used
	// for funding a channel. If Amt is specified then this amount is
	// allocated from the sum of outpoints towards funding. If the
	// FundMax flag is specified the entirety of selected funds is
	// allocated towards channel funding.
	Outpoints []*lnrpc.OutPoint
}

OpenChannelParams houses the params to specify when opening a new channel.

type OpenChannelRequest

type OpenChannelRequest struct {
	// Local is the funding node.
	Local *node.HarnessNode

	// Remote is the receiving node.
	Remote *node.HarnessNode

	// Param is the open channel params.
	Param OpenChannelParams
	// contains filtered or unexported fields
}

OpenChannelRequest is used to open a channel using the method OpenMultiChannelsAsync.

type TestCase

type TestCase struct {
	// Name specifies the test name.
	Name string

	// TestFunc is the test case wrapped in a function.
	TestFunc func(t *HarnessTest)
}

TestCase defines a test case that's been used in the integration test.

type WebFeeService

type WebFeeService interface {
	// Start starts the service.
	Start() error

	// Stop stops the service.
	Stop() error

	// URL returns the service's endpoint.
	URL() string

	// SetFeeRate sets the estimated fee rate for a given confirmation
	// target.
	SetFeeRate(feeRate chainfee.SatPerKWeight, conf uint32)

	// Reset resets the fee rate map to the default value.
	Reset()
}

WebFeeService defines an interface that's used to provide fee estimation service used in the integration tests. It must provide an URL so that a lnd node can be started with the flag `--fee.url` and uses the customized fee estimator.

Directories

Path Synopsis

Jump to

Keyboard shortcuts

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