mirror of
https://github.com/lightningnetwork/lnd.git
synced 2025-05-13 13:20:08 +02:00
lntest: add more methods to assert mempool state
This commit is contained in:
parent
dccf9c77ca
commit
774db0dfe1
@ -1610,6 +1610,57 @@ func (h *HarnessTest) MineBlocksAndAssertNumTxes(num uint32,
|
|||||||
return blocks
|
return blocks
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// cleanMempool mines blocks till the mempool is empty and asserts all active
|
||||||
|
// nodes have synced to the chain.
|
||||||
|
func (h *HarnessTest) cleanMempool() {
|
||||||
|
_, startHeight := h.Miner.GetBestBlock()
|
||||||
|
|
||||||
|
// Mining the blocks slow to give `lnd` more time to sync.
|
||||||
|
var bestBlock *wire.MsgBlock
|
||||||
|
err := wait.NoError(func() error {
|
||||||
|
// If mempool is empty, exit.
|
||||||
|
mem := h.Miner.GetRawMempool()
|
||||||
|
if len(mem) == 0 {
|
||||||
|
_, height := h.Miner.GetBestBlock()
|
||||||
|
h.Logf("Mined %d blocks when cleanup the mempool",
|
||||||
|
height-startHeight)
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// Otherwise mine a block.
|
||||||
|
blocks := h.Miner.MineBlocksSlow(1)
|
||||||
|
bestBlock = blocks[len(blocks)-1]
|
||||||
|
|
||||||
|
return fmt.Errorf("still have %d txes in mempool", len(mem))
|
||||||
|
}, wait.MinerMempoolTimeout)
|
||||||
|
require.NoError(h, err, "timeout cleaning up mempool")
|
||||||
|
|
||||||
|
// Exit early if the best block is nil, which means we haven't mined
|
||||||
|
// any blocks during the cleanup.
|
||||||
|
if bestBlock == nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// Make sure all the active nodes are synced.
|
||||||
|
h.AssertActiveNodesSyncedTo(bestBlock)
|
||||||
|
}
|
||||||
|
|
||||||
|
// 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 (h *HarnessTest) CleanShutDown() {
|
||||||
|
// First, shutdown all non-standby nodes to prevent new transactions
|
||||||
|
// being created and fed into the mempool.
|
||||||
|
h.shutdownNonStandbyNodes()
|
||||||
|
|
||||||
|
// Now mine blocks till the mempool is empty.
|
||||||
|
h.cleanMempool()
|
||||||
|
}
|
||||||
|
|
||||||
// MineEmptyBlocks mines a given number of empty blocks.
|
// MineEmptyBlocks mines a given number of empty blocks.
|
||||||
//
|
//
|
||||||
// NOTE: this differs from miner's `MineEmptyBlocks` as it requires the nodes
|
// NOTE: this differs from miner's `MineEmptyBlocks` as it requires the nodes
|
||||||
|
@ -887,6 +887,15 @@ func (h *HarnessTest) Random32Bytes() []byte {
|
|||||||
return randBuf
|
return randBuf
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// RandomPreimage generates a random preimage which can be used as a payment
|
||||||
|
// preimage.
|
||||||
|
func (h *HarnessTest) RandomPreimage() lntypes.Preimage {
|
||||||
|
var preimage lntypes.Preimage
|
||||||
|
copy(preimage[:], h.Random32Bytes())
|
||||||
|
|
||||||
|
return preimage
|
||||||
|
}
|
||||||
|
|
||||||
// DecodeAddress decodes a given address and asserts there's no error.
|
// DecodeAddress decodes a given address and asserts there's no error.
|
||||||
func (h *HarnessTest) DecodeAddress(addr string) btcutil.Address {
|
func (h *HarnessTest) DecodeAddress(addr string) btcutil.Address {
|
||||||
resp, err := btcutil.DecodeAddress(addr, harnessNetParams)
|
resp, err := btcutil.DecodeAddress(addr, harnessNetParams)
|
||||||
@ -1256,6 +1265,111 @@ func (h *HarnessTest) AssertActiveHtlcs(hn *node.HarnessNode,
|
|||||||
require.NoError(h, err, "timeout checking active HTLCs")
|
require.NoError(h, err, "timeout checking active HTLCs")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// AssertIncomingHTLCActive asserts the node has a pending incoming HTLC in the
|
||||||
|
// given channel. Returns the HTLC if found and active.
|
||||||
|
func (h *HarnessTest) AssertIncomingHTLCActive(hn *node.HarnessNode,
|
||||||
|
cp *lnrpc.ChannelPoint, payHash []byte) *lnrpc.HTLC {
|
||||||
|
|
||||||
|
return h.assertHLTCActive(hn, cp, payHash, true)
|
||||||
|
}
|
||||||
|
|
||||||
|
// AssertOutgoingHTLCActive asserts the node has a pending outgoing HTLC in the
|
||||||
|
// given channel. Returns the HTLC if found and active.
|
||||||
|
func (h *HarnessTest) AssertOutgoingHTLCActive(hn *node.HarnessNode,
|
||||||
|
cp *lnrpc.ChannelPoint, payHash []byte) *lnrpc.HTLC {
|
||||||
|
|
||||||
|
return h.assertHLTCActive(hn, cp, payHash, false)
|
||||||
|
}
|
||||||
|
|
||||||
|
// assertHLTCActive asserts the node has a pending HTLC in the given channel.
|
||||||
|
// Returns the HTLC if found and active.
|
||||||
|
func (h *HarnessTest) assertHLTCActive(hn *node.HarnessNode,
|
||||||
|
cp *lnrpc.ChannelPoint, payHash []byte, incoming bool) *lnrpc.HTLC {
|
||||||
|
|
||||||
|
var result *lnrpc.HTLC
|
||||||
|
target := hex.EncodeToString(payHash)
|
||||||
|
|
||||||
|
err := wait.NoError(func() error {
|
||||||
|
// We require the RPC call to be succeeded and won't wait for
|
||||||
|
// it as it's an unexpected behavior.
|
||||||
|
ch := h.GetChannelByChanPoint(hn, cp)
|
||||||
|
|
||||||
|
// Check all payment hashes active for this channel.
|
||||||
|
for _, htlc := range ch.PendingHtlcs {
|
||||||
|
h := hex.EncodeToString(htlc.HashLock)
|
||||||
|
if h != target {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
// If the payment hash is found, check the incoming
|
||||||
|
// field.
|
||||||
|
if htlc.Incoming == incoming {
|
||||||
|
// Found it and return.
|
||||||
|
result = htlc
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// Otherwise we do have the HTLC but its direction is
|
||||||
|
// not right.
|
||||||
|
have, want := "outgoing", "incoming"
|
||||||
|
if htlc.Incoming {
|
||||||
|
have, want = "incoming", "outgoing"
|
||||||
|
}
|
||||||
|
|
||||||
|
return fmt.Errorf("node[%s] have htlc(%v), want: %s, "+
|
||||||
|
"have: %s", hn.Name(), payHash, want, have)
|
||||||
|
}
|
||||||
|
|
||||||
|
return fmt.Errorf("node [%s:%x] didn't have: the payHash %v",
|
||||||
|
hn.Name(), hn.PubKey[:], payHash)
|
||||||
|
}, DefaultTimeout)
|
||||||
|
require.NoError(h, err, "timeout checking pending HTLC")
|
||||||
|
|
||||||
|
return result
|
||||||
|
}
|
||||||
|
|
||||||
|
// 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 (h *HarnessTest) AssertHLTCNotActive(hn *node.HarnessNode,
|
||||||
|
cp *lnrpc.ChannelPoint, payHash []byte) *lnrpc.HTLC {
|
||||||
|
|
||||||
|
var result *lnrpc.HTLC
|
||||||
|
target := hex.EncodeToString(payHash)
|
||||||
|
|
||||||
|
err := wait.NoError(func() error {
|
||||||
|
// We require the RPC call to be succeeded and won't wait for
|
||||||
|
// it as it's an unexpected behavior.
|
||||||
|
ch := h.GetChannelByChanPoint(hn, cp)
|
||||||
|
|
||||||
|
// Check all payment hashes active for this channel.
|
||||||
|
for _, htlc := range ch.PendingHtlcs {
|
||||||
|
h := hex.EncodeToString(htlc.HashLock)
|
||||||
|
|
||||||
|
// Break if found the htlc.
|
||||||
|
if h == target {
|
||||||
|
result = htlc
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// If we've found nothing, we're done.
|
||||||
|
if result == nil {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// Otherwise return an error.
|
||||||
|
return fmt.Errorf("node [%s:%x] still has: the payHash %x",
|
||||||
|
hn.Name(), hn.PubKey[:], payHash)
|
||||||
|
}, DefaultTimeout)
|
||||||
|
require.NoError(h, err, "timeout checking pending HTLC")
|
||||||
|
|
||||||
|
return result
|
||||||
|
}
|
||||||
|
|
||||||
// ReceiveSingleInvoice waits until a message is received on the subscribe
|
// ReceiveSingleInvoice waits until a message is received on the subscribe
|
||||||
// single invoice stream or the timeout is reached.
|
// single invoice stream or the timeout is reached.
|
||||||
func (h *HarnessTest) ReceiveSingleInvoice(
|
func (h *HarnessTest) ReceiveSingleInvoice(
|
||||||
@ -1450,16 +1564,17 @@ func (h *HarnessTest) AssertPaymentStatus(hn *node.HarnessNode,
|
|||||||
status lnrpc.Payment_PaymentStatus) *lnrpc.Payment {
|
status lnrpc.Payment_PaymentStatus) *lnrpc.Payment {
|
||||||
|
|
||||||
var target *lnrpc.Payment
|
var target *lnrpc.Payment
|
||||||
|
payHash := preimage.Hash()
|
||||||
|
|
||||||
err := wait.NoError(func() error {
|
err := wait.NoError(func() error {
|
||||||
p := h.findPayment(hn, preimage.Hash().String())
|
p := h.findPayment(hn, payHash.String())
|
||||||
if status == p.Status {
|
if status == p.Status {
|
||||||
target = p
|
target = p
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
return fmt.Errorf("payment: %v status not match, want %s "+
|
return fmt.Errorf("payment: %v status not match, want %s "+
|
||||||
"got %s", preimage, status, p.Status)
|
"got %s", payHash, status, p.Status)
|
||||||
}, DefaultTimeout)
|
}, DefaultTimeout)
|
||||||
require.NoError(h, err, "timeout checking payment status")
|
require.NoError(h, err, "timeout checking payment status")
|
||||||
|
|
||||||
@ -2349,3 +2464,53 @@ func (h *HarnessTest) AssertWalletAccountBalance(hn *node.HarnessNode,
|
|||||||
}, DefaultTimeout)
|
}, DefaultTimeout)
|
||||||
require.NoError(h, err, "timeout checking wallet account balance")
|
require.NoError(h, err, "timeout checking wallet account balance")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 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 (h *HarnessTest) AssertClosingTxInMempool(cp *lnrpc.ChannelPoint,
|
||||||
|
c lnrpc.CommitmentType) *wire.MsgTx {
|
||||||
|
|
||||||
|
// Get expected number of txes to be found in the mempool.
|
||||||
|
expectedTxes := 1
|
||||||
|
hasAnchors := CommitTypeHasAnchors(c)
|
||||||
|
if hasAnchors {
|
||||||
|
expectedTxes = 2
|
||||||
|
}
|
||||||
|
|
||||||
|
// Wait for the expected txes to be found in the mempool.
|
||||||
|
h.Miner.AssertNumTxsInMempool(expectedTxes)
|
||||||
|
|
||||||
|
// Get the closing tx from the mempool.
|
||||||
|
op := h.OutPointFromChannelPoint(cp)
|
||||||
|
closeTx := h.Miner.AssertOutpointInMempool(op)
|
||||||
|
|
||||||
|
return closeTx
|
||||||
|
}
|
||||||
|
|
||||||
|
// 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 (h *HarnessTest) MineClosingTx(cp *lnrpc.ChannelPoint,
|
||||||
|
c lnrpc.CommitmentType) *wire.MsgTx {
|
||||||
|
|
||||||
|
// Get expected number of txes to be found in the mempool.
|
||||||
|
expectedTxes := 1
|
||||||
|
hasAnchors := CommitTypeHasAnchors(c)
|
||||||
|
if hasAnchors {
|
||||||
|
expectedTxes = 2
|
||||||
|
}
|
||||||
|
|
||||||
|
// Wait for the expected txes to be found in the mempool.
|
||||||
|
h.Miner.AssertNumTxsInMempool(expectedTxes)
|
||||||
|
|
||||||
|
// Get the closing tx from the mempool.
|
||||||
|
op := h.OutPointFromChannelPoint(cp)
|
||||||
|
closeTx := h.Miner.AssertOutpointInMempool(op)
|
||||||
|
|
||||||
|
// Mine a block to confirm the closing transaction and potential anchor
|
||||||
|
// sweep.
|
||||||
|
h.MineBlocksAndAssertNumTxes(1, expectedTxes)
|
||||||
|
|
||||||
|
return closeTx
|
||||||
|
}
|
||||||
|
@ -301,6 +301,40 @@ func (h *HarnessMiner) AssertTxInMempool(txid *chainhash.Hash) *wire.MsgTx {
|
|||||||
return msgTx
|
return 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 (h *HarnessMiner) AssertTxNotInMempool(txid chainhash.Hash) *wire.MsgTx {
|
||||||
|
var msgTx *wire.MsgTx
|
||||||
|
|
||||||
|
err := wait.NoError(func() error {
|
||||||
|
// We require the RPC call to be succeeded and won't wait for
|
||||||
|
// it as it's an unexpected behavior.
|
||||||
|
mempool := h.GetRawMempool()
|
||||||
|
|
||||||
|
if len(mempool) == 0 {
|
||||||
|
return fmt.Errorf("empty mempool")
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, memTx := range mempool {
|
||||||
|
// Check the values are equal.
|
||||||
|
if txid.IsEqual(memTx) {
|
||||||
|
return fmt.Errorf("expect txid %v to be NOT "+
|
||||||
|
"found in mempool", txid)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}, wait.MinerMempoolTimeout)
|
||||||
|
|
||||||
|
require.NoError(h, err, "timeout checking tx not in mempool")
|
||||||
|
|
||||||
|
return msgTx
|
||||||
|
}
|
||||||
|
|
||||||
// SendOutputsWithoutChange uses the miner to send the given outputs using the
|
// SendOutputsWithoutChange uses the miner to send the given outputs using the
|
||||||
// specified fee rate and returns the txid.
|
// specified fee rate and returns the txid.
|
||||||
func (h *HarnessMiner) SendOutputsWithoutChange(outputs []*wire.TxOut,
|
func (h *HarnessMiner) SendOutputsWithoutChange(outputs []*wire.TxOut,
|
||||||
|
Loading…
x
Reference in New Issue
Block a user