Merge pull request #6825 from yyforyongyu/6-new-itest

itest: fix previously known test flakes
This commit is contained in:
Olaoluwa Osuntokun authored and GitHub committed 2023-02-23 15:35:45 -08:00
commit cfc19a9ac4
134 files changed
+2162 -8844

No files matched your search

+11 -97
View File
@@ -186,10 +186,10 @@ jobs:
parallel: true parallel: true
######################## ########################
# run integration tests # run ubuntu integration tests
######################## ########################
integration-test: ubuntu-integration-test:
name: run itests name: run ubuntu itests
runs-on: ubuntu-latest runs-on: ubuntu-latest
if: '!contains(github.event.pull_request.labels.*.name, ''no-itest'')' if: '!contains(github.event.pull_request.labels.*.name, ''no-itest'')'
strategy: strategy:
@@ -230,17 +230,18 @@ jobs:
- name: Zip log files on failure - name: Zip log files on failure
if: ${{ failure() }} if: ${{ failure() }}
timeout-minutes: 1 # timeout after 1 minute timeout-minutes: 5 # timeout after 5 minute
run: 7z a logs-itest-${{ matrix.name }}.zip lntest/itest/**/*.log run: 7z a logs-itest-${{ matrix.name }}.zip itest/**/*.log
- name: Upload log files on failure - name: Upload log files on failure
uses: actions/upload-artifact@v2.2.4 uses: actions/upload-artifact@v3
if: ${{ failure() }} if: ${{ failure() }}
with: with:
name: logs-itest-${{ matrix.name }} name: logs-itest-${{ matrix.name }}
path: logs-itest-${{ matrix.name }}.zip path: logs-itest-${{ matrix.name }}.zip
retention-days: 5 retention-days: 5
######################## ########################
# run windows integration test # run windows integration test
######################## ########################
@@ -258,102 +259,15 @@ jobs:
go-version: '${{ env.GO_VERSION }}' go-version: '${{ env.GO_VERSION }}'
- name: run itest - name: run itest
run: make itest-parallel windows=1 tranches=2 parallel=2 run: make itest-parallel windows=1
- name: Zip log files on failure - name: Zip log files on failure
if: ${{ failure() }} if: ${{ failure() }}
run: 7z a logs-itest-windows.zip lntest/itest/**/*.log timeout-minutes: 5 # timeout after 5 minute
run: 7z a logs-itest-windows.zip itest/**/*.log
- name: Upload log files on failure - name: Upload log files on failure
uses: actions/upload-artifact@v2 uses: actions/upload-artifact@v3
if: ${{ failure() }}
with:
name: logs-itest-windows
path: logs-itest-windows.zip
retention-days: 5
########################
# run new integration tests
########################
new-integration-test:
name: run new itests
runs-on: ubuntu-latest
if: '!contains(github.event.pull_request.labels.*.name, ''no-itest'')'
strategy:
# Allow other tests in the matrix to continue if one fails.
fail-fast: false
matrix:
include:
- name: btcd
args: backend=btcd
- name: bitcoind
args: backend=bitcoind
- name: bitcoind-notxindex
args: backend="bitcoind notxindex"
- name: bitcoind-rpcpolling
args: backend="bitcoind rpcpolling"
- name: bitcoind-etcd
args: backend=bitcoind dbbackend=etcd
- name: bitcoind-postgres
args: backend=bitcoind dbbackend=postgres
- name: bitcoind-sqlite
args: backend=bitcoind dbbackend=sqlite
- name: neutrino
args: backend=neutrino
steps:
- name: git checkout
uses: actions/checkout@v3
- name: setup go ${{ env.GO_VERSION }}
uses: ./.github/actions/setup-go
with:
go-version: '${{ env.GO_VERSION }}'
- name: install bitcoind
run: ./scripts/install_bitcoind.sh
- name: run new ${{ matrix.name }}
run: make itest-parallel temptest=true ${{ matrix.args }}
- name: Zip log files on failure
if: ${{ failure() }}
timeout-minutes: 1 # timeout after 1 minute
run: 7z a logs-itest-${{ matrix.name }}.zip lntest/itest/**/*.log
- name: Upload log files on failure
uses: actions/upload-artifact@v2.2.4
if: ${{ failure() }}
with:
name: logs-itest-${{ matrix.name }}
path: logs-itest-${{ matrix.name }}.zip
retention-days: 5
########################
# run new windows integration test
########################
new-windows-integration-test:
name: run new windows itest
runs-on: windows-latest
if: '!contains(github.event.pull_request.labels.*.name, ''no-itest'')'
steps:
- name: git checkout
uses: actions/checkout@v3
- name: setup go ${{ env.GO_VERSION }}
uses: ./.github/actions/setup-go
with:
go-version: '${{ env.GO_VERSION }}'
- name: run new itest
run: make itest-parallel temptest=true windows=1 tranches=2 parallel=2
- name: Zip log files on failure
if: ${{ failure() }}
timeout-minutes: 1 # timeout after 1 minute
run: 7z a logs-itest-windows.zip lntest/itest/**/*.log
- name: Upload log files on failure
uses: actions/upload-artifact@v2
if: ${{ failure() }} if: ${{ failure() }}
with: with:
name: logs-itest-windows name: logs-itest-windows
+6 -6
View File
@@ -32,12 +32,12 @@ _testmain.go
/lncli-itest /lncli-itest
# Integration test log files # Integration test log files
lntest/itest/*.log itest/*.log
lntest/itest/.backendlogs itest/.backendlogs
lntest/itest/.minerlogs itest/.minerlogs
lntest/itest/lnd-itest itest/lnd-itest
lntest/itest/btcd-itest itest/btcd-itest
lntest/itest/.logs-* itest/.logs-*
cmd/cmd cmd/cmd
*.key *.key
+4 -7
View File
@@ -27,6 +27,7 @@ run:
- kvdb_etcd - kvdb_etcd
- kvdb_postgres - kvdb_postgres
- kvdb_sqlite - kvdb_sqlite
- integration
linters-settings: linters-settings:
govet: govet:
@@ -96,6 +97,7 @@ linters-settings:
ignored-functions: ignored-functions:
- 'math.*' - 'math.*'
- 'strconv.ParseInt' - 'strconv.ParseInt'
- 'errors.Wrap'
linters: linters:
@@ -237,14 +239,9 @@ issues:
linters: linters:
- forbidigo - forbidigo
# Fix false positives because of build flags in itest directory. - path: itest/.*
- path: lntest/itest/.*
linters: linters:
- unused - paralleltest
- unparam
- govet
# itest case can be very long so we disable long function check.
- funlen
- path: lnmock/* - path: lnmock/*
linters: linters:
+2 -18
View File
@@ -32,31 +32,15 @@ sudo: required
jobs: jobs:
include: include:
- stage: Sanity Check
name: Lint and compile
script:
# Step 1: Make sure no diff is produced when compiling with the correct
# version.
- make rpc-check
# Step 2: Make sure the unit tests compile, but don't run them. They run
# in a GitHub Workflow.
- make unit pkg=... case=_NONE_
# Step 3: Lint go code. Invoke GC more often to reduce memory usage.
- GOGC=30 make lint
- stage: Integration Test - stage: Integration Test
name: Bitcoind Integration ARM name: Bitcoind Integration ARM
script: script:
- bash ./scripts/install_bitcoind.sh - bash ./scripts/install_bitcoind.sh
- GOARM=7 GOARCH=arm GOOS=linux make itest-parallel backend=bitcoind tranches=3 parallel=3 - GOMEMLIMIT=500MiB GOARM=7 GOARCH=arm GOOS=linux travis_wait 30 make itest-parallel backend=bitcoind
arch: arm64 arch: arm64
services:
- docker
after_failure: after_failure:
- |- - |-
LOG_FILES=$(find ./lntest/itest -name '*.log') LOG_FILES=$(find ./itest -name '*.log')
echo "Uploading to termbin.com..." && for f in $LOG_FILES; do echo -n $f; cat $f | nc termbin.com 9999 | xargs -r0 printf ' uploaded to %s'; done echo "Uploading to termbin.com..." && for f in $LOG_FILES; do echo -n $f; cat $f | nc termbin.com 9999 | xargs -r0 printf ' uploaded to %s'; done
echo "Uploading to file.io..." && tar -zcvO $LOG_FILES | curl -s -F 'file=@-;filename=logs.tar.gz' https://file.io | xargs -r0 printf 'logs.tar.gz uploaded to %s\n' echo "Uploading to file.io..." && tar -zcvO $LOG_FILES | curl -s -F 'file=@-;filename=logs.tar.gz' https://file.io | xargs -r0 printf 'logs.tar.gz uploaded to %s\n'
+8 -8
View File
@@ -93,19 +93,19 @@ build:
build-itest: build-itest:
@$(call print, "Building itest btcd and lnd.") @$(call print, "Building itest btcd and lnd.")
CGO_ENABLED=0 $(GOBUILD) -tags="rpctest" -o lntest/itest/btcd-itest$(EXEC_SUFFIX) $(DEV_LDFLAGS) $(BTCD_PKG) CGO_ENABLED=0 $(GOBUILD) -tags="integration" -o itest/btcd-itest$(EXEC_SUFFIX) $(DEV_LDFLAGS) $(BTCD_PKG)
CGO_ENABLED=0 $(GOBUILD) -tags="$(ITEST_TAGS)" -o lntest/itest/lnd-itest$(EXEC_SUFFIX) $(DEV_LDFLAGS) $(PKG)/cmd/lnd CGO_ENABLED=0 $(GOBUILD) -tags="$(ITEST_TAGS)" -o itest/lnd-itest$(EXEC_SUFFIX) $(DEV_LDFLAGS) $(PKG)/cmd/lnd
@$(call print, "Building itest binary for ${backend} backend.") @$(call print, "Building itest binary for ${backend} backend.")
CGO_ENABLED=0 $(GOTEST) -v ./lntest/itest -tags="$(DEV_TAGS) $(RPC_TAGS) rpctest $(backend)" -c -o lntest/itest/itest.test$(EXEC_SUFFIX) CGO_ENABLED=0 $(GOTEST) -v ./itest -tags="$(DEV_TAGS) $(RPC_TAGS) integration $(backend)" -c -o itest/itest.test$(EXEC_SUFFIX)
build-itest-race: build-itest-race:
@$(call print, "Building itest btcd and lnd with race detector.") @$(call print, "Building itest btcd and lnd with race detector.")
CGO_ENABLED=0 $(GOBUILD) -tags="rpctest" -o lntest/itest/btcd-itest$(EXEC_SUFFIX) $(DEV_LDFLAGS) $(BTCD_PKG) CGO_ENABLED=0 $(GOBUILD) -tags="integration" -o itest/btcd-itest$(EXEC_SUFFIX) $(DEV_LDFLAGS) $(BTCD_PKG)
CGO_ENABLED=1 $(GOBUILD) -race -tags="$(ITEST_TAGS)" -o lntest/itest/lnd-itest$(EXEC_SUFFIX) $(DEV_LDFLAGS) $(PKG)/cmd/lnd CGO_ENABLED=1 $(GOBUILD) -race -tags="$(ITEST_TAGS)" -o itest/lnd-itest$(EXEC_SUFFIX) $(DEV_LDFLAGS) $(PKG)/cmd/lnd
@$(call print, "Building itest binary for ${backend} backend.") @$(call print, "Building itest binary for ${backend} backend.")
CGO_ENABLED=0 $(GOTEST) -v ./lntest/itest -tags="$(DEV_TAGS) $(RPC_TAGS) rpctest $(backend)" -c -o lntest/itest/itest.test$(EXEC_SUFFIX) CGO_ENABLED=0 $(GOTEST) -v ./itest -tags="$(DEV_TAGS) $(RPC_TAGS) integration $(backend)" -c -o itest/itest.test$(EXEC_SUFFIX)
install: install:
@$(call print, "Installing lnd and lncli.") @$(call print, "Installing lnd and lncli.")
@@ -164,7 +164,7 @@ endif
itest-only: db-instance itest-only: db-instance
@$(call print, "Running integration tests with ${backend} backend.") @$(call print, "Running integration tests with ${backend} backend.")
rm -rf lntest/itest/*.log lntest/itest/.logs-*; date rm -rf itest/*.log itest/.logs-*; date
EXEC_SUFFIX=$(EXEC_SUFFIX) scripts/itest_part.sh 0 1 $(TEST_FLAGS) $(ITEST_FLAGS) EXEC_SUFFIX=$(EXEC_SUFFIX) scripts/itest_part.sh 0 1 $(TEST_FLAGS) $(ITEST_FLAGS)
itest: build-itest itest-only itest: build-itest itest-only
@@ -173,7 +173,7 @@ itest-race: build-itest-race itest-only
itest-parallel: build-itest db-instance itest-parallel: build-itest db-instance
@$(call print, "Running tests") @$(call print, "Running tests")
rm -rf lntest/itest/*.log lntest/itest/.logs-*; date rm -rf itest/*.log itest/.logs-*; date
EXEC_SUFFIX=$(EXEC_SUFFIX) echo "$$(seq 0 $$(expr $(ITEST_PARALLELISM) - 1))" | xargs -P $(ITEST_PARALLELISM) -n 1 -I {} scripts/itest_part.sh {} $(NUM_ITEST_TRANCHES) $(TEST_FLAGS) $(ITEST_FLAGS) EXEC_SUFFIX=$(EXEC_SUFFIX) echo "$$(seq 0 $$(expr $(ITEST_PARALLELISM) - 1))" | xargs -P $(ITEST_PARALLELISM) -n 1 -I {} scripts/itest_part.sh {} $(NUM_ITEST_TRANCHES) $(TEST_FLAGS) $(ITEST_FLAGS)
itest-clean: itest-clean:
@@ -1,5 +1,4 @@
//go:build rpctest //go:build integration
// +build rpctest
package aezeed package aezeed
-3
View File
@@ -1,6 +1,3 @@
//go:build !rpctest
// +build !rpctest
package contractcourt package contractcourt
import ( import (
+3 -3
View File
@@ -497,10 +497,10 @@ func newChainSet(chanState *channeldb.OpenChannel) (*chainSet, error) {
"chan_point=%v", chanState.FundingOutpoint) "chan_point=%v", chanState.FundingOutpoint)
} }
log.Debugf("ChannelPoint(%v): local_commit_type=%v, local_commit=%v", log.Tracef("ChannelPoint(%v): local_commit_type=%v, local_commit=%v",
chanState.FundingOutpoint, chanState.ChanType, chanState.FundingOutpoint, chanState.ChanType,
spew.Sdump(localCommit)) spew.Sdump(localCommit))
log.Debugf("ChannelPoint(%v): remote_commit_type=%v, remote_commit=%v", log.Tracef("ChannelPoint(%v): remote_commit_type=%v, remote_commit=%v",
chanState.FundingOutpoint, chanState.ChanType, chanState.FundingOutpoint, chanState.ChanType,
spew.Sdump(remoteCommit)) spew.Sdump(remoteCommit))
@@ -527,7 +527,7 @@ func newChainSet(chanState *channeldb.OpenChannel) (*chainSet, error) {
var remotePendingCommit *channeldb.ChannelCommitment var remotePendingCommit *channeldb.ChannelCommitment
if remoteChainTip != nil { if remoteChainTip != nil {
remotePendingCommit = &remoteChainTip.Commitment remotePendingCommit = &remoteChainTip.Commitment
log.Debugf("ChannelPoint(%v): remote_pending_commit_type=%v, "+ log.Tracef("ChannelPoint(%v): remote_pending_commit_type=%v, "+
"remote_pending_commit=%v", chanState.FundingOutpoint, "remote_pending_commit=%v", chanState.FundingOutpoint,
chanState.ChanType, chanState.ChanType,
spew.Sdump(remoteChainTip.Commitment)) spew.Sdump(remoteChainTip.Commitment))
-3
View File
@@ -1,6 +1,3 @@
//go:build !rpctest
// +build !rpctest
package contractcourt package contractcourt
import ( import (
-3
View File
@@ -1,6 +1,3 @@
//go:build !rpctest
// +build !rpctest
package contractcourt package contractcourt
import ( import (
+15
View File
@@ -316,6 +316,11 @@ type Config struct {
// ChannelID. This is used to sign updates for them if the channel has // ChannelID. This is used to sign updates for them if the channel has
// no AuthProof and the option-scid-alias feature bit was negotiated. // no AuthProof and the option-scid-alias feature bit was negotiated.
GetAlias func(lnwire.ChannelID) (lnwire.ShortChannelID, error) GetAlias func(lnwire.ChannelID) (lnwire.ShortChannelID, error)
// FindChannel allows the gossiper to find a channel that we're party
// to without iterating over the entire set of open channels.
FindChannel func(node *btcec.PublicKey, chanID lnwire.ChannelID) (
*channeldb.OpenChannel, error)
} }
// processedNetworkMsg is a wrapper around networkMsg and a boolean. It is // processedNetworkMsg is a wrapper around networkMsg and a boolean. It is
@@ -3016,6 +3021,16 @@ func (d *AuthenticatedGossiper) handleAnnSig(nMsg *networkMsg,
ann.ShortChannelID, ann.ShortChannelID,
) )
if err != nil { if err != nil {
_, err = d.cfg.FindChannel(nMsg.source, ann.ChannelID)
if err != nil {
err := fmt.Errorf("unable to store the proof for "+
"short_chan_id=%v: %v", shortChanID, err)
log.Error(err)
nMsg.err <- err
return nil, false
}
proof := channeldb.NewWaitingProof(nMsg.isRemote, ann) proof := channeldb.NewWaitingProof(nMsg.isRemote, ann)
err := d.cfg.WaitingProofStore.Add(proof) err := d.cfg.WaitingProofStore.Add(proof)
if err != nil { if err != nil {
+7
View File
@@ -697,6 +697,12 @@ func createChannelAnnouncement(blockHeight uint32, key1, key2 *btcec.PrivateKey,
return a, nil return a, nil
} }
func mockFindChannel(node *btcec.PublicKey, chanID lnwire.ChannelID) (
*channeldb.OpenChannel, error) {
return nil, nil
}
type testCtx struct { type testCtx struct {
gossiper *AuthenticatedGossiper gossiper *AuthenticatedGossiper
router *mockGraphSource router *mockGraphSource
@@ -792,6 +798,7 @@ func createTestCtx(t *testing.T, startHeight uint32) (*testCtx, error) {
SignAliasUpdate: signAliasUpdate, SignAliasUpdate: signAliasUpdate,
FindBaseByAlias: findBaseByAlias, FindBaseByAlias: findBaseByAlias,
GetAlias: getAlias, GetAlias: getAlias,
FindChannel: mockFindChannel,
}, selfKeyDesc) }, selfKeyDesc)
if err := gossiper.Start(); err != nil { if err := gossiper.Start(); err != nil {
+1 -1
View File
@@ -155,7 +155,7 @@ A quick summary of test practices follows:
or RPC's will need to be accompanied by integration tests which use the or RPC's will need to be accompanied by integration tests which use the
[`networkHarness`framework](https://github.com/lightningnetwork/lnd/blob/master/lntest/harness.go) [`networkHarness`framework](https://github.com/lightningnetwork/lnd/blob/master/lntest/harness.go)
contained within `lnd`. For example integration tests, see contained within `lnd`. For example integration tests, see
[`lnd_test.go`](https://github.com/lightningnetwork/lnd/blob/master/lntest/itest/lnd_test.go). [`lnd_test.go`](https://github.com/lightningnetwork/lnd/blob/master/itest/lnd_test.go).
- The itest log files are automatically scanned for `[ERR]` lines. There - The itest log files are automatically scanned for `[ERR]` lines. There
shouldn't be any of those in the logs, see [Use of Log Levels](#use-of-log-levels). shouldn't be any of those in the logs, see [Use of Log Levels](#use-of-log-levels).
+3 -3
View File
@@ -44,7 +44,7 @@ to test the RPCs and to showcase the different use cases.
### 3-of-3 Taproot key spend path (BIP-0086) ### 3-of-3 Taproot key spend path (BIP-0086)
See `testTaprootMuSig2KeySpendBip86` in See `testTaprootMuSig2KeySpendBip86` in
[`lntest/itest/lnd_taproot_test.go`](../lntest/itest/lnd_taproot_test.go) to see [`itest/lnd_taproot_test.go`](../itest/lnd_taproot_test.go) to see
the full code. the full code.
This example uses combines the public keys of 3 participants into a shared This example uses combines the public keys of 3 participants into a shared
@@ -73,7 +73,7 @@ the `MuSig2CreateSession` RPC call:
### 3-of-3 Taproot key spend path with root hash commitment ### 3-of-3 Taproot key spend path with root hash commitment
See `testTaprootMuSig2KeySpendRootHash` in See `testTaprootMuSig2KeySpendRootHash` in
[`lntest/itest/lnd_taproot_test.go`](../lntest/itest/lnd_taproot_test.go) to see [`itest/lnd_taproot_test.go`](../itest/lnd_taproot_test.go) to see
the full code. the full code.
This is very similar to the above example but with the main difference that the This is very similar to the above example but with the main difference that the
@@ -101,7 +101,7 @@ the `MuSig2CreateSession` RPC call:
### 3-of-3 `OP_CHECKSIG` in Taproot script spend path ### 3-of-3 `OP_CHECKSIG` in Taproot script spend path
See `testTaprootMuSig2CombinedLeafKeySpend` in See `testTaprootMuSig2CombinedLeafKeySpend` in
[`lntest/itest/lnd_taproot_test.go`](../lntest/itest/lnd_taproot_test.go) to see [`itest/lnd_taproot_test.go`](../itest/lnd_taproot_test.go) to see
the full code. the full code.
This example is definitely the most involved one. To be able to use a MuSig2 This example is definitely the most involved one. To be able to use a MuSig2
+2 -1
View File
@@ -487,7 +487,8 @@ PRs([6776](https://github.com/lightningnetwork/lnd/pull/6776),
[7242](https://github.com/lightningnetwork/lnd/pull/7242), [7242](https://github.com/lightningnetwork/lnd/pull/7242),
[7245](https://github.com/lightningnetwork/lnd/pull/7245)), [7245](https://github.com/lightningnetwork/lnd/pull/7245)),
[6823](https://github.com/lightningnetwork/lnd/pull/6823), [6823](https://github.com/lightningnetwork/lnd/pull/6823),
[6824](https://github.com/lightningnetwork/lnd/pull/6824),) have been made to [6824](https://github.com/lightningnetwork/lnd/pull/6824),
[6825](https://github.com/lightningnetwork/lnd/pull/6825)) have been made to
refactor the itest for code health and maintenance. refactor the itest for code health and maintenance.
# Contributors (Alphabetical Order) # Contributors (Alphabetical Order)
@@ -1,4 +1,4 @@
//go:build rpctest //go:build integration
package funding package funding
+24
View File
@@ -108,6 +108,11 @@ const (
// for the funding transaction to be confirmed before forgetting // for the funding transaction to be confirmed before forgetting
// channels that aren't initiated by us. 2016 blocks is ~2 weeks. // channels that aren't initiated by us. 2016 blocks is ~2 weeks.
maxWaitNumBlocksFundingConf = 2016 maxWaitNumBlocksFundingConf = 2016
// pendingChansLimit is the maximum number of pending channels that we
// can have. After this point, pending channel opens will start to be
// rejected.
pendingChansLimit = 1_000
) )
var ( var (
@@ -1320,6 +1325,25 @@ func (f *Manager) handleFundingOpen(peer lnpeer.Peer,
return return
} }
// Ensure that the pendingChansLimit is respected.
pendingChans, err := f.cfg.Wallet.Cfg.Database.FetchPendingChannels()
if err != nil {
f.failFundingFlow(
peer, msg.PendingChannelID, err,
)
return
}
if len(pendingChans) > pendingChansLimit {
f.failFundingFlow(
peer, msg.PendingChannelID,
lnwire.ErrMaxPendingChannels,
)
return
}
// We'll also reject any requests to create channels until we're fully // We'll also reject any requests to create channels until we're fully
// synced to the network as we won't be able to properly validate the // synced to the network as we won't be able to properly validate the
// confirmation of the funding transaction. // confirmation of the funding transaction.
-3
View File
@@ -1,6 +1,3 @@
//go:build !rpctest
// +build !rpctest
package funding package funding
import ( import (
+9
View File
@@ -2743,6 +2743,15 @@ func (l *channelLink) handleSwitchPacket(pkt *htlcPacket) error {
// //
// NOTE: Part of the ChannelLink interface. // NOTE: Part of the ChannelLink interface.
func (l *channelLink) HandleChannelUpdate(message lnwire.Message) { func (l *channelLink) HandleChannelUpdate(message lnwire.Message) {
select {
case <-l.quit:
// Return early if the link is already in the process of
// quitting. It doesn't make sense to hand the message to the
// mailbox here.
return
default:
}
l.mailBox.AddMessage(message) l.mailBox.AddMessage(message)
} }
+106
View File
@@ -0,0 +1,106 @@
# Integration Test
`itest` is a package that houses the integration tests made for `lnd`. This
package builds test cases using the test framework `lntest`.
## Add New Tests
To add a new test case, create a `TestFunc` and add it in `list_on_test.go`.
Ideally, the `Name` should just be the snake case of the name used in
`TestFunc` without the leading `test` and underscores. For instance, to test
`lnd`'s exporting channel backup, we have,
```go
{
Name: "export channel backup",
TestFunc: testExportChannelBackup,
}
```
The place to put the code of the `TestFunc` is case-specific. `itest` package
has loosely defined a list of files to test different functionalities of `lnd`.
The new test needs to be put into one of these files, otherwise, a new file
needs to be created.
## Run Tests
#### Run a single test case
To run a single test case, use `make itest icase=$case`, where `case` is the
name defined in `list_on_test.go`, with spaces replaced with underscores(`_`).
```shell
# Run `testListChannels`.
make itest icase=list_channels
```
#### Run multiple test cases
There are two ways to run multiple test cases. One way is to use `make itest
icase=$cases`, where `cases` has the format `cases='(case|case|...)'`. The
`case` is the name defined in `list_on_test.go`, with spaces replaced with
underscores(`_`).
```shell
# Run `testListChannels` and `testListAddresses` together.
make itest icase='(list_channels|list_addresses)'
```
Another way to run multiple cases is similar to how Go runs its tests - by
simple regex matching. For instance, the following command will run three cases
since they all start with the word `list`,
```shell
# Run `testListChannels`, `testListAddresses`, and `testListPayments` together.
make itest icase=list
```
#### Run all tests
To run all tests, use `make itest` without `icase` flag.
```shell
# Run all test cases.
make itest
```
#### Run tests in parallel
To run tests in parallel, use `make itest-parallel`. This command takes two
special arguments,
- `tranches`, specifies the number of parts the test cases will be split into.
- `parallel`, specifies the number of threads to run in parallel. This value
must be smaller than or equal to `tranches`.
```shell
# Split the tests into 4 parts, and run them using 2 threads.
make itest-parallel tranches=4 parallel=2
```
By default, `itest-parallel` splits the tests into 4 parts and uses 4 threads
to run each of them.
#### Additional arguments
For both `make itest` and `make itest-parallel`, the following arguments are
allowed,
- `timeout`, specifies the timeout value used in testing.
- `dbbackend`, specifies the database backend. Must be `bbolt`, `etcd`, or
`postgres`, default to `bbolt`.
- `backend`, specifies the chain backend to be used. Must be one of,
- `btcd`, the default value.
- `neutrino`
- `bitcoind`
- `bitcoind notxindex`
- `bitcoind rpcpolling`
```shell
# Run a single test case using bitcoind as the chain backend and etcd as the
# database backend, with a timeout of 5 minutes.
make itest icase=list_channels backend=bitcoind dbbackend=etcd timeout=5m
# Run all test cases in parallel, using bitcoind notxindex as the chain backend
# and etcd as the database backend, with a timeout of 60 minutes for each
# parallel.
make itest-parallel backend="bitcoind notxindex" dbbackend=etcd timeout=60m
```
+7
View File
@@ -0,0 +1,7 @@
//go:build !integration
package itest
import "github.com/lightningnetwork/lnd/lntest"
var allTestCases = []*lntest.TestCase{}
@@ -1,12 +1,10 @@
//go:build rpctest //go:build integration
// +build rpctest
package itest package itest
import "github.com/lightningnetwork/lnd/lntemp" import "github.com/lightningnetwork/lnd/lntest"
// TODO(yy): remove the temp. var allTestCases = []*lntest.TestCase{
var allTestCasesTemp = []*lntemp.TestCase{
{ {
Name: "update channel status", Name: "update channel status",
TestFunc: testUpdateChanStatus, TestFunc: testUpdateChanStatus,
@@ -509,4 +507,8 @@ var allTestCasesTemp = []*lntemp.TestCase{
Name: "zero conf reorg edge existence", Name: "zero conf reorg edge existence",
TestFunc: testZeroConfReorg, TestFunc: testZeroConfReorg,
}, },
{
Name: "async bidirectional payments",
TestFunc: testBidirectionalAsyncPayments,
},
} }
@@ -11,15 +11,15 @@ import (
"github.com/lightningnetwork/lnd/lnrpc" "github.com/lightningnetwork/lnd/lnrpc"
"github.com/lightningnetwork/lnd/lnrpc/invoicesrpc" "github.com/lightningnetwork/lnd/lnrpc/invoicesrpc"
"github.com/lightningnetwork/lnd/lnrpc/routerrpc" "github.com/lightningnetwork/lnd/lnrpc/routerrpc"
"github.com/lightningnetwork/lnd/lntemp" "github.com/lightningnetwork/lnd/lntest"
"github.com/lightningnetwork/lnd/lntemp/node" "github.com/lightningnetwork/lnd/lntest/node"
"github.com/lightningnetwork/lnd/lntypes" "github.com/lightningnetwork/lnd/lntypes"
"github.com/stretchr/testify/require" "github.com/stretchr/testify/require"
) )
// testSendPaymentAMPInvoice tests that we can send an AMP payment to a // testSendPaymentAMPInvoice tests that we can send an AMP payment to a
// specified AMP invoice using SendPaymentV2. // specified AMP invoice using SendPaymentV2.
func testSendPaymentAMPInvoice(ht *lntemp.HarnessTest) { func testSendPaymentAMPInvoice(ht *lntest.HarnessTest) {
succeed := ht.Run("native payaddr", func(t *testing.T) { succeed := ht.Run("native payaddr", func(t *testing.T) {
tt := ht.Subtest(t) tt := ht.Subtest(t)
testSendPaymentAMPInvoiceCase(tt, false) testSendPaymentAMPInvoiceCase(tt, false)
@@ -36,7 +36,7 @@ func testSendPaymentAMPInvoice(ht *lntemp.HarnessTest) {
}) })
} }
func testSendPaymentAMPInvoiceCase(ht *lntemp.HarnessTest, func testSendPaymentAMPInvoiceCase(ht *lntest.HarnessTest,
useExternalPayAddr bool) { useExternalPayAddr bool) {
mts := newMppTestScenario(ht) mts := newMppTestScenario(ht)
@@ -196,7 +196,7 @@ func testSendPaymentAMPInvoiceCase(ht *lntemp.HarnessTest,
// testSendPaymentAMPInvoiceRepeat tests that it's possible to pay an AMP // testSendPaymentAMPInvoiceRepeat tests that it's possible to pay an AMP
// invoice multiple times by having the client generate a new setID each time. // invoice multiple times by having the client generate a new setID each time.
func testSendPaymentAMPInvoiceRepeat(ht *lntemp.HarnessTest) { func testSendPaymentAMPInvoiceRepeat(ht *lntest.HarnessTest) {
// In this basic test, we'll only need two nodes as we want to // In this basic test, we'll only need two nodes as we want to
// primarily test the recurring payment feature. So we'll re-use the // primarily test the recurring payment feature. So we'll re-use the
carol := ht.NewNode("Carol", nil) carol := ht.NewNode("Carol", nil)
@@ -218,7 +218,7 @@ func testSendPaymentAMPInvoiceRepeat(ht *lntemp.HarnessTest) {
// Establish a channel between Carol and Dave. // Establish a channel between Carol and Dave.
chanAmt := btcutil.Amount(100_000) chanAmt := btcutil.Amount(100_000)
ht.OpenChannel( ht.OpenChannel(
carol, dave, lntemp.OpenChannelParams{Amt: chanAmt}, carol, dave, lntest.OpenChannelParams{Amt: chanAmt},
) )
// Create an AMP invoice of a trivial amount, that we'll pay repeatedly // Create an AMP invoice of a trivial amount, that we'll pay repeatedly
@@ -353,7 +353,7 @@ func testSendPaymentAMPInvoiceRepeat(ht *lntemp.HarnessTest) {
// testSendPaymentAMP tests that we can send an AMP payment to a specified // testSendPaymentAMP tests that we can send an AMP payment to a specified
// destination using SendPaymentV2. // destination using SendPaymentV2.
func testSendPaymentAMP(ht *lntemp.HarnessTest) { func testSendPaymentAMP(ht *lntest.HarnessTest) {
mts := newMppTestScenario(ht) mts := newMppTestScenario(ht)
const paymentAmt = btcutil.Amount(300000) const paymentAmt = btcutil.Amount(300000)
@@ -460,7 +460,7 @@ func testSendPaymentAMP(ht *lntemp.HarnessTest) {
mts.closeChannels() mts.closeChannels()
} }
func testSendToRouteAMP(ht *lntemp.HarnessTest) { func testSendToRouteAMP(ht *lntest.HarnessTest) {
mts := newMppTestScenario(ht) mts := newMppTestScenario(ht)
const ( const (
paymentAmt = btcutil.Amount(300000) paymentAmt = btcutil.Amount(300000)
@@ -18,8 +18,8 @@ import (
"github.com/lightningnetwork/lnd/funding" "github.com/lightningnetwork/lnd/funding"
"github.com/lightningnetwork/lnd/lnrpc" "github.com/lightningnetwork/lnd/lnrpc"
"github.com/lightningnetwork/lnd/lnrpc/walletrpc" "github.com/lightningnetwork/lnd/lnrpc/walletrpc"
"github.com/lightningnetwork/lnd/lntemp" "github.com/lightningnetwork/lnd/lntest"
"github.com/lightningnetwork/lnd/lntemp/node" "github.com/lightningnetwork/lnd/lntest/node"
"github.com/lightningnetwork/lnd/lntest/wait" "github.com/lightningnetwork/lnd/lntest/wait"
"github.com/stretchr/testify/require" "github.com/stretchr/testify/require"
) )
@@ -34,7 +34,7 @@ type (
// that'll return the same node, but with its state restored via a // that'll return the same node, but with its state restored via a
// custom method. We use this to abstract away _how_ a node is restored // custom method. We use this to abstract away _how_ a node is restored
// from our assertions once the node has been fully restored itself. // from our assertions once the node has been fully restored itself.
restoreMethodType func(ht *lntemp.HarnessTest, restoreMethodType func(ht *lntest.HarnessTest,
oldNode *node.HarnessNode, backupFilePath string, oldNode *node.HarnessNode, backupFilePath string,
password []byte, mnemonic []string) nodeRestorer password []byte, mnemonic []string) nodeRestorer
) )
@@ -50,12 +50,12 @@ type chanRestoreScenario struct {
dave *node.HarnessNode dave *node.HarnessNode
password []byte password []byte
mnemonic []string mnemonic []string
params lntemp.OpenChannelParams params lntest.OpenChannelParams
} }
// newChanRestoreScenario creates a new scenario that has two nodes, Carol and // newChanRestoreScenario creates a new scenario that has two nodes, Carol and
// Dave, connected and funded. // Dave, connected and funded.
func newChanRestoreScenario(ht *lntemp.HarnessTest, ct lnrpc.CommitmentType, func newChanRestoreScenario(ht *lntest.HarnessTest, ct lnrpc.CommitmentType,
zeroConf bool) *chanRestoreScenario { zeroConf bool) *chanRestoreScenario {
const ( const (
@@ -70,7 +70,7 @@ func newChanRestoreScenario(ht *lntemp.HarnessTest, ct lnrpc.CommitmentType,
} }
if ct != lnrpc.CommitmentType_UNKNOWN_COMMITMENT_TYPE { if ct != lnrpc.CommitmentType_UNKNOWN_COMMITMENT_TYPE {
args := nodeArgsForCommitType(ct) args := lntest.NodeArgsForCommitType(ct)
nodeArgs = append(nodeArgs, args...) nodeArgs = append(nodeArgs, args...)
} }
@@ -99,7 +99,7 @@ func newChanRestoreScenario(ht *lntemp.HarnessTest, ct lnrpc.CommitmentType,
// For the anchor output case we need two UTXOs for Carol so she can // For the anchor output case we need two UTXOs for Carol so she can
// sweep both the local and remote anchor. // sweep both the local and remote anchor.
if commitTypeHasAnchors(ct) { if lntest.CommitTypeHasAnchors(ct) {
ht.FundCoins(btcutil.SatoshiPerBitcoin, carol) ht.FundCoins(btcutil.SatoshiPerBitcoin, carol)
} }
@@ -112,7 +112,7 @@ func newChanRestoreScenario(ht *lntemp.HarnessTest, ct lnrpc.CommitmentType,
dave: dave, dave: dave,
mnemonic: mnemonic, mnemonic: mnemonic,
password: password, password: password,
params: lntemp.OpenChannelParams{ params: lntest.OpenChannelParams{
Amt: chanAmt, Amt: chanAmt,
PushAmt: pushAmt, PushAmt: pushAmt,
ZeroConf: zeroConf, ZeroConf: zeroConf,
@@ -123,7 +123,7 @@ func newChanRestoreScenario(ht *lntemp.HarnessTest, ct lnrpc.CommitmentType,
// restoreDave will call the `nodeRestorer` and asserts Dave is restored by // restoreDave will call the `nodeRestorer` and asserts Dave is restored by
// checking his wallet balance against zero. // checking his wallet balance against zero.
func (c *chanRestoreScenario) restoreDave(ht *lntemp.HarnessTest, func (c *chanRestoreScenario) restoreDave(ht *lntest.HarnessTest,
restoredNodeFunc nodeRestorer) *node.HarnessNode { restoredNodeFunc nodeRestorer) *node.HarnessNode {
// Next, we'll make a new Dave and start the bulk of our recovery // Next, we'll make a new Dave and start the bulk of our recovery
@@ -154,7 +154,7 @@ func (c *chanRestoreScenario) restoreDave(ht *lntemp.HarnessTest,
// 4. validate pending channel state and check we cannot force close it. // 4. validate pending channel state and check we cannot force close it.
// 5. validate Carol's UTXOs. // 5. validate Carol's UTXOs.
// 6. assert DLP is executed. // 6. assert DLP is executed.
func (c *chanRestoreScenario) testScenario(ht *lntemp.HarnessTest, func (c *chanRestoreScenario) testScenario(ht *lntest.HarnessTest,
restoredNodeFunc nodeRestorer) { restoredNodeFunc nodeRestorer) {
carol, dave := c.carol, c.dave carol, dave := c.carol, c.dave
@@ -212,7 +212,7 @@ func (c *chanRestoreScenario) testScenario(ht *lntemp.HarnessTest,
// let's start up Carol again. // let's start up Carol again.
require.NoError(ht, restartCarol(), "restart carol failed") require.NoError(ht, restartCarol(), "restart carol failed")
if commitTypeHasAnchors(c.params.CommitmentType) { if lntest.CommitTypeHasAnchors(c.params.CommitmentType) {
ht.AssertNumUTXOs(carol, 2) ht.AssertNumUTXOs(carol, 2)
} else { } else {
ht.AssertNumUTXOs(carol, 1) ht.AssertNumUTXOs(carol, 1)
@@ -232,7 +232,7 @@ func (c *chanRestoreScenario) testScenario(ht *lntemp.HarnessTest,
// restoring from initial wallet creation. We'll also alternate between // restoring from initial wallet creation. We'll also alternate between
// restoring form the on disk file, and restoring from the exported RPC command // restoring form the on disk file, and restoring from the exported RPC command
// as well. // as well.
func testChannelBackupRestoreBasic(ht *lntemp.HarnessTest) { func testChannelBackupRestoreBasic(ht *lntest.HarnessTest) {
var testCases = []struct { var testCases = []struct {
name string name string
restoreMethod restoreMethodType restoreMethod restoreMethodType
@@ -241,7 +241,7 @@ func testChannelBackupRestoreBasic(ht *lntemp.HarnessTest) {
// was the initiator, of the non-advertised channel. // was the initiator, of the non-advertised channel.
{ {
name: "restore from RPC backup", name: "restore from RPC backup",
restoreMethod: func(st *lntemp.HarnessTest, restoreMethod: func(st *lntest.HarnessTest,
oldNode *node.HarnessNode, oldNode *node.HarnessNode,
backupFilePath string, backupFilePath string,
password []byte, password []byte,
@@ -269,7 +269,7 @@ func testChannelBackupRestoreBasic(ht *lntemp.HarnessTest) {
// interface. // interface.
{ {
name: "restore from backup file", name: "restore from backup file",
restoreMethod: func(st *lntemp.HarnessTest, restoreMethod: func(st *lntest.HarnessTest,
oldNode *node.HarnessNode, oldNode *node.HarnessNode,
backupFilePath string, backupFilePath string,
password []byte, password []byte,
@@ -293,7 +293,7 @@ func testChannelBackupRestoreBasic(ht *lntemp.HarnessTest) {
// prior mnemonic and new backup seed. // prior mnemonic and new backup seed.
{ {
name: "restore during creation", name: "restore during creation",
restoreMethod: func(st *lntemp.HarnessTest, restoreMethod: func(st *lntest.HarnessTest,
oldNode *node.HarnessNode, oldNode *node.HarnessNode,
backupFilePath string, backupFilePath string,
password []byte, password []byte,
@@ -325,7 +325,7 @@ func testChannelBackupRestoreBasic(ht *lntemp.HarnessTest) {
// re-created, using the Unlock call. // re-created, using the Unlock call.
{ {
name: "restore during unlock", name: "restore during unlock",
restoreMethod: func(st *lntemp.HarnessTest, restoreMethod: func(st *lntest.HarnessTest,
oldNode *node.HarnessNode, oldNode *node.HarnessNode,
backupFilePath string, backupFilePath string,
password []byte, password []byte,
@@ -362,7 +362,7 @@ func testChannelBackupRestoreBasic(ht *lntemp.HarnessTest) {
// make sure imports can be canceled and later resumed. // make sure imports can be canceled and later resumed.
{ {
name: "restore from backup file twice", name: "restore from backup file twice",
restoreMethod: func(st *lntemp.HarnessTest, restoreMethod: func(st *lntest.HarnessTest,
oldNode *node.HarnessNode, oldNode *node.HarnessNode,
backupFilePath string, backupFilePath string,
password []byte, password []byte,
@@ -376,6 +376,8 @@ func testChannelBackupRestoreBasic(ht *lntemp.HarnessTest) {
// Now that we have Dave's backup file, we'll // Now that we have Dave's backup file, we'll
// create a new nodeRestorer that will restore // create a new nodeRestorer that will restore
// using the on-disk channel.backup. // using the on-disk channel.backup.
//
//nolint:lll
backup := &lnrpc.RestoreChanBackupRequest_MultiChanBackup{ backup := &lnrpc.RestoreChanBackupRequest_MultiChanBackup{
MultiChanBackup: multi, MultiChanBackup: multi,
} }
@@ -420,7 +422,7 @@ func testChannelBackupRestoreBasic(ht *lntemp.HarnessTest) {
// ensuring that after Dave restores his channel state according to the // ensuring that after Dave restores his channel state according to the
// testCase, the DLP protocol is executed properly and both nodes are made // testCase, the DLP protocol is executed properly and both nodes are made
// whole. // whole.
func runChanRestoreScenarioBasic(ht *lntemp.HarnessTest, func runChanRestoreScenarioBasic(ht *lntest.HarnessTest,
restoreMethod restoreMethodType) { restoreMethod restoreMethodType) {
// Create a new retore scenario. // Create a new retore scenario.
@@ -445,7 +447,7 @@ func runChanRestoreScenarioBasic(ht *lntemp.HarnessTest,
// testChannelBackupRestoreUnconfirmed tests that we're able to restore from // testChannelBackupRestoreUnconfirmed tests that we're able to restore from
// disk file and the exported RPC command for unconfirmed channel. // disk file and the exported RPC command for unconfirmed channel.
func testChannelBackupRestoreUnconfirmed(ht *lntemp.HarnessTest) { func testChannelBackupRestoreUnconfirmed(ht *lntest.HarnessTest) {
// Use the channel backup file that contains an unconfirmed channel and // Use the channel backup file that contains an unconfirmed channel and
// make sure recovery works as well. // make sure recovery works as well.
ht.Run("restore unconfirmed channel file", func(t *testing.T) { ht.Run("restore unconfirmed channel file", func(t *testing.T) {
@@ -463,7 +465,7 @@ func testChannelBackupRestoreUnconfirmed(ht *lntemp.HarnessTest) {
// runChanRestoreScenarioUnConfirmed checks that Dave is able to restore for an // runChanRestoreScenarioUnConfirmed checks that Dave is able to restore for an
// unconfirmed channel. // unconfirmed channel.
func runChanRestoreScenarioUnConfirmed(ht *lntemp.HarnessTest, useFile bool) { func runChanRestoreScenarioUnConfirmed(ht *lntest.HarnessTest, useFile bool) {
// Create a new retore scenario. // Create a new retore scenario.
crs := newChanRestoreScenario( crs := newChanRestoreScenario(
ht, lnrpc.CommitmentType_UNKNOWN_COMMITMENT_TYPE, false, ht, lnrpc.CommitmentType_UNKNOWN_COMMITMENT_TYPE, false,
@@ -527,7 +529,7 @@ func runChanRestoreScenarioUnConfirmed(ht *lntemp.HarnessTest, useFile bool) {
// testChannelBackupRestoreCommitTypes tests that we're able to recover from, // testChannelBackupRestoreCommitTypes tests that we're able to recover from,
// and initiate the DLP protocol for different channel commitment types and // and initiate the DLP protocol for different channel commitment types and
// zero-conf channel. // zero-conf channel.
func testChannelBackupRestoreCommitTypes(ht *lntemp.HarnessTest) { func testChannelBackupRestoreCommitTypes(ht *lntest.HarnessTest) {
var testCases = []struct { var testCases = []struct {
name string name string
ct lnrpc.CommitmentType ct lnrpc.CommitmentType
@@ -584,7 +586,7 @@ func testChannelBackupRestoreCommitTypes(ht *lntemp.HarnessTest) {
// runChanRestoreScenarioCommitTypes tests that the DLP is applied for // runChanRestoreScenarioCommitTypes tests that the DLP is applied for
// different channel commitment types and zero-conf channel. // different channel commitment types and zero-conf channel.
func runChanRestoreScenarioCommitTypes(ht *lntemp.HarnessTest, func runChanRestoreScenarioCommitTypes(ht *lntest.HarnessTest,
ct lnrpc.CommitmentType, zeroConf bool) { ct lnrpc.CommitmentType, zeroConf bool) {
// Create a new retore scenario. // Create a new retore scenario.
@@ -606,7 +608,7 @@ func runChanRestoreScenarioCommitTypes(ht *lntemp.HarnessTest,
_, minerHeight := ht.Miner.GetBestBlock() _, minerHeight := ht.Miner.GetBestBlock()
thawHeight := uint32(minerHeight + thawHeightDelta) thawHeight := uint32(minerHeight + thawHeightDelta)
fundingShim, _, _ = deriveFundingShim( fundingShim, _ = deriveFundingShim(
ht, dave, carol, crs.params.Amt, thawHeight, true, ht, dave, carol, crs.params.Amt, thawHeight, true,
) )
crs.params.FundingShim = fundingShim crs.params.FundingShim = fundingShim
@@ -639,7 +641,7 @@ func runChanRestoreScenarioCommitTypes(ht *lntemp.HarnessTest,
// testChannelBackupRestoreLegacy checks a channel with the legacy revocation // testChannelBackupRestoreLegacy checks a channel with the legacy revocation
// producer format and makes sure old SCBs can still be recovered. // producer format and makes sure old SCBs can still be recovered.
func testChannelBackupRestoreLegacy(ht *lntemp.HarnessTest) { func testChannelBackupRestoreLegacy(ht *lntest.HarnessTest) {
// Create a new retore scenario. // Create a new retore scenario.
crs := newChanRestoreScenario( crs := newChanRestoreScenario(
ht, lnrpc.CommitmentType_UNKNOWN_COMMITMENT_TYPE, false, ht, lnrpc.CommitmentType_UNKNOWN_COMMITMENT_TYPE, false,
@@ -668,7 +670,7 @@ func testChannelBackupRestoreLegacy(ht *lntemp.HarnessTest) {
// testChannelBackupRestoreForceClose checks that Dave can restore from force // testChannelBackupRestoreForceClose checks that Dave can restore from force
// closed channels. // closed channels.
func testChannelBackupRestoreForceClose(ht *lntemp.HarnessTest) { func testChannelBackupRestoreForceClose(ht *lntest.HarnessTest) {
// Restore a channel that was force closed by dave just before going // Restore a channel that was force closed by dave just before going
// offline. // offline.
success := ht.Run("from backup file anchors", func(t *testing.T) { success := ht.Run("from backup file anchors", func(t *testing.T) {
@@ -691,7 +693,7 @@ func testChannelBackupRestoreForceClose(ht *lntemp.HarnessTest) {
// runChanRestoreScenarioForceClose creates anchor-enabled force close channels // runChanRestoreScenarioForceClose creates anchor-enabled force close channels
// and checks that Dave is able to restore from them. // and checks that Dave is able to restore from them.
func runChanRestoreScenarioForceClose(ht *lntemp.HarnessTest, zeroConf bool) { func runChanRestoreScenarioForceClose(ht *lntest.HarnessTest, zeroConf bool) {
crs := newChanRestoreScenario( crs := newChanRestoreScenario(
ht, lnrpc.CommitmentType_ANCHORS, zeroConf, ht, lnrpc.CommitmentType_ANCHORS, zeroConf,
) )
@@ -792,7 +794,7 @@ func runChanRestoreScenarioForceClose(ht *lntemp.HarnessTest, zeroConf bool) {
// testChannelBackupUpdates tests that both the streaming channel update RPC, // testChannelBackupUpdates tests that both the streaming channel update RPC,
// and the on-disk channel.backup are updated each time a channel is // and the on-disk channel.backup are updated each time a channel is
// opened/closed. // opened/closed.
func testChannelBackupUpdates(ht *lntemp.HarnessTest) { func testChannelBackupUpdates(ht *lntest.HarnessTest) {
alice := ht.Alice alice := ht.Alice
// First, we'll make a temp directory that we'll use to store our // First, we'll make a temp directory that we'll use to store our
@@ -850,7 +852,7 @@ func testChannelBackupUpdates(ht *lntemp.HarnessTest) {
chanAmt := btcutil.Amount(1000000) chanAmt := btcutil.Amount(1000000)
for i := 0; i < numChans; i++ { for i := 0; i < numChans; i++ {
chanPoint := ht.OpenChannel( chanPoint := ht.OpenChannel(
alice, carol, lntemp.OpenChannelParams{Amt: chanAmt}, alice, carol, lntest.OpenChannelParams{Amt: chanAmt},
) )
chanPoints = append(chanPoints, chanPoint) chanPoints = append(chanPoints, chanPoint)
} }
@@ -962,7 +964,7 @@ func testChannelBackupUpdates(ht *lntemp.HarnessTest) {
// testExportChannelBackup tests that we're able to properly export either a // testExportChannelBackup tests that we're able to properly export either a
// targeted channel's backup, or export backups of all the currents open // targeted channel's backup, or export backups of all the currents open
// channels. // channels.
func testExportChannelBackup(ht *lntemp.HarnessTest) { func testExportChannelBackup(ht *lntest.HarnessTest) {
// First, we'll create our primary test node: Carol. We'll use Carol to // First, we'll create our primary test node: Carol. We'll use Carol to
// open channels and also export backups that we'll examine throughout // open channels and also export backups that we'll examine throughout
// the test. // the test.
@@ -979,7 +981,7 @@ func testExportChannelBackup(ht *lntemp.HarnessTest) {
chanAmt := btcutil.Amount(1000000) chanAmt := btcutil.Amount(1000000)
for i := 0; i < numChans; i++ { for i := 0; i < numChans; i++ {
chanPoint := ht.OpenChannel( chanPoint := ht.OpenChannel(
alice, carol, lntemp.OpenChannelParams{Amt: chanAmt}, alice, carol, lntest.OpenChannelParams{Amt: chanAmt},
) )
chanPoints = append(chanPoints, chanPoint) chanPoints = append(chanPoints, chanPoint)
} }
@@ -1022,17 +1024,20 @@ func testExportChannelBackup(ht *lntemp.HarnessTest) {
require.NoError(ht, err, "timeout checking num single backup") require.NoError(ht, err, "timeout checking num single backup")
} }
assertMultiBackupFound := func() func(bool, map[wire.OutPoint]struct{}) { assertMultiBackupFound := func() func(bool,
map[wire.OutPoint]struct{}) {
chanSnapshot := carol.RPC.ExportAllChanBackups() chanSnapshot := carol.RPC.ExportAllChanBackups()
return func(found bool, chanPoints map[wire.OutPoint]struct{}) { return func(found bool, chanPoints map[wire.OutPoint]struct{}) {
num := len(chanSnapshot.MultiChanBackup.MultiChanBackup)
switch { switch {
case found && chanSnapshot.MultiChanBackup == nil: case found && chanSnapshot.MultiChanBackup == nil:
require.Fail(ht, "multi-backup not present") require.Fail(ht, "multi-backup not present")
case !found && chanSnapshot.MultiChanBackup != nil && case !found && chanSnapshot.MultiChanBackup != nil &&
(len(chanSnapshot.MultiChanBackup.MultiChanBackup) != num != chanbackup.NilMultiSizePacked:
chanbackup.NilMultiSizePacked):
require.Fail(ht, "found multi-backup when "+ require.Fail(ht, "found multi-backup when "+
"non should be found") "non should be found")
@@ -1086,7 +1091,7 @@ func testExportChannelBackup(ht *lntemp.HarnessTest) {
// relationship lost state, they will detect this during channel sync, and the // relationship lost state, they will detect this during channel sync, and the
// up-to-date party will force close the channel, giving the outdated party the // up-to-date party will force close the channel, giving the outdated party the
// opportunity to sweep its output. // opportunity to sweep its output.
func testDataLossProtection(ht *lntemp.HarnessTest) { func testDataLossProtection(ht *lntest.HarnessTest) {
const ( const (
chanAmt = funding.MaxBtcFundingAmount chanAmt = funding.MaxBtcFundingAmount
paymentAmt = 10000 paymentAmt = 10000
@@ -1107,22 +1112,20 @@ func testDataLossProtection(ht *lntemp.HarnessTest) {
// directly from the miner. // directly from the miner.
ht.FundCoins(btcutil.SatoshiPerBitcoin, carol) ht.FundCoins(btcutil.SatoshiPerBitcoin, carol)
// timeTravel is a method that will make Carol open a channel to the // timeTravelDave is a method that will make Carol open a channel to
// passed node, settle a series of payments, then reset the node back // Dave, settle a series of payments, then Dave back to the state
// to the state before the payments happened. When this method returns // before the payments happened. When this method returns Dave will
// the node will be unaware of the new state updates. The returned // be unaware of the new state updates. The returned function can be
// function can be used to restart the node in this state. // used to restart Dave in this state.
timeTravel := func(node *node.HarnessNode) (func() error, timeTravelDave := func() (func() error, *lnrpc.ChannelPoint, int64) {
*lnrpc.ChannelPoint, int64) {
// We must let the node communicate with Carol before they are // We must let the node communicate with Carol before they are
// able to open channel, so we connect them. // able to open channel, so we connect them.
ht.EnsureConnected(carol, node) ht.EnsureConnected(carol, dave)
// We'll first open up a channel between them with a 0.5 BTC // We'll first open up a channel between them with a 0.5 BTC
// value. // value.
chanPoint := ht.OpenChannel( chanPoint := ht.OpenChannel(
carol, node, lntemp.OpenChannelParams{ carol, dave, lntest.OpenChannelParams{
Amt: chanAmt, Amt: chanAmt,
}, },
) )
@@ -1132,17 +1135,17 @@ func testDataLossProtection(ht *lntemp.HarnessTest) {
// the channel. // the channel.
// TODO(halseth): have dangling HTLCs on the commitment, able to // TODO(halseth): have dangling HTLCs on the commitment, able to
// retrieve funds? // retrieve funds?
payReqs, _, _ := ht.CreatePayReqs(node, paymentAmt, numInvoices) payReqs, _, _ := ht.CreatePayReqs(dave, paymentAmt, numInvoices)
// Send payments from Carol using 3 of the payment hashes // Send payments from Carol using 3 of the payment hashes
// generated above. // generated above.
ht.CompletePaymentRequests(carol, payReqs[:numInvoices/2]) ht.CompletePaymentRequests(carol, payReqs[:numInvoices/2])
// Next query for the node's channel state, as we sent 3 // Next query for Dave's channel state, as we sent 3 payments
// payments of 10k satoshis each, it should now see his balance // of 10k satoshis each, it should now see his balance as being
// as being 30k satoshis. // 30k satoshis.
nodeChan := ht.AssertChannelLocalBalance( nodeChan := ht.AssertChannelLocalBalance(
node, chanPoint, 30_000, dave, chanPoint, 30_000,
) )
// Grab the current commitment height (update number), we'll // Grab the current commitment height (update number), we'll
@@ -1153,39 +1156,46 @@ func testDataLossProtection(ht *lntemp.HarnessTest) {
// With the temporary file created, copy the current state into // With the temporary file created, copy the current state into
// the temporary file we created above. Later after more // the temporary file we created above. Later after more
// updates, we'll restore this state. // updates, we'll restore this state.
ht.BackupDB(node) ht.BackupDB(dave)
// Reconnect the peers after the restart that was needed for // Reconnect the peers after the restart that was needed for
// the db backup. // the db backup.
ht.EnsureConnected(carol, node) ht.EnsureConnected(carol, dave)
// Finally, send more payments from , using the remaining // Finally, send more payments from Carol, using the remaining
// payment hashes. // payment hashes.
ht.CompletePaymentRequests(carol, payReqs[numInvoices/2:]) ht.CompletePaymentRequests(carol, payReqs[numInvoices/2:])
// Now we shutdown the node, copying over the its temporary // TODO(yy): remove the sleep once the following bug is fixed.
//
// While the payment is reported as settled, the commitment
// dance may not be finished, which leaves several HTLCs in the
// commitment. Later on, when Carol force closes this channel,
// she would have HTLCs there and the test won't pass.
time.Sleep(2 * time.Second)
// Now we shutdown Dave, copying over the its temporary
// database state which has the *prior* channel state over his // database state which has the *prior* channel state over his
// current most up to date state. With this, we essentially // current most up to date state. With this, we essentially
// force the node to travel back in time within the channel's // force Dave to travel back in time within the channel's
// history. // history.
ht.RestartNodeAndRestoreDB(node) ht.RestartNodeAndRestoreDB(dave)
// Make sure the channel is still there from the PoV of the // Make sure the channel is still there from the PoV of Dave.
// node. ht.AssertNodeNumChannels(dave, 1)
ht.AssertNodeNumChannels(node, 1)
// Now query for the channel state, it should show that it's at // Now query for the channel state, it should show that it's at
// a state number in the past, not the *latest* state. // a state number in the past, not the *latest* state.
ht.AssertChannelNumUpdates(node, stateNumPreCopy, chanPoint) ht.AssertChannelNumUpdates(dave, stateNumPreCopy, chanPoint)
balResp := node.RPC.WalletBalance() balResp := dave.RPC.WalletBalance()
restart := ht.SuspendNode(node) restart := ht.SuspendNode(dave)
return restart, chanPoint, balResp.ConfirmedBalance return restart, chanPoint, balResp.ConfirmedBalance
} }
// Reset Dave to a state where he has an outdated channel state. // Reset Dave to a state where he has an outdated channel state.
restartDave, _, daveStartingBalance := timeTravel(dave) restartDave, _, daveStartingBalance := timeTravelDave()
// We make a note of the nodes' current on-chain balances, to make sure // We make a note of the nodes' current on-chain balances, to make sure
// they are able to retrieve the channel funds eventually, // they are able to retrieve the channel funds eventually,
@@ -1209,7 +1219,7 @@ func testDataLossProtection(ht *lntemp.HarnessTest) {
// closed channel, such that Dave can retrieve his funds. // closed channel, such that Dave can retrieve his funds.
// //
// We start by letting Dave time travel back to an outdated state. // We start by letting Dave time travel back to an outdated state.
restartDave, chanPoint2, daveStartingBalance := timeTravel(dave) restartDave, chanPoint2, daveStartingBalance := timeTravelDave()
carolBalResp = carol.RPC.WalletBalance() carolBalResp = carol.RPC.WalletBalance()
carolStartingBalance = carolBalResp.ConfirmedBalance carolStartingBalance = carolBalResp.ConfirmedBalance
@@ -1255,7 +1265,7 @@ func testDataLossProtection(ht *lntemp.HarnessTest) {
// createLegacyRevocationChannel creates a single channel using the legacy // createLegacyRevocationChannel creates a single channel using the legacy
// revocation producer format by using PSBT to signal a special pending channel // revocation producer format by using PSBT to signal a special pending channel
// ID. // ID.
func createLegacyRevocationChannel(ht *lntemp.HarnessTest, func createLegacyRevocationChannel(ht *lntest.HarnessTest,
chanAmt, pushAmt btcutil.Amount, from, to *node.HarnessNode) { chanAmt, pushAmt btcutil.Amount, from, to *node.HarnessNode) {
// We'll signal to the wallet that we also want to create a channel // We'll signal to the wallet that we also want to create a channel
@@ -1277,7 +1287,7 @@ func createLegacyRevocationChannel(ht *lntemp.HarnessTest,
}, },
}, },
} }
openChannelReq := lntemp.OpenChannelParams{ openChannelReq := lntest.OpenChannelParams{
Amt: chanAmt, Amt: chanAmt,
PushAmt: pushAmt, PushAmt: pushAmt,
FundingShim: shim, FundingShim: shim,
@@ -1295,8 +1305,9 @@ func createLegacyRevocationChannel(ht *lntemp.HarnessTest,
} }
fundResp := from.RPC.FundPsbt(fundReq) fundResp := from.RPC.FundPsbt(fundReq)
// We have a PSBT that has no witness data yet, which is exactly what we // We have a PSBT that has no witness data yet, which is exactly what
// need for the next step of verifying the PSBT with the funding intents. // we need for the next step of verifying the PSBT with the funding
// intents.
msg := &lnrpc.FundingTransitionMsg{ msg := &lnrpc.FundingTransitionMsg{
Trigger: &lnrpc.FundingTransitionMsg_PsbtVerify{ Trigger: &lnrpc.FundingTransitionMsg_PsbtVerify{
PsbtVerify: &lnrpc.FundingPsbtVerify{ PsbtVerify: &lnrpc.FundingPsbtVerify{
@@ -1345,7 +1356,7 @@ func createLegacyRevocationChannel(ht *lntemp.HarnessTest,
// chanRestoreViaRPC is a helper test method that returns a nodeRestorer // chanRestoreViaRPC is a helper test method that returns a nodeRestorer
// instance which will restore the target node from a password+seed, then // instance which will restore the target node from a password+seed, then
// trigger a SCB restore using the RPC interface. // trigger a SCB restore using the RPC interface.
func chanRestoreViaRPC(ht *lntemp.HarnessTest, password []byte, func chanRestoreViaRPC(ht *lntest.HarnessTest, password []byte,
mnemonic []string, multi []byte, mnemonic []string, multi []byte,
oldNode *node.HarnessNode) nodeRestorer { oldNode *node.HarnessNode) nodeRestorer {
@@ -1382,7 +1393,7 @@ func copyPorts(oldNode *node.HarnessNode) node.Option {
// //
// Note: this function is only used in this test file and has been made // Note: this function is only used in this test file and has been made
// specifically for testChanRestoreScenario. // specifically for testChanRestoreScenario.
func assertTimeLockSwept(ht *lntemp.HarnessTest, carol, dave *node.HarnessNode, func assertTimeLockSwept(ht *lntest.HarnessTest, carol, dave *node.HarnessNode,
carolStartingBalance, daveStartingBalance int64) { carolStartingBalance, daveStartingBalance int64) {
// We expect Carol to sweep her funds and also the anchor tx. // We expect Carol to sweep her funds and also the anchor tx.
@@ -1450,11 +1461,13 @@ func assertTimeLockSwept(ht *lntemp.HarnessTest, carol, dave *node.HarnessNode,
// funds immediately, and Carol sweeping her fund after her CSV delay is up. If // funds immediately, and Carol sweeping her fund after her CSV delay is up. If
// the blankSlate value is true, then this means that Dave won't need to sweep // the blankSlate value is true, then this means that Dave won't need to sweep
// on chain as he has no funds in the channel. // on chain as he has no funds in the channel.
func assertDLPExecuted(ht *lntemp.HarnessTest, func assertDLPExecuted(ht *lntest.HarnessTest,
carol *node.HarnessNode, carolStartingBalance int64, carol *node.HarnessNode, carolStartingBalance int64,
dave *node.HarnessNode, daveStartingBalance int64, dave *node.HarnessNode, daveStartingBalance int64,
commitType lnrpc.CommitmentType) { commitType lnrpc.CommitmentType) {
ht.Helper()
// Increase the fee estimate so that the following force close tx will // Increase the fee estimate so that the following force close tx will
// be cpfp'ed. // be cpfp'ed.
ht.SetFeeEstimate(30000) ht.SetFeeEstimate(30000)
@@ -1467,7 +1480,7 @@ func assertDLPExecuted(ht *lntemp.HarnessTest,
// Upon reconnection, the nodes should detect that Dave is out of sync. // Upon reconnection, the nodes should detect that Dave is out of sync.
// Carol should force close the channel using her latest commitment. // Carol should force close the channel using her latest commitment.
expectedTxes := 1 expectedTxes := 1
if commitTypeHasAnchors(commitType) { if lntest.CommitTypeHasAnchors(commitType) {
expectedTxes = 2 expectedTxes = 2
} }
ht.Miner.AssertNumTxsInMempool(expectedTxes) ht.Miner.AssertNumTxsInMempool(expectedTxes)
@@ -7,8 +7,8 @@ import (
"github.com/lightningnetwork/lnd/funding" "github.com/lightningnetwork/lnd/funding"
"github.com/lightningnetwork/lnd/lnrpc" "github.com/lightningnetwork/lnd/lnrpc"
"github.com/lightningnetwork/lnd/lnrpc/routerrpc" "github.com/lightningnetwork/lnd/lnrpc/routerrpc"
"github.com/lightningnetwork/lnd/lntemp" "github.com/lightningnetwork/lnd/lntest"
"github.com/lightningnetwork/lnd/lntemp/node" "github.com/lightningnetwork/lnd/lntest/node"
"github.com/lightningnetwork/lnd/lntest/wait" "github.com/lightningnetwork/lnd/lntest/wait"
"github.com/lightningnetwork/lnd/lnwire" "github.com/lightningnetwork/lnd/lnwire"
"github.com/stretchr/testify/require" "github.com/stretchr/testify/require"
@@ -16,7 +16,7 @@ import (
// testChannelBalance creates a new channel between Alice and Bob, then checks // testChannelBalance creates a new channel between Alice and Bob, then checks
// channel balance to be equal amount specified while creation of channel. // channel balance to be equal amount specified while creation of channel.
func testChannelBalance(ht *lntemp.HarnessTest) { func testChannelBalance(ht *lntest.HarnessTest) {
// Open a channel with 0.16 BTC between Alice and Bob, ensuring the // Open a channel with 0.16 BTC between Alice and Bob, ensuring the
// channel has been opened properly. // channel has been opened properly.
amount := funding.MaxBtcFundingAmount amount := funding.MaxBtcFundingAmount
@@ -52,16 +52,16 @@ func testChannelBalance(ht *lntemp.HarnessTest) {
ht.EnsureConnected(alice, bob) ht.EnsureConnected(alice, bob)
chanPoint := ht.OpenChannel( chanPoint := ht.OpenChannel(
alice, bob, lntemp.OpenChannelParams{Amt: amount}, alice, bob, lntest.OpenChannelParams{Amt: amount},
) )
cType := ht.GetChannelCommitType(alice, chanPoint) cType := ht.GetChannelCommitType(alice, chanPoint)
// As this is a single funder channel, Alice's balance should be // As this is a single funder channel, Alice's balance should be
// exactly 0.5 BTC since now state transitions have taken place yet. // exactly 0.5 BTC since now state transitions have taken place yet.
checkChannelBalance(alice, amount-calcStaticFee(cType, 0), 0) checkChannelBalance(alice, amount-lntest.CalcStaticFee(cType, 0), 0)
// Ensure Bob currently has no available balance within the channel. // Ensure Bob currently has no available balance within the channel.
checkChannelBalance(bob, 0, amount-calcStaticFee(cType, 0)) checkChannelBalance(bob, 0, amount-lntest.CalcStaticFee(cType, 0))
// Finally close the channel between Alice and Bob, asserting that the // Finally close the channel between Alice and Bob, asserting that the
// channel has been properly closed on-chain. // channel has been properly closed on-chain.
@@ -73,7 +73,7 @@ func testChannelBalance(ht *lntemp.HarnessTest) {
// Alice will send Htlcs to Carol while she is in hodl mode. This will result // Alice will send Htlcs to Carol while she is in hodl mode. This will result
// in a build of pending Htlcs. We expect the channels unsettled balance to // in a build of pending Htlcs. We expect the channels unsettled balance to
// equal the sum of all the Pending Htlcs. // equal the sum of all the Pending Htlcs.
func testChannelUnsettledBalance(ht *lntemp.HarnessTest) { func testChannelUnsettledBalance(ht *lntest.HarnessTest) {
const chanAmt = btcutil.Amount(1000000) const chanAmt = btcutil.Amount(1000000)
// Creates a helper closure to be used below which asserts the proper // Creates a helper closure to be used below which asserts the proper
@@ -123,17 +123,21 @@ func testChannelUnsettledBalance(ht *lntemp.HarnessTest) {
// Open a channel between Alice and Carol. // Open a channel between Alice and Carol.
chanPointAlice := ht.OpenChannel( chanPointAlice := ht.OpenChannel(
alice, carol, lntemp.OpenChannelParams{Amt: chanAmt}, alice, carol, lntest.OpenChannelParams{Amt: chanAmt},
) )
cType := ht.GetChannelCommitType(alice, chanPointAlice) cType := ht.GetChannelCommitType(alice, chanPointAlice)
// Check alice's channel balance, which should have zero remote and zero // Check alice's channel balance, which should have zero remote and zero
// pending balance. // pending balance.
checkChannelBalance(alice, chanAmt-calcStaticFee(cType, 0), 0, 0, 0) checkChannelBalance(
alice, chanAmt-lntest.CalcStaticFee(cType, 0), 0, 0, 0,
)
// Check carol's channel balance, which should have zero local and zero // Check carol's channel balance, which should have zero local and zero
// pending balance. // pending balance.
checkChannelBalance(carol, 0, chanAmt-calcStaticFee(cType, 0), 0, 0) checkChannelBalance(
carol, 0, chanAmt-lntest.CalcStaticFee(cType, 0), 0, 0,
)
// Channel should be ready for payments. // Channel should be ready for payments.
const ( const (
@@ -195,7 +199,8 @@ func testChannelUnsettledBalance(ht *lntemp.HarnessTest) {
// Check alice's channel balance, which should have a remote unsettled // Check alice's channel balance, which should have a remote unsettled
// balance that equals to the amount of invoices * payAmt. The remote // balance that equals to the amount of invoices * payAmt. The remote
// balance remains zero. // balance remains zero.
aliceLocal := chanAmt - calcStaticFee(cType, 0) - numInvoices*payAmt fee := lntest.CalcStaticFee(cType, 0)
aliceLocal := chanAmt - fee - numInvoices*payAmt
checkChannelBalance(alice, aliceLocal, 0, 0, numInvoices*payAmt) checkChannelBalance(alice, aliceLocal, 0, 0, numInvoices*payAmt)
// Check carol's channel balance, which should have a local unsettled // Check carol's channel balance, which should have a local unsettled
@@ -13,8 +13,8 @@ import (
"github.com/lightningnetwork/lnd/chainreg" "github.com/lightningnetwork/lnd/chainreg"
"github.com/lightningnetwork/lnd/lnrpc" "github.com/lightningnetwork/lnd/lnrpc"
"github.com/lightningnetwork/lnd/lnrpc/routerrpc" "github.com/lightningnetwork/lnd/lnrpc/routerrpc"
"github.com/lightningnetwork/lnd/lntemp" "github.com/lightningnetwork/lnd/lntest"
"github.com/lightningnetwork/lnd/lntemp/node" "github.com/lightningnetwork/lnd/lntest/node"
"github.com/lightningnetwork/lnd/lntest/wait" "github.com/lightningnetwork/lnd/lntest/wait"
"github.com/lightningnetwork/lnd/lnwallet" "github.com/lightningnetwork/lnd/lnwallet"
"github.com/lightningnetwork/lnd/lnwallet/chainfee" "github.com/lightningnetwork/lnd/lnwallet/chainfee"
@@ -30,7 +30,7 @@ import (
// //
// Note that whether the deadline is used or not is implicitly checked by its // Note that whether the deadline is used or not is implicitly checked by its
// corresponding fee rates. // corresponding fee rates.
func testCommitmentTransactionDeadline(ht *lntemp.HarnessTest) { func testCommitmentTransactionDeadline(ht *lntest.HarnessTest) {
// Get the default max fee rate used in sweeping the commitment // Get the default max fee rate used in sweeping the commitment
// transaction. // transaction.
defaultMax := lnwallet.DefaultAnchorsCommitMaxFeeRateSatPerVByte defaultMax := lnwallet.DefaultAnchorsCommitMaxFeeRateSatPerVByte
@@ -72,7 +72,7 @@ func testCommitmentTransactionDeadline(ht *lntemp.HarnessTest) {
setupNode := func(name string) *node.HarnessNode { setupNode := func(name string) *node.HarnessNode {
// Create the node. // Create the node.
args := []string{"--hodl.exit-settle"} args := []string{"--hodl.exit-settle"}
args = append(args, nodeArgsForCommitType( args = append(args, lntest.NodeArgsForCommitType(
lnrpc.CommitmentType_ANCHORS)..., lnrpc.CommitmentType_ANCHORS)...,
) )
node := ht.NewNode(name, args) node := ht.NewNode(name, args)
@@ -104,7 +104,7 @@ func testCommitmentTransactionDeadline(ht *lntemp.HarnessTest) {
// Open a channel between Alice and Bob. // Open a channel between Alice and Bob.
chanPoint := ht.OpenChannel( chanPoint := ht.OpenChannel(
alice, bob, lntemp.OpenChannelParams{ alice, bob, lntest.OpenChannelParams{
Amt: 10e6, Amt: 10e6,
PushAmt: 5e6, PushAmt: 5e6,
}, },
@@ -194,7 +194,7 @@ func testCommitmentTransactionDeadline(ht *lntemp.HarnessTest) {
// process. // process.
// //
// TODO(roasbeef): also add an unsettled HTLC before force closing. // TODO(roasbeef): also add an unsettled HTLC before force closing.
func testChannelForceClosure(ht *lntemp.HarnessTest) { func testChannelForceClosure(ht *lntest.HarnessTest) {
// We'll test the scenario for some of the commitment types, to ensure // We'll test the scenario for some of the commitment types, to ensure
// outputs can be swept. // outputs can be swept.
commitTypes := []lnrpc.CommitmentType{ commitTypes := []lnrpc.CommitmentType{
@@ -209,7 +209,7 @@ func testChannelForceClosure(ht *lntemp.HarnessTest) {
success := ht.Run(testName, func(t *testing.T) { success := ht.Run(testName, func(t *testing.T) {
st := ht.Subtest(t) st := ht.Subtest(t)
args := nodeArgsForCommitType(channelType) args := lntest.NodeArgsForCommitType(channelType)
alice := st.NewNode("Alice", args) alice := st.NewNode("Alice", args)
defer st.Shutdown(alice) defer st.Shutdown(alice)
@@ -237,7 +237,7 @@ func testChannelForceClosure(ht *lntemp.HarnessTest) {
} }
} }
func channelForceClosureTest(ht *lntemp.HarnessTest, func channelForceClosureTest(ht *lntest.HarnessTest,
alice, carol *node.HarnessNode, channelType lnrpc.CommitmentType) { alice, carol *node.HarnessNode, channelType lnrpc.CommitmentType) {
const ( const (
@@ -268,7 +268,7 @@ func channelForceClosureTest(ht *lntemp.HarnessTest,
carolStartingBalance := carolBalResp.ConfirmedBalance carolStartingBalance := carolBalResp.ConfirmedBalance
chanPoint := ht.OpenChannel( chanPoint := ht.OpenChannel(
alice, carol, lntemp.OpenChannelParams{ alice, carol, lntest.OpenChannelParams{
Amt: chanAmt, Amt: chanAmt,
PushAmt: pushAmt, PushAmt: pushAmt,
}, },
@@ -600,6 +600,20 @@ func channelForceClosureTest(ht *lntemp.HarnessTest,
// Update current height // Update current height
_, curHeight = ht.Miner.GetBestBlock() _, curHeight = ht.Miner.GetBestBlock()
// checkForceClosedChannelNumHtlcs verifies that a force closed channel
// has the proper number of htlcs.
checkPendingChannelNumHtlcs := func(
forceClose lntest.PendingForceClose) error {
if len(forceClose.PendingHtlcs) != numInvoices {
return fmt.Errorf("expected force closed channel to "+
"have %d pending htlcs, found %d instead",
numInvoices, len(forceClose.PendingHtlcs))
}
return nil
}
err = wait.NoError(func() error { err = wait.NoError(func() error {
// Now that the commit output has been fully swept, check to // Now that the commit output has been fully swept, check to
// see that the channel remains open for the pending htlc // see that the channel remains open for the pending htlc
@@ -611,7 +625,7 @@ func channelForceClosureTest(ht *lntemp.HarnessTest,
// The commitment funds will have been recovered after the // The commitment funds will have been recovered after the
// commit txn was included in the last block. The htlc funds // commit txn was included in the last block. The htlc funds
// will be shown in limbo. // will be shown in limbo.
err := checkPendingChannelNumHtlcs(forceClose, numInvoices) err := checkPendingChannelNumHtlcs(forceClose)
if err != nil { if err != nil {
return err return err
} }
@@ -659,7 +673,7 @@ func channelForceClosureTest(ht *lntemp.HarnessTest,
// We should now be at the block just before the utxo nursery // We should now be at the block just before the utxo nursery
// will attempt to broadcast the htlc timeout transactions. // will attempt to broadcast the htlc timeout transactions.
err = checkPendingChannelNumHtlcs(forceClose, numInvoices) err = checkPendingChannelNumHtlcs(forceClose)
if err != nil { if err != nil {
return err return err
} }
@@ -702,9 +716,9 @@ func channelForceClosureTest(ht *lntemp.HarnessTest,
// Retrieve each htlc timeout txn from the mempool, and ensure it is // Retrieve each htlc timeout txn from the mempool, and ensure it is
// well-formed. This entails verifying that each only spends from // well-formed. This entails verifying that each only spends from
// output, and that that output is from the commitment txn. In case // output, and that output is from the commitment txn. In case this is
// this is an anchor channel, the transactions are aggregated by the // an anchor channel, the transactions are aggregated by the sweeper
// sweeper into one. // into one.
numInputs := 1 numInputs := 1
if channelType == lnrpc.CommitmentType_ANCHORS { if channelType == lnrpc.CommitmentType_ANCHORS {
numInputs = numInvoices + 1 numInputs = numInvoices + 1
@@ -796,7 +810,7 @@ func channelForceClosureTest(ht *lntemp.HarnessTest,
// We record the htlc amount less fees here, so that we know // We record the htlc amount less fees here, so that we know
// what value to expect for the second stage of our htlc // what value to expect for the second stage of our htlc
// htlc resolution. // resolution.
htlcLessFees = uint64(outputs[0].Value) htlcLessFees = uint64(outputs[0].Value)
} }
@@ -838,7 +852,7 @@ func channelForceClosureTest(ht *lntemp.HarnessTest,
return fmt.Errorf("htlc funds should still be in limbo") return fmt.Errorf("htlc funds should still be in limbo")
} }
return checkPendingChannelNumHtlcs(forceClose, numInvoices) return checkPendingChannelNumHtlcs(forceClose)
}, defaultTimeout) }, defaultTimeout)
require.NoError(ht, err, "timeout while checking force closed channel") require.NoError(ht, err, "timeout while checking force closed channel")
@@ -913,7 +927,7 @@ func channelForceClosureTest(ht *lntemp.HarnessTest,
forceClose := ht.AssertChannelPendingForceClose( forceClose := ht.AssertChannelPendingForceClose(
alice, chanPoint, alice, chanPoint,
) )
err := checkPendingChannelNumHtlcs(forceClose, numInvoices) err := checkPendingChannelNumHtlcs(forceClose)
if err != nil { if err != nil {
return err return err
} }
@@ -986,7 +1000,7 @@ func padCLTV(cltv uint32) uint32 {
// testFailingChannel tests that we will fail the channel by force closing it // testFailingChannel tests that we will fail the channel by force closing it
// in the case where a counterparty tries to settle an HTLC with the wrong // in the case where a counterparty tries to settle an HTLC with the wrong
// preimage. // preimage.
func testFailingChannel(ht *lntemp.HarnessTest) { func testFailingChannel(ht *lntest.HarnessTest) {
const paymentAmt = 10000 const paymentAmt = 10000
chanAmt := lnd.MaxFundingAmount chanAmt := lnd.MaxFundingAmount
@@ -999,7 +1013,7 @@ func testFailingChannel(ht *lntemp.HarnessTest) {
ht.ConnectNodes(alice, carol) ht.ConnectNodes(alice, carol)
// Let Alice connect and open a channel to Carol, // Let Alice connect and open a channel to Carol,
ht.OpenChannel(alice, carol, lntemp.OpenChannelParams{Amt: chanAmt}) ht.OpenChannel(alice, carol, lntest.OpenChannelParams{Amt: chanAmt})
// With the channel open, we'll create a invoice for Carol that Alice // With the channel open, we'll create a invoice for Carol that Alice
// will attempt to pay. // will attempt to pay.
@@ -1058,7 +1072,7 @@ func testFailingChannel(ht *lntemp.HarnessTest) {
// type matches a set of expected resolutions. // type matches a set of expected resolutions.
// //
// NOTE: only used in current test file. // NOTE: only used in current test file.
func assertReports(ht *lntemp.HarnessTest, hn *node.HarnessNode, func assertReports(ht *lntest.HarnessTest, hn *node.HarnessNode,
chanPoint *lnrpc.ChannelPoint, expected map[string]*lnrpc.Resolution) { chanPoint *lnrpc.ChannelPoint, expected map[string]*lnrpc.Resolution) {
op := ht.OutPointFromChannelPoint(chanPoint) op := ht.OutPointFromChannelPoint(chanPoint)
@@ -1087,3 +1101,54 @@ func assertReports(ht *lntemp.HarnessTest, hn *node.HarnessNode,
require.Equal(ht, expected, res) require.Equal(ht, expected, res)
} }
} }
// checkCommitmentMaturity checks that both the maturity height and blocks
// maturity height are as expected.
//
// NOTE: only used in current test file.
func checkCommitmentMaturity(forceClose lntest.PendingForceClose,
maturityHeight uint32, blocksTilMaturity int32) error {
if forceClose.MaturityHeight != maturityHeight {
return fmt.Errorf("expected commitment maturity height to be "+
"%d, found %d instead", maturityHeight,
forceClose.MaturityHeight)
}
if forceClose.BlocksTilMaturity != blocksTilMaturity {
return fmt.Errorf("expected commitment blocks til maturity to "+
"be %d, found %d instead", blocksTilMaturity,
forceClose.BlocksTilMaturity)
}
return nil
}
// checkPendingHtlcStageAndMaturity uniformly tests all pending htlc's belonging
// to a force closed channel, testing for the expected stage number, blocks till
// maturity, and the maturity height.
//
// NOTE: only used in current test file.
func checkPendingHtlcStageAndMaturity(
forceClose *lnrpc.PendingChannelsResponse_ForceClosedChannel,
stage, maturityHeight uint32, blocksTillMaturity int32) error {
for _, pendingHtlc := range forceClose.PendingHtlcs {
if pendingHtlc.Stage != stage {
return fmt.Errorf("expected pending htlc to be stage "+
"%d, found %d", stage, pendingHtlc.Stage)
}
if pendingHtlc.MaturityHeight != maturityHeight {
return fmt.Errorf("expected pending htlc maturity "+
"height to be %d, instead has %d",
maturityHeight, pendingHtlc.MaturityHeight)
}
if pendingHtlc.BlocksTilMaturity != blocksTillMaturity {
return fmt.Errorf("expected pending htlc blocks til "+
"maturity to be %d, instead has %d",
blocksTillMaturity,
pendingHtlc.BlocksTilMaturity)
}
}
return nil
}
@@ -11,8 +11,8 @@ import (
"github.com/lightningnetwork/lnd/lnrpc" "github.com/lightningnetwork/lnd/lnrpc"
"github.com/lightningnetwork/lnd/lnrpc/peersrpc" "github.com/lightningnetwork/lnd/lnrpc/peersrpc"
"github.com/lightningnetwork/lnd/lnrpc/routerrpc" "github.com/lightningnetwork/lnd/lnrpc/routerrpc"
"github.com/lightningnetwork/lnd/lntemp" "github.com/lightningnetwork/lnd/lntest"
"github.com/lightningnetwork/lnd/lntemp/node" "github.com/lightningnetwork/lnd/lntest/node"
"github.com/lightningnetwork/lnd/lntest/wait" "github.com/lightningnetwork/lnd/lntest/wait"
"github.com/stretchr/testify/require" "github.com/stretchr/testify/require"
) )
@@ -40,7 +40,7 @@ import (
// take more than 5 seconds to finish, the channel will be marked as disabled, // take more than 5 seconds to finish, the channel will be marked as disabled,
// thus a following operation will fail if it relies on the channel being // thus a following operation will fail if it relies on the channel being
// enabled. // enabled.
func testUpdateChanStatus(ht *lntemp.HarnessTest) { func testUpdateChanStatus(ht *lntest.HarnessTest) {
// Create two fresh nodes and open a channel between them. // Create two fresh nodes and open a channel between them.
alice, bob := ht.Alice, ht.Bob alice, bob := ht.Alice, ht.Bob
args := []string{ args := []string{
@@ -57,7 +57,7 @@ func testUpdateChanStatus(ht *lntemp.HarnessTest) {
// being the sole funder of the channel. // being the sole funder of the channel.
chanAmt := btcutil.Amount(100000) chanAmt := btcutil.Amount(100000)
chanPoint := ht.OpenChannel( chanPoint := ht.OpenChannel(
alice, bob, lntemp.OpenChannelParams{Amt: chanAmt}, alice, bob, lntest.OpenChannelParams{Amt: chanAmt},
) )
defer ht.CloseChannel(alice, chanPoint) defer ht.CloseChannel(alice, chanPoint)
@@ -141,7 +141,7 @@ func testUpdateChanStatus(ht *lntemp.HarnessTest) {
FeeRateMilliMsat: int64(chainreg.DefaultBitcoinFeeRate), FeeRateMilliMsat: int64(chainreg.DefaultBitcoinFeeRate),
TimeLockDelta: chainreg.DefaultBitcoinTimeLockDelta, TimeLockDelta: chainreg.DefaultBitcoinTimeLockDelta,
MinHtlc: 1000, // default value MinHtlc: 1000, // default value
MaxHtlcMsat: calculateMaxHtlc(chanAmt), MaxHtlcMsat: lntest.CalculateMaxHtlc(chanAmt),
} }
// Manually disable the channel and ensure that a "Disabled = true" // Manually disable the channel and ensure that a "Disabled = true"
@@ -217,14 +217,14 @@ func testUpdateChanStatus(ht *lntemp.HarnessTest) {
// testUnannouncedChannels checks unannounced channels are not returned by // testUnannouncedChannels checks unannounced channels are not returned by
// describeGraph RPC request unless explicitly asked for. // describeGraph RPC request unless explicitly asked for.
func testUnannouncedChannels(ht *lntemp.HarnessTest) { func testUnannouncedChannels(ht *lntest.HarnessTest) {
amount := funding.MaxBtcFundingAmount amount := funding.MaxBtcFundingAmount
alice, bob := ht.Alice, ht.Bob alice, bob := ht.Alice, ht.Bob
// Open a channel between Alice and Bob, ensuring the // Open a channel between Alice and Bob, ensuring the
// channel has been opened properly. // channel has been opened properly.
chanOpenUpdate := ht.OpenChannelAssertStream( chanOpenUpdate := ht.OpenChannelAssertStream(
alice, bob, lntemp.OpenChannelParams{Amt: amount}, alice, bob, lntest.OpenChannelParams{Amt: amount},
) )
// Mine 2 blocks, and check that the channel is opened but not yet // Mine 2 blocks, and check that the channel is opened but not yet
@@ -252,7 +252,7 @@ func testUnannouncedChannels(ht *lntemp.HarnessTest) {
ht.CloseChannel(alice, fundingChanPoint) ht.CloseChannel(alice, fundingChanPoint)
} }
func testGraphTopologyNotifications(ht *lntemp.HarnessTest) { func testGraphTopologyNotifications(ht *lntest.HarnessTest) {
ht.Run("pinned", func(t *testing.T) { ht.Run("pinned", func(t *testing.T) {
subT := ht.Subtest(t) subT := ht.Subtest(t)
testGraphTopologyNtfns(subT, true) testGraphTopologyNtfns(subT, true)
@@ -263,7 +263,7 @@ func testGraphTopologyNotifications(ht *lntemp.HarnessTest) {
}) })
} }
func testGraphTopologyNtfns(ht *lntemp.HarnessTest, pinned bool) { func testGraphTopologyNtfns(ht *lntest.HarnessTest, pinned bool) {
const chanAmt = funding.MaxBtcFundingAmount const chanAmt = funding.MaxBtcFundingAmount
// Spin up Bob first, since we will need to grab his pubkey when // Spin up Bob first, since we will need to grab his pubkey when
@@ -305,7 +305,7 @@ func testGraphTopologyNtfns(ht *lntemp.HarnessTest, pinned bool) {
// Open a new channel between Alice and Bob. // Open a new channel between Alice and Bob.
chanPoint := ht.OpenChannel( chanPoint := ht.OpenChannel(
alice, bob, lntemp.OpenChannelParams{Amt: chanAmt}, alice, bob, lntest.OpenChannelParams{Amt: chanAmt},
) )
// The channel opening above should have triggered a few notifications // The channel opening above should have triggered a few notifications
@@ -335,17 +335,30 @@ func testGraphTopologyNtfns(ht *lntemp.HarnessTest, pinned bool) {
// For the final portion of the test, we'll ensure that once a new node // For the final portion of the test, we'll ensure that once a new node
// appears in the network, the proper notification is dispatched. Note // appears in the network, the proper notification is dispatched. Note
// that a node that does not have any channels open is ignored, so first // that a node that does not have any channels open is ignored, so
// we disconnect Alice and Bob, open a channel between Bob and Carol, // first we disconnect Alice and Bob, open a channel between Bob and
// and finally connect Alice to Bob again. // Carol, and finally connect Alice to Bob again.
ht.DisconnectNodes(alice, bob) ht.DisconnectNodes(bob, alice)
// Since Alice and Bob has a permanent connection, the above
// disconnection won't be enough as Alice will try to reconnect to Bob
// again. Atm, it seems nothing is stopping the reconnection. So we
// need to shutdown Alice here.
//
// TODO(yy): clearly define what `disconnectpeer` rpc is responsible
// for and its effect. If we disconnect a peer, we shouldn't allow the
// peer to connect to us again.
restartAlice := ht.SuspendNode(alice)
carol := ht.NewNode("Carol", nil) carol := ht.NewNode("Carol", nil)
ht.ConnectNodes(bob, carol) ht.ConnectNodes(bob, carol)
chanPoint = ht.OpenChannel( chanPoint = ht.OpenChannel(
bob, carol, lntemp.OpenChannelParams{Amt: chanAmt}, bob, carol, lntest.OpenChannelParams{Amt: chanAmt},
) )
// Restart Alice so she can receive the channel updates from Bob.
require.NoError(ht, restartAlice(), "failed to restart Alice")
// Reconnect Alice and Bob. This should result in the nodes syncing up // Reconnect Alice and Bob. This should result in the nodes syncing up
// their respective graph state, with the new addition being the // their respective graph state, with the new addition being the
// existence of Carol in the graph, and also the channel between Bob // existence of Carol in the graph, and also the channel between Bob
@@ -366,7 +379,7 @@ func testGraphTopologyNtfns(ht *lntemp.HarnessTest, pinned bool) {
// testNodeAnnouncement ensures that when a node is started with one or more // testNodeAnnouncement ensures that when a node is started with one or more
// external IP addresses specified on the command line, that those addresses // external IP addresses specified on the command line, that those addresses
// announced to the network and reported in the network graph. // announced to the network and reported in the network graph.
func testNodeAnnouncement(ht *lntemp.HarnessTest) { func testNodeAnnouncement(ht *lntest.HarnessTest) {
alice, bob := ht.Alice, ht.Bob alice, bob := ht.Alice, ht.Bob
advertisedAddrs := []string{ advertisedAddrs := []string{
@@ -392,7 +405,7 @@ func testNodeAnnouncement(ht *lntemp.HarnessTest) {
// ensures that Alice receives the node announcement from Bob as part of // ensures that Alice receives the node announcement from Bob as part of
// the announcement broadcast. // the announcement broadcast.
chanPoint := ht.OpenChannel( chanPoint := ht.OpenChannel(
bob, dave, lntemp.OpenChannelParams{Amt: 1000000}, bob, dave, lntest.OpenChannelParams{Amt: 1000000},
) )
assertAddrs := func(addrsFound []string, targetAddrs ...string) { assertAddrs := func(addrsFound []string, targetAddrs ...string) {
@@ -421,7 +434,7 @@ func testNodeAnnouncement(ht *lntemp.HarnessTest) {
// testUpdateNodeAnnouncement ensures that the RPC endpoint validates // testUpdateNodeAnnouncement ensures that the RPC endpoint validates
// the requests correctly and that the new node announcement is brodcasted // the requests correctly and that the new node announcement is brodcasted
// with the right information after updating our node. // with the right information after updating our node.
func testUpdateNodeAnnouncement(ht *lntemp.HarnessTest) { func testUpdateNodeAnnouncement(ht *lntest.HarnessTest) {
alice, bob := ht.Alice, ht.Bob alice, bob := ht.Alice, ht.Bob
var lndArgs []string var lndArgs []string
@@ -500,7 +513,7 @@ func testUpdateNodeAnnouncement(ht *lntemp.HarnessTest) {
// ensures that Alice receives the node announcement from Bob as part of // ensures that Alice receives the node announcement from Bob as part of
// the announcement broadcast. // the announcement broadcast.
chanPoint := ht.OpenChannel( chanPoint := ht.OpenChannel(
bob, dave, lntemp.OpenChannelParams{ bob, dave, lntest.OpenChannelParams{
Amt: 1000000, Amt: 1000000,
}, },
) )
@@ -637,7 +650,7 @@ func testUpdateNodeAnnouncement(ht *lntemp.HarnessTest) {
// assertSyncType asserts that the peer has an expected syncType. // assertSyncType asserts that the peer has an expected syncType.
// //
// NOTE: only made for tests in this file. // NOTE: only made for tests in this file.
func assertSyncType(ht *lntemp.HarnessTest, hn *node.HarnessNode, func assertSyncType(ht *lntest.HarnessTest, hn *node.HarnessNode,
peer string, syncType lnrpc.Peer_SyncType) { peer string, syncType lnrpc.Peer_SyncType) {
resp := hn.RPC.ListPeers() resp := hn.RPC.ListPeers()
@@ -693,7 +706,7 @@ func compareNodeAnns(n1, n2 *lnrpc.NodeUpdate) error {
// the response expected values. // the response expected values.
// //
// NOTE: only used for tests in this file. // NOTE: only used for tests in this file.
func assertUpdateNodeAnnouncementResponse(ht *lntemp.HarnessTest, func assertUpdateNodeAnnouncementResponse(ht *lntest.HarnessTest,
response *peersrpc.NodeAnnouncementUpdateResponse, response *peersrpc.NodeAnnouncementUpdateResponse,
expectedOps map[string]int) { expectedOps map[string]int) {
@@ -10,37 +10,22 @@ import (
"github.com/lightningnetwork/lnd/funding" "github.com/lightningnetwork/lnd/funding"
"github.com/lightningnetwork/lnd/lnrpc" "github.com/lightningnetwork/lnd/lnrpc"
"github.com/lightningnetwork/lnd/lnrpc/routerrpc" "github.com/lightningnetwork/lnd/lnrpc/routerrpc"
"github.com/lightningnetwork/lnd/lntemp"
"github.com/lightningnetwork/lnd/lntemp/node"
"github.com/lightningnetwork/lnd/lntest" "github.com/lightningnetwork/lnd/lntest"
"github.com/lightningnetwork/lnd/lntest/node"
"github.com/lightningnetwork/lnd/lnwire" "github.com/lightningnetwork/lnd/lnwire"
"github.com/stretchr/testify/require" "github.com/stretchr/testify/require"
) )
// assertPolicyUpdate checks that a given policy update has been received by a
// list of given nodes.
// TODO(yy): delete.
func assertPolicyUpdate(t *harnessTest, nodes []*lntest.HarnessNode,
advertisingNode string, policy *lnrpc.RoutingPolicy,
chanPoint *lnrpc.ChannelPoint) {
for _, node := range nodes {
assertChannelPolicyUpdate(
t.t, node, advertisingNode, policy, chanPoint, false,
)
}
}
// testUpdateChannelPolicy tests that policy updates made to a channel // testUpdateChannelPolicy tests that policy updates made to a channel
// gets propagated to other nodes in the network. // gets propagated to other nodes in the network.
func testUpdateChannelPolicy(ht *lntemp.HarnessTest) { func testUpdateChannelPolicy(ht *lntest.HarnessTest) {
const ( const (
defaultFeeBase = 1000 defaultFeeBase = 1000
defaultFeeRate = 1 defaultFeeRate = 1
defaultTimeLockDelta = chainreg.DefaultBitcoinTimeLockDelta defaultTimeLockDelta = chainreg.DefaultBitcoinTimeLockDelta
defaultMinHtlc = 1000 defaultMinHtlc = 1000
) )
defaultMaxHtlc := calculateMaxHtlc(funding.MaxBtcFundingAmount) defaultMaxHtlc := lntest.CalculateMaxHtlc(funding.MaxBtcFundingAmount)
chanAmt := funding.MaxBtcFundingAmount chanAmt := funding.MaxBtcFundingAmount
pushAmt := chanAmt / 2 pushAmt := chanAmt / 2
@@ -49,7 +34,7 @@ func testUpdateChannelPolicy(ht *lntemp.HarnessTest) {
// Create a channel Alice->Bob. // Create a channel Alice->Bob.
chanPoint := ht.OpenChannel( chanPoint := ht.OpenChannel(
alice, bob, lntemp.OpenChannelParams{ alice, bob, lntest.OpenChannelParams{
Amt: chanAmt, Amt: chanAmt,
PushAmt: pushAmt, PushAmt: pushAmt,
}, },
@@ -102,7 +87,7 @@ func testUpdateChannelPolicy(ht *lntemp.HarnessTest) {
// part of his ChannelUpdate. // part of his ChannelUpdate.
const customMinHtlc = 5000 const customMinHtlc = 5000
chanPoint2 := ht.OpenChannel( chanPoint2 := ht.OpenChannel(
carol, bob, lntemp.OpenChannelParams{ carol, bob, lntest.OpenChannelParams{
Amt: chanAmt, Amt: chanAmt,
PushAmt: pushAmt, PushAmt: pushAmt,
MinHtlc: customMinHtlc, MinHtlc: customMinHtlc,
@@ -182,9 +167,9 @@ func testUpdateChannelPolicy(ht *lntemp.HarnessTest) {
payAmt = btcutil.Amount(4) payAmt = btcutil.Amount(4)
amtSat := int64(payAmt) amtSat := int64(payAmt)
amtMSat := int64(lnwire.NewMSatFromSatoshis(payAmt)) amtMSat := int64(lnwire.NewMSatFromSatoshis(payAmt))
routes.Routes[0].Hops[0].AmtToForward = amtSat // nolint:staticcheck routes.Routes[0].Hops[0].AmtToForward = amtSat
routes.Routes[0].Hops[0].AmtToForwardMsat = amtMSat routes.Routes[0].Hops[0].AmtToForwardMsat = amtMSat
routes.Routes[0].Hops[1].AmtToForward = amtSat // nolint:staticcheck routes.Routes[0].Hops[1].AmtToForward = amtSat
routes.Routes[0].Hops[1].AmtToForwardMsat = amtMSat routes.Routes[0].Hops[1].AmtToForwardMsat = amtMSat
// Send the payment with the modified value. // Send the payment with the modified value.
@@ -215,9 +200,9 @@ func testUpdateChannelPolicy(ht *lntemp.HarnessTest) {
payAmt = btcutil.Amount(5) payAmt = btcutil.Amount(5)
amtSat = int64(payAmt) amtSat = int64(payAmt)
amtMSat = int64(lnwire.NewMSatFromSatoshis(payAmt)) amtMSat = int64(lnwire.NewMSatFromSatoshis(payAmt))
routes.Routes[0].Hops[0].AmtToForward = amtSat // nolint:staticcheck routes.Routes[0].Hops[0].AmtToForward = amtSat
routes.Routes[0].Hops[0].AmtToForwardMsat = amtMSat routes.Routes[0].Hops[0].AmtToForwardMsat = amtMSat
routes.Routes[0].Hops[1].AmtToForward = amtSat // nolint:staticcheck routes.Routes[0].Hops[1].AmtToForward = amtSat
routes.Routes[0].Hops[1].AmtToForwardMsat = amtMSat routes.Routes[0].Hops[1].AmtToForwardMsat = amtMSat
// Manually set the MPP payload a new for each payment since // Manually set the MPP payload a new for each payment since
@@ -298,7 +283,7 @@ func testUpdateChannelPolicy(ht *lntemp.HarnessTest) {
// We'll now open a channel from Alice directly to Carol. // We'll now open a channel from Alice directly to Carol.
ht.ConnectNodes(alice, carol) ht.ConnectNodes(alice, carol)
chanPoint3 := ht.OpenChannel( chanPoint3 := ht.OpenChannel(
alice, carol, lntemp.OpenChannelParams{ alice, carol, lntest.OpenChannelParams{
Amt: chanAmt, Amt: chanAmt,
PushAmt: pushAmt, PushAmt: pushAmt,
}, },
@@ -439,7 +424,7 @@ func testUpdateChannelPolicy(ht *lntemp.HarnessTest) {
// chan-disable-timeout flags here. For instance, if some operations take more // chan-disable-timeout flags here. For instance, if some operations take more
// than 6 seconds to finish, the channel will be marked as disabled, thus a // than 6 seconds to finish, the channel will be marked as disabled, thus a
// following operation will fail if it relies on the channel being enabled. // following operation will fail if it relies on the channel being enabled.
func testSendUpdateDisableChannel(ht *lntemp.HarnessTest) { func testSendUpdateDisableChannel(ht *lntest.HarnessTest) {
const chanAmt = 100000 const chanAmt = 100000
alice, bob := ht.Alice, ht.Bob alice, bob := ht.Alice, ht.Bob
@@ -482,8 +467,8 @@ func testSendUpdateDisableChannel(ht *lntemp.HarnessTest) {
// We now proceed to open channels: Alice=>Bob, Alice=>Carol and // We now proceed to open channels: Alice=>Bob, Alice=>Carol and
// Eve=>Carol. // Eve=>Carol.
p := lntemp.OpenChannelParams{Amt: chanAmt} p := lntest.OpenChannelParams{Amt: chanAmt}
reqs := []*lntemp.OpenChannelRequest{ reqs := []*lntest.OpenChannelRequest{
{Local: alice, Remote: bob, Param: p}, {Local: alice, Remote: bob, Param: p},
{Local: alice, Remote: carol, Param: p}, {Local: alice, Remote: carol, Param: p},
{Local: eve, Remote: carol, Param: p}, {Local: eve, Remote: carol, Param: p},
@@ -528,7 +513,7 @@ func testSendUpdateDisableChannel(ht *lntemp.HarnessTest) {
FeeRateMilliMsat: int64(chainreg.DefaultBitcoinFeeRate), FeeRateMilliMsat: int64(chainreg.DefaultBitcoinFeeRate),
TimeLockDelta: chainreg.DefaultBitcoinTimeLockDelta, TimeLockDelta: chainreg.DefaultBitcoinTimeLockDelta,
MinHtlc: 1000, // default value MinHtlc: 1000, // default value
MaxHtlcMsat: calculateMaxHtlc(chanAmt), MaxHtlcMsat: lntest.CalculateMaxHtlc(chanAmt),
Disabled: true, Disabled: true,
} }
@@ -670,7 +655,7 @@ func testSendUpdateDisableChannel(ht *lntemp.HarnessTest) {
// Bob will update the base fee via UpdateChannelPolicy, we will test that // Bob will update the base fee via UpdateChannelPolicy, we will test that
// Alice will not fail the payment and send it using the updated channel // Alice will not fail the payment and send it using the updated channel
// policy. // policy.
func testUpdateChannelPolicyForPrivateChannel(ht *lntemp.HarnessTest) { func testUpdateChannelPolicyForPrivateChannel(ht *lntest.HarnessTest) {
const ( const (
chanAmt = btcutil.Amount(100000) chanAmt = btcutil.Amount(100000)
paymentAmt = 20000 paymentAmt = 20000
@@ -683,7 +668,7 @@ func testUpdateChannelPolicyForPrivateChannel(ht *lntemp.HarnessTest) {
// Open a channel with 100k satoshis between Alice and Bob. // Open a channel with 100k satoshis between Alice and Bob.
chanPointAliceBob := ht.OpenChannel( chanPointAliceBob := ht.OpenChannel(
alice, bob, lntemp.OpenChannelParams{ alice, bob, lntest.OpenChannelParams{
Amt: chanAmt, Amt: chanAmt,
}, },
) )
@@ -696,7 +681,7 @@ func testUpdateChannelPolicyForPrivateChannel(ht *lntemp.HarnessTest) {
// Open a channel with 100k satoshis between Bob and Carol. // Open a channel with 100k satoshis between Bob and Carol.
chanPointBobCarol := ht.OpenChannel( chanPointBobCarol := ht.OpenChannel(
bob, carol, lntemp.OpenChannelParams{ bob, carol, lntest.OpenChannelParams{
Amt: chanAmt, Amt: chanAmt,
Private: true, Private: true,
}, },
@@ -729,6 +714,19 @@ func testUpdateChannelPolicyForPrivateChannel(ht *lntemp.HarnessTest) {
// Alice pays the invoices. She will use the updated baseFeeMSat in the // Alice pays the invoices. She will use the updated baseFeeMSat in the
// payment // payment
//
// TODO(yy): we may get a flake saying the timeout checking the
// payment's state, which is due to slow round of HTLC settlement. An
// example log is shown below, where Alice sent RevokeAndAck to Bob,
// but it took Bob 7 seconds to reply back the final UpdateFulfillHTLC.
//
// 2022-11-14 06:23:59.774 PEER: Peer(Bob): Sending UpdateAddHTLC
// 2022-11-14 06:24:00.635 PEER: Peer(Bob): Sending CommitSig
// 2022-11-14 06:24:01.784 PEER: Peer(Bob): Sending RevokeAndAck
// 2022-11-14 06:24:08.464 PEER: Peer(Bob): Received UpdateFulfillHTLC
//
// 7 seconds is too long for a local test and this needs more
// investigation.
payReqs := []string{resp.PaymentRequest} payReqs := []string{resp.PaymentRequest}
ht.CompletePaymentRequests(alice, payReqs) ht.CompletePaymentRequests(alice, payReqs)
@@ -770,14 +768,14 @@ func testUpdateChannelPolicyForPrivateChannel(ht *lntemp.HarnessTest) {
// testUpdateChannelPolicyFeeRateAccuracy tests that updating the channel policy // testUpdateChannelPolicyFeeRateAccuracy tests that updating the channel policy
// rounds fee rate values correctly as well as setting fee rate with ppm works // rounds fee rate values correctly as well as setting fee rate with ppm works
// as expected. // as expected.
func testUpdateChannelPolicyFeeRateAccuracy(ht *lntemp.HarnessTest) { func testUpdateChannelPolicyFeeRateAccuracy(ht *lntest.HarnessTest) {
chanAmt := funding.MaxBtcFundingAmount chanAmt := funding.MaxBtcFundingAmount
pushAmt := chanAmt / 2 pushAmt := chanAmt / 2
// Create a channel Alice -> Bob. // Create a channel Alice -> Bob.
alice, bob := ht.Alice, ht.Bob alice, bob := ht.Alice, ht.Bob
chanPoint := ht.OpenChannel( chanPoint := ht.OpenChannel(
alice, bob, lntemp.OpenChannelParams{ alice, bob, lntest.OpenChannelParams{
Amt: chanAmt, Amt: chanAmt,
PushAmt: pushAmt, PushAmt: pushAmt,
}, },
@@ -841,7 +839,7 @@ func testUpdateChannelPolicyFeeRateAccuracy(ht *lntemp.HarnessTest) {
// assertNodesPolicyUpdate checks that a given policy update has been received // assertNodesPolicyUpdate checks that a given policy update has been received
// by a list of given nodes. // by a list of given nodes.
func assertNodesPolicyUpdate(ht *lntemp.HarnessTest, nodes []*node.HarnessNode, func assertNodesPolicyUpdate(ht *lntest.HarnessTest, nodes []*node.HarnessNode,
advertisingNode *node.HarnessNode, policy *lnrpc.RoutingPolicy, advertisingNode *node.HarnessNode, policy *lnrpc.RoutingPolicy,
chanPoint *lnrpc.ChannelPoint) { chanPoint *lnrpc.ChannelPoint) {
@@ -5,7 +5,7 @@ import (
"time" "time"
"github.com/lightningnetwork/lnd/lnrpc" "github.com/lightningnetwork/lnd/lnrpc"
"github.com/lightningnetwork/lnd/lntemp" "github.com/lightningnetwork/lnd/lntest"
"github.com/lightningnetwork/lnd/lnwire" "github.com/lightningnetwork/lnd/lnwire"
"github.com/stretchr/testify/require" "github.com/stretchr/testify/require"
) )
@@ -13,7 +13,7 @@ import (
// testCustomMessage tests sending and receiving of overridden custom message // testCustomMessage tests sending and receiving of overridden custom message
// types (within the message type range usually reserved for protocol messages) // types (within the message type range usually reserved for protocol messages)
// via the send and subscribe custom message APIs. // via the send and subscribe custom message APIs.
func testCustomMessage(ht *lntemp.HarnessTest) { func testCustomMessage(ht *lntest.HarnessTest) {
alice, bob := ht.Alice, ht.Bob alice, bob := ht.Alice, ht.Bob
var ( var (
@@ -82,7 +82,7 @@ func testCustomMessage(ht *lntemp.HarnessTest) {
require.Equal(ht, bob.PubKey[:], msg.Peer, "first msg "+ require.Equal(ht, bob.PubKey[:], msg.Peer, "first msg "+
"peer wrong") "peer wrong")
case <-time.After(defaultTimeout): case <-time.After(lntest.DefaultTimeout):
ht.Fatalf("alice did not receive first custom message: %v", ht.Fatalf("alice did not receive first custom message: %v",
msgType) msgType)
} }
@@ -151,7 +151,7 @@ func testCustomMessage(ht *lntemp.HarnessTest) {
require.Equal(ht, bob.PubKey[:], msg.Peer, "second "+ require.Equal(ht, bob.PubKey[:], msg.Peer, "second "+
"message peer") "message peer")
case <-time.After(defaultTimeout): case <-time.After(lntest.DefaultTimeout):
ht.Fatalf("alice did not receive second custom message") ht.Fatalf("alice did not receive second custom message")
} }
} }
@@ -12,12 +12,12 @@ import (
"github.com/lightningnetwork/lnd/kvdb" "github.com/lightningnetwork/lnd/kvdb"
"github.com/lightningnetwork/lnd/lncfg" "github.com/lightningnetwork/lnd/lncfg"
"github.com/lightningnetwork/lnd/lnrpc" "github.com/lightningnetwork/lnd/lnrpc"
"github.com/lightningnetwork/lnd/lntemp"
"github.com/lightningnetwork/lnd/lntest" "github.com/lightningnetwork/lnd/lntest"
"github.com/lightningnetwork/lnd/lntest/node"
"github.com/stretchr/testify/require" "github.com/stretchr/testify/require"
) )
func assertLeader(ht *lntemp.HarnessTest, observer cluster.LeaderElector, func assertLeader(ht *lntest.HarnessTest, observer cluster.LeaderElector,
expected string) { expected string) {
leader, err := observer.Leader(ht.Context()) leader, err := observer.Leader(ht.Context())
@@ -29,7 +29,7 @@ func assertLeader(ht *lntemp.HarnessTest, observer cluster.LeaderElector,
// testEtcdFailover tests that in a cluster setup where two LND nodes form a // testEtcdFailover tests that in a cluster setup where two LND nodes form a
// single cluster (sharing the same identity) one can hand over the leader role // single cluster (sharing the same identity) one can hand over the leader role
// to the other (failing over after graceful shutdown or forceful abort). // to the other (failing over after graceful shutdown or forceful abort).
func testEtcdFailover(ht *lntemp.HarnessTest) { func testEtcdFailover(ht *lntest.HarnessTest) {
testCases := []struct { testCases := []struct {
name string name string
kill bool kill bool
@@ -54,10 +54,10 @@ func testEtcdFailover(ht *lntemp.HarnessTest) {
} }
} }
func testEtcdFailoverCase(ht *lntemp.HarnessTest, kill bool) { func testEtcdFailoverCase(ht *lntest.HarnessTest, kill bool) {
etcdCfg, cleanup, err := kvdb.StartEtcdTestBackend( etcdCfg, cleanup, err := kvdb.StartEtcdTestBackend(
ht.T.TempDir(), uint16(lntest.NextAvailablePort()), ht.T.TempDir(), uint16(node.NextAvailablePort()),
uint16(lntest.NextAvailablePort()), "", uint16(node.NextAvailablePort()), "",
) )
require.NoError(ht, err, "Failed to start etcd instance") require.NoError(ht, err, "Failed to start etcd instance")
defer cleanup() defer cleanup()
@@ -91,7 +91,7 @@ func testEtcdFailoverCase(ht *lntemp.HarnessTest, kill bool) {
// Open a channel with 100k satoshis between Carol and Alice with Alice // Open a channel with 100k satoshis between Carol and Alice with Alice
// being the sole funder of the channel. // being the sole funder of the channel.
chanAmt := btcutil.Amount(100_000) chanAmt := btcutil.Amount(100_000)
ht.OpenChannel(alice, carol1, lntemp.OpenChannelParams{Amt: chanAmt}) ht.OpenChannel(alice, carol1, lntest.OpenChannelParams{Amt: chanAmt})
// At this point Carol-1 is the elected leader, while Carol-2 will wait // At this point Carol-1 is the elected leader, while Carol-2 will wait
// to become the leader when Carol-1 stops. // to become the leader when Carol-1 stops.
@@ -9,8 +9,8 @@ import (
"github.com/lightningnetwork/lnd/chainreg" "github.com/lightningnetwork/lnd/chainreg"
"github.com/lightningnetwork/lnd/lnrpc" "github.com/lightningnetwork/lnd/lnrpc"
"github.com/lightningnetwork/lnd/lnrpc/routerrpc" "github.com/lightningnetwork/lnd/lnrpc/routerrpc"
"github.com/lightningnetwork/lnd/lntemp" "github.com/lightningnetwork/lnd/lntest"
"github.com/lightningnetwork/lnd/lntemp/node" "github.com/lightningnetwork/lnd/lntest/node"
"github.com/lightningnetwork/lnd/lntest/wait" "github.com/lightningnetwork/lnd/lntest/wait"
"github.com/lightningnetwork/lnd/lntypes" "github.com/lightningnetwork/lnd/lntypes"
"github.com/lightningnetwork/lnd/routing/route" "github.com/lightningnetwork/lnd/routing/route"
@@ -34,7 +34,7 @@ type interceptorTestCase struct {
// testForwardInterceptorDedupHtlc tests that upon reconnection, duplicate // testForwardInterceptorDedupHtlc tests that upon reconnection, duplicate
// HTLCs aren't re-notified using the HTLC interceptor API. // HTLCs aren't re-notified using the HTLC interceptor API.
func testForwardInterceptorDedupHtlc(ht *lntemp.HarnessTest) { func testForwardInterceptorDedupHtlc(ht *lntest.HarnessTest) {
// Initialize the test context with 3 connected nodes. // Initialize the test context with 3 connected nodes.
ts := newInterceptorTestScenario(ht) ts := newInterceptorTestScenario(ht)
@@ -42,8 +42,8 @@ func testForwardInterceptorDedupHtlc(ht *lntemp.HarnessTest) {
// Open and wait for channels. // Open and wait for channels.
const chanAmt = btcutil.Amount(300000) const chanAmt = btcutil.Amount(300000)
p := lntemp.OpenChannelParams{Amt: chanAmt} p := lntest.OpenChannelParams{Amt: chanAmt}
reqs := []*lntemp.OpenChannelRequest{ reqs := []*lntest.OpenChannelRequest{
{Local: alice, Remote: bob, Param: p}, {Local: alice, Remote: bob, Param: p},
{Local: bob, Remote: carol, Param: p}, {Local: bob, Remote: carol, Param: p},
} }
@@ -106,6 +106,7 @@ func testForwardInterceptorDedupHtlc(ht *lntemp.HarnessTest) {
ht.EnsureConnected(bob, alice) ht.EnsureConnected(bob, alice)
// Here we wait for the channel to be active again. // Here we wait for the channel to be active again.
ht.AssertChannelExists(alice, cpAB)
ht.AssertChannelExists(bob, cpAB) ht.AssertChannelExists(bob, cpAB)
// Now that the channel is active we make sure the test passes as // Now that the channel is active we make sure the test passes as
@@ -185,15 +186,15 @@ func testForwardInterceptorDedupHtlc(ht *lntemp.HarnessTest) {
// 3. Intercepted held htlcs result in no payment (invoice is not settled). // 3. Intercepted held htlcs result in no payment (invoice is not settled).
// 4. When Interceptor disconnects it resumes all held htlcs, which result in // 4. When Interceptor disconnects it resumes all held htlcs, which result in
// valid payment (invoice is settled). // valid payment (invoice is settled).
func testForwardInterceptorBasic(ht *lntemp.HarnessTest) { func testForwardInterceptorBasic(ht *lntest.HarnessTest) {
ts := newInterceptorTestScenario(ht) ts := newInterceptorTestScenario(ht)
alice, bob, carol := ts.alice, ts.bob, ts.carol alice, bob, carol := ts.alice, ts.bob, ts.carol
// Open and wait for channels. // Open and wait for channels.
const chanAmt = btcutil.Amount(300000) const chanAmt = btcutil.Amount(300000)
p := lntemp.OpenChannelParams{Amt: chanAmt} p := lntest.OpenChannelParams{Amt: chanAmt}
reqs := []*lntemp.OpenChannelRequest{ reqs := []*lntest.OpenChannelRequest{
{Local: alice, Remote: bob, Param: p}, {Local: alice, Remote: bob, Param: p},
{Local: bob, Remote: carol, Param: p}, {Local: bob, Remote: carol, Param: p},
} }
@@ -296,7 +297,8 @@ func testForwardInterceptorBasic(ht *lntemp.HarnessTest) {
restartAlice := ht.SuspendNode(alice) restartAlice := ht.SuspendNode(alice)
require.NoError(ht, restartAlice(), "failed to restart alice") require.NoError(ht, restartAlice(), "failed to restart alice")
// Make sure the channel is active from Bob's PoV. // Make sure the channel is active from both Alice and Bob's PoV.
ht.AssertChannelExists(alice, cpAB)
ht.AssertChannelExists(bob, cpAB) ht.AssertChannelExists(bob, cpAB)
// Create a new interceptor as the old one has quit. // Create a new interceptor as the old one has quit.
@@ -345,7 +347,7 @@ func testForwardInterceptorBasic(ht *lntemp.HarnessTest) {
// interceptorTestScenario is a helper struct to hold the test context and // interceptorTestScenario is a helper struct to hold the test context and
// provide the needed functionality. // provide the needed functionality.
type interceptorTestScenario struct { type interceptorTestScenario struct {
ht *lntemp.HarnessTest ht *lntest.HarnessTest
alice, bob, carol *node.HarnessNode alice, bob, carol *node.HarnessNode
} }
@@ -356,7 +358,7 @@ type interceptorTestScenario struct {
// //
// Among them, Alice and Bob are standby nodes and Carol is a new node. // Among them, Alice and Bob are standby nodes and Carol is a new node.
func newInterceptorTestScenario( func newInterceptorTestScenario(
ht *lntemp.HarnessTest) *interceptorTestScenario { ht *lntest.HarnessTest) *interceptorTestScenario {
alice, bob := ht.Alice, ht.Bob alice, bob := ht.Alice, ht.Bob
carol := ht.NewNode("carol", nil) carol := ht.NewNode("carol", nil)
@@ -416,6 +418,7 @@ func (c *interceptorTestScenario) prepareTestCases() []*interceptorTestCase {
t.invoice = invoice t.invoice = invoice
t.payAddr = payReq.PaymentAddr t.payAddr = payReq.PaymentAddr
} }
return cases return cases
} }
@@ -13,8 +13,8 @@ import (
"github.com/lightningnetwork/lnd/labels" "github.com/lightningnetwork/lnd/labels"
"github.com/lightningnetwork/lnd/lnrpc" "github.com/lightningnetwork/lnd/lnrpc"
"github.com/lightningnetwork/lnd/lnrpc/signrpc" "github.com/lightningnetwork/lnd/lnrpc/signrpc"
"github.com/lightningnetwork/lnd/lntemp" "github.com/lightningnetwork/lnd/lntest"
"github.com/lightningnetwork/lnd/lntemp/node" "github.com/lightningnetwork/lnd/lntest/node"
"github.com/lightningnetwork/lnd/lnwire" "github.com/lightningnetwork/lnd/lnwire"
"github.com/stretchr/testify/require" "github.com/stretchr/testify/require"
) )
@@ -24,7 +24,7 @@ import (
// Bob, then immediately closes the channel after asserting some expected post // Bob, then immediately closes the channel after asserting some expected post
// conditions. Finally, the chain itself is checked to ensure the closing // conditions. Finally, the chain itself is checked to ensure the closing
// transaction was mined. // transaction was mined.
func testBasicChannelFunding(ht *lntemp.HarnessTest) { func testBasicChannelFunding(ht *lntest.HarnessTest) {
// Run through the test with combinations of all the different // Run through the test with combinations of all the different
// commitment types. // commitment types.
allTypes := []lnrpc.CommitmentType{ allTypes := []lnrpc.CommitmentType{
@@ -35,20 +35,20 @@ func testBasicChannelFunding(ht *lntemp.HarnessTest) {
// testFunding is a function closure that takes Carol and Dave's // testFunding is a function closure that takes Carol and Dave's
// commitment types and test the funding flow. // commitment types and test the funding flow.
testFunding := func(ht *lntemp.HarnessTest, carolCommitType, testFunding := func(ht *lntest.HarnessTest, carolCommitType,
daveCommitType lnrpc.CommitmentType) { daveCommitType lnrpc.CommitmentType) {
// Based on the current tweak variable for Carol, we'll // Based on the current tweak variable for Carol, we'll
// preferentially signal the legacy commitment format. We do // preferentially signal the legacy commitment format. We do
// the same for Dave shortly below. // the same for Dave shortly below.
carolArgs := nodeArgsForCommitType(carolCommitType) carolArgs := lntest.NodeArgsForCommitType(carolCommitType)
carol := ht.NewNode("Carol", carolArgs) carol := ht.NewNode("Carol", carolArgs)
// Each time, we'll send Carol a new set of coins in order to // Each time, we'll send Carol a new set of coins in order to
// fund the channel. // fund the channel.
ht.FundCoins(btcutil.SatoshiPerBitcoin, carol) ht.FundCoins(btcutil.SatoshiPerBitcoin, carol)
daveArgs := nodeArgsForCommitType(daveCommitType) daveArgs := lntest.NodeArgsForCommitType(daveCommitType)
dave := ht.NewNode("Dave", daveArgs) dave := ht.NewNode("Dave", daveArgs)
// Before we start the test, we'll ensure both sides are // Before we start the test, we'll ensure both sides are
@@ -140,7 +140,7 @@ test:
// test. Given two nodes: Alice and Bob, it'll assert proper channel creation, // test. Given two nodes: Alice and Bob, it'll assert proper channel creation,
// then return a function closure that should be called to assert proper // then return a function closure that should be called to assert proper
// channel closure. // channel closure.
func basicChannelFundingTest(ht *lntemp.HarnessTest, func basicChannelFundingTest(ht *lntest.HarnessTest,
alice, bob *node.HarnessNode, alice, bob *node.HarnessNode,
fundingShim *lnrpc.FundingShim) (*lnrpc.Channel, fundingShim *lnrpc.FundingShim) (*lnrpc.Channel,
*lnrpc.Channel, func()) { *lnrpc.Channel, func()) {
@@ -181,7 +181,7 @@ func basicChannelFundingTest(ht *lntemp.HarnessTest,
// assertions will be executed to ensure the funding process completed // assertions will be executed to ensure the funding process completed
// successfully. // successfully.
chanPoint := ht.OpenChannel( chanPoint := ht.OpenChannel(
alice, bob, lntemp.OpenChannelParams{ alice, bob, lntest.OpenChannelParams{
Amt: chanAmt, Amt: chanAmt,
PushAmt: pushAmt, PushAmt: pushAmt,
FundingShim: fundingShim, FundingShim: fundingShim,
@@ -193,7 +193,7 @@ func basicChannelFundingTest(ht *lntemp.HarnessTest,
// With the channel open, ensure that the amount specified above has // With the channel open, ensure that the amount specified above has
// properly been pushed to Bob. // properly been pushed to Bob.
aliceLocalBalance := chanAmt - pushAmt - calcStaticFee(cType, 0) aliceLocalBalance := chanAmt - pushAmt - lntest.CalcStaticFee(cType, 0)
checkChannelBalance( checkChannelBalance(
alice, aliceChannelBalance, aliceLocalBalance, pushAmt, alice, aliceChannelBalance, aliceLocalBalance, pushAmt,
) )
@@ -216,7 +216,7 @@ func basicChannelFundingTest(ht *lntemp.HarnessTest,
// testUnconfirmedChannelFunding tests that our unconfirmed change outputs can // testUnconfirmedChannelFunding tests that our unconfirmed change outputs can
// be used to fund channels. // be used to fund channels.
func testUnconfirmedChannelFunding(ht *lntemp.HarnessTest) { func testUnconfirmedChannelFunding(ht *lntest.HarnessTest) {
const ( const (
chanAmt = funding.MaxBtcFundingAmount chanAmt = funding.MaxBtcFundingAmount
pushAmt = btcutil.Amount(100000) pushAmt = btcutil.Amount(100000)
@@ -236,7 +236,7 @@ func testUnconfirmedChannelFunding(ht *lntemp.HarnessTest) {
ht.ConnectNodes(carol, alice) ht.ConnectNodes(carol, alice)
chanOpenUpdate := ht.OpenChannelAssertStream( chanOpenUpdate := ht.OpenChannelAssertStream(
carol, alice, lntemp.OpenChannelParams{ carol, alice, lntest.OpenChannelParams{
Amt: chanAmt, Amt: chanAmt,
PushAmt: pushAmt, PushAmt: pushAmt,
SpendUnconfirmed: true, SpendUnconfirmed: true,
@@ -289,7 +289,7 @@ func testUnconfirmedChannelFunding(ht *lntemp.HarnessTest) {
// Note that atm we haven't obtained the chanPoint yet, so we use the // Note that atm we haven't obtained the chanPoint yet, so we use the
// type directly. // type directly.
cType := lnrpc.CommitmentType_STATIC_REMOTE_KEY cType := lnrpc.CommitmentType_STATIC_REMOTE_KEY
carolLocalBalance := chanAmt - pushAmt - calcStaticFee(cType, 0) carolLocalBalance := chanAmt - pushAmt - lntest.CalcStaticFee(cType, 0)
checkChannelBalance(carol, 0, 0, carolLocalBalance, pushAmt) checkChannelBalance(carol, 0, 0, carolLocalBalance, pushAmt)
// For Alice, her local/remote balances should be zero, and the // For Alice, her local/remote balances should be zero, and the
@@ -329,7 +329,12 @@ func testUnconfirmedChannelFunding(ht *lntemp.HarnessTest) {
// testChannelFundingInputTypes tests that any type of supported input type can // testChannelFundingInputTypes tests that any type of supported input type can
// be used to fund channels. // be used to fund channels.
func testChannelFundingInputTypes(ht *lntemp.HarnessTest) { func testChannelFundingInputTypes(ht *lntest.HarnessTest) {
const (
chanAmt = funding.MaxBtcFundingAmount
burnAddr = "bcrt1qxsnqpdc842lu8c0xlllgvejt6rhy49u6fmpgyz"
)
// We'll start off by creating a node for Carol. // We'll start off by creating a node for Carol.
carol := ht.NewNode("Carol", nil) carol := ht.NewNode("Carol", nil)
@@ -342,7 +347,7 @@ func testChannelFundingInputTypes(ht *lntemp.HarnessTest) {
// runChannelFundingInputTypes tests that any type of supported input type can // runChannelFundingInputTypes tests that any type of supported input type can
// be used to fund channels. // be used to fund channels.
func runChannelFundingInputTypes(ht *lntemp.HarnessTest, alice, func runChannelFundingInputTypes(ht *lntest.HarnessTest, alice,
carol *node.HarnessNode) { carol *node.HarnessNode) {
const ( const (
@@ -411,7 +416,7 @@ func runChannelFundingInputTypes(ht *lntemp.HarnessTest, alice,
funder((chanAmt*11)/10, carol) funder((chanAmt*11)/10, carol)
chanOpenUpdate := ht.OpenChannelAssertStream( chanOpenUpdate := ht.OpenChannelAssertStream(
carol, alice, lntemp.OpenChannelParams{ carol, alice, lntest.OpenChannelParams{
Amt: chanAmt, Amt: chanAmt,
}, },
) )
@@ -423,7 +428,7 @@ func runChannelFundingInputTypes(ht *lntemp.HarnessTest, alice,
// Note that atm we haven't obtained the chanPoint yet, so we // Note that atm we haven't obtained the chanPoint yet, so we
// use the type directly. // use the type directly.
cType := lnrpc.CommitmentType_STATIC_REMOTE_KEY cType := lnrpc.CommitmentType_STATIC_REMOTE_KEY
carolLocalBalance := chanAmt - calcStaticFee(cType, 0) carolLocalBalance := chanAmt - lntest.CalcStaticFee(cType, 0)
checkChannelBalance(carol, 0, 0, carolLocalBalance, 0) checkChannelBalance(carol, 0, 0, carolLocalBalance, 0)
// For Alice, her local/remote balances should be zero, and the // For Alice, her local/remote balances should be zero, and the
@@ -463,7 +468,7 @@ func runChannelFundingInputTypes(ht *lntemp.HarnessTest, alice,
// sendAllCoinsConfirm sends all coins of the node's wallet to the given address // sendAllCoinsConfirm sends all coins of the node's wallet to the given address
// and awaits one confirmation. // and awaits one confirmation.
func sendAllCoinsConfirm(ht *lntemp.HarnessTest, node *node.HarnessNode, func sendAllCoinsConfirm(ht *lntest.HarnessTest, node *node.HarnessNode,
addr string) { addr string) {
sweepReq := &lnrpc.SendCoinsRequest{ sweepReq := &lnrpc.SendCoinsRequest{
@@ -477,7 +482,7 @@ func sendAllCoinsConfirm(ht *lntemp.HarnessTest, node *node.HarnessNode,
// testExternalFundingChanPoint tests that we're able to carry out a normal // testExternalFundingChanPoint tests that we're able to carry out a normal
// channel funding workflow given a channel point that was constructed outside // channel funding workflow given a channel point that was constructed outside
// the main daemon. // the main daemon.
func testExternalFundingChanPoint(ht *lntemp.HarnessTest) { func testExternalFundingChanPoint(ht *lntest.HarnessTest) {
// First, we'll create two new nodes that we'll use to open channel // First, we'll create two new nodes that we'll use to open channel
// between for this test. // between for this test.
carol := ht.NewNode("carol", nil) carol := ht.NewNode("carol", nil)
@@ -496,11 +501,11 @@ func testExternalFundingChanPoint(ht *lntemp.HarnessTest) {
// a transaction that will never be published. // a transaction that will never be published.
const thawHeight uint32 = 10 const thawHeight uint32 = 10
const chanSize = funding.MaxBtcFundingAmount const chanSize = funding.MaxBtcFundingAmount
fundingShim1, chanPoint1, _ := deriveFundingShim( fundingShim1, chanPoint1 := deriveFundingShim(
ht, carol, dave, chanSize, thawHeight, false, ht, carol, dave, chanSize, thawHeight, false,
) )
ht.OpenChannelAssertPending( ht.OpenChannelAssertPending(
carol, dave, lntemp.OpenChannelParams{ carol, dave, lntest.OpenChannelParams{
Amt: chanSize, Amt: chanSize,
FundingShim: fundingShim1, FundingShim: fundingShim1,
}, },
@@ -512,7 +517,7 @@ func testExternalFundingChanPoint(ht *lntemp.HarnessTest) {
// externally funded, we should still be able to open another one. Let's // externally funded, we should still be able to open another one. Let's
// do exactly that now. For this one we publish the transaction so we // do exactly that now. For this one we publish the transaction so we
// can mine it later. // can mine it later.
fundingShim2, chanPoint2, _ := deriveFundingShim( fundingShim2, chanPoint2 := deriveFundingShim(
ht, carol, dave, chanSize, thawHeight, true, ht, carol, dave, chanSize, thawHeight, true,
) )
@@ -591,7 +596,7 @@ func testExternalFundingChanPoint(ht *lntemp.HarnessTest) {
// representation of channels if the system is restarted or disconnected. // representation of channels if the system is restarted or disconnected.
// testFundingPersistence mirrors testBasicChannelFunding, but adds restarts // testFundingPersistence mirrors testBasicChannelFunding, but adds restarts
// and checks for the state of channels with unconfirmed funding transactions. // and checks for the state of channels with unconfirmed funding transactions.
func testChannelFundingPersistence(ht *lntemp.HarnessTest) { func testChannelFundingPersistence(ht *lntest.HarnessTest) {
chanAmt := funding.MaxBtcFundingAmount chanAmt := funding.MaxBtcFundingAmount
pushAmt := btcutil.Amount(0) pushAmt := btcutil.Amount(0)
@@ -609,7 +614,7 @@ func testChannelFundingPersistence(ht *lntemp.HarnessTest) {
// Create a new channel that requires 5 confs before it's considered // Create a new channel that requires 5 confs before it's considered
// open, then broadcast the funding transaction // open, then broadcast the funding transaction
param := lntemp.OpenChannelParams{ param := lntest.OpenChannelParams{
Amt: chanAmt, Amt: chanAmt,
PushAmt: pushAmt, PushAmt: pushAmt,
} }
@@ -676,7 +681,7 @@ func testChannelFundingPersistence(ht *lntemp.HarnessTest) {
// The channel should be listed in the peer information returned by // The channel should be listed in the peer information returned by
// both peers. // both peers.
chanPoint := lntemp.ChanPointFromPendingUpdate(update) chanPoint := lntest.ChanPointFromPendingUpdate(update)
// Re-lookup our transaction in the block that it confirmed in. // Re-lookup our transaction in the block that it confirmed in.
tx = ht.AssertTxAtHeight(alice, height, fundingTxID) tx = ht.AssertTxAtHeight(alice, height, fundingTxID)
@@ -685,6 +690,11 @@ func testChannelFundingPersistence(ht *lntemp.HarnessTest) {
chanAlice := ht.AssertChannelExists(alice, chanPoint) chanAlice := ht.AssertChannelExists(alice, chanPoint)
ht.AssertChannelExists(carol, chanPoint) ht.AssertChannelExists(carol, chanPoint)
// Make sure Alice and Carol have seen the channel in their network
// topology.
ht.AssertTopologyChannelOpen(alice, chanPoint)
ht.AssertTopologyChannelOpen(carol, chanPoint)
// Create an additional check for our channel assertion that will // Create an additional check for our channel assertion that will
// check that our label is as expected. // check that our label is as expected.
shortChanID := lnwire.NewShortChanIDFromInt(chanAlice.ChanId) shortChanID := lnwire.NewShortChanIDFromInt(chanAlice.ChanId)
@@ -699,7 +709,7 @@ func testChannelFundingPersistence(ht *lntemp.HarnessTest) {
// testBatchChanFunding makes sure multiple channels can be opened in one batch // testBatchChanFunding makes sure multiple channels can be opened in one batch
// transaction in an atomic way. // transaction in an atomic way.
func testBatchChanFunding(ht *lntemp.HarnessTest) { func testBatchChanFunding(ht *lntest.HarnessTest) {
// First, we'll create two new nodes that we'll use to open channels // First, we'll create two new nodes that we'll use to open channels
// to during this test. Carol has a high minimum funding amount that // to during this test. Carol has a high minimum funding amount that
// we'll use to trigger an error during the batch channel open. // we'll use to trigger an error during the batch channel open.
@@ -793,10 +803,10 @@ func testBatchChanFunding(ht *lntemp.HarnessTest) {
// deriveFundingShim creates a channel funding shim by deriving the necessary // deriveFundingShim creates a channel funding shim by deriving the necessary
// keys on both sides. // keys on both sides.
func deriveFundingShim(ht *lntemp.HarnessTest, func deriveFundingShim(ht *lntest.HarnessTest,
carol, dave *node.HarnessNode, chanSize btcutil.Amount, carol, dave *node.HarnessNode, chanSize btcutil.Amount,
thawHeight uint32, publish bool) (*lnrpc.FundingShim, thawHeight uint32, publish bool) (*lnrpc.FundingShim,
*lnrpc.ChannelPoint, *chainhash.Hash) { *lnrpc.ChannelPoint) {
keyLoc := &signrpc.KeyLocator{KeyFamily: 9999} keyLoc := &signrpc.KeyLocator{KeyFamily: 9999}
carolFundingKey := carol.RPC.DeriveKey(keyLoc) carolFundingKey := carol.RPC.DeriveKey(keyLoc)
@@ -882,5 +892,5 @@ func deriveFundingShim(ht *lntemp.HarnessTest,
} }
fundingShim.GetChanPointShim().RemoteKey = daveFundingKey.RawKeyBytes fundingShim.GetChanPointShim().RemoteKey = daveFundingKey.RawKeyBytes
return fundingShim, chanPoint, txid return fundingShim, chanPoint
} }
@@ -7,7 +7,7 @@ import (
"github.com/lightningnetwork/lnd/lnrpc" "github.com/lightningnetwork/lnd/lnrpc"
"github.com/lightningnetwork/lnd/lnrpc/invoicesrpc" "github.com/lightningnetwork/lnd/lnrpc/invoicesrpc"
"github.com/lightningnetwork/lnd/lnrpc/routerrpc" "github.com/lightningnetwork/lnd/lnrpc/routerrpc"
"github.com/lightningnetwork/lnd/lntemp" "github.com/lightningnetwork/lnd/lntest"
"github.com/lightningnetwork/lnd/lntest/wait" "github.com/lightningnetwork/lnd/lntest/wait"
"github.com/lightningnetwork/lnd/lntypes" "github.com/lightningnetwork/lnd/lntypes"
"github.com/stretchr/testify/require" "github.com/stretchr/testify/require"
@@ -15,11 +15,11 @@ import (
// testHoldInvoiceForceClose tests cancellation of accepted hold invoices which // testHoldInvoiceForceClose tests cancellation of accepted hold invoices which
// would otherwise trigger force closes when they expire. // would otherwise trigger force closes when they expire.
func testHoldInvoiceForceClose(ht *lntemp.HarnessTest) { func testHoldInvoiceForceClose(ht *lntest.HarnessTest) {
// Open a channel between alice and bob. // Open a channel between alice and bob.
alice, bob := ht.Alice, ht.Bob alice, bob := ht.Alice, ht.Bob
chanPoint := ht.OpenChannel( chanPoint := ht.OpenChannel(
alice, bob, lntemp.OpenChannelParams{Amt: 300000}, alice, bob, lntest.OpenChannelParams{Amt: 300000},
) )
// Create a non-dust hold invoice for bob. // Create a non-dust hold invoice for bob.
@@ -7,8 +7,8 @@ import (
"github.com/lightningnetwork/lnd/lnrpc" "github.com/lightningnetwork/lnd/lnrpc"
"github.com/lightningnetwork/lnd/lnrpc/invoicesrpc" "github.com/lightningnetwork/lnd/lnrpc/invoicesrpc"
"github.com/lightningnetwork/lnd/lnrpc/routerrpc" "github.com/lightningnetwork/lnd/lnrpc/routerrpc"
"github.com/lightningnetwork/lnd/lntemp" "github.com/lightningnetwork/lnd/lntest"
"github.com/lightningnetwork/lnd/lntemp/rpc" "github.com/lightningnetwork/lnd/lntest/rpc"
"github.com/lightningnetwork/lnd/lntest/wait" "github.com/lightningnetwork/lnd/lntest/wait"
"github.com/lightningnetwork/lnd/lntypes" "github.com/lightningnetwork/lnd/lntypes"
"github.com/stretchr/testify/require" "github.com/stretchr/testify/require"
@@ -17,7 +17,7 @@ import (
// testHoldInvoicePersistence tests that a sender to a hold-invoice, can be // testHoldInvoicePersistence tests that a sender to a hold-invoice, can be
// restarted before the payment gets settled, and still be able to receive the // restarted before the payment gets settled, and still be able to receive the
// preimage. // preimage.
func testHoldInvoicePersistence(ht *lntemp.HarnessTest) { func testHoldInvoicePersistence(ht *lntest.HarnessTest) {
const ( const (
chanAmt = btcutil.Amount(1000000) chanAmt = btcutil.Amount(1000000)
numPayments = 10 numPayments = 10
@@ -34,7 +34,7 @@ func testHoldInvoicePersistence(ht *lntemp.HarnessTest) {
// Open a channel between Alice and Carol which is private so that we // Open a channel between Alice and Carol which is private so that we
// cover the addition of hop hints for hold invoices. // cover the addition of hop hints for hold invoices.
chanPointAlice := ht.OpenChannel( chanPointAlice := ht.OpenChannel(
alice, carol, lntemp.OpenChannelParams{ alice, carol, lntest.OpenChannelParams{
Amt: chanAmt, Amt: chanAmt,
Private: true, Private: true,
}, },
@@ -45,7 +45,7 @@ func testHoldInvoicePersistence(ht *lntemp.HarnessTest) {
// has at least one public channel in the graph. We open a public // has at least one public channel in the graph. We open a public
// channel from Alice -> Bob and wait for Carol to see it. // channel from Alice -> Bob and wait for Carol to see it.
chanPointBob := ht.OpenChannel( chanPointBob := ht.OpenChannel(
alice, bob, lntemp.OpenChannelParams{ alice, bob, lntest.OpenChannelParams{
Amt: chanAmt, Amt: chanAmt,
}, },
) )
@@ -11,8 +11,8 @@ import (
"github.com/golang/protobuf/proto" "github.com/golang/protobuf/proto"
"github.com/lightningnetwork/lnd/lnrpc" "github.com/lightningnetwork/lnd/lnrpc"
"github.com/lightningnetwork/lnd/lntemp" "github.com/lightningnetwork/lnd/lntest"
"github.com/lightningnetwork/lnd/lntemp/node" "github.com/lightningnetwork/lnd/lntest/node"
"github.com/lightningnetwork/lnd/macaroons" "github.com/lightningnetwork/lnd/macaroons"
"github.com/stretchr/testify/assert" "github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require" "github.com/stretchr/testify/require"
@@ -23,7 +23,7 @@ import (
// enabled on the gRPC interface, no requests with missing or invalid // enabled on the gRPC interface, no requests with missing or invalid
// macaroons are allowed. Further, the specific access rights (read/write, // macaroons are allowed. Further, the specific access rights (read/write,
// entity based) and first-party caveats are tested as well. // entity based) and first-party caveats are tested as well.
func testMacaroonAuthentication(ht *lntemp.HarnessTest) { func testMacaroonAuthentication(ht *lntest.HarnessTest) {
var ( var (
infoReq = &lnrpc.GetInfoRequest{} infoReq = &lnrpc.GetInfoRequest{}
newAddrReq = &lnrpc.NewAddressRequest{ newAddrReq = &lnrpc.NewAddressRequest{
@@ -294,7 +294,7 @@ func testMacaroonAuthentication(ht *lntemp.HarnessTest) {
// testBakeMacaroon checks that when creating macaroons, the permissions param // testBakeMacaroon checks that when creating macaroons, the permissions param
// in the request must be set correctly, and the baked macaroon has the intended // in the request must be set correctly, and the baked macaroon has the intended
// permissions. // permissions.
func testBakeMacaroon(ht *lntemp.HarnessTest) { func testBakeMacaroon(ht *lntest.HarnessTest) {
var testNode = ht.Alice var testNode = ht.Alice
testCases := []struct { testCases := []struct {
@@ -518,7 +518,7 @@ func testBakeMacaroon(ht *lntemp.HarnessTest) {
// specified ID and invalidates all macaroons derived from the key with that ID. // specified ID and invalidates all macaroons derived from the key with that ID.
// Also, it checks deleting the reserved marcaroon ID, DefaultRootKeyID or is // Also, it checks deleting the reserved marcaroon ID, DefaultRootKeyID or is
// forbidden. // forbidden.
func testDeleteMacaroonID(ht *lntemp.HarnessTest) { func testDeleteMacaroonID(ht *lntest.HarnessTest) {
var ( var (
ctxb = ht.Context() ctxb = ht.Context()
testNode = ht.Alice testNode = ht.Alice
@@ -610,7 +610,7 @@ func testDeleteMacaroonID(ht *lntemp.HarnessTest) {
// does not write any macaroon files to the daemon's file system and returns // does not write any macaroon files to the daemon's file system and returns
// the admin macaroon in the response. It then checks that the password // the admin macaroon in the response. It then checks that the password
// change of the wallet can also happen stateless. // change of the wallet can also happen stateless.
func testStatelessInit(ht *lntemp.HarnessTest) { func testStatelessInit(ht *lntest.HarnessTest) {
var ( var (
initPw = []byte("stateless") initPw = []byte("stateless")
newPw = []byte("stateless-new") newPw = []byte("stateless-new")
@@ -1,6 +1,3 @@
//go:build rpctest
// +build rpctest
package itest package itest
import ( import (
@@ -8,14 +5,14 @@ import (
"github.com/btcsuite/btcd/btcutil" "github.com/btcsuite/btcd/btcutil"
"github.com/lightningnetwork/lnd/funding" "github.com/lightningnetwork/lnd/funding"
"github.com/lightningnetwork/lnd/lntemp" "github.com/lightningnetwork/lnd/lntest"
"github.com/lightningnetwork/lnd/lnwallet" "github.com/lightningnetwork/lnd/lnwallet"
) )
// testMaxChannelSize tests that lnd handles --maxchansize parameter correctly. // testMaxChannelSize tests that lnd handles --maxchansize parameter correctly.
// Wumbo nodes should enforce a default soft limit of 10 BTC by default. This // Wumbo nodes should enforce a default soft limit of 10 BTC by default. This
// limit can be adjusted with --maxchansize config option. // limit can be adjusted with --maxchansize config option.
func testMaxChannelSize(ht *lntemp.HarnessTest) { func testMaxChannelSize(ht *lntest.HarnessTest) {
// We'll make two new nodes, both wumbo but with the default limit on // We'll make two new nodes, both wumbo but with the default limit on
// maximum channel size (10 BTC) // maximum channel size (10 BTC)
wumboNode := ht.NewNode( wumboNode := ht.NewNode(
@@ -42,7 +39,7 @@ func testMaxChannelSize(ht *lntemp.HarnessTest) {
) )
ht.OpenChannelAssertErr( ht.OpenChannelAssertErr(
wumboNode, wumboNode2, wumboNode, wumboNode2,
lntemp.OpenChannelParams{Amt: chanAmt}, expectedErr, lntest.OpenChannelParams{Amt: chanAmt}, expectedErr,
) )
// We'll now make another wumbo node with appropriate maximum channel // We'll now make another wumbo node with appropriate maximum channel
@@ -60,7 +57,7 @@ func testMaxChannelSize(ht *lntemp.HarnessTest) {
// Creating a wumbo channel between these two nodes should succeed. // Creating a wumbo channel between these two nodes should succeed.
ht.EnsureConnected(wumboNode, wumboNode3) ht.EnsureConnected(wumboNode, wumboNode3)
chanPoint := ht.OpenChannel( chanPoint := ht.OpenChannel(
wumboNode, wumboNode3, lntemp.OpenChannelParams{Amt: chanAmt}, wumboNode, wumboNode3, lntest.OpenChannelParams{Amt: chanAmt},
) )
ht.CloseChannel(wumboNode, chanPoint) ht.CloseChannel(wumboNode, chanPoint)
@@ -4,8 +4,8 @@ import (
"github.com/lightningnetwork/lnd/lnrpc" "github.com/lightningnetwork/lnd/lnrpc"
"github.com/lightningnetwork/lnd/lnrpc/invoicesrpc" "github.com/lightningnetwork/lnd/lnrpc/invoicesrpc"
"github.com/lightningnetwork/lnd/lnrpc/routerrpc" "github.com/lightningnetwork/lnd/lnrpc/routerrpc"
"github.com/lightningnetwork/lnd/lntemp" "github.com/lightningnetwork/lnd/lntest"
"github.com/lightningnetwork/lnd/lntemp/node" "github.com/lightningnetwork/lnd/lntest/node"
"github.com/lightningnetwork/lnd/lntypes" "github.com/lightningnetwork/lnd/lntypes"
"github.com/stretchr/testify/require" "github.com/stretchr/testify/require"
) )
@@ -14,14 +14,14 @@ import (
// channel where we have already reached the limit of the number of htlcs that // channel where we have already reached the limit of the number of htlcs that
// we may add to the remote party's commitment. This test asserts that we do // we may add to the remote party's commitment. This test asserts that we do
// not attempt to use the full channel at all in our pathfinding. // not attempt to use the full channel at all in our pathfinding.
func testMaxHtlcPathfind(ht *lntemp.HarnessTest) { func testMaxHtlcPathfind(ht *lntest.HarnessTest) {
// Setup a channel between Alice and Bob where Alice will only allow // Setup a channel between Alice and Bob where Alice will only allow
// Bob to add a maximum of 5 htlcs to her commitment. // Bob to add a maximum of 5 htlcs to her commitment.
maxHtlcs := 5 maxHtlcs := 5
alice, bob := ht.Alice, ht.Bob alice, bob := ht.Alice, ht.Bob
chanPoint := ht.OpenChannel( chanPoint := ht.OpenChannel(
alice, bob, lntemp.OpenChannelParams{ alice, bob, lntest.OpenChannelParams{
Amt: 1000000, Amt: 1000000,
PushAmt: 800000, PushAmt: 800000,
RemoteMaxHtlcs: uint16(maxHtlcs), RemoteMaxHtlcs: uint16(maxHtlcs),
@@ -84,7 +84,7 @@ type holdSubscription struct {
// cancel updates a hold invoice to cancel from the recipient and consumes // cancel updates a hold invoice to cancel from the recipient and consumes
// updates from the payer until it has reached a final, failed state. // updates from the payer until it has reached a final, failed state.
func (h *holdSubscription) cancel(ht *lntemp.HarnessTest) { func (h *holdSubscription) cancel(ht *lntest.HarnessTest) {
h.recipient.RPC.CancelInvoice(h.hash[:]) h.recipient.RPC.CancelInvoice(h.hash[:])
invUpdate := ht.ReceiveSingleInvoice(h.invSubscription) invUpdate := ht.ReceiveSingleInvoice(h.invSubscription)
@@ -110,7 +110,7 @@ func (h *holdSubscription) cancel(ht *lntemp.HarnessTest) {
// acceptHoldInvoice adds a hold invoice to the recipient node, pays it from // acceptHoldInvoice adds a hold invoice to the recipient node, pays it from
// the sender and asserts that we have reached the accepted state where htlcs // the sender and asserts that we have reached the accepted state where htlcs
// are locked in for the payment. // are locked in for the payment.
func acceptHoldInvoice(ht *lntemp.HarnessTest, idx int, sender, func acceptHoldInvoice(ht *lntest.HarnessTest, idx int, sender,
receiver *node.HarnessNode) *holdSubscription { receiver *node.HarnessNode) *holdSubscription {
hash := [lntypes.HashSize]byte{byte(idx + 1)} hash := [lntypes.HashSize]byte{byte(idx + 1)}
@@ -15,8 +15,8 @@ import (
"github.com/lightningnetwork/lnd/lnrpc/invoicesrpc" "github.com/lightningnetwork/lnd/lnrpc/invoicesrpc"
"github.com/lightningnetwork/lnd/lnrpc/routerrpc" "github.com/lightningnetwork/lnd/lnrpc/routerrpc"
"github.com/lightningnetwork/lnd/lnrpc/walletrpc" "github.com/lightningnetwork/lnd/lnrpc/walletrpc"
"github.com/lightningnetwork/lnd/lntemp" "github.com/lightningnetwork/lnd/lntest"
"github.com/lightningnetwork/lnd/lntemp/node" "github.com/lightningnetwork/lnd/lntest/node"
"github.com/lightningnetwork/lnd/lntest/wait" "github.com/lightningnetwork/lnd/lntest/wait"
"github.com/lightningnetwork/lnd/lnwallet" "github.com/lightningnetwork/lnd/lnwallet"
"github.com/lightningnetwork/lnd/lnwire" "github.com/lightningnetwork/lnd/lnwire"
@@ -28,7 +28,7 @@ import (
// disconnect at any point. // disconnect at any point.
// //
// TODO(yy): move to lnd_network_test. // TODO(yy): move to lnd_network_test.
func testDisconnectingTargetPeer(ht *lntemp.HarnessTest) { func testDisconnectingTargetPeer(ht *lntest.HarnessTest) {
// We'll start both nodes with a high backoff so that they don't // We'll start both nodes with a high backoff so that they don't
// reconnect automatically during our test. // reconnect automatically during our test.
args := []string{ args := []string{
@@ -49,7 +49,7 @@ func testDisconnectingTargetPeer(ht *lntemp.HarnessTest) {
// Create a new channel that requires 1 confs before it's considered // Create a new channel that requires 1 confs before it's considered
// open, then broadcast the funding transaction // open, then broadcast the funding transaction
const numConfs = 1 const numConfs = 1
p := lntemp.OpenChannelParams{ p := lntest.OpenChannelParams{
Amt: chanAmt, Amt: chanAmt,
PushAmt: pushAmt, PushAmt: pushAmt,
} }
@@ -119,7 +119,7 @@ func testDisconnectingTargetPeer(ht *lntemp.HarnessTest) {
// configuration arguments to force Carol to replay the same sphinx packet // configuration arguments to force Carol to replay the same sphinx packet
// after reconnecting to Dave, and compare the returned failure message with // after reconnecting to Dave, and compare the returned failure message with
// what we expect for replayed onion packets. // what we expect for replayed onion packets.
func testSphinxReplayPersistence(ht *lntemp.HarnessTest) { func testSphinxReplayPersistence(ht *lntest.HarnessTest) {
// Open a channel with 100k satoshis between Carol and Dave with Carol // Open a channel with 100k satoshis between Carol and Dave with Carol
// being the sole funder of the channel. // being the sole funder of the channel.
chanAmt := btcutil.Amount(100000) chanAmt := btcutil.Amount(100000)
@@ -135,7 +135,7 @@ func testSphinxReplayPersistence(ht *lntemp.HarnessTest) {
ht.ConnectNodes(carol, dave) ht.ConnectNodes(carol, dave)
chanPoint := ht.OpenChannel( chanPoint := ht.OpenChannel(
carol, dave, lntemp.OpenChannelParams{ carol, dave, lntest.OpenChannelParams{
Amt: chanAmt, Amt: chanAmt,
}, },
) )
@@ -150,7 +150,7 @@ func testSphinxReplayPersistence(ht *lntemp.HarnessTest) {
ht.ConnectNodes(fred, carol) ht.ConnectNodes(fred, carol)
chanPointFC := ht.OpenChannel( chanPointFC := ht.OpenChannel(
fred, carol, lntemp.OpenChannelParams{ fred, carol, lntest.OpenChannelParams{
Amt: chanAmt, Amt: chanAmt,
}, },
) )
@@ -232,7 +232,7 @@ func testSphinxReplayPersistence(ht *lntemp.HarnessTest) {
// tests the values in all ChannelConstraints are returned as expected. Once // tests the values in all ChannelConstraints are returned as expected. Once
// ListChannels becomes mature, a test against all fields in ListChannels // ListChannels becomes mature, a test against all fields in ListChannels
// should be performed. // should be performed.
func testListChannels(ht *lntemp.HarnessTest) { func testListChannels(ht *lntest.HarnessTest) {
const aliceRemoteMaxHtlcs = 50 const aliceRemoteMaxHtlcs = 50
const bobRemoteMaxHtlcs = 100 const bobRemoteMaxHtlcs = 100
@@ -255,7 +255,7 @@ func testListChannels(ht *lntemp.HarnessTest) {
chanAmt := btcutil.Amount(100000) chanAmt := btcutil.Amount(100000)
pushAmt := btcutil.Amount(1000) pushAmt := btcutil.Amount(1000)
p := lntemp.OpenChannelParams{ p := lntest.OpenChannelParams{
Amt: chanAmt, Amt: chanAmt,
PushAmt: pushAmt, PushAmt: pushAmt,
MinHtlc: customizedMinHtlc, MinHtlc: customizedMinHtlc,
@@ -337,7 +337,7 @@ func testListChannels(ht *lntemp.HarnessTest) {
// testMaxPendingChannels checks that error is returned from remote peer if // testMaxPendingChannels checks that error is returned from remote peer if
// max pending channel number was exceeded and that '--maxpendingchannels' flag // max pending channel number was exceeded and that '--maxpendingchannels' flag
// exists and works properly. // exists and works properly.
func testMaxPendingChannels(ht *lntemp.HarnessTest) { func testMaxPendingChannels(ht *lntest.HarnessTest) {
maxPendingChannels := lncfg.DefaultMaxPendingChannels + 1 maxPendingChannels := lncfg.DefaultMaxPendingChannels + 1
amount := funding.MaxBtcFundingAmount amount := funding.MaxBtcFundingAmount
@@ -362,7 +362,7 @@ func testMaxPendingChannels(ht *lntemp.HarnessTest) {
) )
for i := 0; i < maxPendingChannels; i++ { for i := 0; i < maxPendingChannels; i++ {
stream := ht.OpenChannelAssertStream( stream := ht.OpenChannelAssertStream(
alice, carol, lntemp.OpenChannelParams{ alice, carol, lntest.OpenChannelParams{
Amt: amount, Amt: amount,
}, },
) )
@@ -372,7 +372,7 @@ func testMaxPendingChannels(ht *lntemp.HarnessTest) {
// Carol exhausted available amount of pending channels, next open // Carol exhausted available amount of pending channels, next open
// channel request should cause ErrorGeneric to be sent back to Alice. // channel request should cause ErrorGeneric to be sent back to Alice.
ht.OpenChannelAssertErr( ht.OpenChannelAssertErr(
alice, carol, lntemp.OpenChannelParams{ alice, carol, lntest.OpenChannelParams{
Amt: amount, Amt: amount,
}, lnwire.ErrMaxPendingChannels, }, lnwire.ErrMaxPendingChannels,
) )
@@ -415,7 +415,7 @@ func testMaxPendingChannels(ht *lntemp.HarnessTest) {
// testGarbageCollectLinkNodes tests that we properly garbage collect link // testGarbageCollectLinkNodes tests that we properly garbage collect link
// nodes from the database and the set of persistent connections within the // nodes from the database and the set of persistent connections within the
// server. // server.
func testGarbageCollectLinkNodes(ht *lntemp.HarnessTest) { func testGarbageCollectLinkNodes(ht *lntest.HarnessTest) {
const chanAmt = 1000000 const chanAmt = 1000000
alice, bob := ht.Alice, ht.Bob alice, bob := ht.Alice, ht.Bob
@@ -423,7 +423,7 @@ func testGarbageCollectLinkNodes(ht *lntemp.HarnessTest) {
// Open a channel between Alice and Bob which will later be // Open a channel between Alice and Bob which will later be
// cooperatively closed. // cooperatively closed.
coopChanPoint := ht.OpenChannel( coopChanPoint := ht.OpenChannel(
alice, bob, lntemp.OpenChannelParams{ alice, bob, lntest.OpenChannelParams{
Amt: chanAmt, Amt: chanAmt,
}, },
) )
@@ -435,7 +435,7 @@ func testGarbageCollectLinkNodes(ht *lntemp.HarnessTest) {
// Open a channel between Alice and Carol which will later be force // Open a channel between Alice and Carol which will later be force
// closed. // closed.
forceCloseChanPoint := ht.OpenChannel( forceCloseChanPoint := ht.OpenChannel(
alice, carol, lntemp.OpenChannelParams{ alice, carol, lntest.OpenChannelParams{
Amt: chanAmt, Amt: chanAmt,
}, },
) )
@@ -447,7 +447,7 @@ func testGarbageCollectLinkNodes(ht *lntemp.HarnessTest) {
ht.ConnectNodes(alice, dave) ht.ConnectNodes(alice, dave)
persistentChanPoint := ht.OpenChannel( persistentChanPoint := ht.OpenChannel(
alice, dave, lntemp.OpenChannelParams{ alice, dave, lntest.OpenChannelParams{
Amt: chanAmt, Amt: chanAmt,
}, },
) )
@@ -527,7 +527,7 @@ func testGarbageCollectLinkNodes(ht *lntemp.HarnessTest) {
// testRejectHTLC tests that a node can be created with the flag --rejecthtlc. // testRejectHTLC tests that a node can be created with the flag --rejecthtlc.
// This means that the node will reject all forwarded HTLCs but can still // This means that the node will reject all forwarded HTLCs but can still
// accept direct HTLCs as well as send HTLCs. // accept direct HTLCs as well as send HTLCs.
func testRejectHTLC(ht *lntemp.HarnessTest) { func testRejectHTLC(ht *lntest.HarnessTest) {
// RejectHTLC // RejectHTLC
// Alice ------> Carol ------> Bob // Alice ------> Carol ------> Bob
// //
@@ -548,14 +548,14 @@ func testRejectHTLC(ht *lntemp.HarnessTest) {
// Open a channel between Alice and Carol. // Open a channel between Alice and Carol.
chanPointAlice := ht.OpenChannel( chanPointAlice := ht.OpenChannel(
alice, carol, lntemp.OpenChannelParams{ alice, carol, lntest.OpenChannelParams{
Amt: chanAmt, Amt: chanAmt,
}, },
) )
// Open a channel between Carol and Bob. // Open a channel between Carol and Bob.
chanPointCarol := ht.OpenChannel( chanPointCarol := ht.OpenChannel(
carol, bob, lntemp.OpenChannelParams{ carol, bob, lntest.OpenChannelParams{
Amt: chanAmt, Amt: chanAmt,
}, },
) )
@@ -623,14 +623,14 @@ func testRejectHTLC(ht *lntemp.HarnessTest) {
// testNodeSignVerify checks that only connected nodes are allowed to perform // testNodeSignVerify checks that only connected nodes are allowed to perform
// signing and verifying messages. // signing and verifying messages.
func testNodeSignVerify(ht *lntemp.HarnessTest) { func testNodeSignVerify(ht *lntest.HarnessTest) {
chanAmt := funding.MaxBtcFundingAmount chanAmt := funding.MaxBtcFundingAmount
pushAmt := btcutil.Amount(100000) pushAmt := btcutil.Amount(100000)
alice, bob := ht.Alice, ht.Bob alice, bob := ht.Alice, ht.Bob
// Create a channel between alice and bob. // Create a channel between alice and bob.
aliceBobCh := ht.OpenChannel( aliceBobCh := ht.OpenChannel(
alice, bob, lntemp.OpenChannelParams{ alice, bob, lntest.OpenChannelParams{
Amt: chanAmt, Amt: chanAmt,
PushAmt: pushAmt, PushAmt: pushAmt,
}, },
@@ -670,11 +670,11 @@ func testNodeSignVerify(ht *lntemp.HarnessTest) {
// testAbandonChannel abandons a channel and asserts that it is no longer open // testAbandonChannel abandons a channel and asserts that it is no longer open
// and not in one of the pending closure states. It also verifies that the // and not in one of the pending closure states. It also verifies that the
// abandoned channel is reported as closed with close type 'abandoned'. // abandoned channel is reported as closed with close type 'abandoned'.
func testAbandonChannel(ht *lntemp.HarnessTest) { func testAbandonChannel(ht *lntest.HarnessTest) {
alice, bob := ht.Alice, ht.Bob alice, bob := ht.Alice, ht.Bob
// First establish a channel between Alice and Bob. // First establish a channel between Alice and Bob.
channelParam := lntemp.OpenChannelParams{ channelParam := lntest.OpenChannelParams{
Amt: funding.MaxBtcFundingAmount, Amt: funding.MaxBtcFundingAmount,
PushAmt: btcutil.Amount(100000), PushAmt: btcutil.Amount(100000),
} }
@@ -741,7 +741,7 @@ func testAbandonChannel(ht *lntemp.HarnessTest) {
// wallet into a single target address at the specified fee rate. // wallet into a single target address at the specified fee rate.
// //
// TODO(yy): expand this test to also use P2TR. // TODO(yy): expand this test to also use P2TR.
func testSweepAllCoins(ht *lntemp.HarnessTest) { func testSweepAllCoins(ht *lntest.HarnessTest) {
// First, we'll make a new node, ainz who'll we'll use to test wallet // First, we'll make a new node, ainz who'll we'll use to test wallet
// sweeping. // sweeping.
// //
@@ -917,7 +917,7 @@ func testSweepAllCoins(ht *lntemp.HarnessTest) {
// testListAddresses tests that we get all the addresses and their // testListAddresses tests that we get all the addresses and their
// corresponding balance correctly. // corresponding balance correctly.
func testListAddresses(ht *lntemp.HarnessTest) { func testListAddresses(ht *lntest.HarnessTest) {
// First, we'll make a new node - Alice, which will be generating // First, we'll make a new node - Alice, which will be generating
// new addresses. // new addresses.
alice := ht.NewNode("Alice", nil) alice := ht.NewNode("Alice", nil)
@@ -964,7 +964,8 @@ func testListAddresses(ht *lntemp.HarnessTest) {
}) })
generatedAddr[resp.Address] = addressDetails{ generatedAddr[resp.Address] = addressDetails{
Balance: 400_000, Balance: 400_000,
Type: walletrpc.AddressType_HYBRID_NESTED_WITNESS_PUBKEY_HASH, Type: walletrpc.
AddressType_HYBRID_NESTED_WITNESS_PUBKEY_HASH,
} }
for addr, addressDetail := range generatedAddr { for addr, addressDetail := range generatedAddr {
@@ -985,7 +986,7 @@ func testListAddresses(ht *lntemp.HarnessTest) {
foundAddresses := 0 foundAddresses := 0
for _, addressList := range addressLists.AccountWithAddresses { for _, addressList := range addressLists.AccountWithAddresses {
addresses := addressList.Addresses addresses := addressList.Addresses
derivationPath, err := lntemp.ParseDerivationPath( derivationPath, err := lntest.ParseDerivationPath(
addressList.DerivationPath, addressList.DerivationPath,
) )
require.NoError(ht, err) require.NoError(ht, err)
@@ -1023,7 +1024,7 @@ func testListAddresses(ht *lntemp.HarnessTest) {
for _, addressList := range addressLists.AccountWithAddresses { for _, addressList := range addressLists.AccountWithAddresses {
addresses := addressList.Addresses addresses := addressList.Addresses
derivationPath, err := lntemp.ParseDerivationPath( derivationPath, err := lntest.ParseDerivationPath(
addressList.DerivationPath, addressList.DerivationPath,
) )
require.NoError(ht, err) require.NoError(ht, err)
@@ -1053,7 +1054,7 @@ func testListAddresses(ht *lntemp.HarnessTest) {
require.Equal(ht, len(generatedAddr), foundAddresses) require.Equal(ht, len(generatedAddr), foundAddresses)
} }
func assertChannelConstraintsEqual(ht *lntemp.HarnessTest, func assertChannelConstraintsEqual(ht *lntest.HarnessTest,
want, got *lnrpc.ChannelConstraints) { want, got *lnrpc.ChannelConstraints) {
require.Equal(ht, want.CsvDelay, got.CsvDelay, "CsvDelay mismatched") require.Equal(ht, want.CsvDelay, got.CsvDelay, "CsvDelay mismatched")
@@ -1076,7 +1077,7 @@ func assertChannelConstraintsEqual(ht *lntemp.HarnessTest,
// testSignVerifyMessageWithAddr tests signing and also verifying a signature // testSignVerifyMessageWithAddr tests signing and also verifying a signature
// on a message with a provided address. // on a message with a provided address.
func testSignVerifyMessageWithAddr(ht *lntemp.HarnessTest) { func testSignVerifyMessageWithAddr(ht *lntest.HarnessTest) {
// Using different nodes to sign the message and verify the signature. // Using different nodes to sign the message and verify the signature.
alice, bob := ht.Alice, ht.Bob alice, bob := ht.Alice, ht.Bob
@@ -7,8 +7,8 @@ import (
"github.com/lightningnetwork/lnd/chainreg" "github.com/lightningnetwork/lnd/chainreg"
"github.com/lightningnetwork/lnd/lnrpc" "github.com/lightningnetwork/lnd/lnrpc"
"github.com/lightningnetwork/lnd/lnrpc/routerrpc" "github.com/lightningnetwork/lnd/lnrpc/routerrpc"
"github.com/lightningnetwork/lnd/lntemp" "github.com/lightningnetwork/lnd/lntest"
"github.com/lightningnetwork/lnd/lntemp/node" "github.com/lightningnetwork/lnd/lntest/node"
"github.com/lightningnetwork/lnd/lntypes" "github.com/lightningnetwork/lnd/lntypes"
"github.com/lightningnetwork/lnd/routing/route" "github.com/lightningnetwork/lnd/routing/route"
"github.com/stretchr/testify/require" "github.com/stretchr/testify/require"
@@ -16,7 +16,7 @@ import (
// testSendToRouteMultiPath tests that we are able to successfully route a // testSendToRouteMultiPath tests that we are able to successfully route a
// payment using multiple shards across different paths, by using SendToRoute. // payment using multiple shards across different paths, by using SendToRoute.
func testSendToRouteMultiPath(ht *lntemp.HarnessTest) { func testSendToRouteMultiPath(ht *lntest.HarnessTest) {
mts := newMppTestScenario(ht) mts := newMppTestScenario(ht)
// To ensure the payment goes through separate paths, we'll set a // To ensure the payment goes through separate paths, we'll set a
@@ -162,7 +162,7 @@ func testSendToRouteMultiPath(ht *lntemp.HarnessTest) {
// It has two standby nodes, alice and bob, and three new nodes, carol, dave, // It has two standby nodes, alice and bob, and three new nodes, carol, dave,
// and eve. // and eve.
type mppTestScenario struct { type mppTestScenario struct {
ht *lntemp.HarnessTest ht *lntest.HarnessTest
alice, bob, carol, dave, eve *node.HarnessNode alice, bob, carol, dave, eve *node.HarnessNode
nodes []*node.HarnessNode nodes []*node.HarnessNode
@@ -179,7 +179,7 @@ type mppTestScenario struct {
// Alice -- Carol ---- Bob // Alice -- Carol ---- Bob
// \ / // \ /
// \__ Dave ____/ // \__ Dave ____/
func newMppTestScenario(ht *lntemp.HarnessTest) *mppTestScenario { func newMppTestScenario(ht *lntest.HarnessTest) *mppTestScenario {
alice, bob := ht.Alice, ht.Bob alice, bob := ht.Alice, ht.Bob
ht.RestartNodeWithExtraArgs(bob, []string{ ht.RestartNodeWithExtraArgs(bob, []string{
"--maxpendingchannels=2", "--maxpendingchannels=2",
@@ -256,36 +256,36 @@ type mppOpenChannelRequest struct {
// //
// NOTE: all the channels are open together to save blocks mined. // NOTE: all the channels are open together to save blocks mined.
func (m *mppTestScenario) openChannels(r *mppOpenChannelRequest) { func (m *mppTestScenario) openChannels(r *mppOpenChannelRequest) {
reqs := []*lntemp.OpenChannelRequest{ reqs := []*lntest.OpenChannelRequest{
{ {
Local: m.alice, Local: m.alice,
Remote: m.carol, Remote: m.carol,
Param: lntemp.OpenChannelParams{Amt: r.amtAliceCarol}, Param: lntest.OpenChannelParams{Amt: r.amtAliceCarol},
}, },
{ {
Local: m.alice, Local: m.alice,
Remote: m.dave, Remote: m.dave,
Param: lntemp.OpenChannelParams{Amt: r.amtAliceDave}, Param: lntest.OpenChannelParams{Amt: r.amtAliceDave},
}, },
{ {
Local: m.carol, Local: m.carol,
Remote: m.bob, Remote: m.bob,
Param: lntemp.OpenChannelParams{Amt: r.amtCarolBob}, Param: lntest.OpenChannelParams{Amt: r.amtCarolBob},
}, },
{ {
Local: m.carol, Local: m.carol,
Remote: m.eve, Remote: m.eve,
Param: lntemp.OpenChannelParams{Amt: r.amtCarolEve}, Param: lntest.OpenChannelParams{Amt: r.amtCarolEve},
}, },
{ {
Local: m.dave, Local: m.dave,
Remote: m.bob, Remote: m.bob,
Param: lntemp.OpenChannelParams{Amt: r.amtDaveBob}, Param: lntest.OpenChannelParams{Amt: r.amtDaveBob},
}, },
{ {
Local: m.eve, Local: m.eve,
Remote: m.bob, Remote: m.bob,
Param: lntemp.OpenChannelParams{Amt: r.amtEveBob}, Param: lntest.OpenChannelParams{Amt: r.amtEveBob},
}, },
} }
@@ -313,7 +313,7 @@ func (m *mppTestScenario) closeChannels() {
// active htlcs` or `link failed to shutdown` if we close the channel. // active htlcs` or `link failed to shutdown` if we close the channel.
// We need to investigate the order of settling the payments and // We need to investigate the order of settling the payments and
// updating commitments to understand and fix . // updating commitments to understand and fix .
time.Sleep(2 * time.Second) time.Sleep(5 * time.Second)
// Close all channels without mining the closing transactions. // Close all channels without mining the closing transactions.
m.ht.CloseChannelAssertPending(m.alice, m.channelPoints[0], false) m.ht.CloseChannelAssertPending(m.alice, m.channelPoints[0], false)
@@ -6,12 +6,12 @@ import (
"github.com/lightningnetwork/lnd/funding" "github.com/lightningnetwork/lnd/funding"
"github.com/lightningnetwork/lnd/lnrpc" "github.com/lightningnetwork/lnd/lnrpc"
"github.com/lightningnetwork/lnd/lnrpc/routerrpc" "github.com/lightningnetwork/lnd/lnrpc/routerrpc"
"github.com/lightningnetwork/lnd/lntemp" "github.com/lightningnetwork/lnd/lntest"
"github.com/lightningnetwork/lnd/lnwire" "github.com/lightningnetwork/lnd/lnwire"
"github.com/stretchr/testify/require" "github.com/stretchr/testify/require"
) )
func testHtlcErrorPropagation(ht *lntemp.HarnessTest) { func testHtlcErrorPropagation(ht *lntest.HarnessTest) {
// In this test we wish to exercise the daemon's correct parsing, // In this test we wish to exercise the daemon's correct parsing,
// handling, and propagation of errors that occur while processing a // handling, and propagation of errors that occur while processing a
// multi-hop payment. // multi-hop payment.
@@ -39,23 +39,22 @@ func testHtlcErrorPropagation(ht *lntemp.HarnessTest) {
// and Bob. // and Bob.
chanPointAlice := ht.OpenChannel( chanPointAlice := ht.OpenChannel(
alice, bob, alice, bob,
lntemp.OpenChannelParams{Amt: chanAmt}, lntest.OpenChannelParams{Amt: chanAmt},
) )
// Next, we'll create a connection from Bob to Carol, and open a // Next, we'll create a connection from Bob to Carol, and open a
// channel between them so we have the topology: Alice -> Bob -> Carol. // channel between them so we have the topology: Alice -> Bob -> Carol.
// The channel created will be of lower capacity that the one created // The channel created will be of lower capacity that the one created
// above. // above.
const bobChanAmt = funding.MaxBtcFundingAmount
chanPointBob := ht.OpenChannel( chanPointBob := ht.OpenChannel(
bob, carol, lntemp.OpenChannelParams{Amt: chanAmt}, bob, carol, lntest.OpenChannelParams{Amt: chanAmt},
) )
// Ensure that Alice has Carol in her routing table before proceeding. // Ensure that Alice has Carol in her routing table before proceeding.
ht.AssertTopologyChannelOpen(alice, chanPointBob) ht.AssertTopologyChannelOpen(alice, chanPointBob)
cType := ht.GetChannelCommitType(alice, chanPointAlice) cType := ht.GetChannelCommitType(alice, chanPointAlice)
commitFee := calcStaticFee(cType, 0) commitFee := lntest.CalcStaticFee(cType, 0)
assertBaseBalance := func() { assertBaseBalance := func() {
// Alice has opened a channel with Bob with zero push amount, // Alice has opened a channel with Bob with zero push amount,
@@ -153,24 +152,24 @@ func testHtlcErrorPropagation(ht *lntemp.HarnessTest) {
assertAliceAndBob := func() { assertAliceAndBob := func() {
ht.AssertHtlcEventTypes( ht.AssertHtlcEventTypes(
aliceEvents, routerrpc.HtlcEvent_SEND, aliceEvents, routerrpc.HtlcEvent_SEND,
lntemp.HtlcEventForward, lntest.HtlcEventForward,
) )
ht.AssertHtlcEventTypes( ht.AssertHtlcEventTypes(
aliceEvents, routerrpc.HtlcEvent_SEND, aliceEvents, routerrpc.HtlcEvent_SEND,
lntemp.HtlcEventForwardFail, lntest.HtlcEventForwardFail,
) )
ht.AssertHtlcEventTypes( ht.AssertHtlcEventTypes(
bobEvents, routerrpc.HtlcEvent_FORWARD, bobEvents, routerrpc.HtlcEvent_FORWARD,
lntemp.HtlcEventForward, lntest.HtlcEventForward,
) )
ht.AssertHtlcEventTypes( ht.AssertHtlcEventTypes(
bobEvents, routerrpc.HtlcEvent_FORWARD, bobEvents, routerrpc.HtlcEvent_FORWARD,
lntemp.HtlcEventForwardFail, lntest.HtlcEventForwardFail,
) )
ht.AssertHtlcEventTypes( ht.AssertHtlcEventTypes(
bobEvents, routerrpc.HtlcEvent_UNKNOWN, bobEvents, routerrpc.HtlcEvent_UNKNOWN,
lntemp.HtlcEventFinal, lntest.HtlcEventFinal,
) )
} }
@@ -188,7 +187,7 @@ func testHtlcErrorPropagation(ht *lntemp.HarnessTest) {
// There's also a final htlc event that gives the final outcome of the // There's also a final htlc event that gives the final outcome of the
// htlc. // htlc.
ht.AssertHtlcEventTypes( ht.AssertHtlcEventTypes(
carolEvents, routerrpc.HtlcEvent_UNKNOWN, lntemp.HtlcEventFinal, carolEvents, routerrpc.HtlcEvent_UNKNOWN, lntest.HtlcEventFinal,
) )
// The balances of all parties should be the same as initially since // The balances of all parties should be the same as initially since
@@ -228,7 +227,7 @@ func testHtlcErrorPropagation(ht *lntemp.HarnessTest) {
// There's also a final htlc event that gives the final outcome of the // There's also a final htlc event that gives the final outcome of the
// htlc. // htlc.
ht.AssertHtlcEventTypes( ht.AssertHtlcEventTypes(
carolEvents, routerrpc.HtlcEvent_UNKNOWN, lntemp.HtlcEventFinal, carolEvents, routerrpc.HtlcEvent_UNKNOWN, lntest.HtlcEventFinal,
) )
// The balances of all parties should be the same as initially since // The balances of all parties should be the same as initially since
@@ -273,19 +272,19 @@ func testHtlcErrorPropagation(ht *lntemp.HarnessTest) {
// settle event and a final htlc event for her receive. // settle event and a final htlc event for her receive.
ht.AssertHtlcEventTypes( ht.AssertHtlcEventTypes(
bobEvents, routerrpc.HtlcEvent_SEND, bobEvents, routerrpc.HtlcEvent_SEND,
lntemp.HtlcEventForward, lntest.HtlcEventForward,
) )
ht.AssertHtlcEventTypes( ht.AssertHtlcEventTypes(
bobEvents, routerrpc.HtlcEvent_SEND, bobEvents, routerrpc.HtlcEvent_SEND,
lntemp.HtlcEventSettle, lntest.HtlcEventSettle,
) )
ht.AssertHtlcEventTypes( ht.AssertHtlcEventTypes(
carolEvents, routerrpc.HtlcEvent_RECEIVE, carolEvents, routerrpc.HtlcEvent_RECEIVE,
lntemp.HtlcEventSettle, lntest.HtlcEventSettle,
) )
ht.AssertHtlcEventTypes( ht.AssertHtlcEventTypes(
carolEvents, routerrpc.HtlcEvent_UNKNOWN, carolEvents, routerrpc.HtlcEvent_UNKNOWN,
lntemp.HtlcEventFinal, lntest.HtlcEventFinal,
) )
amtSent += toSend amtSent += toSend
@@ -316,11 +315,11 @@ func testHtlcErrorPropagation(ht *lntemp.HarnessTest) {
// Alice should have a forwarding event and a forwarding failure. // Alice should have a forwarding event and a forwarding failure.
ht.AssertHtlcEventTypes( ht.AssertHtlcEventTypes(
aliceEvents, routerrpc.HtlcEvent_SEND, aliceEvents, routerrpc.HtlcEvent_SEND,
lntemp.HtlcEventForward, lntest.HtlcEventForward,
) )
ht.AssertHtlcEventTypes( ht.AssertHtlcEventTypes(
aliceEvents, routerrpc.HtlcEvent_SEND, aliceEvents, routerrpc.HtlcEvent_SEND,
lntemp.HtlcEventForwardFail, lntest.HtlcEventForwardFail,
) )
// Bob should have a link failure because the htlc failed on his // Bob should have a link failure because the htlc failed on his
@@ -331,7 +330,7 @@ func testHtlcErrorPropagation(ht *lntemp.HarnessTest) {
// There's also a final htlc event that gives the final outcome of the // There's also a final htlc event that gives the final outcome of the
// htlc. // htlc.
ht.AssertHtlcEventTypes( ht.AssertHtlcEventTypes(
bobEvents, routerrpc.HtlcEvent_UNKNOWN, lntemp.HtlcEventFinal, bobEvents, routerrpc.HtlcEvent_UNKNOWN, lntest.HtlcEventFinal,
) )
// Generate new invoice to not pay same invoice twice. // Generate new invoice to not pay same invoice twice.
@@ -362,11 +361,11 @@ func testHtlcErrorPropagation(ht *lntemp.HarnessTest) {
// Alice should have a forwarding event and subsequent fail. // Alice should have a forwarding event and subsequent fail.
ht.AssertHtlcEventTypes( ht.AssertHtlcEventTypes(
aliceEvents, routerrpc.HtlcEvent_SEND, aliceEvents, routerrpc.HtlcEvent_SEND,
lntemp.HtlcEventForward, lntest.HtlcEventForward,
) )
ht.AssertHtlcEventTypes( ht.AssertHtlcEventTypes(
aliceEvents, routerrpc.HtlcEvent_SEND, aliceEvents, routerrpc.HtlcEvent_SEND,
lntemp.HtlcEventForwardFail, lntest.HtlcEventForwardFail,
) )
// Bob should have a link failure because he could not find the next // Bob should have a link failure because he could not find the next
@@ -377,7 +376,7 @@ func testHtlcErrorPropagation(ht *lntemp.HarnessTest) {
// There's also a final htlc event that gives the final outcome of the // There's also a final htlc event that gives the final outcome of the
// htlc. // htlc.
ht.AssertHtlcEventTypes( ht.AssertHtlcEventTypes(
bobEvents, routerrpc.HtlcEvent_UNKNOWN, lntemp.HtlcEventFinal, bobEvents, routerrpc.HtlcEvent_UNKNOWN, lntest.HtlcEventFinal,
) )
// Finally, immediately close the channel. This function will also // Finally, immediately close the channel. This function will also
@@ -5,12 +5,12 @@ import (
"github.com/lightningnetwork/lnd/chainreg" "github.com/lightningnetwork/lnd/chainreg"
"github.com/lightningnetwork/lnd/lnrpc" "github.com/lightningnetwork/lnd/lnrpc"
"github.com/lightningnetwork/lnd/lnrpc/routerrpc" "github.com/lightningnetwork/lnd/lnrpc/routerrpc"
"github.com/lightningnetwork/lnd/lntemp" "github.com/lightningnetwork/lnd/lntest"
"github.com/lightningnetwork/lnd/lntemp/node" "github.com/lightningnetwork/lnd/lntest/node"
"github.com/stretchr/testify/require" "github.com/stretchr/testify/require"
) )
func testMultiHopPayments(ht *lntemp.HarnessTest) { func testMultiHopPayments(ht *lntest.HarnessTest) {
const chanAmt = btcutil.Amount(100000) const chanAmt = btcutil.Amount(100000)
// As preliminary setup, we'll create two new nodes: Carol and Dave, // As preliminary setup, we'll create two new nodes: Carol and Dave,
@@ -43,21 +43,21 @@ func testMultiHopPayments(ht *lntemp.HarnessTest) {
// Open a channel with 100k satoshis between Alice and Bob with Alice // Open a channel with 100k satoshis between Alice and Bob with Alice
// being the sole funder of the channel. // being the sole funder of the channel.
chanPointAlice := ht.OpenChannel( chanPointAlice := ht.OpenChannel(
alice, bob, lntemp.OpenChannelParams{Amt: chanAmt}, alice, bob, lntest.OpenChannelParams{Amt: chanAmt},
) )
// We'll create Dave and establish a channel to Alice. Dave will be // We'll create Dave and establish a channel to Alice. Dave will be
// running an older node that requires the legacy onion payload. // running an older node that requires the legacy onion payload.
ht.FundCoins(btcutil.SatoshiPerBitcoin, dave) ht.FundCoins(btcutil.SatoshiPerBitcoin, dave)
chanPointDave := ht.OpenChannel( chanPointDave := ht.OpenChannel(
dave, alice, lntemp.OpenChannelParams{Amt: chanAmt}, dave, alice, lntest.OpenChannelParams{Amt: chanAmt},
) )
// Next, we'll create Carol and establish a channel to from her to // Next, we'll create Carol and establish a channel to from her to
// Dave. // Dave.
ht.FundCoins(btcutil.SatoshiPerBitcoin, carol) ht.FundCoins(btcutil.SatoshiPerBitcoin, carol)
chanPointCarol := ht.OpenChannel( chanPointCarol := ht.OpenChannel(
carol, dave, lntemp.OpenChannelParams{Amt: chanAmt}, carol, dave, lntest.OpenChannelParams{Amt: chanAmt},
) )
// Create 5 invoices for Bob, which expect a payment from Carol for 1k // Create 5 invoices for Bob, which expect a payment from Carol for 1k
@@ -69,7 +69,7 @@ func testMultiHopPayments(ht *lntemp.HarnessTest) {
// Set the fee policies of the Alice -> Bob and the Dave -> Alice // Set the fee policies of the Alice -> Bob and the Dave -> Alice
// channel edges to relatively large non default values. This makes it // channel edges to relatively large non default values. This makes it
// possible to pick up more subtle fee calculation errors. // possible to pick up more subtle fee calculation errors.
maxHtlc := calculateMaxHtlc(chanAmt) maxHtlc := lntest.CalculateMaxHtlc(chanAmt)
const aliceBaseFeeSat = 1 const aliceBaseFeeSat = 1
const aliceFeeRatePPM = 100000 const aliceFeeRatePPM = 100000
updateChannelPolicy( updateChannelPolicy(
@@ -222,7 +222,7 @@ func testMultiHopPayments(ht *lntemp.HarnessTest) {
// policy update. // policy update.
// //
// NOTE: only used in current test. // NOTE: only used in current test.
func updateChannelPolicy(ht *lntemp.HarnessTest, hn *node.HarnessNode, func updateChannelPolicy(ht *lntest.HarnessTest, hn *node.HarnessNode,
chanPoint *lnrpc.ChannelPoint, baseFee int64, chanPoint *lnrpc.ChannelPoint, baseFee int64,
feeRate int64, timeLockDelta uint32, feeRate int64, timeLockDelta uint32,
maxHtlc uint64, listenerNode *node.HarnessNode) { maxHtlc uint64, listenerNode *node.HarnessNode) {
@@ -12,10 +12,9 @@ import (
"github.com/lightningnetwork/lnd/lnrpc" "github.com/lightningnetwork/lnd/lnrpc"
"github.com/lightningnetwork/lnd/lnrpc/invoicesrpc" "github.com/lightningnetwork/lnd/lnrpc/invoicesrpc"
"github.com/lightningnetwork/lnd/lnrpc/routerrpc" "github.com/lightningnetwork/lnd/lnrpc/routerrpc"
"github.com/lightningnetwork/lnd/lntemp"
"github.com/lightningnetwork/lnd/lntemp/node"
"github.com/lightningnetwork/lnd/lntemp/rpc"
"github.com/lightningnetwork/lnd/lntest" "github.com/lightningnetwork/lnd/lntest"
"github.com/lightningnetwork/lnd/lntest/node"
"github.com/lightningnetwork/lnd/lntest/rpc"
"github.com/lightningnetwork/lnd/lntypes" "github.com/lightningnetwork/lnd/lntypes"
"github.com/lightningnetwork/lnd/routing" "github.com/lightningnetwork/lnd/routing"
"github.com/stretchr/testify/require" "github.com/stretchr/testify/require"
@@ -52,109 +51,13 @@ var commitWithZeroConf = []struct {
}, },
} }
// waitForInvoiceAccepted waits until the specified invoice moved to the
// accepted state by the node.
func waitForInvoiceAccepted(t *harnessTest, node *lntest.HarnessNode,
payHash lntypes.Hash) {
ctx, cancel := context.WithTimeout(context.Background(), defaultTimeout)
defer cancel()
invoiceUpdates, err := node.SubscribeSingleInvoice(ctx,
&invoicesrpc.SubscribeSingleInvoiceRequest{
RHash: payHash[:],
},
)
if err != nil {
t.Fatalf("subscribe single invoice: %v", err)
}
for {
update, err := invoiceUpdates.Recv()
if err != nil {
t.Fatalf("invoice update err: %v", err)
}
if update.State == lnrpc.Invoice_ACCEPTED {
break
}
}
}
// checkPaymentStatus asserts that the given node list a payment with the given
// preimage has the expected status.
func checkPaymentStatus(node *lntest.HarnessNode, preimage lntypes.Preimage,
status lnrpc.Payment_PaymentStatus) error {
ctxb := context.Background()
ctxt, cancel := context.WithTimeout(ctxb, defaultTimeout)
defer cancel()
req := &lnrpc.ListPaymentsRequest{
IncludeIncomplete: true,
}
paymentsResp, err := node.ListPayments(ctxt, req)
if err != nil {
return fmt.Errorf("error when obtaining Alice payments: %v",
err)
}
payHash := preimage.Hash()
var found bool
for _, p := range paymentsResp.Payments {
if p.PaymentHash != payHash.String() {
continue
}
found = true
if p.Status != status {
return fmt.Errorf("expected payment status "+
"%v, got %v", status, p.Status)
}
switch status {
// If this expected status is SUCCEEDED, we expect the final preimage.
case lnrpc.Payment_SUCCEEDED:
if p.PaymentPreimage != preimage.String() {
return fmt.Errorf("preimage doesn't match: %v vs %v",
p.PaymentPreimage, preimage.String())
}
// Otherwise we expect an all-zero preimage.
default:
if p.PaymentPreimage != (lntypes.Preimage{}).String() {
return fmt.Errorf("expected zero preimage, got %v",
p.PaymentPreimage)
}
}
}
if !found {
return fmt.Errorf("payment with payment hash %v not found "+
"in response", payHash)
}
return nil
}
// assertAllTxesSpendFrom asserts that all txes in the list spend from the given
// tx.
func assertAllTxesSpendFrom(t *harnessTest, txes []*wire.MsgTx,
prevTxid chainhash.Hash) {
for _, tx := range txes {
if tx.TxIn[0].PreviousOutPoint.Hash != prevTxid {
t.Fatalf("tx %v did not spend from %v",
tx.TxHash(), prevTxid)
}
}
}
// caseRunner defines a single test case runner. // caseRunner defines a single test case runner.
type caseRunner func(ht *lntemp.HarnessTest, alice, bob *node.HarnessNode, type caseRunner func(ht *lntest.HarnessTest, alice, bob *node.HarnessNode,
c lnrpc.CommitmentType, zeroConf bool) c lnrpc.CommitmentType, zeroConf bool)
// runMultiHopHtlcClaimTest is a helper method to build test cases based on // runMultiHopHtlcClaimTest is a helper method to build test cases based on
// different commitment types and zero-conf config and run them. // different commitment types and zero-conf config and run them.
func runMultiHopHtlcClaimTest(ht *lntemp.HarnessTest, tester caseRunner) { func runMultiHopHtlcClaimTest(ht *lntest.HarnessTest, tester caseRunner) {
for _, typeAndConf := range commitWithZeroConf { for _, typeAndConf := range commitWithZeroConf {
typeAndConf := typeAndConf typeAndConf := typeAndConf
name := fmt.Sprintf("zeroconf=%v/committype=%v", name := fmt.Sprintf("zeroconf=%v/committype=%v",
@@ -162,7 +65,7 @@ func runMultiHopHtlcClaimTest(ht *lntemp.HarnessTest, tester caseRunner) {
// Create the nodes here so that separate logs will be created // Create the nodes here so that separate logs will be created
// for Alice and Bob. // for Alice and Bob.
args := nodeArgsForCommitType(typeAndConf.commitType) args := lntest.NodeArgsForCommitType(typeAndConf.commitType)
if typeAndConf.zeroConf { if typeAndConf.zeroConf {
args = append( args = append(
args, "--protocol.option-scid-alias", args, "--protocol.option-scid-alias",
@@ -200,11 +103,11 @@ func runMultiHopHtlcClaimTest(ht *lntemp.HarnessTest, tester caseRunner) {
// it using the HTLC timeout transaction. Any dust HTLC's should be immediately // it using the HTLC timeout transaction. Any dust HTLC's should be immediately
// canceled backwards. Once the timeout has been reached, then we should sweep // canceled backwards. Once the timeout has been reached, then we should sweep
// it on-chain, and cancel the HTLC backwards. // it on-chain, and cancel the HTLC backwards.
func testMultiHopHtlcLocalTimeout(ht *lntemp.HarnessTest) { func testMultiHopHtlcLocalTimeout(ht *lntest.HarnessTest) {
runMultiHopHtlcClaimTest(ht, runMultiHopHtlcLocalTimeout) runMultiHopHtlcClaimTest(ht, runMultiHopHtlcLocalTimeout)
} }
func runMultiHopHtlcLocalTimeout(ht *lntemp.HarnessTest, func runMultiHopHtlcLocalTimeout(ht *lntest.HarnessTest,
alice, bob *node.HarnessNode, c lnrpc.CommitmentType, zeroConf bool) { alice, bob *node.HarnessNode, c lnrpc.CommitmentType, zeroConf bool) {
// First, we'll create a three hop network: Alice -> Bob -> Carol, with // First, we'll create a three hop network: Alice -> Bob -> Carol, with
@@ -268,7 +171,7 @@ func runMultiHopHtlcLocalTimeout(ht *lntemp.HarnessTest,
// Bob's force close transaction should now be found in the mempool. If // Bob's force close transaction should now be found in the mempool. If
// there are anchors, we also expect Bob's anchor sweep. // there are anchors, we also expect Bob's anchor sweep.
expectedTxes := 1 expectedTxes := 1
hasAnchors := commitTypeHasAnchors(c) hasAnchors := lntest.CommitTypeHasAnchors(c)
if hasAnchors { if hasAnchors {
expectedTxes = 2 expectedTxes = 2
} }
@@ -369,11 +272,11 @@ func runMultiHopHtlcLocalTimeout(ht *lntemp.HarnessTest,
// transaction. In this scenario, the node that sent the outgoing HTLC should // transaction. In this scenario, the node that sent the outgoing HTLC should
// extract the preimage from the sweep transaction, and finish settling the // extract the preimage from the sweep transaction, and finish settling the
// HTLC backwards into the route. // HTLC backwards into the route.
func testMultiHopReceiverChainClaim(ht *lntemp.HarnessTest) { func testMultiHopReceiverChainClaim(ht *lntest.HarnessTest) {
runMultiHopHtlcClaimTest(ht, runMultiHopReceiverChainClaim) runMultiHopHtlcClaimTest(ht, runMultiHopReceiverChainClaim)
} }
func runMultiHopReceiverChainClaim(ht *lntemp.HarnessTest, func runMultiHopReceiverChainClaim(ht *lntest.HarnessTest,
alice, bob *node.HarnessNode, c lnrpc.CommitmentType, zeroConf bool) { alice, bob *node.HarnessNode, c lnrpc.CommitmentType, zeroConf bool) {
// First, we'll create a three hop network: Alice -> Bob -> Carol, with // First, we'll create a three hop network: Alice -> Bob -> Carol, with
@@ -445,7 +348,7 @@ func runMultiHopReceiverChainClaim(ht *lntemp.HarnessTest,
// transaction in order to go to the chain and sweep her HTLC. If there // transaction in order to go to the chain and sweep her HTLC. If there
// are anchors, Carol also sweeps hers. // are anchors, Carol also sweeps hers.
expectedTxes := 1 expectedTxes := 1
hasAnchors := commitTypeHasAnchors(c) hasAnchors := lntest.CommitTypeHasAnchors(c)
if hasAnchors { if hasAnchors {
expectedTxes = 2 expectedTxes = 2
} }
@@ -567,13 +470,13 @@ func runMultiHopReceiverChainClaim(ht *lntemp.HarnessTest,
// commitment on-chain early, then it eventually recognizes this HTLC as one // commitment on-chain early, then it eventually recognizes this HTLC as one
// that's timed out. At this point, the node should timeout the HTLC using the // that's timed out. At this point, the node should timeout the HTLC using the
// HTLC timeout transaction, then cancel it backwards as normal. // HTLC timeout transaction, then cancel it backwards as normal.
func testMultiHopLocalForceCloseOnChainHtlcTimeout(ht *lntemp.HarnessTest) { func testMultiHopLocalForceCloseOnChainHtlcTimeout(ht *lntest.HarnessTest) {
runMultiHopHtlcClaimTest( runMultiHopHtlcClaimTest(
ht, runMultiHopLocalForceCloseOnChainHtlcTimeout, ht, runMultiHopLocalForceCloseOnChainHtlcTimeout,
) )
} }
func runMultiHopLocalForceCloseOnChainHtlcTimeout(ht *lntemp.HarnessTest, func runMultiHopLocalForceCloseOnChainHtlcTimeout(ht *lntest.HarnessTest,
alice, bob *node.HarnessNode, c lnrpc.CommitmentType, zeroConf bool) { alice, bob *node.HarnessNode, c lnrpc.CommitmentType, zeroConf bool) {
// First, we'll create a three hop network: Alice -> Bob -> Carol, with // First, we'll create a three hop network: Alice -> Bob -> Carol, with
@@ -614,7 +517,7 @@ func runMultiHopLocalForceCloseOnChainHtlcTimeout(ht *lntemp.HarnessTest,
// Now that all parties have the HTLC locked in, we'll immediately // Now that all parties have the HTLC locked in, we'll immediately
// force close the Bob -> Carol channel. This should trigger contract // force close the Bob -> Carol channel. This should trigger contract
// resolution mode for both of them. // resolution mode for both of them.
hasAnchors := commitTypeHasAnchors(c) hasAnchors := lntest.CommitTypeHasAnchors(c)
stream, _ := ht.CloseChannelAssertPending(bob, bobChanPoint, true) stream, _ := ht.CloseChannelAssertPending(bob, bobChanPoint, true)
closeTx := ht.AssertStreamChannelForceClosed( closeTx := ht.AssertStreamChannelForceClosed(
bob, bobChanPoint, hasAnchors, stream, bob, bobChanPoint, hasAnchors, stream,
@@ -723,13 +626,13 @@ func runMultiHopLocalForceCloseOnChainHtlcTimeout(ht *lntemp.HarnessTest,
// channel, then we properly timeout the HTLC directly on *their* commitment // channel, then we properly timeout the HTLC directly on *their* commitment
// transaction once the timeout has expired. Once we sweep the transaction, we // transaction once the timeout has expired. Once we sweep the transaction, we
// should also cancel back the initial HTLC. // should also cancel back the initial HTLC.
func testMultiHopRemoteForceCloseOnChainHtlcTimeout(ht *lntemp.HarnessTest) { func testMultiHopRemoteForceCloseOnChainHtlcTimeout(ht *lntest.HarnessTest) {
runMultiHopHtlcClaimTest( runMultiHopHtlcClaimTest(
ht, runMultiHopRemoteForceCloseOnChainHtlcTimeout, ht, runMultiHopRemoteForceCloseOnChainHtlcTimeout,
) )
} }
func runMultiHopRemoteForceCloseOnChainHtlcTimeout(ht *lntemp.HarnessTest, func runMultiHopRemoteForceCloseOnChainHtlcTimeout(ht *lntest.HarnessTest,
alice, bob *node.HarnessNode, c lnrpc.CommitmentType, zeroConf bool) { alice, bob *node.HarnessNode, c lnrpc.CommitmentType, zeroConf bool) {
// First, we'll create a three hop network: Alice -> Bob -> Carol, with // First, we'll create a three hop network: Alice -> Bob -> Carol, with
@@ -779,7 +682,7 @@ func runMultiHopRemoteForceCloseOnChainHtlcTimeout(ht *lntemp.HarnessTest,
// transaction. This will let us exercise that Bob is able to sweep the // transaction. This will let us exercise that Bob is able to sweep the
// expired HTLC on Carol's version of the commitment transaction. If // expired HTLC on Carol's version of the commitment transaction. If
// Carol has an anchor, it will be swept too. // Carol has an anchor, it will be swept too.
hasAnchors := commitTypeHasAnchors(c) hasAnchors := lntest.CommitTypeHasAnchors(c)
closeStream, _ := ht.CloseChannelAssertPending( closeStream, _ := ht.CloseChannelAssertPending(
carol, bobChanPoint, true, carol, bobChanPoint, true,
) )
@@ -879,11 +782,11 @@ func runMultiHopRemoteForceCloseOnChainHtlcTimeout(ht *lntemp.HarnessTest,
// we force close a channel with an incoming HTLC, and later find out the // we force close a channel with an incoming HTLC, and later find out the
// preimage via the witness beacon, we properly settle the HTLC on-chain using // preimage via the witness beacon, we properly settle the HTLC on-chain using
// the HTLC success transaction in order to ensure we don't lose any funds. // the HTLC success transaction in order to ensure we don't lose any funds.
func testMultiHopHtlcLocalChainClaim(ht *lntemp.HarnessTest) { func testMultiHopHtlcLocalChainClaim(ht *lntest.HarnessTest) {
runMultiHopHtlcClaimTest(ht, runMultiHopHtlcLocalChainClaim) runMultiHopHtlcClaimTest(ht, runMultiHopHtlcLocalChainClaim)
} }
func runMultiHopHtlcLocalChainClaim(ht *lntemp.HarnessTest, func runMultiHopHtlcLocalChainClaim(ht *lntest.HarnessTest,
alice, bob *node.HarnessNode, c lnrpc.CommitmentType, zeroConf bool) { alice, bob *node.HarnessNode, c lnrpc.CommitmentType, zeroConf bool) {
// First, we'll create a three hop network: Alice -> Bob -> Carol, with // First, we'll create a three hop network: Alice -> Bob -> Carol, with
@@ -937,7 +840,7 @@ func runMultiHopHtlcLocalChainClaim(ht *lntemp.HarnessTest,
// At this point, Bob decides that he wants to exit the channel // At this point, Bob decides that he wants to exit the channel
// immediately, so he force closes his commitment transaction. // immediately, so he force closes his commitment transaction.
hasAnchors := commitTypeHasAnchors(c) hasAnchors := lntest.CommitTypeHasAnchors(c)
closeStream, _ := ht.CloseChannelAssertPending( closeStream, _ := ht.CloseChannelAssertPending(
bob, aliceChanPoint, true, bob, aliceChanPoint, true,
) )
@@ -985,7 +888,7 @@ func runMultiHopHtlcLocalChainClaim(ht *lntemp.HarnessTest,
// Carol's commitment transaction should now be in the mempool. If // Carol's commitment transaction should now be in the mempool. If
// there is an anchor, Carol will sweep that too. // there is an anchor, Carol will sweep that too.
if commitTypeHasAnchors(c) { if lntest.CommitTypeHasAnchors(c) {
expectedTxes = 2 expectedTxes = 2
} }
ht.Miner.AssertNumTxsInMempool(expectedTxes) ht.Miner.AssertNumTxsInMempool(expectedTxes)
@@ -1173,11 +1076,11 @@ func runMultiHopHtlcLocalChainClaim(ht *lntemp.HarnessTest,
// we found out the preimage via the witness beacon, we properly settle the // we found out the preimage via the witness beacon, we properly settle the
// HTLC directly on-chain using the preimage in order to ensure that we don't // HTLC directly on-chain using the preimage in order to ensure that we don't
// lose any funds. // lose any funds.
func testMultiHopHtlcRemoteChainClaim(ht *lntemp.HarnessTest) { func testMultiHopHtlcRemoteChainClaim(ht *lntest.HarnessTest) {
runMultiHopHtlcClaimTest(ht, runMultiHopHtlcRemoteChainClaim) runMultiHopHtlcClaimTest(ht, runMultiHopHtlcRemoteChainClaim)
} }
func runMultiHopHtlcRemoteChainClaim(ht *lntemp.HarnessTest, func runMultiHopHtlcRemoteChainClaim(ht *lntest.HarnessTest,
alice, bob *node.HarnessNode, c lnrpc.CommitmentType, zeroConf bool) { alice, bob *node.HarnessNode, c lnrpc.CommitmentType, zeroConf bool) {
// First, we'll create a three hop network: Alice -> Bob -> Carol, with // First, we'll create a three hop network: Alice -> Bob -> Carol, with
@@ -1232,7 +1135,7 @@ func runMultiHopHtlcRemoteChainClaim(ht *lntemp.HarnessTest,
// Next, Alice decides that she wants to exit the channel, so she'll // Next, Alice decides that she wants to exit the channel, so she'll
// immediately force close the channel by broadcast her commitment // immediately force close the channel by broadcast her commitment
// transaction. // transaction.
hasAnchors := commitTypeHasAnchors(c) hasAnchors := lntest.CommitTypeHasAnchors(c)
closeStream, _ := ht.CloseChannelAssertPending( closeStream, _ := ht.CloseChannelAssertPending(
alice, aliceChanPoint, true, alice, aliceChanPoint, true,
) )
@@ -1443,11 +1346,11 @@ func runMultiHopHtlcRemoteChainClaim(ht *lntemp.HarnessTest,
// resolve them using the second level timeout and success transactions. In // resolve them using the second level timeout and success transactions. In
// case of anchor channels, the second-level spends can also be aggregated and // case of anchor channels, the second-level spends can also be aggregated and
// properly feebumped, so we'll check that as well. // properly feebumped, so we'll check that as well.
func testMultiHopHtlcAggregation(ht *lntemp.HarnessTest) { func testMultiHopHtlcAggregation(ht *lntest.HarnessTest) {
runMultiHopHtlcClaimTest(ht, runMultiHopHtlcAggregation) runMultiHopHtlcClaimTest(ht, runMultiHopHtlcAggregation)
} }
func runMultiHopHtlcAggregation(ht *lntemp.HarnessTest, func runMultiHopHtlcAggregation(ht *lntest.HarnessTest,
alice, bob *node.HarnessNode, c lnrpc.CommitmentType, zeroConf bool) { alice, bob *node.HarnessNode, c lnrpc.CommitmentType, zeroConf bool) {
// First, we'll create a three hop network: Alice -> Bob -> Carol. // First, we'll create a three hop network: Alice -> Bob -> Carol.
@@ -1586,7 +1489,7 @@ func runMultiHopHtlcAggregation(ht *lntemp.HarnessTest,
// Bob's force close transaction should now be found in the mempool. If // Bob's force close transaction should now be found in the mempool. If
// there are anchors, we also expect Bob's anchor sweep. // there are anchors, we also expect Bob's anchor sweep.
hasAnchors := commitTypeHasAnchors(c) hasAnchors := lntest.CommitTypeHasAnchors(c)
expectedTxes := 1 expectedTxes := 1
if hasAnchors { if hasAnchors {
expectedTxes = 2 expectedTxes = 2
@@ -1825,7 +1728,7 @@ func runMultiHopHtlcAggregation(ht *lntemp.HarnessTest,
} }
// createThreeHopNetwork creates a topology of `Alice -> Bob -> Carol`. // createThreeHopNetwork creates a topology of `Alice -> Bob -> Carol`.
func createThreeHopNetwork(ht *lntemp.HarnessTest, func createThreeHopNetwork(ht *lntest.HarnessTest,
alice, bob *node.HarnessNode, carolHodl bool, c lnrpc.CommitmentType, alice, bob *node.HarnessNode, carolHodl bool, c lnrpc.CommitmentType,
zeroConf bool) (*lnrpc.ChannelPoint, zeroConf bool) (*lnrpc.ChannelPoint,
*lnrpc.ChannelPoint, *node.HarnessNode) { *lnrpc.ChannelPoint, *node.HarnessNode) {
@@ -1835,7 +1738,7 @@ func createThreeHopNetwork(ht *lntemp.HarnessTest,
// We'll create a new node "carol" and have Bob connect to her. // We'll create a new node "carol" and have Bob connect to her.
// If the carolHodl flag is set, we'll make carol always hold onto the // If the carolHodl flag is set, we'll make carol always hold onto the
// HTLC, this way it'll force Bob to go to chain to resolve the HTLC. // HTLC, this way it'll force Bob to go to chain to resolve the HTLC.
carolFlags := nodeArgsForCommitType(c) carolFlags := lntest.NodeArgsForCommitType(c)
if carolHodl { if carolHodl {
carolFlags = append(carolFlags, "--hodl.exit-settle") carolFlags = append(carolFlags, "--hodl.exit-settle")
} }
@@ -1871,7 +1774,7 @@ func createThreeHopNetwork(ht *lntemp.HarnessTest,
if c == lnrpc.CommitmentType_SCRIPT_ENFORCED_LEASE { if c == lnrpc.CommitmentType_SCRIPT_ENFORCED_LEASE {
_, minerHeight := ht.Miner.GetBestBlock() _, minerHeight := ht.Miner.GetBestBlock()
thawHeight = uint32(minerHeight + thawHeightDelta) thawHeight = uint32(minerHeight + thawHeightDelta)
aliceFundingShim, _, _ = deriveFundingShim( aliceFundingShim, _ = deriveFundingShim(
ht, alice, bob, chanAmt, thawHeight, true, ht, alice, bob, chanAmt, thawHeight, true,
) )
} }
@@ -1887,7 +1790,7 @@ func createThreeHopNetwork(ht *lntemp.HarnessTest,
go acceptChannel(ht.T, true, acceptStream) go acceptChannel(ht.T, true, acceptStream)
} }
aliceParams := lntemp.OpenChannelParams{ aliceParams := lntest.OpenChannelParams{
Amt: chanAmt, Amt: chanAmt,
CommitmentType: c, CommitmentType: c,
FundingShim: aliceFundingShim, FundingShim: aliceFundingShim,
@@ -1904,7 +1807,7 @@ func createThreeHopNetwork(ht *lntemp.HarnessTest,
// open, our topology looks like: A -> B -> C. // open, our topology looks like: A -> B -> C.
var bobFundingShim *lnrpc.FundingShim var bobFundingShim *lnrpc.FundingShim
if c == lnrpc.CommitmentType_SCRIPT_ENFORCED_LEASE { if c == lnrpc.CommitmentType_SCRIPT_ENFORCED_LEASE {
bobFundingShim, _, _ = deriveFundingShim( bobFundingShim, _ = deriveFundingShim(
ht, bob, carol, chanAmt, thawHeight, true, ht, bob, carol, chanAmt, thawHeight, true,
) )
} }
@@ -1916,7 +1819,7 @@ func createThreeHopNetwork(ht *lntemp.HarnessTest,
go acceptChannel(ht.T, true, acceptStream) go acceptChannel(ht.T, true, acceptStream)
} }
bobParams := lntemp.OpenChannelParams{ bobParams := lntest.OpenChannelParams{
Amt: chanAmt, Amt: chanAmt,
CommitmentType: c, CommitmentType: c,
FundingShim: bobFundingShim, FundingShim: bobFundingShim,
@@ -3,12 +3,12 @@ package itest
import ( import (
"fmt" "fmt"
"net" "net"
"time"
"github.com/lightningnetwork/lnd/lncfg" "github.com/lightningnetwork/lnd/lncfg"
"github.com/lightningnetwork/lnd/lnrpc" "github.com/lightningnetwork/lnd/lnrpc"
"github.com/lightningnetwork/lnd/lntemp"
"github.com/lightningnetwork/lnd/lntemp/node"
"github.com/lightningnetwork/lnd/lntest" "github.com/lightningnetwork/lnd/lntest"
"github.com/lightningnetwork/lnd/lntest/node"
"github.com/lightningnetwork/lnd/lntest/wait" "github.com/lightningnetwork/lnd/lntest/wait"
"github.com/stretchr/testify/require" "github.com/stretchr/testify/require"
) )
@@ -16,7 +16,7 @@ import (
// testNetworkConnectionTimeout checks that the connectiontimeout is taking // testNetworkConnectionTimeout checks that the connectiontimeout is taking
// effect. It creates a node with a small connection timeout value, and // effect. It creates a node with a small connection timeout value, and
// connects it to a non-routable IP address. // connects it to a non-routable IP address.
func testNetworkConnectionTimeout(ht *lntemp.HarnessTest) { func testNetworkConnectionTimeout(ht *lntest.HarnessTest) {
var ( var (
// testPub is a random public key for testing only. // testPub is a random public key for testing only.
testPub = "0332bda7da70fefe4b6ab92f53b3c4f4ee7999" + testPub = "0332bda7da70fefe4b6ab92f53b3c4f4ee7999" +
@@ -75,7 +75,7 @@ func testNetworkConnectionTimeout(ht *lntemp.HarnessTest) {
// testReconnectAfterIPChange verifies that if a persistent inbound node changes // testReconnectAfterIPChange verifies that if a persistent inbound node changes
// its listening address then it's peer will still be able to reconnect to it. // its listening address then it's peer will still be able to reconnect to it.
func testReconnectAfterIPChange(ht *lntemp.HarnessTest) { func testReconnectAfterIPChange(ht *lntest.HarnessTest) {
// In this test, the following network will be set up. A single // In this test, the following network will be set up. A single
// dash line represents a peer connection and a double dash line // dash line represents a peer connection and a double dash line
// represents a channel. // represents a channel.
@@ -105,7 +105,7 @@ func testReconnectAfterIPChange(ht *lntemp.HarnessTest) {
// We derive an extra port for Dave, and we initialise his node with // We derive an extra port for Dave, and we initialise his node with
// the port advertised as `--externalip` arguments. // the port advertised as `--externalip` arguments.
ip2 := lntest.NextAvailablePort() ip2 := node.NextAvailablePort()
// Create a new node, Dave, which will initialize a P2P port for him. // Create a new node, Dave, which will initialize a P2P port for him.
daveArgs := []string{fmt.Sprintf("--externalip=127.0.0.1:%d", ip2)} daveArgs := []string{fmt.Sprintf("--externalip=127.0.0.1:%d", ip2)}
@@ -127,7 +127,7 @@ func testReconnectAfterIPChange(ht *lntemp.HarnessTest) {
// ensures that Charlie receives the node announcement from Alice as // ensures that Charlie receives the node announcement from Alice as
// part of the announcement broadcast. // part of the announcement broadcast.
chanPoint := ht.OpenChannel( chanPoint := ht.OpenChannel(
alice, dave, lntemp.OpenChannelParams{Amt: 1000000}, alice, dave, lntest.OpenChannelParams{Amt: 1000000},
) )
// waitForNodeAnnouncement is a closure used to wait on the given graph // waitForNodeAnnouncement is a closure used to wait on the given graph
@@ -184,7 +184,7 @@ func testReconnectAfterIPChange(ht *lntemp.HarnessTest) {
// address. // address.
// Change Dave's listening port and restart. // Change Dave's listening port and restart.
dave.Cfg.P2PPort = lntest.NextAvailablePort() dave.Cfg.P2PPort = node.NextAvailablePort()
dave.Cfg.ExtraArgs = []string{ dave.Cfg.ExtraArgs = []string{
fmt.Sprintf( fmt.Sprintf(
"--externalip=127.0.0.1:%d", dave.Cfg.P2PPort, "--externalip=127.0.0.1:%d", dave.Cfg.P2PPort,
@@ -210,7 +210,7 @@ func testReconnectAfterIPChange(ht *lntemp.HarnessTest) {
// testAddPeerConfig tests that the "--addpeer" config flag successfully adds // testAddPeerConfig tests that the "--addpeer" config flag successfully adds
// a new peer. // a new peer.
func testAddPeerConfig(ht *lntemp.HarnessTest) { func testAddPeerConfig(ht *lntest.HarnessTest) {
alice := ht.Alice alice := ht.Alice
info := alice.RPC.GetInfo() info := alice.RPC.GetInfo()
@@ -220,6 +220,9 @@ func testAddPeerConfig(ht *lntemp.HarnessTest) {
args := []string{fmt.Sprintf("--addpeer=%v", alicePeerAddress)} args := []string{fmt.Sprintf("--addpeer=%v", alicePeerAddress)}
carol := ht.NewNode("Carol", args) carol := ht.NewNode("Carol", args)
// TODO(yy): remove this once the peer conn race is fixed.
time.Sleep(1 * time.Second)
ht.EnsureConnected(alice, carol) ht.EnsureConnected(alice, carol)
// If we list Carol's peers, Alice should already be // If we list Carol's peers, Alice should already be
@@ -2,15 +2,14 @@ package itest
import ( import (
"github.com/lightningnetwork/lnd/lnrpc/neutrinorpc" "github.com/lightningnetwork/lnd/lnrpc/neutrinorpc"
"github.com/lightningnetwork/lnd/lntemp"
"github.com/lightningnetwork/lnd/lntest" "github.com/lightningnetwork/lnd/lntest"
"github.com/stretchr/testify/require" "github.com/stretchr/testify/require"
) )
// testNeutrino checks that the neutrino sub-server can fetch compact // testNeutrino checks that the neutrino sub-server can fetch compact
// block filters, server status and connect to a connected peer. // block filters, server status and connect to a connected peer.
func testNeutrino(ht *lntemp.HarnessTest) { func testNeutrino(ht *lntest.HarnessTest) {
if ht.ChainBackendName() != lntest.NeutrinoBackendName { if !ht.IsNeutrinoBackend() {
ht.Skipf("skipping test for non neutrino backends") ht.Skipf("skipping test for non neutrino backends")
} }
@@ -3,8 +3,8 @@
package itest package itest
import "github.com/lightningnetwork/lnd/lntemp" import "github.com/lightningnetwork/lnd/lntest"
// testEtcdFailover is an empty itest when LND is not compiled with etcd // testEtcdFailover is an empty itest when LND is not compiled with etcd
// support. // support.
func testEtcdFailover(ht *lntemp.HarnessTest) {} func testEtcdFailover(ht *lntest.HarnessTest) {}
@@ -5,11 +5,11 @@ import (
"github.com/btcsuite/btcd/btcutil" "github.com/btcsuite/btcd/btcutil"
"github.com/lightningnetwork/lnd/lnrpc" "github.com/lightningnetwork/lnd/lnrpc"
"github.com/lightningnetwork/lnd/lntemp" "github.com/lightningnetwork/lnd/lntest"
"github.com/stretchr/testify/require" "github.com/stretchr/testify/require"
) )
func testNonstdSweep(ht *lntemp.HarnessTest) { func testNonstdSweep(ht *lntest.HarnessTest) {
p2shAddr, err := btcutil.NewAddressScriptHash( p2shAddr, err := btcutil.NewAddressScriptHash(
make([]byte, 1), harnessNetParams, make([]byte, 1), harnessNetParams,
) )
@@ -74,7 +74,7 @@ func testNonstdSweep(ht *lntemp.HarnessTest) {
} }
} }
func testNonStdSweepInner(ht *lntemp.HarnessTest, address string) { func testNonStdSweepInner(ht *lntest.HarnessTest, address string) {
carol := ht.NewNode("carol", nil) carol := ht.NewNode("carol", nil)
// Give Carol a UTXO so SendCoins will behave as expected. // Give Carol a UTXO so SendCoins will behave as expected.
@@ -11,8 +11,8 @@ import (
"github.com/lightningnetwork/lnd/lnrpc" "github.com/lightningnetwork/lnd/lnrpc"
"github.com/lightningnetwork/lnd/lnrpc/chainrpc" "github.com/lightningnetwork/lnd/lnrpc/chainrpc"
"github.com/lightningnetwork/lnd/lnrpc/walletrpc" "github.com/lightningnetwork/lnd/lnrpc/walletrpc"
"github.com/lightningnetwork/lnd/lntemp" "github.com/lightningnetwork/lnd/lntest"
"github.com/lightningnetwork/lnd/lntemp/node" "github.com/lightningnetwork/lnd/lntest/node"
"github.com/lightningnetwork/lnd/lntest/wait" "github.com/lightningnetwork/lnd/lntest/wait"
"github.com/lightningnetwork/lnd/lnwallet" "github.com/lightningnetwork/lnd/lnwallet"
"github.com/lightningnetwork/lnd/sweep" "github.com/lightningnetwork/lnd/sweep"
@@ -20,7 +20,7 @@ import (
) )
// testChainKit tests ChainKit RPC endpoints. // testChainKit tests ChainKit RPC endpoints.
func testChainKit(ht *lntemp.HarnessTest) { func testChainKit(ht *lntest.HarnessTest) {
// Test functions registered as test cases spin up separate nodes // Test functions registered as test cases spin up separate nodes
// during execution. By calling sub-test functions as seen below we // during execution. By calling sub-test functions as seen below we
// avoid the need to start separate nodes. // avoid the need to start separate nodes.
@@ -30,7 +30,7 @@ func testChainKit(ht *lntemp.HarnessTest) {
// testChainKitGetBlock ensures that given a block hash, the RPC endpoint // testChainKitGetBlock ensures that given a block hash, the RPC endpoint
// returns the correct target block. // returns the correct target block.
func testChainKitGetBlock(ht *lntemp.HarnessTest) { func testChainKitGetBlock(ht *lntest.HarnessTest) {
// Get best block hash. // Get best block hash.
bestBlockRes := ht.Alice.RPC.GetBestBlock(nil) bestBlockRes := ht.Alice.RPC.GetBestBlock(nil)
@@ -58,7 +58,7 @@ func testChainKitGetBlock(ht *lntemp.HarnessTest) {
// testChainKitGetBlockHash ensures that given a block height, the RPC endpoint // testChainKitGetBlockHash ensures that given a block height, the RPC endpoint
// returns the correct target block hash. // returns the correct target block hash.
func testChainKitGetBlockHash(ht *lntemp.HarnessTest) { func testChainKitGetBlockHash(ht *lntest.HarnessTest) {
// Get best block hash. // Get best block hash.
bestBlockRes := ht.Alice.RPC.GetBestBlock(nil) bestBlockRes := ht.Alice.RPC.GetBestBlock(nil)
@@ -78,13 +78,13 @@ func testChainKitGetBlockHash(ht *lntemp.HarnessTest) {
// rate by broadcasting a Child-Pays-For-Parent (CPFP) transaction. // rate by broadcasting a Child-Pays-For-Parent (CPFP) transaction.
// //
// TODO(wilmer): Add RBF case once btcd supports it. // TODO(wilmer): Add RBF case once btcd supports it.
func testCPFP(ht *lntemp.HarnessTest) { func testCPFP(ht *lntest.HarnessTest) {
runCPFP(ht, ht.Alice, ht.Bob) runCPFP(ht, ht.Alice, ht.Bob)
} }
// runCPFP ensures that the daemon can bump an unconfirmed transaction's fee // runCPFP ensures that the daemon can bump an unconfirmed transaction's fee
// rate by broadcasting a Child-Pays-For-Parent (CPFP) transaction. // rate by broadcasting a Child-Pays-For-Parent (CPFP) transaction.
func runCPFP(ht *lntemp.HarnessTest, alice, bob *node.HarnessNode) { func runCPFP(ht *lntest.HarnessTest, alice, bob *node.HarnessNode) {
// Skip this test for neutrino, as it's not aware of mempool // Skip this test for neutrino, as it's not aware of mempool
// transactions. // transactions.
if ht.IsNeutrinoBackend() { if ht.IsNeutrinoBackend() {
@@ -172,6 +172,7 @@ func runCPFP(ht *lntemp.HarnessTest, alice, bob *node.HarnessNode) {
return fmt.Errorf("expected 0 pending sweeps, found %d", return fmt.Errorf("expected 0 pending sweeps, found %d",
len(resp.PendingSweeps)) len(resp.PendingSweeps))
} }
return nil return nil
}, defaultTimeout) }, defaultTimeout)
require.NoError(ht, err, "timeout checking bob's pending sweeps") require.NoError(ht, err, "timeout checking bob's pending sweeps")
@@ -180,9 +181,9 @@ func runCPFP(ht *lntemp.HarnessTest, alice, bob *node.HarnessNode) {
// testAnchorReservedValue tests that we won't allow sending transactions when // testAnchorReservedValue tests that we won't allow sending transactions when
// that would take the value we reserve for anchor fee bumping out of our // that would take the value we reserve for anchor fee bumping out of our
// wallet. // wallet.
func testAnchorReservedValue(ht *lntemp.HarnessTest) { func testAnchorReservedValue(ht *lntest.HarnessTest) {
// Start two nodes supporting anchor channels. // Start two nodes supporting anchor channels.
args := nodeArgsForCommitType(lnrpc.CommitmentType_ANCHORS) args := lntest.NodeArgsForCommitType(lnrpc.CommitmentType_ANCHORS)
// NOTE: we cannot reuse the standby node here as the test requires the // NOTE: we cannot reuse the standby node here as the test requires the
// node to start with no UTXOs. // node to start with no UTXOs.
@@ -203,7 +204,7 @@ func testAnchorReservedValue(ht *lntemp.HarnessTest) {
// wallet, without a change output. This should not be allowed. // wallet, without a change output. This should not be allowed.
ht.OpenChannelAssertErr( ht.OpenChannelAssertErr(
alice, bob, lntemp.OpenChannelParams{ alice, bob, lntest.OpenChannelParams{
Amt: chanAmt, Amt: chanAmt,
}, lnwallet.ErrReservedValueInvalidated, }, lnwallet.ErrReservedValueInvalidated,
) )
@@ -211,13 +212,13 @@ func testAnchorReservedValue(ht *lntemp.HarnessTest) {
// Alice opens a smaller channel. This works since it will have a // Alice opens a smaller channel. This works since it will have a
// change output. // change output.
chanPoint1 := ht.OpenChannel( chanPoint1 := ht.OpenChannel(
alice, bob, lntemp.OpenChannelParams{Amt: chanAmt / 4}, alice, bob, lntest.OpenChannelParams{Amt: chanAmt / 4},
) )
// If Alice tries to open another anchor channel to Bob, Bob should not // If Alice tries to open another anchor channel to Bob, Bob should not
// reject it as he is not contributing any funds. // reject it as he is not contributing any funds.
chanPoint2 := ht.OpenChannel( chanPoint2 := ht.OpenChannel(
alice, bob, lntemp.OpenChannelParams{Amt: chanAmt / 4}, alice, bob, lntest.OpenChannelParams{Amt: chanAmt / 4},
) )
// Similarly, if Alice tries to open a legacy channel to Bob, Bob // Similarly, if Alice tries to open a legacy channel to Bob, Bob
@@ -229,7 +230,7 @@ func testAnchorReservedValue(ht *lntemp.HarnessTest) {
ht.EnsureConnected(alice, bob) ht.EnsureConnected(alice, bob)
chanPoint3 := ht.OpenChannel( chanPoint3 := ht.OpenChannel(
alice, bob, lntemp.OpenChannelParams{Amt: chanAmt / 4}, alice, bob, lntest.OpenChannelParams{Amt: chanAmt / 4},
) )
chanPoints := []*lnrpc.ChannelPoint{chanPoint1, chanPoint2, chanPoint3} chanPoints := []*lnrpc.ChannelPoint{chanPoint1, chanPoint2, chanPoint3}
@@ -276,6 +277,7 @@ func testAnchorReservedValue(ht *lntemp.HarnessTest) {
} }
balance = resp.TotalBalance balance = resp.TotalBalance
return nil return nil
}, defaultTimeout) }, defaultTimeout)
require.NoError(ht, err, "timeout checking alice's balance") require.NoError(ht, err, "timeout checking alice's balance")
@@ -347,18 +349,15 @@ func testAnchorReservedValue(ht *lntemp.HarnessTest) {
// testAnchorThirdPartySpend tests that if we force close a channel, but then // testAnchorThirdPartySpend tests that if we force close a channel, but then
// don't sweep the anchor in time and a 3rd party spends it, that we remove any // don't sweep the anchor in time and a 3rd party spends it, that we remove any
// transactions that are a descendent of that sweep. // transactions that are a descendent of that sweep.
func testAnchorThirdPartySpend(ht *lntemp.HarnessTest) { func testAnchorThirdPartySpend(ht *lntest.HarnessTest) {
// First, we'll create two new nodes that both default to anchor // First, we'll create two new nodes that both default to anchor
// channels. // channels.
// //
// NOTE: The itests differ here as anchors is default off vs the normal // NOTE: The itests differ here as anchors is default off vs the normal
// lnd binary. // lnd binary.
args := nodeArgsForCommitType(lnrpc.CommitmentType_ANCHORS) args := lntest.NodeArgsForCommitType(lnrpc.CommitmentType_ANCHORS)
alice := ht.NewNode("Alice", args) alice := ht.NewNode("Alice", args)
defer ht.Shutdown(alice)
bob := ht.NewNode("Bob", args) bob := ht.NewNode("Bob", args)
defer ht.Shutdown(bob)
ht.EnsureConnected(alice, bob) ht.EnsureConnected(alice, bob)
@@ -374,7 +373,7 @@ func testAnchorThirdPartySpend(ht *lntemp.HarnessTest) {
// Open the channel between the two nodes and wait for it to confirm // Open the channel between the two nodes and wait for it to confirm
// fully. // fully.
aliceChanPoint1 := ht.OpenChannel( aliceChanPoint1 := ht.OpenChannel(
alice, bob, lntemp.OpenChannelParams{ alice, bob, lntest.OpenChannelParams{
Amt: firstChanSize, Amt: firstChanSize,
}, },
) )
@@ -493,7 +492,7 @@ func testAnchorThirdPartySpend(ht *lntemp.HarnessTest) {
// assertAnchorOutputLost asserts that the anchor output for the given channel // assertAnchorOutputLost asserts that the anchor output for the given channel
// has the state of being lost. // has the state of being lost.
func assertAnchorOutputLost(ht *lntemp.HarnessTest, hn *node.HarnessNode, func assertAnchorOutputLost(ht *lntest.HarnessTest, hn *node.HarnessNode,
chanPoint *lnrpc.ChannelPoint) { chanPoint *lnrpc.ChannelPoint) {
cp := ht.OutPointFromChannelPoint(chanPoint) cp := ht.OutPointFromChannelPoint(chanPoint)
@@ -527,8 +526,8 @@ func assertAnchorOutputLost(ht *lntemp.HarnessTest, hn *node.HarnessNode,
// genAnchorSweep generates a "3rd party" anchor sweeping from an existing one. // genAnchorSweep generates a "3rd party" anchor sweeping from an existing one.
// In practice, we just re-use the existing witness, and track on our own // In practice, we just re-use the existing witness, and track on our own
// output producing a 1-in-1-out transaction. // output producing a 1-in-1-out transaction.
func genAnchorSweep(ht *lntemp.HarnessTest, func genAnchorSweep(ht *lntest.HarnessTest,
aliceAnchor *lntemp.SweptOutput, anchorCsv uint32) *btcutil.Tx { aliceAnchor *lntest.SweptOutput, anchorCsv uint32) *btcutil.Tx {
// At this point, we have the transaction that Alice used to try to // At this point, we have the transaction that Alice used to try to
// sweep her anchor. As this is actually just something anyone can // sweep her anchor. As this is actually just something anyone can
@@ -10,9 +10,9 @@ import (
"github.com/lightningnetwork/lnd/chainreg" "github.com/lightningnetwork/lnd/chainreg"
"github.com/lightningnetwork/lnd/funding" "github.com/lightningnetwork/lnd/funding"
"github.com/lightningnetwork/lnd/lnrpc" "github.com/lightningnetwork/lnd/lnrpc"
"github.com/lightningnetwork/lnd/lntemp" "github.com/lightningnetwork/lnd/lntest"
"github.com/lightningnetwork/lnd/lntemp/node" "github.com/lightningnetwork/lnd/lntest/node"
"github.com/lightningnetwork/lnd/lntemp/rpc" "github.com/lightningnetwork/lnd/lntest/rpc"
"github.com/lightningnetwork/lnd/lntest/wait" "github.com/lightningnetwork/lnd/lntest/wait"
"github.com/stretchr/testify/require" "github.com/stretchr/testify/require"
) )
@@ -20,7 +20,7 @@ import (
// testOpenChannelAfterReorg tests that in the case where we have an open // testOpenChannelAfterReorg tests that in the case where we have an open
// channel where the funding tx gets reorged out, the channel will no // channel where the funding tx gets reorged out, the channel will no
// longer be present in the node's routing table. // longer be present in the node's routing table.
func testOpenChannelAfterReorg(ht *lntemp.HarnessTest) { func testOpenChannelAfterReorg(ht *lntest.HarnessTest) {
// Skip test for neutrino, as we cannot disconnect the miner at will. // Skip test for neutrino, as we cannot disconnect the miner at will.
// TODO(halseth): remove when either can disconnect at will, or restart // TODO(halseth): remove when either can disconnect at will, or restart
// node with connection to new miner. // node with connection to new miner.
@@ -33,7 +33,7 @@ func testOpenChannelAfterReorg(ht *lntemp.HarnessTest) {
// Set up a new miner that we can use to cause a reorg. // Set up a new miner that we can use to cause a reorg.
tempLogDir := ".tempminerlogs" tempLogDir := ".tempminerlogs"
logFilename := "output-open_channel_reorg-temp_miner.log" logFilename := "output-open_channel_reorg-temp_miner.log"
tempMiner := lntemp.NewTempMiner( tempMiner := lntest.NewTempMiner(
ht.Context(), ht.T, tempLogDir, logFilename, ht.Context(), ht.T, tempLogDir, logFilename,
) )
defer tempMiner.Stop() defer tempMiner.Stop()
@@ -68,7 +68,7 @@ func testOpenChannelAfterReorg(ht *lntemp.HarnessTest) {
// Create a new channel that requires 1 confs before it's considered // Create a new channel that requires 1 confs before it's considered
// open, then broadcast the funding transaction // open, then broadcast the funding transaction
params := lntemp.OpenChannelParams{ params := lntest.OpenChannelParams{
Amt: funding.MaxBtcFundingAmount, Amt: funding.MaxBtcFundingAmount,
Private: true, Private: true,
} }
@@ -172,7 +172,7 @@ func testOpenChannelAfterReorg(ht *lntemp.HarnessTest) {
// ChannelUpdate --> defaultBaseFee, provided FeeRate // ChannelUpdate --> defaultBaseFee, provided FeeRate
// 4.) baseFee and feeRate provided to OpenChannelRequest // 4.) baseFee and feeRate provided to OpenChannelRequest
// ChannelUpdate --> provided baseFee, provided feeRate. // ChannelUpdate --> provided baseFee, provided feeRate.
func testOpenChannelUpdateFeePolicy(ht *lntemp.HarnessTest) { func testOpenChannelUpdateFeePolicy(ht *lntest.HarnessTest) {
const ( const (
defaultBaseFee = 1000 defaultBaseFee = 1000
defaultFeeRate = 1 defaultFeeRate = 1
@@ -182,12 +182,12 @@ func testOpenChannelUpdateFeePolicy(ht *lntemp.HarnessTest) {
optionalFeeRate = 1337 optionalFeeRate = 1337
) )
defaultMaxHtlc := calculateMaxHtlc(funding.MaxBtcFundingAmount) defaultMaxHtlc := lntest.CalculateMaxHtlc(funding.MaxBtcFundingAmount)
chanAmt := funding.MaxBtcFundingAmount chanAmt := funding.MaxBtcFundingAmount
pushAmt := chanAmt / 2 pushAmt := chanAmt / 2
feeScenarios := []lntemp.OpenChannelParams{ feeScenarios := []lntest.OpenChannelParams{
{ {
Amt: chanAmt, Amt: chanAmt,
PushAmt: pushAmt, PushAmt: pushAmt,
@@ -259,8 +259,8 @@ func testOpenChannelUpdateFeePolicy(ht *lntemp.HarnessTest) {
alice, bob := ht.Alice, ht.Bob alice, bob := ht.Alice, ht.Bob
runTestCase := func(ht *lntemp.HarnessTest, runTestCase := func(ht *lntest.HarnessTest,
fs lntemp.OpenChannelParams, fs lntest.OpenChannelParams,
alicePolicy, bobPolicy *lnrpc.RoutingPolicy) { alicePolicy, bobPolicy *lnrpc.RoutingPolicy) {
// Create a channel Alice->Bob. // Create a channel Alice->Bob.
@@ -305,14 +305,14 @@ func testOpenChannelUpdateFeePolicy(ht *lntemp.HarnessTest) {
// testBasicChannelCreationAndUpdates tests multiple channel opening and // testBasicChannelCreationAndUpdates tests multiple channel opening and
// closing, and ensures that if a node is subscribed to channel updates they // closing, and ensures that if a node is subscribed to channel updates they
// will be received correctly for both cooperative and force closed channels. // will be received correctly for both cooperative and force closed channels.
func testBasicChannelCreationAndUpdates(ht *lntemp.HarnessTest) { func testBasicChannelCreationAndUpdates(ht *lntest.HarnessTest) {
runBasicChannelCreationAndUpdates(ht, ht.Alice, ht.Bob) runBasicChannelCreationAndUpdates(ht, ht.Alice, ht.Bob)
} }
// runBasicChannelCreationAndUpdates tests multiple channel opening and closing, // runBasicChannelCreationAndUpdates tests multiple channel opening and closing,
// and ensures that if a node is subscribed to channel updates they will be // and ensures that if a node is subscribed to channel updates they will be
// received correctly for both cooperative and force closed channels. // received correctly for both cooperative and force closed channels.
func runBasicChannelCreationAndUpdates(ht *lntemp.HarnessTest, func runBasicChannelCreationAndUpdates(ht *lntest.HarnessTest,
alice, bob *node.HarnessNode) { alice, bob *node.HarnessNode) {
const ( const (
@@ -329,7 +329,7 @@ func runBasicChannelCreationAndUpdates(ht *lntemp.HarnessTest,
chanPoints := make([]*lnrpc.ChannelPoint, numChannels) chanPoints := make([]*lnrpc.ChannelPoint, numChannels)
for i := 0; i < numChannels; i++ { for i := 0; i < numChannels; i++ {
chanPoints[i] = ht.OpenChannel( chanPoints[i] = ht.OpenChannel(
alice, bob, lntemp.OpenChannelParams{ alice, bob, lntest.OpenChannelParams{
Amt: amount, Amt: amount,
}, },
) )
@@ -458,8 +458,8 @@ func runBasicChannelCreationAndUpdates(ht *lntemp.HarnessTest,
// assertMinerBlockHeightDelta ensures that tempMiner is 'delta' blocks ahead // assertMinerBlockHeightDelta ensures that tempMiner is 'delta' blocks ahead
// of miner. // of miner.
func assertMinerBlockHeightDelta(ht *lntemp.HarnessTest, func assertMinerBlockHeightDelta(ht *lntest.HarnessTest,
miner, tempMiner *lntemp.HarnessMiner, delta int32) { miner, tempMiner *lntest.HarnessMiner, delta int32) {
// Ensure the chain lengths are what we expect. // Ensure the chain lengths are what we expect.
err := wait.NoError(func() error { err := wait.NoError(func() error {
@@ -1,7 +1,6 @@
package itest package itest
import ( import (
"context"
"crypto/sha256" "crypto/sha256"
"encoding/hex" "encoding/hex"
"fmt" "fmt"
@@ -11,14 +10,13 @@ import (
"github.com/lightningnetwork/lnd/input" "github.com/lightningnetwork/lnd/input"
"github.com/lightningnetwork/lnd/lnrpc" "github.com/lightningnetwork/lnd/lnrpc"
"github.com/lightningnetwork/lnd/lnrpc/routerrpc" "github.com/lightningnetwork/lnd/lnrpc/routerrpc"
"github.com/lightningnetwork/lnd/lntemp"
"github.com/lightningnetwork/lnd/lntemp/node"
"github.com/lightningnetwork/lnd/lntest" "github.com/lightningnetwork/lnd/lntest"
"github.com/lightningnetwork/lnd/lntest/node"
"github.com/lightningnetwork/lnd/lntest/wait" "github.com/lightningnetwork/lnd/lntest/wait"
"github.com/stretchr/testify/require" "github.com/stretchr/testify/require"
) )
func testListPayments(ht *lntemp.HarnessTest) { func testListPayments(ht *lntest.HarnessTest) {
alice, bob := ht.Alice, ht.Bob alice, bob := ht.Alice, ht.Bob
// Check that there are no payments before test. // Check that there are no payments before test.
@@ -28,7 +26,7 @@ func testListPayments(ht *lntemp.HarnessTest) {
// being the sole funder of the channel. // being the sole funder of the channel.
chanAmt := btcutil.Amount(100000) chanAmt := btcutil.Amount(100000)
chanPoint := ht.OpenChannel( chanPoint := ht.OpenChannel(
alice, bob, lntemp.OpenChannelParams{Amt: chanAmt}, alice, bob, lntest.OpenChannelParams{Amt: chanAmt},
) )
// Get the number of invoices Bob already has. // Get the number of invoices Bob already has.
@@ -171,13 +169,13 @@ func testListPayments(ht *lntemp.HarnessTest) {
// subsystems trying to update the channel state in the db. We follow this // subsystems trying to update the channel state in the db. We follow this
// transition with a payment that updates the commitment state and verify that // transition with a payment that updates the commitment state and verify that
// the pending state is up to date. // the pending state is up to date.
func testPaymentFollowingChannelOpen(ht *lntemp.HarnessTest) { func testPaymentFollowingChannelOpen(ht *lntest.HarnessTest) {
const paymentAmt = btcutil.Amount(100) const paymentAmt = btcutil.Amount(100)
channelCapacity := paymentAmt * 1000 channelCapacity := paymentAmt * 1000
// We first establish a channel between Alice and Bob. // We first establish a channel between Alice and Bob.
alice, bob := ht.Alice, ht.Bob alice, bob := ht.Alice, ht.Bob
p := lntemp.OpenChannelParams{ p := lntest.OpenChannelParams{
Amt: channelCapacity, Amt: channelCapacity,
} }
pendingUpdate := ht.OpenChannelAssertPending(alice, bob, p) pendingUpdate := ht.OpenChannelAssertPending(alice, bob, p)
@@ -198,7 +196,7 @@ func testPaymentFollowingChannelOpen(ht *lntemp.HarnessTest) {
ht.MineBlocksAndAssertNumTxes(6, 1) ht.MineBlocksAndAssertNumTxes(6, 1)
// We verify that the channel is open from both nodes point of view. // We verify that the channel is open from both nodes point of view.
chanPoint := lntemp.ChanPointFromPendingUpdate(pendingUpdate) chanPoint := lntest.ChanPointFromPendingUpdate(pendingUpdate)
ht.AssertNodesNumPendingOpenChannels(alice, bob, 0) ht.AssertNodesNumPendingOpenChannels(alice, bob, 0)
ht.AssertChannelExists(alice, chanPoint) ht.AssertChannelExists(alice, chanPoint)
ht.AssertChannelExists(bob, chanPoint) ht.AssertChannelExists(bob, chanPoint)
@@ -226,7 +224,7 @@ func testPaymentFollowingChannelOpen(ht *lntemp.HarnessTest) {
} }
// testAsyncPayments tests the performance of the async payments. // testAsyncPayments tests the performance of the async payments.
func testAsyncPayments(ht *lntemp.HarnessTest) { func testAsyncPayments(ht *lntest.HarnessTest) {
// We use new nodes here as the benchmark test creates lots of data // We use new nodes here as the benchmark test creates lots of data
// which can be costly to be carried on. // which can be costly to be carried on.
alice := ht.NewNode("Alice", []string{"--pending-commit-interval=3m"}) alice := ht.NewNode("Alice", []string{"--pending-commit-interval=3m"})
@@ -239,7 +237,7 @@ func testAsyncPayments(ht *lntemp.HarnessTest) {
} }
// runAsyncPayments tests the performance of the async payments. // runAsyncPayments tests the performance of the async payments.
func runAsyncPayments(ht *lntemp.HarnessTest, alice, bob *node.HarnessNode) { func runAsyncPayments(ht *lntest.HarnessTest, alice, bob *node.HarnessNode) {
const paymentAmt = 100 const paymentAmt = 100
// First establish a channel with a capacity equals to the overall // First establish a channel with a capacity equals to the overall
@@ -247,7 +245,7 @@ func runAsyncPayments(ht *lntemp.HarnessTest, alice, bob *node.HarnessNode) {
// Alice should send all money from her side to Bob. // Alice should send all money from her side to Bob.
channelCapacity := btcutil.Amount(paymentAmt * 2000) channelCapacity := btcutil.Amount(paymentAmt * 2000)
chanPoint := ht.OpenChannel( chanPoint := ht.OpenChannel(
alice, bob, lntemp.OpenChannelParams{Amt: channelCapacity}, alice, bob, lntest.OpenChannelParams{Amt: channelCapacity},
) )
info := ht.QueryChannelByChanPoint(alice, chanPoint) info := ht.QueryChannelByChanPoint(alice, chanPoint)
@@ -273,7 +271,7 @@ func runAsyncPayments(ht *lntemp.HarnessTest, alice, bob *node.HarnessNode) {
settled := make(chan struct{}) settled := make(chan struct{})
defer close(settled) defer close(settled)
timeout := lntest.AsyncBenchmarkTimeout * 2 timeout := wait.AsyncBenchmarkTimeout
for i := 0; i < numInvoices; i++ { for i := 0; i < numInvoices; i++ {
payReq := bobPayReqs[i] payReq := bobPayReqs[i]
go func() { go func() {
@@ -304,46 +302,13 @@ func runAsyncPayments(ht *lntemp.HarnessTest, alice, bob *node.HarnessNode) {
// All payments have been sent, mark the finish time. // All payments have been sent, mark the finish time.
timeTaken := time.Since(now) timeTaken := time.Since(now)
// assertChannelState asserts the channel state by checking the values
// in fields, LocalBalance, RemoteBalance and num of PendingHtlcs.
assertChannelState := func(hn *node.HarnessNode, cp *lnrpc.ChannelPoint,
localBalance, remoteBalance int64, numPendingHtlcs int) {
// Get the funding point.
err := wait.NoError(func() error {
// Find the target channel first.
target := ht.GetChannelByChanPoint(hn, cp)
if len(target.PendingHtlcs) != numPendingHtlcs {
return fmt.Errorf("pending htlcs is "+
"incorrect, got %v, expected %v",
len(target.PendingHtlcs), 0)
}
if target.LocalBalance != localBalance {
return fmt.Errorf("local balance is "+
"incorrect, got %v, expected %v",
target.LocalBalance, localBalance)
}
if target.RemoteBalance != remoteBalance {
return fmt.Errorf("remote balance is "+
"incorrect, got %v, expected %v",
target.RemoteBalance, remoteBalance)
}
return nil
}, lntemp.DefaultTimeout)
require.NoError(ht, err, "timeout while chekcing for balance")
}
// Wait for the revocation to be received so alice no longer has // Wait for the revocation to be received so alice no longer has
// pending htlcs listed and has correct balances. This is needed due to // pending htlcs listed and has correct balances. This is needed due to
// the fact that we now pipeline the settles. // the fact that we now pipeline the settles.
assertChannelState(alice, chanPoint, aliceAmt, bobAmt, 0) assertChannelState(ht, alice, chanPoint, aliceAmt, bobAmt)
// Wait for Bob to receive revocation from Alice. // Wait for Bob to receive revocation from Alice.
assertChannelState(bob, chanPoint, bobAmt, aliceAmt, 0) assertChannelState(ht, bob, chanPoint, bobAmt, aliceAmt)
ht.Log("\tBenchmark info: Elapsed time: ", timeTaken) ht.Log("\tBenchmark info: Elapsed time: ", timeTaken)
ht.Log("\tBenchmark info: TPS: ", ht.Log("\tBenchmark info: TPS: ",
@@ -357,28 +322,41 @@ func runAsyncPayments(ht *lntemp.HarnessTest, alice, bob *node.HarnessNode) {
// testBidirectionalAsyncPayments tests that nodes are able to send the // testBidirectionalAsyncPayments tests that nodes are able to send the
// payments to each other in async manner without blocking. // payments to each other in async manner without blocking.
func testBidirectionalAsyncPayments(net *lntest.NetworkHarness, t *harnessTest) { func testBidirectionalAsyncPayments(ht *lntest.HarnessTest) {
ctxb := context.Background() const paymentAmt = 1000
const ( // We use new nodes here as the benchmark test creates lots of data
paymentAmt = 1000 // which can be costly to be carried on.
) args := []string{
// Increase the dust threshold to avoid the payments fail due
// to threshold limit reached.
"--dust-threshold=5000000",
// Increase the pending commit interval since there are lots of
// commitment dances.
"--pending-commit-interval=5m",
// Increase the mailbox delivery timeout as there are lots of
// ADDs going on.
"--htlcswitch.mailboxdeliverytimeout=2m",
}
alice := ht.NewNode("Alice", args)
bob := ht.NewNode("Bob", args)
ht.EnsureConnected(alice, bob)
ht.FundCoins(btcutil.SatoshiPerBitcoin, alice)
// First establish a channel with a capacity equals to the overall // First establish a channel with a capacity equals to the overall
// amount of payments, between Alice and Bob, at the end of the test // amount of payments, between Alice and Bob, at the end of the test
// Alice should send all money from her side to Bob. // Alice should send all money from her side to Bob.
chanPoint := openChannelAndAssert( chanPoint := ht.OpenChannel(
t, net, net.Alice, net.Bob, alice, bob, lntest.OpenChannelParams{
lntest.OpenChannelParams{
Amt: paymentAmt * 2000, Amt: paymentAmt * 2000,
PushAmt: paymentAmt * 1000, PushAmt: paymentAmt * 1000,
}, },
) )
info, err := getChanInfo(net.Alice) info := ht.QueryChannelByChanPoint(alice, chanPoint)
if err != nil {
t.Fatalf("unable to get alice channel info: %v", err)
}
// We'll create a number of invoices equal the max number of HTLCs that // We'll create a number of invoices equal the max number of HTLCs that
// can be carried in one direction. The number on the commitment will // can be carried in one direction. The number on the commitment will
@@ -394,158 +372,67 @@ func testBidirectionalAsyncPayments(net *lntest.NetworkHarness, t *harnessTest)
// With the channel open, we'll create invoices for Bob that Alice // With the channel open, we'll create invoices for Bob that Alice
// will pay to in order to advance the state of the channel. // will pay to in order to advance the state of the channel.
bobPayReqs, _, _, err := createPayReqs( bobPayReqs, _, _ := ht.CreatePayReqs(bob, paymentAmt, numInvoices)
net.Bob, paymentAmt, numInvoices,
)
if err != nil {
t.Fatalf("unable to create pay reqs: %v", err)
}
// With the channel open, we'll create invoices for Alice that Bob // With the channel open, we'll create invoices for Alice that Bob
// will pay to in order to advance the state of the channel. // will pay to in order to advance the state of the channel.
alicePayReqs, _, _, err := createPayReqs( alicePayReqs, _, _ := ht.CreatePayReqs(alice, paymentAmt, numInvoices)
net.Alice, paymentAmt, numInvoices,
)
if err != nil {
t.Fatalf("unable to create pay reqs: %v", err)
}
// Wait for Alice to receive the channel edge from the funding manager.
if err = net.Alice.WaitForNetworkChannelOpen(chanPoint); err != nil {
t.Fatalf("alice didn't see the alice->bob channel before "+
"timeout: %v", err)
}
if err = net.Bob.WaitForNetworkChannelOpen(chanPoint); err != nil {
t.Fatalf("bob didn't see the bob->alice channel before "+
"timeout: %v", err)
}
// Reset mission control to prevent previous payment results from // Reset mission control to prevent previous payment results from
// interfering with this test. A new channel has been opened, but // interfering with this test. A new channel has been opened, but
// mission control operates on node pairs. // mission control operates on node pairs.
ctxt, _ := context.WithTimeout(ctxb, defaultTimeout) alice.RPC.ResetMissionControl()
_, err = net.Alice.RouterClient.ResetMissionControl(
ctxt, &routerrpc.ResetMissionControlRequest{},
)
if err != nil {
t.Fatalf("unable to reset mc for alice: %v", err)
}
// Send payments from Alice to Bob and from Bob to Alice in async // Send payments from Alice to Bob and from Bob to Alice in async
// manner. // manner.
errChan := make(chan error) settled := make(chan struct{})
statusChan := make(chan *lnrpc.Payment) defer close(settled)
send := func(node *lntest.HarnessNode, payReq string) { timeout := wait.AsyncBenchmarkTimeout * 2
go func() { send := func(node *node.HarnessNode, payReq string) {
ctxt, _ = context.WithTimeout( req := &routerrpc.SendPaymentRequest{
ctxb, lntest.AsyncBenchmarkTimeout, PaymentRequest: payReq,
) TimeoutSeconds: int32(timeout.Seconds()),
stream, err := node.RouterClient.SendPaymentV2( FeeLimitMsat: noFeeLimitMsat,
ctxt, }
&routerrpc.SendPaymentRequest{ // AssertPaymentStatusWithTimeout will assert that the
PaymentRequest: payReq, // payment is settled.
TimeoutSeconds: 60, stream := node.RPC.SendPayment(req)
FeeLimitMsat: noFeeLimitMsat, ht.AssertPaymentSucceedWithTimeout(stream, timeout)
},
)
if err != nil {
errChan <- err
}
result, err := getPaymentResult(stream)
if err != nil {
errChan <- err
}
statusChan <- result settled <- struct{}{}
}()
} }
for i := 0; i < numInvoices; i++ { for i := 0; i < numInvoices; i++ {
send(net.Bob, alicePayReqs[i]) go send(bob, alicePayReqs[i])
send(net.Alice, bobPayReqs[i]) go send(alice, bobPayReqs[i])
} }
// Expect all payments to succeed. // Expect all payments to succeed.
timer := time.After(timeout)
for i := 0; i < 2*numInvoices; i++ { for i := 0; i < 2*numInvoices; i++ {
select { select {
case result := <-statusChan: case <-settled:
if result.Status != lnrpc.Payment_SUCCEEDED { case <-timer:
t.Fatalf("payment error: %v", result.Status) require.Fail(ht, "timeout", "wait payment failed")
}
case err := <-errChan:
t.Fatalf("payment error: %v", err)
} }
} }
// Wait for Alice and Bob to receive revocations messages, and update // Wait for Alice and Bob to receive revocations messages, and update
// states, i.e. balance info. // states, i.e. balance info.
err = wait.NoError(func() error { assertChannelState(ht, alice, chanPoint, aliceAmt, bobAmt)
aliceInfo, err := getChanInfo(net.Alice)
if err != nil {
t.Fatalf("unable to get alice's channel info: %v", err)
}
if aliceInfo.RemoteBalance != bobAmt {
return fmt.Errorf("alice's remote balance is incorrect, "+
"got %v, expected %v", aliceInfo.RemoteBalance,
bobAmt)
}
if aliceInfo.LocalBalance != aliceAmt {
return fmt.Errorf("alice's local balance is incorrect, "+
"got %v, expected %v", aliceInfo.LocalBalance,
aliceAmt)
}
if len(aliceInfo.PendingHtlcs) != 0 {
return fmt.Errorf("alice's pending htlcs is incorrect, "+
"got %v expected %v",
len(aliceInfo.PendingHtlcs), 0)
}
return nil
}, defaultTimeout)
require.NoError(t.t, err)
// Next query for Bob's and Alice's channel states, in order to confirm // Next query for Bob's and Alice's channel states, in order to confirm
// that all payment have been successful transmitted. // that all payment have been successful transmitted.
err = wait.NoError(func() error { assertChannelState(ht, bob, chanPoint, bobAmt, aliceAmt)
bobInfo, err := getChanInfo(net.Bob)
if err != nil {
t.Fatalf("unable to get bob's channel info: %v", err)
}
if bobInfo.LocalBalance != bobAmt {
return fmt.Errorf("bob's local balance is incorrect, "+
"got %v, expected %v", bobInfo.LocalBalance,
bobAmt)
}
if bobInfo.RemoteBalance != aliceAmt {
return fmt.Errorf("bob's remote balance is incorrect, "+
"got %v, expected %v", bobInfo.RemoteBalance,
aliceAmt)
}
if len(bobInfo.PendingHtlcs) != 0 {
return fmt.Errorf("bob's pending htlcs is incorrect, "+
"got %v, expected %v",
len(bobInfo.PendingHtlcs), 0)
}
return nil
}, defaultTimeout)
require.NoError(t.t, err)
// Finally, immediately close the channel. This function will also // Finally, immediately close the channel. This function will also
// block until the channel is closed and will additionally assert the // block until the channel is closed and will additionally assert the
// relevant channel closing post conditions. // relevant channel closing post conditions.
closeChannelAndAssert(t, net, net.Alice, chanPoint, false) ht.CloseChannel(alice, chanPoint)
} }
func testInvoiceSubscriptions(ht *lntemp.HarnessTest) { func testInvoiceSubscriptions(ht *lntest.HarnessTest) {
const chanAmt = btcutil.Amount(500000) const chanAmt = btcutil.Amount(500000)
alice, bob := ht.Alice, ht.Bob alice, bob := ht.Alice, ht.Bob
@@ -558,7 +445,7 @@ func testInvoiceSubscriptions(ht *lntemp.HarnessTest) {
// Open a channel with 500k satoshis between Alice and Bob with Alice // Open a channel with 500k satoshis between Alice and Bob with Alice
// being the sole funder of the channel. // being the sole funder of the channel.
chanPoint := ht.OpenChannel( chanPoint := ht.OpenChannel(
alice, bob, lntemp.OpenChannelParams{Amt: chanAmt}, alice, bob, lntest.OpenChannelParams{Amt: chanAmt},
) )
// Next create a new invoice for Bob requesting 1k satoshis. // Next create a new invoice for Bob requesting 1k satoshis.
@@ -672,3 +559,36 @@ func testInvoiceSubscriptions(ht *lntemp.HarnessTest) {
ht.CloseChannel(alice, chanPoint) ht.CloseChannel(alice, chanPoint)
} }
// assertChannelState asserts the channel state by checking the values in
// fields, LocalBalance, RemoteBalance and num of PendingHtlcs.
func assertChannelState(ht *lntest.HarnessTest, hn *node.HarnessNode,
cp *lnrpc.ChannelPoint, localBalance, remoteBalance int64) {
// Get the funding point.
err := wait.NoError(func() error {
// Find the target channel first.
target := ht.GetChannelByChanPoint(hn, cp)
if len(target.PendingHtlcs) != 0 {
return fmt.Errorf("pending htlcs is "+
"incorrect, got %v, expected %v",
len(target.PendingHtlcs), 0)
}
if target.LocalBalance != localBalance {
return fmt.Errorf("local balance is "+
"incorrect, got %v, expected %v",
target.LocalBalance, localBalance)
}
if target.RemoteBalance != remoteBalance {
return fmt.Errorf("remote balance is "+
"incorrect, got %v, expected %v",
target.RemoteBalance, remoteBalance)
}
return nil
}, lntest.DefaultTimeout)
require.NoError(ht, err, "timeout while chekcing for balance")
}
@@ -2,8 +2,6 @@ package itest
import ( import (
"bytes" "bytes"
"context"
"fmt"
"time" "time"
"github.com/btcsuite/btcd/btcec/v2" "github.com/btcsuite/btcd/btcec/v2"
@@ -20,16 +18,15 @@ import (
"github.com/lightningnetwork/lnd/lnrpc" "github.com/lightningnetwork/lnd/lnrpc"
"github.com/lightningnetwork/lnd/lnrpc/signrpc" "github.com/lightningnetwork/lnd/lnrpc/signrpc"
"github.com/lightningnetwork/lnd/lnrpc/walletrpc" "github.com/lightningnetwork/lnd/lnrpc/walletrpc"
"github.com/lightningnetwork/lnd/lntemp"
"github.com/lightningnetwork/lnd/lntemp/node"
"github.com/lightningnetwork/lnd/lntest" "github.com/lightningnetwork/lnd/lntest"
"github.com/lightningnetwork/lnd/lntest/node"
"github.com/stretchr/testify/require" "github.com/stretchr/testify/require"
) )
// testPsbtChanFunding makes sure a channel can be opened between carol and dave // testPsbtChanFunding makes sure a channel can be opened between carol and dave
// by using a Partially Signed Bitcoin Transaction that funds the channel // by using a Partially Signed Bitcoin Transaction that funds the channel
// multisig funding output. // multisig funding output.
func testPsbtChanFunding(ht *lntemp.HarnessTest) { func testPsbtChanFunding(ht *lntest.HarnessTest) {
// First, we'll create two new nodes that we'll use to open channels // First, we'll create two new nodes that we'll use to open channels
// between for this test. Dave gets some coins that will be used to // between for this test. Dave gets some coins that will be used to
// fund the PSBT, just to make sure that Carol has an empty wallet. // fund the PSBT, just to make sure that Carol has an empty wallet.
@@ -42,7 +39,7 @@ func testPsbtChanFunding(ht *lntemp.HarnessTest) {
// runPsbtChanFunding makes sure a channel can be opened between carol and dave // runPsbtChanFunding makes sure a channel can be opened between carol and dave
// by using a Partially Signed Bitcoin Transaction that funds the channel // by using a Partially Signed Bitcoin Transaction that funds the channel
// multisig funding output. // multisig funding output.
func runPsbtChanFunding(ht *lntemp.HarnessTest, carol, dave *node.HarnessNode) { func runPsbtChanFunding(ht *lntest.HarnessTest, carol, dave *node.HarnessNode) {
const chanSize = funding.MaxBtcFundingAmount const chanSize = funding.MaxBtcFundingAmount
ht.FundCoins(btcutil.SatoshiPerBitcoin, dave) ht.FundCoins(btcutil.SatoshiPerBitcoin, dave)
@@ -64,7 +61,7 @@ func runPsbtChanFunding(ht *lntemp.HarnessTest, carol, dave *node.HarnessNode) {
// by specifying a PSBT shim. We use the NoPublish flag here to avoid // by specifying a PSBT shim. We use the NoPublish flag here to avoid
// publishing the whole batch TX too early. // publishing the whole batch TX too early.
chanUpdates, tempPsbt := ht.OpenChannelPsbt( chanUpdates, tempPsbt := ht.OpenChannelPsbt(
carol, dave, lntemp.OpenChannelParams{ carol, dave, lntest.OpenChannelParams{
Amt: chanSize, Amt: chanSize,
FundingShim: &lnrpc.FundingShim{ FundingShim: &lnrpc.FundingShim{
Shim: &lnrpc.FundingShim_PsbtShim{ Shim: &lnrpc.FundingShim_PsbtShim{
@@ -81,7 +78,7 @@ func runPsbtChanFunding(ht *lntemp.HarnessTest, carol, dave *node.HarnessNode) {
// Alice. We will publish the batch TX once this channel funding is // Alice. We will publish the batch TX once this channel funding is
// complete. // complete.
chanUpdates2, psbtBytes2 := ht.OpenChannelPsbt( chanUpdates2, psbtBytes2 := ht.OpenChannelPsbt(
carol, alice, lntemp.OpenChannelParams{ carol, alice, lntest.OpenChannelParams{
Amt: chanSize, Amt: chanSize,
FundingShim: &lnrpc.FundingShim{ FundingShim: &lnrpc.FundingShim{
Shim: &lnrpc.FundingShim_PsbtShim{ Shim: &lnrpc.FundingShim_PsbtShim{
@@ -231,7 +228,7 @@ func runPsbtChanFunding(ht *lntemp.HarnessTest, carol, dave *node.HarnessNode) {
// and dave by using a Partially Signed Bitcoin Transaction that funds the // and dave by using a Partially Signed Bitcoin Transaction that funds the
// channel multisig funding output and is fully funded by an external third // channel multisig funding output and is fully funded by an external third
// party. // party.
func testPsbtChanFundingExternal(ht *lntemp.HarnessTest) { func testPsbtChanFundingExternal(ht *lntest.HarnessTest) {
const chanSize = funding.MaxBtcFundingAmount const chanSize = funding.MaxBtcFundingAmount
// First, we'll create two new nodes that we'll use to open channels // First, we'll create two new nodes that we'll use to open channels
@@ -258,7 +255,7 @@ func testPsbtChanFundingExternal(ht *lntemp.HarnessTest) {
// by specifying a PSBT shim. We use the NoPublish flag here to avoid // by specifying a PSBT shim. We use the NoPublish flag here to avoid
// publishing the whole batch TX too early. // publishing the whole batch TX too early.
chanUpdates, tempPsbt := ht.OpenChannelPsbt( chanUpdates, tempPsbt := ht.OpenChannelPsbt(
carol, dave, lntemp.OpenChannelParams{ carol, dave, lntest.OpenChannelParams{
Amt: chanSize, Amt: chanSize,
FundingShim: &lnrpc.FundingShim{ FundingShim: &lnrpc.FundingShim{
Shim: &lnrpc.FundingShim_PsbtShim{ Shim: &lnrpc.FundingShim_PsbtShim{
@@ -275,7 +272,7 @@ func testPsbtChanFundingExternal(ht *lntemp.HarnessTest) {
// Alice. We will publish the batch TX once this channel funding is // Alice. We will publish the batch TX once this channel funding is
// complete. // complete.
chanUpdates2, psbtBytes2 := ht.OpenChannelPsbt( chanUpdates2, psbtBytes2 := ht.OpenChannelPsbt(
carol, alice, lntemp.OpenChannelParams{ carol, alice, lntest.OpenChannelParams{
Amt: chanSize, Amt: chanSize,
FundingShim: &lnrpc.FundingShim{ FundingShim: &lnrpc.FundingShim{
Shim: &lnrpc.FundingShim_PsbtShim{ Shim: &lnrpc.FundingShim_PsbtShim{
@@ -413,19 +410,16 @@ func testPsbtChanFundingExternal(ht *lntemp.HarnessTest) {
// the wallet of both nodes are empty and one of them uses PSBT and an external // the wallet of both nodes are empty and one of them uses PSBT and an external
// wallet to fund the channel while creating reserve output in the same // wallet to fund the channel while creating reserve output in the same
// transaction. // transaction.
func testPsbtChanFundingSingleStep(ht *lntemp.HarnessTest) { func testPsbtChanFundingSingleStep(ht *lntest.HarnessTest) {
const chanSize = funding.MaxBtcFundingAmount const chanSize = funding.MaxBtcFundingAmount
args := nodeArgsForCommitType(lnrpc.CommitmentType_ANCHORS) args := lntest.NodeArgsForCommitType(lnrpc.CommitmentType_ANCHORS)
// First, we'll create two new nodes that we'll use to open channels // First, we'll create two new nodes that we'll use to open channels
// between for this test. But in this case both nodes have an empty // between for this test. But in this case both nodes have an empty
// wallet. // wallet.
carol := ht.NewNode("carol", args) carol := ht.NewNode("carol", args)
defer ht.Shutdown(carol)
dave := ht.NewNode("dave", args) dave := ht.NewNode("dave", args)
defer ht.Shutdown(dave)
alice := ht.Alice alice := ht.Alice
ht.FundCoins(btcutil.SatoshiPerBitcoin, alice) ht.FundCoins(btcutil.SatoshiPerBitcoin, alice)
@@ -454,7 +448,7 @@ func testPsbtChanFundingSingleStep(ht *lntemp.HarnessTest) {
// Now that we have the pending channel ID, Carol will open the channel // Now that we have the pending channel ID, Carol will open the channel
// by specifying a PSBT shim. // by specifying a PSBT shim.
chanUpdates, tempPsbt := ht.OpenChannelPsbt( chanUpdates, tempPsbt := ht.OpenChannelPsbt(
carol, dave, lntemp.OpenChannelParams{ carol, dave, lntest.OpenChannelParams{
Amt: chanSize, Amt: chanSize,
FundingShim: &lnrpc.FundingShim{ FundingShim: &lnrpc.FundingShim{
Shim: &lnrpc.FundingShim_PsbtShim{ Shim: &lnrpc.FundingShim_PsbtShim{
@@ -576,7 +570,7 @@ func testPsbtChanFundingSingleStep(ht *lntemp.HarnessTest) {
} }
// testSignPsbt tests that the SignPsbt RPC works correctly. // testSignPsbt tests that the SignPsbt RPC works correctly.
func testSignPsbt(ht *lntemp.HarnessTest) { func testSignPsbt(ht *lntest.HarnessTest) {
runSignPsbtSegWitV0P2WKH(ht, ht.Alice) runSignPsbtSegWitV0P2WKH(ht, ht.Alice)
runSignPsbtSegWitV0NP2WKH(ht, ht.Alice) runSignPsbtSegWitV0NP2WKH(ht, ht.Alice)
runSignPsbtSegWitV1KeySpendBip86(ht, ht.Alice) runSignPsbtSegWitV1KeySpendBip86(ht, ht.Alice)
@@ -591,7 +585,7 @@ func testSignPsbt(ht *lntemp.HarnessTest) {
// runSignPsbtSegWitV0P2WKH tests that the SignPsbt RPC works correctly for a // runSignPsbtSegWitV0P2WKH tests that the SignPsbt RPC works correctly for a
// SegWit v0 p2wkh input. // SegWit v0 p2wkh input.
func runSignPsbtSegWitV0P2WKH(ht *lntemp.HarnessTest, alice *node.HarnessNode) { func runSignPsbtSegWitV0P2WKH(ht *lntest.HarnessTest, alice *node.HarnessNode) {
// We test that we can sign a PSBT that spends funds from an input that // We test that we can sign a PSBT that spends funds from an input that
// the wallet doesn't know about. To set up that test case, we first // the wallet doesn't know about. To set up that test case, we first
// derive an address manually that the wallet won't be watching on // derive an address manually that the wallet won't be watching on
@@ -670,7 +664,7 @@ func runSignPsbtSegWitV0P2WKH(ht *lntemp.HarnessTest, alice *node.HarnessNode) {
// runSignPsbtSegWitV0NP2WKH tests that the SignPsbt RPC works correctly for a // runSignPsbtSegWitV0NP2WKH tests that the SignPsbt RPC works correctly for a
// SegWit v0 np2wkh input. // SegWit v0 np2wkh input.
func runSignPsbtSegWitV0NP2WKH(ht *lntemp.HarnessTest, func runSignPsbtSegWitV0NP2WKH(ht *lntest.HarnessTest,
alice *node.HarnessNode) { alice *node.HarnessNode) {
// We test that we can sign a PSBT that spends funds from an input that // We test that we can sign a PSBT that spends funds from an input that
@@ -759,7 +753,7 @@ func runSignPsbtSegWitV0NP2WKH(ht *lntemp.HarnessTest,
// runSignPsbtSegWitV1KeySpendBip86 tests that the SignPsbt RPC works correctly // runSignPsbtSegWitV1KeySpendBip86 tests that the SignPsbt RPC works correctly
// for a SegWit v1 p2tr key spend BIP-0086 input. // for a SegWit v1 p2tr key spend BIP-0086 input.
func runSignPsbtSegWitV1KeySpendBip86(ht *lntemp.HarnessTest, func runSignPsbtSegWitV1KeySpendBip86(ht *lntest.HarnessTest,
alice *node.HarnessNode) { alice *node.HarnessNode) {
// Derive a key we can use for signing. // Derive a key we can use for signing.
@@ -803,7 +797,7 @@ func runSignPsbtSegWitV1KeySpendBip86(ht *lntemp.HarnessTest,
// runSignPsbtSegWitV1KeySpendRootHash tests that the SignPsbt RPC works // runSignPsbtSegWitV1KeySpendRootHash tests that the SignPsbt RPC works
// correctly for a SegWit v1 p2tr key spend that also commits to a script tree // correctly for a SegWit v1 p2tr key spend that also commits to a script tree
// root hash. // root hash.
func runSignPsbtSegWitV1KeySpendRootHash(ht *lntemp.HarnessTest, func runSignPsbtSegWitV1KeySpendRootHash(ht *lntest.HarnessTest,
alice *node.HarnessNode) { alice *node.HarnessNode) {
// Derive a key we can use for signing. // Derive a key we can use for signing.
@@ -850,7 +844,7 @@ func runSignPsbtSegWitV1KeySpendRootHash(ht *lntemp.HarnessTest,
// runSignPsbtSegWitV1ScriptSpend tests that the SignPsbt RPC works correctly // runSignPsbtSegWitV1ScriptSpend tests that the SignPsbt RPC works correctly
// for a SegWit v1 p2tr script spend. // for a SegWit v1 p2tr script spend.
func runSignPsbtSegWitV1ScriptSpend(ht *lntemp.HarnessTest, func runSignPsbtSegWitV1ScriptSpend(ht *lntest.HarnessTest,
alice *node.HarnessNode) { alice *node.HarnessNode) {
// Derive a key we can use for signing. // Derive a key we can use for signing.
@@ -911,7 +905,7 @@ func runSignPsbtSegWitV1ScriptSpend(ht *lntemp.HarnessTest,
// runFundAndSignPsbt makes sure we can sign PSBTs that were funded by our // runFundAndSignPsbt makes sure we can sign PSBTs that were funded by our
// internal wallet. // internal wallet.
func runFundAndSignPsbt(ht *lntemp.HarnessTest, alice *node.HarnessNode) { func runFundAndSignPsbt(ht *lntest.HarnessTest, alice *node.HarnessNode) {
alice.AddToLogf("================ runFundAndSignPsbt ===============") alice.AddToLogf("================ runFundAndSignPsbt ===============")
// We'll be using a "main" address where we send the funds to and from // We'll be using a "main" address where we send the funds to and from
@@ -965,7 +959,7 @@ func runFundAndSignPsbt(ht *lntemp.HarnessTest, alice *node.HarnessNode) {
// assertPsbtSpend creates an output with the given pkScript on chain and then // assertPsbtSpend creates an output with the given pkScript on chain and then
// attempts to create a sweep transaction that is signed using the SignPsbt RPC // attempts to create a sweep transaction that is signed using the SignPsbt RPC
// that spends that output again. // that spends that output again.
func assertPsbtSpend(ht *lntemp.HarnessTest, alice *node.HarnessNode, func assertPsbtSpend(ht *lntest.HarnessTest, alice *node.HarnessNode,
pkScript []byte, decorateUnsigned func(*psbt.Packet), pkScript []byte, decorateUnsigned func(*psbt.Packet),
verifySigned func(*psbt.Packet)) { verifySigned func(*psbt.Packet)) {
@@ -1074,7 +1068,7 @@ func assertPsbtSpend(ht *lntemp.HarnessTest, alice *node.HarnessNode,
// assertPsbtFundSignSpend funds a PSBT from the internal wallet and then // assertPsbtFundSignSpend funds a PSBT from the internal wallet and then
// attempts to sign it by using the SignPsbt or FinalizePsbt method. // attempts to sign it by using the SignPsbt or FinalizePsbt method.
func assertPsbtFundSignSpend(ht *lntemp.HarnessTest, alice *node.HarnessNode, func assertPsbtFundSignSpend(ht *lntest.HarnessTest, alice *node.HarnessNode,
fundOutputs map[string]uint64, changeType walletrpc.ChangeAddressType, fundOutputs map[string]uint64, changeType walletrpc.ChangeAddressType,
useFinalize bool) { useFinalize bool) {
@@ -1149,7 +1143,7 @@ func assertPsbtFundSignSpend(ht *lntemp.HarnessTest, alice *node.HarnessNode,
// assertChangeScriptType checks if the given script has the right type given // assertChangeScriptType checks if the given script has the right type given
// the change address type we used in FundPsbt. By default, the script should // the change address type we used in FundPsbt. By default, the script should
// be a P2WPKH one. // be a P2WPKH one.
func assertChangeScriptType(ht *lntemp.HarnessTest, script []byte, func assertChangeScriptType(ht *lntest.HarnessTest, script []byte,
fundChangeType walletrpc.ChangeAddressType) { fundChangeType walletrpc.ChangeAddressType) {
switch fundChangeType { switch fundChangeType {
@@ -1163,7 +1157,7 @@ func assertChangeScriptType(ht *lntemp.HarnessTest, script []byte,
// deriveInternalKey derives a signing key and returns its descriptor, full // deriveInternalKey derives a signing key and returns its descriptor, full
// derivation path and parsed public key. // derivation path and parsed public key.
func deriveInternalKey(ht *lntemp.HarnessTest, func deriveInternalKey(ht *lntest.HarnessTest,
alice *node.HarnessNode) (*signrpc.KeyDescriptor, *btcec.PublicKey, alice *node.HarnessNode) (*signrpc.KeyDescriptor, *btcec.PublicKey,
[]uint32) { []uint32) {
@@ -1187,96 +1181,9 @@ func deriveInternalKey(ht *lntemp.HarnessTest,
return keyDesc, parsedPubKey, fullDerivationPath return keyDesc, parsedPubKey, fullDerivationPath
} }
// openChannelPsbt attempts to open a channel between srcNode and destNode with
// the passed channel funding parameters. If the passed context has a timeout,
// then if the timeout is reached before the channel pending notification is
// received, an error is returned. An error is returned if the expected step
// of funding the PSBT is not received from the source node.
func openChannelPsbt(ctx context.Context, srcNode, destNode *lntest.HarnessNode,
p lntest.OpenChannelParams) (lnrpc.Lightning_OpenChannelClient, []byte,
error) {
// Wait until srcNode and destNode have the latest chain synced.
// Otherwise, we may run into a check within the funding manager that
// prevents any funding workflows from being kicked off if the chain
// isn't yet synced.
if err := srcNode.WaitForBlockchainSync(); err != nil {
return nil, nil, fmt.Errorf("unable to sync srcNode chain: %v",
err)
}
if err := destNode.WaitForBlockchainSync(); err != nil {
return nil, nil, fmt.Errorf("unable to sync destNode chain: %v",
err)
}
// Send the request to open a channel to the source node now. This will
// open a long-lived stream where we'll receive status updates about the
// progress of the channel.
respStream, err := srcNode.OpenChannel(ctx, &lnrpc.OpenChannelRequest{
NodePubkey: destNode.PubKey[:],
LocalFundingAmount: int64(p.Amt),
PushSat: int64(p.PushAmt),
Private: p.Private,
SpendUnconfirmed: p.SpendUnconfirmed,
MinHtlcMsat: int64(p.MinHtlc),
FundingShim: p.FundingShim,
})
if err != nil {
return nil, nil, fmt.Errorf("unable to open channel between "+
"source and dest: %v", err)
}
// Consume the "PSBT funding ready" update. This waits until the node
// notifies us that the PSBT can now be funded.
resp, err := receiveChanUpdate(ctx, respStream)
if err != nil {
return nil, nil, fmt.Errorf("unable to consume channel update "+
"message: %v", err)
}
upd, ok := resp.Update.(*lnrpc.OpenStatusUpdate_PsbtFund)
if !ok {
return nil, nil, fmt.Errorf("expected PSBT funding update, "+
"instead got %v", resp)
}
return respStream, upd.PsbtFund.Psbt, nil
}
// receiveChanUpdate waits until a message is received on the stream or the
// context is canceled. The context must have a timeout or must be canceled
// in case no message is received, otherwise this function will block forever.
func receiveChanUpdate(ctx context.Context,
stream lnrpc.Lightning_OpenChannelClient) (*lnrpc.OpenStatusUpdate,
error) {
chanMsg := make(chan *lnrpc.OpenStatusUpdate)
errChan := make(chan error)
go func() {
// Consume one message. This will block until the message is
// received.
resp, err := stream.Recv()
if err != nil {
errChan <- err
return
}
chanMsg <- resp
}()
select {
case <-ctx.Done():
return nil, fmt.Errorf("timeout reached before chan pending " +
"update sent")
case err := <-errChan:
return nil, err
case updateMsg := <-chanMsg:
return updateMsg, nil
}
}
// sendAllCoinsToAddrType sweeps all coins from the wallet and sends them to a // sendAllCoinsToAddrType sweeps all coins from the wallet and sends them to a
// new address of the given type. // new address of the given type.
func sendAllCoinsToAddrType(ht *lntemp.HarnessTest, func sendAllCoinsToAddrType(ht *lntest.HarnessTest,
hn *node.HarnessNode, addrType lnrpc.AddressType) { hn *node.HarnessNode, addrType lnrpc.AddressType) {
resp := hn.RPC.NewAddress(&lnrpc.NewAddressRequest{ resp := hn.RPC.NewAddress(&lnrpc.NewAddressRequest{
@@ -15,8 +15,8 @@ import (
"github.com/lightningnetwork/lnd/lnrpc" "github.com/lightningnetwork/lnd/lnrpc"
"github.com/lightningnetwork/lnd/lnrpc/signrpc" "github.com/lightningnetwork/lnd/lnrpc/signrpc"
"github.com/lightningnetwork/lnd/lnrpc/walletrpc" "github.com/lightningnetwork/lnd/lnrpc/walletrpc"
"github.com/lightningnetwork/lnd/lntemp" "github.com/lightningnetwork/lnd/lntest"
"github.com/lightningnetwork/lnd/lntemp/node" "github.com/lightningnetwork/lnd/lntest/node"
"github.com/lightningnetwork/lnd/lntest/wait" "github.com/lightningnetwork/lnd/lntest/wait"
"github.com/lightningnetwork/lnd/lnwallet/chainfee" "github.com/lightningnetwork/lnd/lnwallet/chainfee"
"github.com/stretchr/testify/require" "github.com/stretchr/testify/require"
@@ -24,7 +24,7 @@ import (
// testGetRecoveryInfo checks whether lnd gives the right information about // testGetRecoveryInfo checks whether lnd gives the right information about
// the wallet recovery process. // the wallet recovery process.
func testGetRecoveryInfo(ht *lntemp.HarnessTest) { func testGetRecoveryInfo(ht *lntest.HarnessTest) {
// First, create a new node with strong passphrase and grab the mnemonic // First, create a new node with strong passphrase and grab the mnemonic
// used for key derivation. This will bring up Carol with an empty // used for key derivation. This will bring up Carol with an empty
// wallet, and such that she is synced up. // wallet, and such that she is synced up.
@@ -94,7 +94,7 @@ func testGetRecoveryInfo(ht *lntemp.HarnessTest) {
// when providing a valid aezeed that owns outputs on the chain. This test // when providing a valid aezeed that owns outputs on the chain. This test
// performs multiple restorations using the same seed and various recovery // performs multiple restorations using the same seed and various recovery
// windows to ensure we detect funds properly. // windows to ensure we detect funds properly.
func testOnchainFundRecovery(ht *lntemp.HarnessTest) { func testOnchainFundRecovery(ht *lntest.HarnessTest) {
// First, create a new node with strong passphrase and grab the mnemonic // First, create a new node with strong passphrase and grab the mnemonic
// used for key derivation. This will bring up Carol with an empty // used for key derivation. This will bring up Carol with an empty
// wallet, and such that she is synced up. // wallet, and such that she is synced up.
@@ -321,7 +321,7 @@ func testOnchainFundRecovery(ht *lntemp.HarnessTest) {
// The fix in the wallet is simple: In step 6, don't detect addresses from // The fix in the wallet is simple: In step 6, don't detect addresses from
// internal scopes while re-scanning to be in line with the logic in other areas // internal scopes while re-scanning to be in line with the logic in other areas
// of the wallet code. // of the wallet code.
func testRescanAddressDetection(ht *lntemp.HarnessTest) { func testRescanAddressDetection(ht *lntest.HarnessTest) {
// We start off by creating a new node with the wallet re-scan flag // We start off by creating a new node with the wallet re-scan flag
// enabled. This won't have any effect on the first startup but will // enabled. This won't have any effect on the first startup but will
// come into effect after we re-start the node. // come into effect after we re-start the node.
@@ -11,8 +11,8 @@ import (
"github.com/lightningnetwork/lnd/lnrpc" "github.com/lightningnetwork/lnd/lnrpc"
"github.com/lightningnetwork/lnd/lnrpc/signrpc" "github.com/lightningnetwork/lnd/lnrpc/signrpc"
"github.com/lightningnetwork/lnd/lnrpc/walletrpc" "github.com/lightningnetwork/lnd/lnrpc/walletrpc"
"github.com/lightningnetwork/lnd/lntemp" "github.com/lightningnetwork/lnd/lntest"
"github.com/lightningnetwork/lnd/lntemp/node" "github.com/lightningnetwork/lnd/lntest/node"
"github.com/stretchr/testify/require" "github.com/stretchr/testify/require"
) )
@@ -55,24 +55,24 @@ var (
// testRemoteSigner tests that a watch-only wallet can use a remote signing // testRemoteSigner tests that a watch-only wallet can use a remote signing
// wallet to perform any signing or ECDH operations. // wallet to perform any signing or ECDH operations.
func testRemoteSigner(ht *lntemp.HarnessTest) { func testRemoteSigner(ht *lntest.HarnessTest) {
type testCase struct { type testCase struct {
name string name string
randomSeed bool randomSeed bool
sendCoins bool sendCoins bool
fn func(tt *lntemp.HarnessTest, fn func(tt *lntest.HarnessTest,
wo, carol *node.HarnessNode) wo, carol *node.HarnessNode)
} }
subTests := []testCase{{ subTests := []testCase{{
name: "random seed", name: "random seed",
randomSeed: true, randomSeed: true,
fn: func(tt *lntemp.HarnessTest, wo, carol *node.HarnessNode) { fn: func(tt *lntest.HarnessTest, wo, carol *node.HarnessNode) {
// Nothing more to test here. // Nothing more to test here.
}, },
}, { }, {
name: "account import", name: "account import",
fn: func(tt *lntemp.HarnessTest, wo, carol *node.HarnessNode) { fn: func(tt *lntest.HarnessTest, wo, carol *node.HarnessNode) {
runWalletImportAccountScenario( runWalletImportAccountScenario(
tt, walletrpc.AddressType_WITNESS_PUBKEY_HASH, tt, walletrpc.AddressType_WITNESS_PUBKEY_HASH,
carol, wo, carol, wo,
@@ -81,36 +81,36 @@ func testRemoteSigner(ht *lntemp.HarnessTest) {
}, { }, {
name: "basic channel open close", name: "basic channel open close",
sendCoins: true, sendCoins: true,
fn: func(tt *lntemp.HarnessTest, wo, carol *node.HarnessNode) { fn: func(tt *lntest.HarnessTest, wo, carol *node.HarnessNode) {
runBasicChannelCreationAndUpdates(tt, wo, carol) runBasicChannelCreationAndUpdates(tt, wo, carol)
}, },
}, { }, {
name: "channel funding input types", name: "channel funding input types",
sendCoins: false, sendCoins: false,
fn: func(tt *lntemp.HarnessTest, wo, carol *node.HarnessNode) { fn: func(tt *lntest.HarnessTest, wo, carol *node.HarnessNode) {
runChannelFundingInputTypes(tt, carol, wo) runChannelFundingInputTypes(tt, carol, wo)
}, },
}, { }, {
name: "async payments", name: "async payments",
sendCoins: true, sendCoins: true,
fn: func(tt *lntemp.HarnessTest, wo, carol *node.HarnessNode) { fn: func(tt *lntest.HarnessTest, wo, carol *node.HarnessNode) {
runAsyncPayments(tt, wo, carol) runAsyncPayments(tt, wo, carol)
}, },
}, { }, {
name: "shared key", name: "shared key",
fn: func(tt *lntemp.HarnessTest, wo, carol *node.HarnessNode) { fn: func(tt *lntest.HarnessTest, wo, carol *node.HarnessNode) {
runDeriveSharedKey(tt, wo) runDeriveSharedKey(tt, wo)
}, },
}, { }, {
name: "cpfp", name: "cpfp",
sendCoins: true, sendCoins: true,
fn: func(tt *lntemp.HarnessTest, wo, carol *node.HarnessNode) { fn: func(tt *lntest.HarnessTest, wo, carol *node.HarnessNode) {
runCPFP(tt, wo, carol) runCPFP(tt, wo, carol)
}, },
}, { }, {
name: "psbt", name: "psbt",
randomSeed: true, randomSeed: true,
fn: func(tt *lntemp.HarnessTest, wo, carol *node.HarnessNode) { fn: func(tt *lntest.HarnessTest, wo, carol *node.HarnessNode) {
runPsbtChanFunding(tt, carol, wo) runPsbtChanFunding(tt, carol, wo)
runSignPsbtSegWitV0P2WKH(tt, wo) runSignPsbtSegWitV0P2WKH(tt, wo)
runSignPsbtSegWitV1KeySpendBip86(tt, wo) runSignPsbtSegWitV1KeySpendBip86(tt, wo)
@@ -125,20 +125,20 @@ func testRemoteSigner(ht *lntemp.HarnessTest) {
}, { }, {
name: "sign output raw", name: "sign output raw",
sendCoins: true, sendCoins: true,
fn: func(tt *lntemp.HarnessTest, wo, carol *node.HarnessNode) { fn: func(tt *lntest.HarnessTest, wo, carol *node.HarnessNode) {
runSignOutputRaw(tt, wo) runSignOutputRaw(tt, wo)
}, },
}, { }, {
name: "sign verify msg", name: "sign verify msg",
sendCoins: true, sendCoins: true,
fn: func(tt *lntemp.HarnessTest, wo, carol *node.HarnessNode) { fn: func(tt *lntest.HarnessTest, wo, carol *node.HarnessNode) {
runSignVerifyMessage(tt, wo) runSignVerifyMessage(tt, wo)
}, },
}, { }, {
name: "taproot", name: "taproot",
sendCoins: true, sendCoins: true,
randomSeed: true, randomSeed: true,
fn: func(tt *lntemp.HarnessTest, wo, carol *node.HarnessNode) { fn: func(tt *lntest.HarnessTest, wo, carol *node.HarnessNode) {
testTaprootSendCoinsKeySpendBip86(tt, wo) testTaprootSendCoinsKeySpendBip86(tt, wo)
testTaprootComputeInputScriptKeySpendBip86(tt, wo) testTaprootComputeInputScriptKeySpendBip86(tt, wo)
testTaprootSignOutputRawScriptSpend(tt, wo) testTaprootSignOutputRawScriptSpend(tt, wo)
@@ -162,7 +162,7 @@ func testRemoteSigner(ht *lntemp.HarnessTest) {
}, },
}} }}
prepareTest := func(st *lntemp.HarnessTest, prepareTest := func(st *lntest.HarnessTest,
subTest testCase) (*node.HarnessNode, subTest testCase) (*node.HarnessNode,
*node.HarnessNode, *node.HarnessNode) { *node.HarnessNode, *node.HarnessNode) {
@@ -5,13 +5,13 @@ import (
"github.com/btcsuite/btcd/btcutil" "github.com/btcsuite/btcd/btcutil"
"github.com/lightningnetwork/lnd/lnrpc" "github.com/lightningnetwork/lnd/lnrpc"
"github.com/lightningnetwork/lnd/lntemp" "github.com/lightningnetwork/lnd/lntest"
"github.com/stretchr/testify/require" "github.com/stretchr/testify/require"
) )
// testResHandoff tests that the contractcourt is able to properly hand-off // testResHandoff tests that the contractcourt is able to properly hand-off
// resolution messages to the switch. // resolution messages to the switch.
func testResHandoff(ht *lntemp.HarnessTest) { func testResHandoff(ht *lntest.HarnessTest) {
const ( const (
chanAmt = btcutil.Amount(1000000) chanAmt = btcutil.Amount(1000000)
paymentAmt = 50000 paymentAmt = 50000
@@ -22,14 +22,13 @@ func testResHandoff(ht *lntemp.HarnessTest) {
// First we'll create a channel between Alice and Bob. // First we'll create a channel between Alice and Bob.
ht.EnsureConnected(alice, bob) ht.EnsureConnected(alice, bob)
params := lntemp.OpenChannelParams{Amt: chanAmt} params := lntest.OpenChannelParams{Amt: chanAmt}
chanPointAlice := ht.OpenChannel(alice, bob, params) chanPointAlice := ht.OpenChannel(alice, bob, params)
// Create a new node Carol that will be in hodl mode. This is used to // Create a new node Carol that will be in hodl mode. This is used to
// trigger the behavior of checkRemoteDanglingActions in the // trigger the behavior of checkRemoteDanglingActions in the
// contractcourt. This will cause Bob to fail the HTLC back to Alice. // contractcourt. This will cause Bob to fail the HTLC back to Alice.
carol := ht.NewNode("Carol", []string{"--hodl.commit"}) carol := ht.NewNode("Carol", []string{"--hodl.commit"})
defer ht.Shutdown(carol)
// Connect Bob to Carol. // Connect Bob to Carol.
ht.ConnectNodes(bob, carol) ht.ConnectNodes(bob, carol)
@@ -23,8 +23,8 @@ import (
"github.com/lightningnetwork/lnd/lnrpc/routerrpc" "github.com/lightningnetwork/lnd/lnrpc/routerrpc"
"github.com/lightningnetwork/lnd/lnrpc/verrpc" "github.com/lightningnetwork/lnd/lnrpc/verrpc"
"github.com/lightningnetwork/lnd/lnrpc/walletrpc" "github.com/lightningnetwork/lnd/lnrpc/walletrpc"
"github.com/lightningnetwork/lnd/lntemp" "github.com/lightningnetwork/lnd/lntest"
"github.com/lightningnetwork/lnd/lntemp/node" "github.com/lightningnetwork/lnd/lntest/node"
"github.com/stretchr/testify/require" "github.com/stretchr/testify/require"
) )
@@ -56,7 +56,7 @@ var (
// testRestAPI tests that the most important features of the REST API work // testRestAPI tests that the most important features of the REST API work
// correctly. // correctly.
func testRestAPI(ht *lntemp.HarnessTest) { func testRestAPI(ht *lntest.HarnessTest) {
testCases := []struct { testCases := []struct {
name string name string
run func(*testing.T, *node.HarnessNode, *node.HarnessNode) run func(*testing.T, *node.HarnessNode, *node.HarnessNode)
@@ -201,7 +201,7 @@ func testRestAPI(ht *lntemp.HarnessTest) {
}} }}
wsTestCases := []struct { wsTestCases := []struct {
name string name string
run func(ht *lntemp.HarnessTest) run func(ht *lntest.HarnessTest)
}{{ }{{
name: "websocket subscription", name: "websocket subscription",
run: wsTestCaseSubscription, run: wsTestCaseSubscription,
@@ -243,7 +243,7 @@ func testRestAPI(ht *lntemp.HarnessTest) {
} }
} }
func wsTestCaseSubscription(ht *lntemp.HarnessTest) { func wsTestCaseSubscription(ht *lntest.HarnessTest) {
// Find out the current best block so we can subscribe to the next one. // Find out the current best block so we can subscribe to the next one.
hash, height := ht.Miner.GetBestBlock() hash, height := ht.Miner.GetBestBlock()
@@ -317,7 +317,7 @@ func wsTestCaseSubscription(ht *lntemp.HarnessTest) {
} }
} }
func wsTestCaseSubscriptionMacaroon(ht *lntemp.HarnessTest) { func wsTestCaseSubscriptionMacaroon(ht *lntest.HarnessTest) {
// Find out the current best block so we can subscribe to the next one. // Find out the current best block so we can subscribe to the next one.
hash, height := ht.Miner.GetBestBlock() hash, height := ht.Miner.GetBestBlock()
@@ -407,7 +407,7 @@ func wsTestCaseSubscriptionMacaroon(ht *lntemp.HarnessTest) {
} }
} }
func wsTestCaseBiDirectionalSubscription(ht *lntemp.HarnessTest) { func wsTestCaseBiDirectionalSubscription(ht *lntest.HarnessTest) {
initialRequest := &lnrpc.ChannelAcceptResponse{} initialRequest := &lnrpc.ChannelAcceptResponse{}
url := "/v1/channels/acceptor" url := "/v1/channels/acceptor"
@@ -530,7 +530,7 @@ func wsTestCaseBiDirectionalSubscription(ht *lntemp.HarnessTest) {
const numChannels = 3 const numChannels = 3
for i := 0; i < numChannels; i++ { for i := 0; i < numChannels; i++ {
chanPoint := ht.OpenChannel( chanPoint := ht.OpenChannel(
bob, alice, lntemp.OpenChannelParams{Amt: 500000}, bob, alice, lntest.OpenChannelParams{Amt: 500000},
) )
defer ht.CloseChannel(bob, chanPoint) defer ht.CloseChannel(bob, chanPoint)
@@ -545,7 +545,7 @@ func wsTestCaseBiDirectionalSubscription(ht *lntemp.HarnessTest) {
} }
} }
func wsTestPingPongTimeout(ht *lntemp.HarnessTest) { func wsTestPingPongTimeout(ht *lntest.HarnessTest) {
initialRequest := &lnrpc.InvoiceSubscription{ initialRequest := &lnrpc.InvoiceSubscription{
AddIndex: 1, SettleIndex: 1, AddIndex: 1, SettleIndex: 1,
} }
@@ -12,7 +12,6 @@ import (
"github.com/lightningnetwork/lnd/funding" "github.com/lightningnetwork/lnd/funding"
"github.com/lightningnetwork/lnd/lnrpc" "github.com/lightningnetwork/lnd/lnrpc"
"github.com/lightningnetwork/lnd/lnrpc/wtclientrpc" "github.com/lightningnetwork/lnd/lnrpc/wtclientrpc"
"github.com/lightningnetwork/lnd/lntemp"
"github.com/lightningnetwork/lnd/lntest" "github.com/lightningnetwork/lnd/lntest"
"github.com/lightningnetwork/lnd/lntest/wait" "github.com/lightningnetwork/lnd/lntest/wait"
"github.com/stretchr/testify/require" "github.com/stretchr/testify/require"
@@ -21,7 +20,7 @@ import (
// testRevokedCloseRetribution tests that Carol is able carry out // testRevokedCloseRetribution tests that Carol is able carry out
// retribution in the event that she fails immediately after detecting Bob's // retribution in the event that she fails immediately after detecting Bob's
// breach txn in the mempool. // breach txn in the mempool.
func testRevokedCloseRetribution(ht *lntemp.HarnessTest) { func testRevokedCloseRetribution(ht *lntest.HarnessTest) {
const ( const (
chanAmt = funding.MaxBtcFundingAmount chanAmt = funding.MaxBtcFundingAmount
paymentAmt = 10000 paymentAmt = 10000
@@ -51,7 +50,7 @@ func testRevokedCloseRetribution(ht *lntemp.HarnessTest) {
// closure by Bob, we'll first open up a channel between them with a // closure by Bob, we'll first open up a channel between them with a
// 0.5 BTC value. // 0.5 BTC value.
chanPoint := ht.OpenChannel( chanPoint := ht.OpenChannel(
carol, bob, lntemp.OpenChannelParams{Amt: chanAmt}, carol, bob, lntest.OpenChannelParams{Amt: chanAmt},
) )
// With the channel open, we'll create a few invoices for Bob that // With the channel open, we'll create a few invoices for Bob that
@@ -158,7 +157,7 @@ func testRevokedCloseRetribution(ht *lntemp.HarnessTest) {
// tx's confHeight+CSV-1 blocks and since we've already mined one that // tx's confHeight+CSV-1 blocks and since we've already mined one that
// included the justice tx we only need to mine extra DefaultCSV-2 // included the justice tx we only need to mine extra DefaultCSV-2
// blocks to unlock it. // blocks to unlock it.
ht.MineBlocks(lntest.DefaultCSV - 2) ht.MineBlocks(defaultCSV - 2)
ht.AssertNumPendingForceClose(bob, 0) ht.AssertNumPendingForceClose(bob, 0)
} }
@@ -166,7 +165,7 @@ func testRevokedCloseRetribution(ht *lntemp.HarnessTest) {
// testRevokedCloseRetributionZeroValueRemoteOutput tests that Dave is able // testRevokedCloseRetributionZeroValueRemoteOutput tests that Dave is able
// carry out retribution in the event that he fails in state where the remote // carry out retribution in the event that he fails in state where the remote
// commitment output has zero-value. // commitment output has zero-value.
func testRevokedCloseRetributionZeroValueRemoteOutput(ht *lntemp.HarnessTest) { func testRevokedCloseRetributionZeroValueRemoteOutput(ht *lntest.HarnessTest) {
const ( const (
chanAmt = funding.MaxBtcFundingAmount chanAmt = funding.MaxBtcFundingAmount
paymentAmt = 10000 paymentAmt = 10000
@@ -199,7 +198,7 @@ func testRevokedCloseRetributionZeroValueRemoteOutput(ht *lntemp.HarnessTest) {
// closure by Carol, we'll first open up a channel between them with a // closure by Carol, we'll first open up a channel between them with a
// 0.5 BTC value. // 0.5 BTC value.
chanPoint := ht.OpenChannel( chanPoint := ht.OpenChannel(
dave, carol, lntemp.OpenChannelParams{Amt: chanAmt}, dave, carol, lntest.OpenChannelParams{Amt: chanAmt},
) )
// With the channel open, we'll create a few invoices for Carol that // With the channel open, we'll create a few invoices for Carol that
@@ -224,6 +223,9 @@ func testRevokedCloseRetributionZeroValueRemoteOutput(ht *lntemp.HarnessTest) {
// backup. // backup.
ht.EnsureConnected(dave, carol) ht.EnsureConnected(dave, carol)
// Once connected, give Dave some time to enable the channel again.
ht.AssertTopologyChannelOpen(dave, chanPoint)
// Finally, send payments from Dave to Carol, consuming Carol's // Finally, send payments from Dave to Carol, consuming Carol's
// remaining payment hashes. // remaining payment hashes.
ht.CompletePaymentRequestsNoWait(dave, carolPayReqs, chanPoint) ht.CompletePaymentRequestsNoWait(dave, carolPayReqs, chanPoint)
@@ -298,7 +300,7 @@ func testRevokedCloseRetributionZeroValueRemoteOutput(ht *lntemp.HarnessTest) {
// testRevokedCloseRetributionRemoteHodl tests that Dave properly responds to a // testRevokedCloseRetributionRemoteHodl tests that Dave properly responds to a
// channel breach made by the remote party, specifically in the case that the // channel breach made by the remote party, specifically in the case that the
// remote party breaches before settling extended HTLCs. // remote party breaches before settling extended HTLCs.
func testRevokedCloseRetributionRemoteHodl(ht *lntemp.HarnessTest) { func testRevokedCloseRetributionRemoteHodl(ht *lntest.HarnessTest) {
const ( const (
chanAmt = funding.MaxBtcFundingAmount chanAmt = funding.MaxBtcFundingAmount
pushAmt = 200000 pushAmt = 200000
@@ -333,7 +335,7 @@ func testRevokedCloseRetributionRemoteHodl(ht *lntemp.HarnessTest) {
// by Carol, we'll first open up a channel between them with a // by Carol, we'll first open up a channel between them with a
// funding.MaxBtcFundingAmount (2^24) satoshis value. // funding.MaxBtcFundingAmount (2^24) satoshis value.
chanPoint := ht.OpenChannel( chanPoint := ht.OpenChannel(
dave, carol, lntemp.OpenChannelParams{ dave, carol, lntest.OpenChannelParams{
Amt: chanAmt, Amt: chanAmt,
PushAmt: pushAmt, PushAmt: pushAmt,
}, },
@@ -401,6 +403,9 @@ func testRevokedCloseRetributionRemoteHodl(ht *lntemp.HarnessTest) {
// backup. // backup.
ht.EnsureConnected(dave, carol) ht.EnsureConnected(dave, carol)
// Once connected, give Dave some time to enable the channel again.
ht.AssertTopologyChannelOpen(dave, chanPoint)
// Finally, send payments from Dave to Carol, consuming Carol's // Finally, send payments from Dave to Carol, consuming Carol's
// remaining payment hashes. // remaining payment hashes.
ht.CompletePaymentRequestsNoWait( ht.CompletePaymentRequestsNoWait(
@@ -472,7 +477,14 @@ func testRevokedCloseRetributionRemoteHodl(ht *lntemp.HarnessTest) {
for _, txid := range mempool { for _, txid := range mempool {
// Check that the justice tx has the appropriate number // Check that the justice tx has the appropriate number
// of inputs. // of inputs.
tx := ht.Miner.GetRawTransaction(txid) //
// NOTE: We don't use `ht.Miner.GetRawTransaction`
// which asserts a txid must be found as the HTLC
// spending txes might be aggregated.
tx, err := ht.Miner.Client.GetRawTransaction(txid)
if err != nil {
return nil, err
}
exNumInputs := 2 + numInvoices exNumInputs := 2 + numInvoices
if len(tx.MsgTx().TxIn) == exNumInputs { if len(tx.MsgTx().TxIn) == exNumInputs {
@@ -578,7 +590,7 @@ func testRevokedCloseRetributionRemoteHodl(ht *lntemp.HarnessTest) {
// trigger a breach. Carol is kept offline throughout the process and the test // trigger a breach. Carol is kept offline throughout the process and the test
// asserts that Willy responds by broadcasting the justice transaction on // asserts that Willy responds by broadcasting the justice transaction on
// Carol's behalf sweeping her funds without a reward. // Carol's behalf sweeping her funds without a reward.
func testRevokedCloseRetributionAltruistWatchtower(ht *lntemp.HarnessTest) { func testRevokedCloseRetributionAltruistWatchtower(ht *lntest.HarnessTest) {
testCases := []struct { testCases := []struct {
name string name string
anchors bool anchors bool
@@ -592,7 +604,7 @@ func testRevokedCloseRetributionAltruistWatchtower(ht *lntemp.HarnessTest) {
for _, tc := range testCases { for _, tc := range testCases {
tc := tc tc := tc
testFunc := func(ht *lntemp.HarnessTest) { testFunc := func(ht *lntest.HarnessTest) {
testRevokedCloseRetributionAltruistWatchtowerCase( testRevokedCloseRetributionAltruistWatchtowerCase(
ht, tc.anchors, ht, tc.anchors,
) )
@@ -601,7 +613,7 @@ func testRevokedCloseRetributionAltruistWatchtower(ht *lntemp.HarnessTest) {
success := ht.Run(tc.name, func(tt *testing.T) { success := ht.Run(tc.name, func(tt *testing.T) {
st := ht.Subtest(tt) st := ht.Subtest(tt)
st.RunTestCase(&lntemp.TestCase{ st.RunTestCase(&lntest.TestCase{
Name: tc.name, Name: tc.name,
TestFunc: testFunc, TestFunc: testFunc,
}) })
@@ -619,7 +631,7 @@ func testRevokedCloseRetributionAltruistWatchtower(ht *lntemp.HarnessTest) {
} }
} }
func testRevokedCloseRetributionAltruistWatchtowerCase(ht *lntemp.HarnessTest, func testRevokedCloseRetributionAltruistWatchtowerCase(ht *lntest.HarnessTest,
anchors bool) { anchors bool) {
const ( const (
@@ -696,7 +708,7 @@ func testRevokedCloseRetributionAltruistWatchtowerCase(ht *lntemp.HarnessTest,
// In order to test Dave's response to an uncooperative channel // In order to test Dave's response to an uncooperative channel
// closure by Carol, we'll first open up a channel between them with a // closure by Carol, we'll first open up a channel between them with a
// 0.5 BTC value. // 0.5 BTC value.
params := lntemp.OpenChannelParams{ params := lntest.OpenChannelParams{
Amt: 3 * (chanAmt / 4), Amt: 3 * (chanAmt / 4),
PushAmt: chanAmt / 4, PushAmt: chanAmt / 4,
} }
@@ -727,6 +739,9 @@ func testRevokedCloseRetributionAltruistWatchtowerCase(ht *lntemp.HarnessTest,
// backup. // backup.
ht.EnsureConnected(dave, carol) ht.EnsureConnected(dave, carol)
// Once connected, give Dave some time to enable the channel again.
ht.AssertTopologyChannelOpen(dave, chanPoint)
// Finally, send payments from Dave to Carol, consuming Carol's // Finally, send payments from Dave to Carol, consuming Carol's
// remaining payment hashes. // remaining payment hashes.
ht.CompletePaymentRequestsNoWait(dave, carolPayReqs, chanPoint) ht.CompletePaymentRequestsNoWait(dave, carolPayReqs, chanPoint)
@@ -10,8 +10,8 @@ import (
"github.com/lightningnetwork/lnd/chainreg" "github.com/lightningnetwork/lnd/chainreg"
"github.com/lightningnetwork/lnd/lnrpc" "github.com/lightningnetwork/lnd/lnrpc"
"github.com/lightningnetwork/lnd/lnrpc/routerrpc" "github.com/lightningnetwork/lnd/lnrpc/routerrpc"
"github.com/lightningnetwork/lnd/lntemp" "github.com/lightningnetwork/lnd/lntest"
"github.com/lightningnetwork/lnd/lntemp/node" "github.com/lightningnetwork/lnd/lntest/node"
"github.com/lightningnetwork/lnd/lntest/wait" "github.com/lightningnetwork/lnd/lntest/wait"
"github.com/lightningnetwork/lnd/lnwire" "github.com/lightningnetwork/lnd/lnwire"
"github.com/stretchr/testify/require" "github.com/stretchr/testify/require"
@@ -65,7 +65,7 @@ var singleHopSendToRouteCases = []singleHopSendToRouteCase{
// by feeding the route back into the various SendToRoute RPC methods. Here we // by feeding the route back into the various SendToRoute RPC methods. Here we
// test all three SendToRoute endpoints, forcing each to perform both a regular // test all three SendToRoute endpoints, forcing each to perform both a regular
// payment and an MPP payment. // payment and an MPP payment.
func testSingleHopSendToRoute(ht *lntemp.HarnessTest) { func testSingleHopSendToRoute(ht *lntest.HarnessTest) {
for _, test := range singleHopSendToRouteCases { for _, test := range singleHopSendToRouteCases {
test := test test := test
@@ -76,7 +76,7 @@ func testSingleHopSendToRoute(ht *lntemp.HarnessTest) {
} }
} }
func testSingleHopSendToRouteCase(ht *lntemp.HarnessTest, func testSingleHopSendToRouteCase(ht *lntest.HarnessTest,
test singleHopSendToRouteCase) { test singleHopSendToRouteCase) {
const chanAmt = btcutil.Amount(100000) const chanAmt = btcutil.Amount(100000)
@@ -97,7 +97,7 @@ func testSingleHopSendToRouteCase(ht *lntemp.HarnessTest,
// Open a channel with 100k satoshis between Carol and Dave with Carol // Open a channel with 100k satoshis between Carol and Dave with Carol
// being the sole funder of the channel. // being the sole funder of the channel.
chanPointCarol := ht.OpenChannel( chanPointCarol := ht.OpenChannel(
carol, dave, lntemp.OpenChannelParams{Amt: chanAmt}, carol, dave, lntest.OpenChannelParams{Amt: chanAmt},
) )
defer ht.CloseChannel(carol, chanPointCarol) defer ht.CloseChannel(carol, chanPointCarol)
@@ -289,7 +289,7 @@ func testSingleHopSendToRouteCase(ht *lntemp.HarnessTest,
// //
// We'll query the daemon for routes from Alice to Carol and then // We'll query the daemon for routes from Alice to Carol and then
// send payments through the routes. // send payments through the routes.
func testMultiHopSendToRoute(ht *lntemp.HarnessTest) { func testMultiHopSendToRoute(ht *lntest.HarnessTest) {
ht.Run("with cache", func(tt *testing.T) { ht.Run("with cache", func(tt *testing.T) {
st := ht.Subtest(tt) st := ht.Subtest(tt)
runMultiHopSendToRoute(st, true) runMultiHopSendToRoute(st, true)
@@ -309,7 +309,7 @@ func testMultiHopSendToRoute(ht *lntemp.HarnessTest) {
// //
// We'll query the daemon for routes from Alice to Carol and then // We'll query the daemon for routes from Alice to Carol and then
// send payments through the routes. // send payments through the routes.
func runMultiHopSendToRoute(ht *lntemp.HarnessTest, useGraphCache bool) { func runMultiHopSendToRoute(ht *lntest.HarnessTest, useGraphCache bool) {
var opts []string var opts []string
if !useGraphCache { if !useGraphCache {
opts = append(opts, "--db.no-graph-cache") opts = append(opts, "--db.no-graph-cache")
@@ -325,7 +325,7 @@ func runMultiHopSendToRoute(ht *lntemp.HarnessTest, useGraphCache bool) {
// Open a channel with 100k satoshis between Alice and Bob with Alice // Open a channel with 100k satoshis between Alice and Bob with Alice
// being the sole funder of the channel. // being the sole funder of the channel.
chanPointAlice := ht.OpenChannel( chanPointAlice := ht.OpenChannel(
alice, bob, lntemp.OpenChannelParams{Amt: chanAmt}, alice, bob, lntest.OpenChannelParams{Amt: chanAmt},
) )
defer ht.CloseChannel(alice, chanPointAlice) defer ht.CloseChannel(alice, chanPointAlice)
@@ -337,10 +337,13 @@ func runMultiHopSendToRoute(ht *lntemp.HarnessTest, useGraphCache bool) {
ht.ConnectNodes(carol, bob) ht.ConnectNodes(carol, bob)
chanPointBob := ht.OpenChannel( chanPointBob := ht.OpenChannel(
bob, carol, lntemp.OpenChannelParams{Amt: chanAmt}, bob, carol, lntest.OpenChannelParams{Amt: chanAmt},
) )
defer ht.CloseChannel(carol, chanPointBob) defer ht.CloseChannel(carol, chanPointBob)
// Make sure Alice knows the channel between Bob and Carol.
ht.AssertTopologyChannelOpen(alice, chanPointBob)
// Create 5 invoices for Carol, which expect a payment from Alice for // Create 5 invoices for Carol, which expect a payment from Alice for
// 1k satoshis with a different preimage each time. // 1k satoshis with a different preimage each time.
const ( const (
@@ -407,14 +410,14 @@ func runMultiHopSendToRoute(ht *lntemp.HarnessTest, useGraphCache bool) {
// testSendToRouteErrorPropagation tests propagation of errors that occur // testSendToRouteErrorPropagation tests propagation of errors that occur
// while processing a multi-hop payment through an unknown route. // while processing a multi-hop payment through an unknown route.
func testSendToRouteErrorPropagation(ht *lntemp.HarnessTest) { func testSendToRouteErrorPropagation(ht *lntest.HarnessTest) {
const chanAmt = btcutil.Amount(100000) const chanAmt = btcutil.Amount(100000)
// Open a channel with 100k satoshis between Alice and Bob with Alice // Open a channel with 100k satoshis between Alice and Bob with Alice
// being the sole funder of the channel. // being the sole funder of the channel.
alice, bob := ht.Alice, ht.Bob alice, bob := ht.Alice, ht.Bob
chanPointAlice := ht.OpenChannel( chanPointAlice := ht.OpenChannel(
alice, bob, lntemp.OpenChannelParams{Amt: chanAmt}, alice, bob, lntest.OpenChannelParams{Amt: chanAmt},
) )
// Create a new nodes (Carol and Charlie), load her with some funds, // Create a new nodes (Carol and Charlie), load her with some funds,
@@ -432,7 +435,7 @@ func testSendToRouteErrorPropagation(ht *lntemp.HarnessTest) {
ht.FundCoins(btcutil.SatoshiPerBitcoin, charlie) ht.FundCoins(btcutil.SatoshiPerBitcoin, charlie)
ht.ConnectNodes(carol, charlie) ht.ConnectNodes(carol, charlie)
ht.OpenChannel(carol, charlie, lntemp.OpenChannelParams{Amt: chanAmt}) ht.OpenChannel(carol, charlie, lntest.OpenChannelParams{Amt: chanAmt})
// Query routes from Carol to Charlie which will be an invalid route // Query routes from Carol to Charlie which will be an invalid route
// for Alice -> Bob. // for Alice -> Bob.
@@ -476,7 +479,9 @@ func testSendToRouteErrorPropagation(ht *lntemp.HarnessTest) {
// testPrivateChannels tests that a private channel can be used for // testPrivateChannels tests that a private channel can be used for
// routing by the two endpoints of the channel, but is not known by // routing by the two endpoints of the channel, but is not known by
// the rest of the nodes in the graph. // the rest of the nodes in the graph.
func testPrivateChannels(ht *lntemp.HarnessTest) { //
//nolint:dupword
func testPrivateChannels(ht *lntest.HarnessTest) {
const chanAmt = btcutil.Amount(100000) const chanAmt = btcutil.Amount(100000)
// We create the following topology: // We create the following topology:
@@ -493,7 +498,7 @@ func testPrivateChannels(ht *lntemp.HarnessTest) {
// Open a channel with 200k satoshis between Alice and Bob. // Open a channel with 200k satoshis between Alice and Bob.
alice, bob := ht.Alice, ht.Bob alice, bob := ht.Alice, ht.Bob
chanPointAlice := ht.OpenChannel( chanPointAlice := ht.OpenChannel(
alice, bob, lntemp.OpenChannelParams{Amt: chanAmt * 2}, alice, bob, lntest.OpenChannelParams{Amt: chanAmt * 2},
) )
// Create Dave, and a channel to Alice of 100k. // Create Dave, and a channel to Alice of 100k.
@@ -502,7 +507,7 @@ func testPrivateChannels(ht *lntemp.HarnessTest) {
ht.FundCoins(btcutil.SatoshiPerBitcoin, dave) ht.FundCoins(btcutil.SatoshiPerBitcoin, dave)
chanPointDave := ht.OpenChannel( chanPointDave := ht.OpenChannel(
dave, alice, lntemp.OpenChannelParams{Amt: chanAmt}, dave, alice, lntest.OpenChannelParams{Amt: chanAmt},
) )
// Next, we'll create Carol and establish a channel from her to // Next, we'll create Carol and establish a channel from her to
@@ -512,14 +517,14 @@ func testPrivateChannels(ht *lntemp.HarnessTest) {
ht.FundCoins(btcutil.SatoshiPerBitcoin, carol) ht.FundCoins(btcutil.SatoshiPerBitcoin, carol)
chanPointCarol := ht.OpenChannel( chanPointCarol := ht.OpenChannel(
carol, dave, lntemp.OpenChannelParams{Amt: chanAmt}, carol, dave, lntest.OpenChannelParams{Amt: chanAmt},
) )
// Now create a _private_ channel directly between Carol and // Now create a _private_ channel directly between Carol and
// Alice of 100k. // Alice of 100k.
ht.ConnectNodes(carol, alice) ht.ConnectNodes(carol, alice)
chanPointPrivate := ht.OpenChannel( chanPointPrivate := ht.OpenChannel(
carol, alice, lntemp.OpenChannelParams{ carol, alice, lntest.OpenChannelParams{
Amt: chanAmt, Amt: chanAmt,
Private: true, Private: true,
}, },
@@ -602,7 +607,7 @@ func testPrivateChannels(ht *lntemp.HarnessTest) {
// testInvoiceRoutingHints tests that the routing hints for an invoice are // testInvoiceRoutingHints tests that the routing hints for an invoice are
// created properly. // created properly.
func testInvoiceRoutingHints(ht *lntemp.HarnessTest) { func testInvoiceRoutingHints(ht *lntest.HarnessTest) {
const chanAmt = btcutil.Amount(100000) const chanAmt = btcutil.Amount(100000)
// Throughout this test, we'll be opening a channel between Alice and // Throughout this test, we'll be opening a channel between Alice and
@@ -615,7 +620,7 @@ func testInvoiceRoutingHints(ht *lntemp.HarnessTest) {
// invoice's payment. // invoice's payment.
alice, bob := ht.Alice, ht.Bob alice, bob := ht.Alice, ht.Bob
chanPointBob := ht.OpenChannel( chanPointBob := ht.OpenChannel(
alice, bob, lntemp.OpenChannelParams{ alice, bob, lntest.OpenChannelParams{
Amt: chanAmt, Amt: chanAmt,
PushAmt: chanAmt / 2, PushAmt: chanAmt / 2,
Private: true, Private: true,
@@ -629,7 +634,7 @@ func testInvoiceRoutingHints(ht *lntemp.HarnessTest) {
ht.ConnectNodes(alice, carol) ht.ConnectNodes(alice, carol)
chanPointCarol := ht.OpenChannel( chanPointCarol := ht.OpenChannel(
alice, carol, lntemp.OpenChannelParams{ alice, carol, lntest.OpenChannelParams{
Amt: chanAmt, Amt: chanAmt,
PushAmt: chanAmt / 2, PushAmt: chanAmt / 2,
}, },
@@ -642,7 +647,7 @@ func testInvoiceRoutingHints(ht *lntemp.HarnessTest) {
// that wish to stay unadvertised. // that wish to stay unadvertised.
ht.ConnectNodes(bob, carol) ht.ConnectNodes(bob, carol)
chanPointBobCarol := ht.OpenChannel( chanPointBobCarol := ht.OpenChannel(
bob, carol, lntemp.OpenChannelParams{ bob, carol, lntest.OpenChannelParams{
Amt: chanAmt, Amt: chanAmt,
PushAmt: chanAmt / 2, PushAmt: chanAmt / 2,
}, },
@@ -656,7 +661,7 @@ func testInvoiceRoutingHints(ht *lntemp.HarnessTest) {
ht.ConnectNodes(alice, dave) ht.ConnectNodes(alice, dave)
chanPointDave := ht.OpenChannel( chanPointDave := ht.OpenChannel(
alice, dave, lntemp.OpenChannelParams{ alice, dave, lntest.OpenChannelParams{
Amt: chanAmt, Amt: chanAmt,
Private: true, Private: true,
}, },
@@ -669,7 +674,7 @@ func testInvoiceRoutingHints(ht *lntemp.HarnessTest) {
eve := ht.NewNode("Eve", nil) eve := ht.NewNode("Eve", nil)
ht.ConnectNodes(alice, eve) ht.ConnectNodes(alice, eve)
chanPointEve := ht.OpenChannel( chanPointEve := ht.OpenChannel(
alice, eve, lntemp.OpenChannelParams{ alice, eve, lntest.OpenChannelParams{
Amt: chanAmt, Amt: chanAmt,
PushAmt: chanAmt / 2, PushAmt: chanAmt / 2,
Private: true, Private: true,
@@ -744,7 +749,7 @@ func testInvoiceRoutingHints(ht *lntemp.HarnessTest) {
// testMultiHopOverPrivateChannels tests that private channels can be used as // testMultiHopOverPrivateChannels tests that private channels can be used as
// intermediate hops in a route for payments. // intermediate hops in a route for payments.
func testMultiHopOverPrivateChannels(ht *lntemp.HarnessTest) { func testMultiHopOverPrivateChannels(ht *lntest.HarnessTest) {
// We'll test that multi-hop payments over private channels work as // We'll test that multi-hop payments over private channels work as
// intended. To do so, we'll create the following topology: // intended. To do so, we'll create the following topology:
// private public private // private public private
@@ -755,7 +760,7 @@ func testMultiHopOverPrivateChannels(ht *lntemp.HarnessTest) {
// being the funder. // being the funder.
alice, bob := ht.Alice, ht.Bob alice, bob := ht.Alice, ht.Bob
chanPointAlice := ht.OpenChannel( chanPointAlice := ht.OpenChannel(
alice, bob, lntemp.OpenChannelParams{ alice, bob, lntest.OpenChannelParams{
Amt: chanAmt, Amt: chanAmt,
Private: true, Private: true,
}, },
@@ -766,7 +771,7 @@ func testMultiHopOverPrivateChannels(ht *lntemp.HarnessTest) {
carol := ht.NewNode("Carol", nil) carol := ht.NewNode("Carol", nil)
ht.ConnectNodes(bob, carol) ht.ConnectNodes(bob, carol)
chanPointBob := ht.OpenChannel( chanPointBob := ht.OpenChannel(
bob, carol, lntemp.OpenChannelParams{ bob, carol, lntest.OpenChannelParams{
Amt: chanAmt, Amt: chanAmt,
}, },
) )
@@ -781,7 +786,7 @@ func testMultiHopOverPrivateChannels(ht *lntemp.HarnessTest) {
ht.FundCoins(btcutil.SatoshiPerBitcoin, carol) ht.FundCoins(btcutil.SatoshiPerBitcoin, carol)
chanPointCarol := ht.OpenChannel( chanPointCarol := ht.OpenChannel(
carol, dave, lntemp.OpenChannelParams{ carol, dave, lntest.OpenChannelParams{
Amt: chanAmt, Amt: chanAmt,
Private: true, Private: true,
}, },
@@ -851,7 +856,7 @@ func testMultiHopOverPrivateChannels(ht *lntemp.HarnessTest) {
// Alice --> Bob --> Carol --> Dave // Alice --> Bob --> Carol --> Dave
// //
// and query the daemon for routes from Alice to Dave. // and query the daemon for routes from Alice to Dave.
func testQueryRoutes(ht *lntemp.HarnessTest) { func testQueryRoutes(ht *lntest.HarnessTest) {
const chanAmt = btcutil.Amount(100000) const chanAmt = btcutil.Amount(100000)
// Grab Alice and Bob from the standby nodes. // Grab Alice and Bob from the standby nodes.
@@ -869,8 +874,8 @@ func testQueryRoutes(ht *lntemp.HarnessTest) {
// We now proceed to open channels: // We now proceed to open channels:
// Alice=>Bob, Bob=>Carol and Carol=>Dave. // Alice=>Bob, Bob=>Carol and Carol=>Dave.
p := lntemp.OpenChannelParams{Amt: chanAmt} p := lntest.OpenChannelParams{Amt: chanAmt}
reqs := []*lntemp.OpenChannelRequest{ reqs := []*lntest.OpenChannelRequest{
{Local: alice, Remote: bob, Param: p}, {Local: alice, Remote: bob, Param: p},
{Local: bob, Remote: carol, Param: p}, {Local: bob, Remote: carol, Param: p},
{Local: carol, Remote: dave, Param: p}, {Local: carol, Remote: dave, Param: p},
@@ -1086,7 +1091,7 @@ func testMissionControlCfg(t *testing.T, hn *node.HarnessNode) {
// testMissionControlImport tests import of mission control results from an // testMissionControlImport tests import of mission control results from an
// external source. // external source.
func testMissionControlImport(ht *lntemp.HarnessTest, hn *node.HarnessNode, func testMissionControlImport(ht *lntest.HarnessTest, hn *node.HarnessNode,
fromNode, toNode []byte) { fromNode, toNode []byte) {
// Reset mission control so that our query will return the default // Reset mission control so that our query will return the default
@@ -1138,7 +1143,7 @@ func testMissionControlImport(ht *lntemp.HarnessTest, hn *node.HarnessNode,
// testRouteFeeCutoff tests that we are able to prevent querying routes and // testRouteFeeCutoff tests that we are able to prevent querying routes and
// sending payments that incur a fee higher than the fee limit. // sending payments that incur a fee higher than the fee limit.
func testRouteFeeCutoff(ht *lntemp.HarnessTest) { func testRouteFeeCutoff(ht *lntest.HarnessTest) {
// For this test, we'll create the following topology: // For this test, we'll create the following topology:
// //
// --- Bob --- // --- Bob ---
@@ -1155,7 +1160,7 @@ func testRouteFeeCutoff(ht *lntemp.HarnessTest) {
// Open a channel between Alice and Bob. // Open a channel between Alice and Bob.
alice, bob := ht.Alice, ht.Bob alice, bob := ht.Alice, ht.Bob
chanPointAliceBob := ht.OpenChannel( chanPointAliceBob := ht.OpenChannel(
alice, bob, lntemp.OpenChannelParams{Amt: chanAmt}, alice, bob, lntest.OpenChannelParams{Amt: chanAmt},
) )
// Create Carol's node and open a channel between her and Alice with // Create Carol's node and open a channel between her and Alice with
@@ -1165,7 +1170,7 @@ func testRouteFeeCutoff(ht *lntemp.HarnessTest) {
ht.FundCoins(btcutil.SatoshiPerBitcoin, carol) ht.FundCoins(btcutil.SatoshiPerBitcoin, carol)
chanPointAliceCarol := ht.OpenChannel( chanPointAliceCarol := ht.OpenChannel(
alice, carol, lntemp.OpenChannelParams{Amt: chanAmt}, alice, carol, lntest.OpenChannelParams{Amt: chanAmt},
) )
// Create Dave's node and open a channel between him and Bob with Bob // Create Dave's node and open a channel between him and Bob with Bob
@@ -1173,13 +1178,13 @@ func testRouteFeeCutoff(ht *lntemp.HarnessTest) {
dave := ht.NewNode("Dave", nil) dave := ht.NewNode("Dave", nil)
ht.ConnectNodes(dave, bob) ht.ConnectNodes(dave, bob)
chanPointBobDave := ht.OpenChannel( chanPointBobDave := ht.OpenChannel(
bob, dave, lntemp.OpenChannelParams{Amt: chanAmt}, bob, dave, lntest.OpenChannelParams{Amt: chanAmt},
) )
// Open a channel between Carol and Dave. // Open a channel between Carol and Dave.
ht.ConnectNodes(carol, dave) ht.ConnectNodes(carol, dave)
chanPointCarolDave := ht.OpenChannel( chanPointCarolDave := ht.OpenChannel(
carol, dave, lntemp.OpenChannelParams{Amt: chanAmt}, carol, dave, lntest.OpenChannelParams{Amt: chanAmt},
) )
// Now that all the channels were set up, we'll wait for all the nodes // Now that all the channels were set up, we'll wait for all the nodes
@@ -1203,7 +1208,7 @@ func testRouteFeeCutoff(ht *lntemp.HarnessTest) {
baseFee := int64(10000) baseFee := int64(10000)
feeRate := int64(5) feeRate := int64(5)
timeLockDelta := uint32(chainreg.DefaultBitcoinTimeLockDelta) timeLockDelta := uint32(chainreg.DefaultBitcoinTimeLockDelta)
maxHtlc := calculateMaxHtlc(chanAmt) maxHtlc := lntest.CalculateMaxHtlc(chanAmt)
expectedPolicy := &lnrpc.RoutingPolicy{ expectedPolicy := &lnrpc.RoutingPolicy{
FeeBaseMsat: baseFee, FeeBaseMsat: baseFee,
@@ -1285,7 +1290,8 @@ func testRouteFeeCutoff(ht *lntemp.HarnessTest) {
case *lnrpc.FeeLimit_Fixed: case *lnrpc.FeeLimit_Fixed:
sendReq.FeeLimitMsat = 1000 * limit.Fixed sendReq.FeeLimitMsat = 1000 * limit.Fixed
case *lnrpc.FeeLimit_Percent: case *lnrpc.FeeLimit_Percent:
sendReq.FeeLimitMsat = 1000 * paymentAmt * limit.Percent / 100 sendReq.FeeLimitMsat = 1000 * paymentAmt *
limit.Percent / 100
} }
result := ht.SendPaymentAssertSettled(alice, sendReq) result := ht.SendPaymentAssertSettled(alice, sendReq)
@@ -8,8 +8,8 @@ import (
"github.com/btcsuite/btcd/btcutil" "github.com/btcsuite/btcd/btcutil"
"github.com/lightningnetwork/lnd/lnrpc" "github.com/lightningnetwork/lnd/lnrpc"
"github.com/lightningnetwork/lnd/lntemp" "github.com/lightningnetwork/lnd/lntest"
"github.com/lightningnetwork/lnd/lntemp/node" "github.com/lightningnetwork/lnd/lntest/node"
"github.com/lightningnetwork/lnd/macaroons" "github.com/lightningnetwork/lnd/macaroons"
"github.com/lightningnetwork/lnd/zpay32" "github.com/lightningnetwork/lnd/zpay32"
"github.com/stretchr/testify/require" "github.com/stretchr/testify/require"
@@ -19,7 +19,7 @@ import (
// testRPCMiddlewareInterceptor tests that the RPC middleware interceptor can // testRPCMiddlewareInterceptor tests that the RPC middleware interceptor can
// be used correctly and in a safe way. // be used correctly and in a safe way.
func testRPCMiddlewareInterceptor(ht *lntemp.HarnessTest) { func testRPCMiddlewareInterceptor(ht *lntest.HarnessTest) {
// Let's first enable the middleware interceptor. // Let's first enable the middleware interceptor.
// //
// NOTE: we cannot use standby nodes here as the test messes with // NOTE: we cannot use standby nodes here as the test messes with
@@ -32,7 +32,7 @@ func testRPCMiddlewareInterceptor(ht *lntemp.HarnessTest) {
// data to inspect when doing RPC calls to Alice later. // data to inspect when doing RPC calls to Alice later.
ht.EnsureConnected(alice, bob) ht.EnsureConnected(alice, bob)
ht.FundCoins(btcutil.SatoshiPerBitcoin, alice) ht.FundCoins(btcutil.SatoshiPerBitcoin, alice)
ht.OpenChannel(alice, bob, lntemp.OpenChannelParams{Amt: 1_234_567}) ht.OpenChannel(alice, bob, lntest.OpenChannelParams{Amt: 1_234_567})
// Load or bake the macaroons that the simulated users will use to // Load or bake the macaroons that the simulated users will use to
// access the RPC. // access the RPC.
@@ -545,7 +545,7 @@ func middlewareRequestManipulationTest(t *testing.T, node *node.HarnessNode,
// middlewareMandatoryTest tests that all RPC requests are blocked if there is // middlewareMandatoryTest tests that all RPC requests are blocked if there is
// a mandatory middleware declared that's currently not registered. // a mandatory middleware declared that's currently not registered.
func middlewareMandatoryTest(ht *lntemp.HarnessTest, node *node.HarnessNode) { func middlewareMandatoryTest(ht *lntest.HarnessTest, node *node.HarnessNode) {
// Let's declare our itest interceptor as mandatory but don't register // Let's declare our itest interceptor as mandatory but don't register
// it just yet. That should cause all RPC requests to fail, except for // it just yet. That should cause all RPC requests to fail, except for
// the registration itself. // the registration itself.
@@ -6,13 +6,13 @@ import (
"github.com/btcsuite/btcd/btcutil" "github.com/btcsuite/btcd/btcutil"
"github.com/lightningnetwork/lnd/lnrpc" "github.com/lightningnetwork/lnd/lnrpc"
"github.com/lightningnetwork/lnd/lnrpc/routerrpc" "github.com/lightningnetwork/lnd/lnrpc/routerrpc"
"github.com/lightningnetwork/lnd/lntemp" "github.com/lightningnetwork/lnd/lntest"
"github.com/stretchr/testify/require" "github.com/stretchr/testify/require"
) )
// testSendMultiPathPayment tests that we are able to successfully route a // testSendMultiPathPayment tests that we are able to successfully route a
// payment using multiple shards across different paths. // payment using multiple shards across different paths.
func testSendMultiPathPayment(ht *lntemp.HarnessTest) { func testSendMultiPathPayment(ht *lntest.HarnessTest) {
mts := newMppTestScenario(ht) mts := newMppTestScenario(ht)
const paymentAmt = btcutil.Amount(300000) const paymentAmt = btcutil.Amount(300000)
@@ -13,8 +13,8 @@ import (
"github.com/lightningnetwork/lnd/lnrpc" "github.com/lightningnetwork/lnd/lnrpc"
"github.com/lightningnetwork/lnd/lnrpc/signrpc" "github.com/lightningnetwork/lnd/lnrpc/signrpc"
"github.com/lightningnetwork/lnd/lnrpc/walletrpc" "github.com/lightningnetwork/lnd/lnrpc/walletrpc"
"github.com/lightningnetwork/lnd/lntemp" "github.com/lightningnetwork/lnd/lntest"
"github.com/lightningnetwork/lnd/lntemp/node" "github.com/lightningnetwork/lnd/lntest/node"
"github.com/stretchr/testify/require" "github.com/stretchr/testify/require"
) )
@@ -22,7 +22,7 @@ import (
// DeriveSharedKey. It creates an ephemeral private key, performing an ECDH with // DeriveSharedKey. It creates an ephemeral private key, performing an ECDH with
// the node's pubkey and a customized public key to check the validity of the // the node's pubkey and a customized public key to check the validity of the
// result. // result.
func testDeriveSharedKey(ht *lntemp.HarnessTest) { func testDeriveSharedKey(ht *lntest.HarnessTest) {
runDeriveSharedKey(ht, ht.Alice) runDeriveSharedKey(ht, ht.Alice)
} }
@@ -30,7 +30,7 @@ func testDeriveSharedKey(ht *lntemp.HarnessTest) {
// DeriveSharedKey. It creates an ephemeral private key, performing an ECDH with // DeriveSharedKey. It creates an ephemeral private key, performing an ECDH with
// the node's pubkey and a customized public key to check the validity of the // the node's pubkey and a customized public key to check the validity of the
// result. // result.
func runDeriveSharedKey(ht *lntemp.HarnessTest, alice *node.HarnessNode) { func runDeriveSharedKey(ht *lntest.HarnessTest, alice *node.HarnessNode) {
// Create an ephemeral key, extracts its public key, and make a // Create an ephemeral key, extracts its public key, and make a
// PrivKeyECDH using the ephemeral key. // PrivKeyECDH using the ephemeral key.
ephemeralPriv, err := btcec.NewPrivateKey() ephemeralPriv, err := btcec.NewPrivateKey()
@@ -194,13 +194,13 @@ func runDeriveSharedKey(ht *lntemp.HarnessTest, alice *node.HarnessNode) {
// testSignOutputRaw makes sure that the SignOutputRaw RPC can be used with all // testSignOutputRaw makes sure that the SignOutputRaw RPC can be used with all
// custom ways of specifying the signing key in the key descriptor/locator. // custom ways of specifying the signing key in the key descriptor/locator.
func testSignOutputRaw(ht *lntemp.HarnessTest) { func testSignOutputRaw(ht *lntest.HarnessTest) {
runSignOutputRaw(ht, ht.Alice) runSignOutputRaw(ht, ht.Alice)
} }
// runSignOutputRaw makes sure that the SignOutputRaw RPC can be used with all // runSignOutputRaw makes sure that the SignOutputRaw RPC can be used with all
// custom ways of specifying the signing key in the key descriptor/locator. // custom ways of specifying the signing key in the key descriptor/locator.
func runSignOutputRaw(ht *lntemp.HarnessTest, alice *node.HarnessNode) { func runSignOutputRaw(ht *lntest.HarnessTest, alice *node.HarnessNode) {
// For the next step, we need a public key. Let's use a special family // For the next step, we need a public key. Let's use a special family
// for this. We want this to be an index of zero. // for this. We want this to be an index of zero.
const testCustomKeyFamily = 44 const testCustomKeyFamily = 44
@@ -272,7 +272,7 @@ func runSignOutputRaw(ht *lntemp.HarnessTest, alice *node.HarnessNode) {
// assertSignOutputRaw sends coins to a p2wkh address derived from the given // assertSignOutputRaw sends coins to a p2wkh address derived from the given
// target public key and then tries to spend that output again by invoking the // target public key and then tries to spend that output again by invoking the
// SignOutputRaw RPC with the key descriptor provided. // SignOutputRaw RPC with the key descriptor provided.
func assertSignOutputRaw(ht *lntemp.HarnessTest, func assertSignOutputRaw(ht *lntest.HarnessTest,
alice *node.HarnessNode, targetPubKey *btcec.PublicKey, alice *node.HarnessNode, targetPubKey *btcec.PublicKey,
keyDesc *signrpc.KeyDescriptor, keyDesc *signrpc.KeyDescriptor,
sigHash txscript.SigHashType) { sigHash txscript.SigHashType) {
@@ -373,14 +373,14 @@ func assertSignOutputRaw(ht *lntemp.HarnessTest,
// testSignVerifyMessage makes sure that the SignMessage RPC can be used with // testSignVerifyMessage makes sure that the SignMessage RPC can be used with
// all custom flags by verifying with VerifyMessage. Tests both ECDSA and // all custom flags by verifying with VerifyMessage. Tests both ECDSA and
// Schnorr signatures. // Schnorr signatures.
func testSignVerifyMessage(ht *lntemp.HarnessTest) { func testSignVerifyMessage(ht *lntest.HarnessTest) {
runSignVerifyMessage(ht, ht.Alice) runSignVerifyMessage(ht, ht.Alice)
} }
// runSignVerifyMessage makes sure that the SignMessage RPC can be used with // runSignVerifyMessage makes sure that the SignMessage RPC can be used with
// all custom flags by verifying with VerifyMessage. Tests both ECDSA and // all custom flags by verifying with VerifyMessage. Tests both ECDSA and
// Schnorr signatures. // Schnorr signatures.
func runSignVerifyMessage(ht *lntemp.HarnessTest, alice *node.HarnessNode) { func runSignVerifyMessage(ht *lntest.HarnessTest, alice *node.HarnessNode) {
aliceMsg := []byte("alice msg") aliceMsg := []byte("alice msg")
keyLoc := &signrpc.KeyLocator{ keyLoc := &signrpc.KeyLocator{
KeyFamily: int32(keychain.KeyFamilyNodeKey), KeyFamily: int32(keychain.KeyFamilyNodeKey),
@@ -7,20 +7,20 @@ import (
"github.com/btcsuite/btcd/btcutil" "github.com/btcsuite/btcd/btcutil"
"github.com/lightningnetwork/lnd/lnrpc" "github.com/lightningnetwork/lnd/lnrpc"
"github.com/lightningnetwork/lnd/lnrpc/routerrpc" "github.com/lightningnetwork/lnd/lnrpc/routerrpc"
"github.com/lightningnetwork/lnd/lntemp" "github.com/lightningnetwork/lnd/lntest"
"github.com/lightningnetwork/lnd/lntypes" "github.com/lightningnetwork/lnd/lntypes"
"github.com/lightningnetwork/lnd/lnwire" "github.com/lightningnetwork/lnd/lnwire"
"github.com/lightningnetwork/lnd/record" "github.com/lightningnetwork/lnd/record"
"github.com/stretchr/testify/require" "github.com/stretchr/testify/require"
) )
func testSingleHopInvoice(ht *lntemp.HarnessTest) { func testSingleHopInvoice(ht *lntest.HarnessTest) {
// Open a channel with 100k satoshis between Alice and Bob with Alice // Open a channel with 100k satoshis between Alice and Bob with Alice
// being the sole funder of the channel. // being the sole funder of the channel.
chanAmt := btcutil.Amount(100000) chanAmt := btcutil.Amount(100000)
alice, bob := ht.Alice, ht.Bob alice, bob := ht.Alice, ht.Bob
cp := ht.OpenChannel( cp := ht.OpenChannel(
alice, bob, lntemp.OpenChannelParams{Amt: chanAmt}, alice, bob, lntest.OpenChannelParams{Amt: chanAmt},
) )
// assertAmountPaid is a helper closure that asserts the amount paid by // assertAmountPaid is a helper closure that asserts the amount paid by
@@ -3,8 +3,8 @@ package itest
import ( import (
"github.com/btcsuite/btcd/btcutil" "github.com/btcsuite/btcd/btcutil"
"github.com/lightningnetwork/lnd/lnrpc" "github.com/lightningnetwork/lnd/lnrpc"
"github.com/lightningnetwork/lnd/lntemp" "github.com/lightningnetwork/lnd/lntest"
"github.com/lightningnetwork/lnd/lntemp/node" "github.com/lightningnetwork/lnd/lntest/node"
"github.com/stretchr/testify/require" "github.com/stretchr/testify/require"
) )
@@ -21,11 +21,11 @@ const (
// //
// The general flow of this test: // The general flow of this test:
// 1. Carol --> Dave --> Alice --> Bob forward payment // 1. Carol --> Dave --> Alice --> Bob forward payment
// 2. -------X X X Bob restart sender and intermediaries // 2. X X X Bob restart sender and intermediaries
// 3. Carol <-- Dave <-- Alice <-- Bob expect settle to propagate // 3. Carol <-- Dave <-- Alice <-- Bob expect settle to propagate
// //
//nolint:dupword //nolint:dupword
func testSwitchCircuitPersistence(ht *lntemp.HarnessTest) { func testSwitchCircuitPersistence(ht *lntest.HarnessTest) {
// Setup our test scenario. We should now have four nodes running with // Setup our test scenario. We should now have four nodes running with
// three channels. // three channels.
s := setupScenarioFourNodes(ht) s := setupScenarioFourNodes(ht)
@@ -95,7 +95,7 @@ func testSwitchCircuitPersistence(ht *lntemp.HarnessTest) {
// 2. Carol --- Dave X Alice --- Bob disconnect intermediaries // 2. Carol --- Dave X Alice --- Bob disconnect intermediaries
// 3. Carol --- Dave X Alice <-- Bob settle last hop // 3. Carol --- Dave X Alice <-- Bob settle last hop
// 4. Carol <-- Dave <-- Alice --- Bob reconnect, expect settle to propagate // 4. Carol <-- Dave <-- Alice --- Bob reconnect, expect settle to propagate
func testSwitchOfflineDelivery(ht *lntemp.HarnessTest) { func testSwitchOfflineDelivery(ht *lntest.HarnessTest) {
// Setup our test scenario. We should now have four nodes running with // Setup our test scenario. We should now have four nodes running with
// three channels. // three channels.
s := setupScenarioFourNodes(ht) s := setupScenarioFourNodes(ht)
@@ -131,11 +131,6 @@ func testSwitchOfflineDelivery(ht *lntemp.HarnessTest) {
// Wait until all outstanding htlcs in the network have been settled. // Wait until all outstanding htlcs in the network have been settled.
s.assertHTLCs(ht, 0) s.assertHTLCs(ht, 0)
// When asserting the amount of satoshis moved, we'll factor in the
// default base fee, as we didn't modify the fee structure when
// creating the seed nodes in the network.
const baseFee = 1
// At this point all the channels within our proto network should be // At this point all the channels within our proto network should be
// shifted by 5k satoshis in the direction of Carol, the sink within the // shifted by 5k satoshis in the direction of Carol, the sink within the
// payment flow generated above. The order of asserts corresponds to // payment flow generated above. The order of asserts corresponds to
@@ -174,7 +169,9 @@ func testSwitchOfflineDelivery(ht *lntemp.HarnessTest) {
// 3. Carol --- Dave X Alice <-- Bob settle last hop // 3. Carol --- Dave X Alice <-- Bob settle last hop
// 4. Carol --- Dave X X Bob restart Alice // 4. Carol --- Dave X X Bob restart Alice
// 5. Carol <-- Dave <-- Alice --- Bob expect settle to propagate // 5. Carol <-- Dave <-- Alice --- Bob expect settle to propagate
func testSwitchOfflineDeliveryPersistence(ht *lntemp.HarnessTest) { //
//nolint:dupword
func testSwitchOfflineDeliveryPersistence(ht *lntest.HarnessTest) {
// Setup our test scenario. We should now have four nodes running with // Setup our test scenario. We should now have four nodes running with
// three channels. // three channels.
s := setupScenarioFourNodes(ht) s := setupScenarioFourNodes(ht)
@@ -260,7 +257,9 @@ func testSwitchOfflineDeliveryPersistence(ht *lntemp.HarnessTest) {
// 3. Carol --- Dave X Alice <-- Bob settle last hop // 3. Carol --- Dave X Alice <-- Bob settle last hop
// 4. Carol --- Dave X X shutdown Bob, restart Alice // 4. Carol --- Dave X X shutdown Bob, restart Alice
// 5. Carol <-- Dave <-- Alice X expect settle to propagate // 5. Carol <-- Dave <-- Alice X expect settle to propagate
func testSwitchOfflineDeliveryOutgoingOffline(ht *lntemp.HarnessTest) { //
//nolint:dupword
func testSwitchOfflineDeliveryOutgoingOffline(ht *lntest.HarnessTest) {
// Setup our test scenario. We should now have four nodes running with // Setup our test scenario. We should now have four nodes running with
// three channels. Note that we won't call the cleanUp function here as // three channels. Note that we won't call the cleanUp function here as
// we will manually stop the node Carol and her channel. // we will manually stop the node Carol and her channel.
@@ -371,13 +370,13 @@ type scenarioFourNodes struct {
// //
// NOTE: caller needs to call cleanUp to clean the nodes and channels created // NOTE: caller needs to call cleanUp to clean the nodes and channels created
// from this setup. // from this setup.
func setupScenarioFourNodes(ht *lntemp.HarnessTest) *scenarioFourNodes { func setupScenarioFourNodes(ht *lntest.HarnessTest) *scenarioFourNodes {
const ( const (
chanAmt = btcutil.Amount(1000000) chanAmt = btcutil.Amount(1000000)
pushAmt = btcutil.Amount(900000) pushAmt = btcutil.Amount(900000)
) )
params := lntemp.OpenChannelParams{ params := lntest.OpenChannelParams{
Amt: chanAmt, Amt: chanAmt,
PushAmt: pushAmt, PushAmt: pushAmt,
} }
@@ -404,7 +403,7 @@ func setupScenarioFourNodes(ht *lntemp.HarnessTest) *scenarioFourNodes {
ht.FundCoins(btcutil.SatoshiPerBitcoin, carol) ht.FundCoins(btcutil.SatoshiPerBitcoin, carol)
// Open channels in batch to save blocks mined. // Open channels in batch to save blocks mined.
reqs := []*lntemp.OpenChannelRequest{ reqs := []*lntest.OpenChannelRequest{
{Local: alice, Remote: bob, Param: params}, {Local: alice, Remote: bob, Param: params},
{Local: dave, Remote: alice, Param: params}, {Local: dave, Remote: alice, Param: params},
{Local: carol, Remote: dave, Param: params}, {Local: carol, Remote: dave, Param: params},
@@ -456,7 +455,7 @@ func setupScenarioFourNodes(ht *lntemp.HarnessTest) *scenarioFourNodes {
// assertHTLCs is a helper function which asserts the desired num of // assertHTLCs is a helper function which asserts the desired num of
// HTLCs has been seen in the nodes. // HTLCs has been seen in the nodes.
func (s *scenarioFourNodes) assertHTLCs(ht *lntemp.HarnessTest, num int) { func (s *scenarioFourNodes) assertHTLCs(ht *lntest.HarnessTest, num int) {
// Alice should have both the same number of outgoing and // Alice should have both the same number of outgoing and
// incoming HTLCs. // incoming HTLCs.
ht.AssertNumActiveHtlcs(s.alice, num*2) ht.AssertNumActiveHtlcs(s.alice, num*2)
@@ -472,7 +471,7 @@ func (s *scenarioFourNodes) assertHTLCs(ht *lntemp.HarnessTest, num int) {
// assertAmoutPaid is a helper method which takes a given paid amount // assertAmoutPaid is a helper method which takes a given paid amount
// and number of payments and asserts the desired payments are made in // and number of payments and asserts the desired payments are made in
// the four nodes. // the four nodes.
func (s *scenarioFourNodes) assertAmoutPaid(ht *lntemp.HarnessTest, func (s *scenarioFourNodes) assertAmoutPaid(ht *lntest.HarnessTest,
amt int64, num int64) { amt int64, num int64) {
ht.AssertAmountPaid( ht.AssertAmountPaid(
@@ -20,8 +20,8 @@ import (
"github.com/lightningnetwork/lnd/lnrpc/chainrpc" "github.com/lightningnetwork/lnd/lnrpc/chainrpc"
"github.com/lightningnetwork/lnd/lnrpc/signrpc" "github.com/lightningnetwork/lnd/lnrpc/signrpc"
"github.com/lightningnetwork/lnd/lnrpc/walletrpc" "github.com/lightningnetwork/lnd/lnrpc/walletrpc"
"github.com/lightningnetwork/lnd/lntemp" "github.com/lightningnetwork/lnd/lntest"
"github.com/lightningnetwork/lnd/lntemp/node" "github.com/lightningnetwork/lnd/lntest/node"
"github.com/lightningnetwork/lnd/lnwallet/chainfee" "github.com/lightningnetwork/lnd/lnwallet/chainfee"
"github.com/stretchr/testify/require" "github.com/stretchr/testify/require"
) )
@@ -47,7 +47,7 @@ var (
// testTaproot ensures that the daemon can send to and spend from taproot (p2tr) // testTaproot ensures that the daemon can send to and spend from taproot (p2tr)
// outputs. // outputs.
func testTaproot(ht *lntemp.HarnessTest) { func testTaproot(ht *lntest.HarnessTest) {
testTaprootSendCoinsKeySpendBip86(ht, ht.Alice) testTaprootSendCoinsKeySpendBip86(ht, ht.Alice)
testTaprootComputeInputScriptKeySpendBip86(ht, ht.Alice) testTaprootComputeInputScriptKeySpendBip86(ht, ht.Alice)
testTaprootSignOutputRawScriptSpend(ht, ht.Alice) testTaprootSignOutputRawScriptSpend(ht, ht.Alice)
@@ -81,7 +81,7 @@ func testTaproot(ht *lntemp.HarnessTest) {
// testTaprootSendCoinsKeySpendBip86 tests sending to and spending from // testTaprootSendCoinsKeySpendBip86 tests sending to and spending from
// p2tr key spend only (BIP-0086) addresses through the SendCoins RPC which // p2tr key spend only (BIP-0086) addresses through the SendCoins RPC which
// internally uses the ComputeInputScript method for signing. // internally uses the ComputeInputScript method for signing.
func testTaprootSendCoinsKeySpendBip86(ht *lntemp.HarnessTest, func testTaprootSendCoinsKeySpendBip86(ht *lntest.HarnessTest,
alice *node.HarnessNode) { alice *node.HarnessNode) {
// We'll start the test by sending Alice some coins, which she'll use to // We'll start the test by sending Alice some coins, which she'll use to
@@ -137,7 +137,7 @@ func testTaprootSendCoinsKeySpendBip86(ht *lntemp.HarnessTest,
// testTaprootComputeInputScriptKeySpendBip86 tests sending to and spending from // testTaprootComputeInputScriptKeySpendBip86 tests sending to and spending from
// p2tr key spend only (BIP-0086) addresses through the SendCoins RPC which // p2tr key spend only (BIP-0086) addresses through the SendCoins RPC which
// internally uses the ComputeInputScript method for signing. // internally uses the ComputeInputScript method for signing.
func testTaprootComputeInputScriptKeySpendBip86(ht *lntemp.HarnessTest, func testTaprootComputeInputScriptKeySpendBip86(ht *lntest.HarnessTest,
alice *node.HarnessNode) { alice *node.HarnessNode) {
// We'll start the test by sending Alice some coins, which she'll use // We'll start the test by sending Alice some coins, which she'll use
@@ -234,7 +234,7 @@ func testTaprootComputeInputScriptKeySpendBip86(ht *lntemp.HarnessTest,
// testTaprootSignOutputRawScriptSpend tests sending to and spending from p2tr // testTaprootSignOutputRawScriptSpend tests sending to and spending from p2tr
// script addresses using the script path with the SignOutputRaw RPC. // script addresses using the script path with the SignOutputRaw RPC.
func testTaprootSignOutputRawScriptSpend(ht *lntemp.HarnessTest, func testTaprootSignOutputRawScriptSpend(ht *lntest.HarnessTest,
alice *node.HarnessNode, sigHashType ...txscript.SigHashType) { alice *node.HarnessNode, sigHashType ...txscript.SigHashType) {
// For the next step, we need a public key. Let's use a special family // For the next step, we need a public key. Let's use a special family
@@ -260,9 +260,7 @@ func testTaprootSignOutputRawScriptSpend(ht *lntemp.HarnessTest,
require.NoError(ht, err) require.NoError(ht, err)
// Send some coins to the generated tapscript address. // Send some coins to the generated tapscript address.
p2trOutpoint, p2trPkScript := sendToTaprootOutput( p2trOutpoint, p2trPkScript := sendToTaprootOutput(ht, alice, taprootKey)
ht, alice, taprootKey, testAmount,
)
// Spend the output again, this time back to a p2wkh address. // Spend the output again, this time back to a p2wkh address.
p2wkhAddr, p2wkhPkScript := newAddrWithScript( p2wkhAddr, p2wkhPkScript := newAddrWithScript(
@@ -392,7 +390,7 @@ func testTaprootSignOutputRawScriptSpend(ht *lntemp.HarnessTest,
// testTaprootSignOutputRawKeySpendBip86 tests that a tapscript address can // testTaprootSignOutputRawKeySpendBip86 tests that a tapscript address can
// also be spent using the key spend path through the SignOutputRaw RPC using a // also be spent using the key spend path through the SignOutputRaw RPC using a
// BIP0086 key spend only commitment. // BIP0086 key spend only commitment.
func testTaprootSignOutputRawKeySpendBip86(ht *lntemp.HarnessTest, func testTaprootSignOutputRawKeySpendBip86(ht *lntest.HarnessTest,
alice *node.HarnessNode, sigHashType ...txscript.SigHashType) { alice *node.HarnessNode, sigHashType ...txscript.SigHashType) {
// For the next step, we need a public key. Let's use a special family // For the next step, we need a public key. Let's use a special family
@@ -413,9 +411,7 @@ func testTaprootSignOutputRawKeySpendBip86(ht *lntemp.HarnessTest,
taprootKey := txscript.ComputeTaprootKeyNoScript(internalKey) taprootKey := txscript.ComputeTaprootKeyNoScript(internalKey)
// Send some coins to the generated tapscript address. // Send some coins to the generated tapscript address.
p2trOutpoint, p2trPkScript := sendToTaprootOutput( p2trOutpoint, p2trPkScript := sendToTaprootOutput(ht, alice, taprootKey)
ht, alice, taprootKey, testAmount,
)
// Spend the output again, this time back to a p2wkh address. // Spend the output again, this time back to a p2wkh address.
p2wkhAddr, p2wkhPkScript := newAddrWithScript( p2wkhAddr, p2wkhPkScript := newAddrWithScript(
@@ -490,7 +486,7 @@ func testTaprootSignOutputRawKeySpendBip86(ht *lntemp.HarnessTest,
// testTaprootSignOutputRawKeySpendRootHash tests that a tapscript address can // testTaprootSignOutputRawKeySpendRootHash tests that a tapscript address can
// also be spent using the key spend path through the SignOutputRaw RPC using a // also be spent using the key spend path through the SignOutputRaw RPC using a
// tapscript root hash. // tapscript root hash.
func testTaprootSignOutputRawKeySpendRootHash(ht *lntemp.HarnessTest, func testTaprootSignOutputRawKeySpendRootHash(ht *lntest.HarnessTest,
alice *node.HarnessNode) { alice *node.HarnessNode) {
// For the next step, we need a public key. Let's use a special family // For the next step, we need a public key. Let's use a special family
@@ -514,9 +510,7 @@ func testTaprootSignOutputRawKeySpendRootHash(ht *lntemp.HarnessTest,
taprootKey := txscript.ComputeTaprootOutputKey(internalKey, rootHash[:]) taprootKey := txscript.ComputeTaprootOutputKey(internalKey, rootHash[:])
// Send some coins to the generated tapscript address. // Send some coins to the generated tapscript address.
p2trOutpoint, p2trPkScript := sendToTaprootOutput( p2trOutpoint, p2trPkScript := sendToTaprootOutput(ht, alice, taprootKey)
ht, alice, taprootKey, testAmount,
)
// Spend the output again, this time back to a p2wkh address. // Spend the output again, this time back to a p2wkh address.
p2wkhAddr, p2wkhPkScript := newAddrWithScript( p2wkhAddr, p2wkhPkScript := newAddrWithScript(
@@ -583,7 +577,7 @@ func testTaprootSignOutputRawKeySpendRootHash(ht *lntemp.HarnessTest,
// testTaprootMuSig2KeySpendBip86 tests that a combined MuSig2 key can also be // testTaprootMuSig2KeySpendBip86 tests that a combined MuSig2 key can also be
// used as a BIP-0086 key spend only key. // used as a BIP-0086 key spend only key.
func testTaprootMuSig2KeySpendBip86(ht *lntemp.HarnessTest, func testTaprootMuSig2KeySpendBip86(ht *lntest.HarnessTest,
alice *node.HarnessNode, version signrpc.MuSig2Version) { alice *node.HarnessNode, version signrpc.MuSig2Version) {
// We're not going to commit to a script. So our taproot tweak will be // We're not going to commit to a script. So our taproot tweak will be
@@ -601,9 +595,7 @@ func testTaprootMuSig2KeySpendBip86(ht *lntemp.HarnessTest,
) )
// Send some coins to the generated tapscript address. // Send some coins to the generated tapscript address.
p2trOutpoint, p2trPkScript := sendToTaprootOutput( p2trOutpoint, p2trPkScript := sendToTaprootOutput(ht, alice, taprootKey)
ht, alice, taprootKey, testAmount,
)
// Spend the output again, this time back to a p2wkh address. // Spend the output again, this time back to a p2wkh address.
p2wkhAddr, p2wkhPkScript := newAddrWithScript( p2wkhAddr, p2wkhPkScript := newAddrWithScript(
@@ -711,7 +703,7 @@ func testTaprootMuSig2KeySpendBip86(ht *lntemp.HarnessTest,
// testTaprootMuSig2KeySpendRootHash tests that a tapscript address can also be // testTaprootMuSig2KeySpendRootHash tests that a tapscript address can also be
// spent using a MuSig2 combined key. // spent using a MuSig2 combined key.
func testTaprootMuSig2KeySpendRootHash(ht *lntemp.HarnessTest, func testTaprootMuSig2KeySpendRootHash(ht *lntest.HarnessTest,
alice *node.HarnessNode, version signrpc.MuSig2Version) { alice *node.HarnessNode, version signrpc.MuSig2Version) {
// We're going to commit to a script as well. This is a hash lock with a // We're going to commit to a script as well. This is a hash lock with a
@@ -733,9 +725,7 @@ func testTaprootMuSig2KeySpendRootHash(ht *lntemp.HarnessTest,
) )
// Send some coins to the generated tapscript address. // Send some coins to the generated tapscript address.
p2trOutpoint, p2trPkScript := sendToTaprootOutput( p2trOutpoint, p2trPkScript := sendToTaprootOutput(ht, alice, taprootKey)
ht, alice, taprootKey, testAmount,
)
// Spend the output again, this time back to a p2wkh address. // Spend the output again, this time back to a p2wkh address.
p2wkhAddr, p2wkhPkScript := newAddrWithScript( p2wkhAddr, p2wkhPkScript := newAddrWithScript(
@@ -843,7 +833,7 @@ func testTaprootMuSig2KeySpendRootHash(ht *lntemp.HarnessTest,
// testTaprootMuSig2ScriptSpend tests that a tapscript address with an internal // testTaprootMuSig2ScriptSpend tests that a tapscript address with an internal
// key that is a MuSig2 combined key can also be spent using the script path. // key that is a MuSig2 combined key can also be spent using the script path.
func testTaprootMuSig2ScriptSpend(ht *lntemp.HarnessTest, func testTaprootMuSig2ScriptSpend(ht *lntest.HarnessTest,
alice *node.HarnessNode, version signrpc.MuSig2Version) { alice *node.HarnessNode, version signrpc.MuSig2Version) {
// We're going to commit to a script and spend the output using the // We're going to commit to a script and spend the output using the
@@ -870,9 +860,7 @@ func testTaprootMuSig2ScriptSpend(ht *lntemp.HarnessTest,
tapscript := input.TapscriptFullTree(internalKey, leaf1) tapscript := input.TapscriptFullTree(internalKey, leaf1)
// Send some coins to the generated tapscript address. // Send some coins to the generated tapscript address.
p2trOutpoint, p2trPkScript := sendToTaprootOutput( p2trOutpoint, p2trPkScript := sendToTaprootOutput(ht, alice, taprootKey)
ht, alice, taprootKey, testAmount,
)
// Spend the output again, this time back to a p2wkh address. // Spend the output again, this time back to a p2wkh address.
p2wkhAddr, p2wkhPkScript := newAddrWithScript( p2wkhAddr, p2wkhPkScript := newAddrWithScript(
@@ -926,7 +914,7 @@ func testTaprootMuSig2ScriptSpend(ht *lntemp.HarnessTest,
// testTaprootMuSig2CombinedLeafKeySpend tests that a MuSig2 combined key can be // testTaprootMuSig2CombinedLeafKeySpend tests that a MuSig2 combined key can be
// used for an OP_CHECKSIG inside a tap script leaf spend. // used for an OP_CHECKSIG inside a tap script leaf spend.
func testTaprootMuSig2CombinedLeafKeySpend(ht *lntemp.HarnessTest, func testTaprootMuSig2CombinedLeafKeySpend(ht *lntest.HarnessTest,
alice *node.HarnessNode, version signrpc.MuSig2Version) { alice *node.HarnessNode, version signrpc.MuSig2Version) {
// We're using the combined MuSig2 key in a script leaf. So we need to // We're using the combined MuSig2 key in a script leaf. So we need to
@@ -951,9 +939,7 @@ func testTaprootMuSig2CombinedLeafKeySpend(ht *lntemp.HarnessTest,
require.NoError(ht, err) require.NoError(ht, err)
// Send some coins to the generated tapscript address. // Send some coins to the generated tapscript address.
p2trOutpoint, p2trPkScript := sendToTaprootOutput( p2trOutpoint, p2trPkScript := sendToTaprootOutput(ht, alice, taprootKey)
ht, alice, taprootKey, testAmount,
)
// Spend the output again, this time back to a p2wkh address. // Spend the output again, this time back to a p2wkh address.
p2wkhAddr, p2wkhPkScript := newAddrWithScript( p2wkhAddr, p2wkhPkScript := newAddrWithScript(
@@ -1102,7 +1088,7 @@ func testTaprootMuSig2CombinedLeafKeySpend(ht *lntemp.HarnessTest,
// testTaprootImportTapscriptScriptSpend tests importing p2tr script addresses // testTaprootImportTapscriptScriptSpend tests importing p2tr script addresses
// using the script path with the full tree known. // using the script path with the full tree known.
func testTaprootImportTapscriptFullTree(ht *lntemp.HarnessTest, func testTaprootImportTapscriptFullTree(ht *lntest.HarnessTest,
alice *node.HarnessNode) { alice *node.HarnessNode) {
// For the next step, we need a public key. Let's use a special family // For the next step, we need a public key. Let's use a special family
@@ -1151,9 +1137,7 @@ func testTaprootImportTapscriptFullTree(ht *lntemp.HarnessTest,
require.Equal(ht, calculatedAddr.String(), importResp.P2TrAddress) require.Equal(ht, calculatedAddr.String(), importResp.P2TrAddress)
// Send some coins to the generated tapscript address. // Send some coins to the generated tapscript address.
p2trOutpoint, p2trPkScript := sendToTaprootOutput( p2trOutpoint, p2trPkScript := sendToTaprootOutput(ht, alice, taprootKey)
ht, alice, taprootKey, testAmount,
)
p2trOutputRPC := &lnrpc.OutPoint{ p2trOutputRPC := &lnrpc.OutPoint{
TxidBytes: p2trOutpoint.Hash[:], TxidBytes: p2trOutpoint.Hash[:],
OutputIndex: p2trOutpoint.Index, OutputIndex: p2trOutpoint.Index,
@@ -1176,7 +1160,7 @@ func testTaprootImportTapscriptFullTree(ht *lntemp.HarnessTest,
// testTaprootImportTapscriptPartialReveal tests importing p2tr script addresses // testTaprootImportTapscriptPartialReveal tests importing p2tr script addresses
// for which we only know part of the tree. // for which we only know part of the tree.
func testTaprootImportTapscriptPartialReveal(ht *lntemp.HarnessTest, func testTaprootImportTapscriptPartialReveal(ht *lntest.HarnessTest,
alice *node.HarnessNode) { alice *node.HarnessNode) {
// For the next step, we need a public key. Let's use a special family // For the next step, we need a public key. Let's use a special family
@@ -1221,9 +1205,7 @@ func testTaprootImportTapscriptPartialReveal(ht *lntemp.HarnessTest,
require.Equal(ht, calculatedAddr.String(), importResp.P2TrAddress) require.Equal(ht, calculatedAddr.String(), importResp.P2TrAddress)
// Send some coins to the generated tapscript address. // Send some coins to the generated tapscript address.
p2trOutpoint, p2trPkScript := sendToTaprootOutput( p2trOutpoint, p2trPkScript := sendToTaprootOutput(ht, alice, taprootKey)
ht, alice, taprootKey, testAmount,
)
p2trOutputRPC := &lnrpc.OutPoint{ p2trOutputRPC := &lnrpc.OutPoint{
TxidBytes: p2trOutpoint.Hash[:], TxidBytes: p2trOutpoint.Hash[:],
@@ -1247,7 +1229,7 @@ func testTaprootImportTapscriptPartialReveal(ht *lntemp.HarnessTest,
// testTaprootImportTapscriptRootHashOnly tests importing p2tr script addresses // testTaprootImportTapscriptRootHashOnly tests importing p2tr script addresses
// for which we only know the root hash. // for which we only know the root hash.
func testTaprootImportTapscriptRootHashOnly(ht *lntemp.HarnessTest, func testTaprootImportTapscriptRootHashOnly(ht *lntest.HarnessTest,
alice *node.HarnessNode) { alice *node.HarnessNode) {
// For the next step, we need a public key. Let's use a special family // For the next step, we need a public key. Let's use a special family
@@ -1280,9 +1262,7 @@ func testTaprootImportTapscriptRootHashOnly(ht *lntemp.HarnessTest,
require.Equal(ht, calculatedAddr.String(), importResp.P2TrAddress) require.Equal(ht, calculatedAddr.String(), importResp.P2TrAddress)
// Send some coins to the generated tapscript address. // Send some coins to the generated tapscript address.
p2trOutpoint, p2trPkScript := sendToTaprootOutput( p2trOutpoint, p2trPkScript := sendToTaprootOutput(ht, alice, taprootKey)
ht, alice, taprootKey, testAmount,
)
p2trOutputRPC := &lnrpc.OutPoint{ p2trOutputRPC := &lnrpc.OutPoint{
TxidBytes: p2trOutpoint.Hash[:], TxidBytes: p2trOutpoint.Hash[:],
@@ -1306,7 +1286,7 @@ func testTaprootImportTapscriptRootHashOnly(ht *lntemp.HarnessTest,
// testTaprootImportTapscriptFullKey tests importing p2tr script addresses for // testTaprootImportTapscriptFullKey tests importing p2tr script addresses for
// which we only know the full Taproot key. // which we only know the full Taproot key.
func testTaprootImportTapscriptFullKey(ht *lntemp.HarnessTest, func testTaprootImportTapscriptFullKey(ht *lntest.HarnessTest,
alice *node.HarnessNode) { alice *node.HarnessNode) {
// For the next step, we need a public key. Let's use a special family // For the next step, we need a public key. Let's use a special family
@@ -1339,9 +1319,7 @@ func testTaprootImportTapscriptFullKey(ht *lntemp.HarnessTest,
require.Equal(ht, calculatedAddr.String(), importResp.P2TrAddress) require.Equal(ht, calculatedAddr.String(), importResp.P2TrAddress)
// Send some coins to the generated tapscript address. // Send some coins to the generated tapscript address.
p2trOutpoint, p2trPkScript := sendToTaprootOutput( p2trOutpoint, p2trPkScript := sendToTaprootOutput(ht, alice, taprootKey)
ht, alice, taprootKey, testAmount,
)
p2trOutputRPC := &lnrpc.OutPoint{ p2trOutputRPC := &lnrpc.OutPoint{
TxidBytes: p2trOutpoint.Hash[:], TxidBytes: p2trOutpoint.Hash[:],
@@ -1365,7 +1343,7 @@ func testTaprootImportTapscriptFullKey(ht *lntemp.HarnessTest,
// clearWalletImportedTapscriptBalance manually assembles and then attempts to // clearWalletImportedTapscriptBalance manually assembles and then attempts to
// sign a TX to sweep funds from an imported tapscript address. // sign a TX to sweep funds from an imported tapscript address.
func clearWalletImportedTapscriptBalance(ht *lntemp.HarnessTest, func clearWalletImportedTapscriptBalance(ht *lntest.HarnessTest,
hn *node.HarnessNode, utxo *wire.TxOut, outPoint wire.OutPoint, hn *node.HarnessNode, utxo *wire.TxOut, outPoint wire.OutPoint,
internalKey *btcec.PublicKey, derivationPath []uint32, internalKey *btcec.PublicKey, derivationPath []uint32,
rootHash []byte) { rootHash []byte) {
@@ -1460,7 +1438,7 @@ func testScriptSchnorrSig(t *testing.T,
} }
// newAddrWithScript returns a new address and its pkScript. // newAddrWithScript returns a new address and its pkScript.
func newAddrWithScript(ht *lntemp.HarnessTest, node *node.HarnessNode, func newAddrWithScript(ht *lntest.HarnessTest, node *node.HarnessNode,
addrType lnrpc.AddressType) (btcutil.Address, []byte) { addrType lnrpc.AddressType) (btcutil.Address, []byte) {
p2wkhResp := node.RPC.NewAddress(&lnrpc.NewAddressRequest{ p2wkhResp := node.RPC.NewAddress(&lnrpc.NewAddressRequest{
@@ -1479,8 +1457,8 @@ func newAddrWithScript(ht *lntemp.HarnessTest, node *node.HarnessNode,
// sendToTaprootOutput sends coins to a p2tr output of the given taproot key and // sendToTaprootOutput sends coins to a p2tr output of the given taproot key and
// mines a block to confirm the coins. // mines a block to confirm the coins.
func sendToTaprootOutput(ht *lntemp.HarnessTest, hn *node.HarnessNode, func sendToTaprootOutput(ht *lntest.HarnessTest, hn *node.HarnessNode,
taprootKey *btcec.PublicKey, amt int64) (wire.OutPoint, []byte) { taprootKey *btcec.PublicKey) (wire.OutPoint, []byte) {
tapScriptAddr, err := btcutil.NewAddressTaproot( tapScriptAddr, err := btcutil.NewAddressTaproot(
schnorr.SerializePubKey(taprootKey), harnessNetParams, schnorr.SerializePubKey(taprootKey), harnessNetParams,
@@ -1492,7 +1470,7 @@ func sendToTaprootOutput(ht *lntemp.HarnessTest, hn *node.HarnessNode,
// Send some coins to the generated tapscript address. // Send some coins to the generated tapscript address.
req := &lnrpc.SendCoinsRequest{ req := &lnrpc.SendCoinsRequest{
Addr: tapScriptAddr.String(), Addr: tapScriptAddr.String(),
Amount: amt, Amount: testAmount,
} }
hn.RPC.SendCoins(req) hn.RPC.SendCoins(req)
@@ -1542,7 +1520,7 @@ func sendToTaprootOutput(ht *lntemp.HarnessTest, hn *node.HarnessNode,
// after checking its weight against an estimate. After asserting the given // after checking its weight against an estimate. After asserting the given
// spend request, the given sweep address' balance is verified to be seen as // spend request, the given sweep address' balance is verified to be seen as
// funds belonging to the wallet. // funds belonging to the wallet.
func publishTxAndConfirmSweep(ht *lntemp.HarnessTest, node *node.HarnessNode, func publishTxAndConfirmSweep(ht *lntest.HarnessTest, node *node.HarnessNode,
tx *wire.MsgTx, estimatedWeight int64, tx *wire.MsgTx, estimatedWeight int64,
spendRequest *chainrpc.SpendRequest, sweepAddr string) { spendRequest *chainrpc.SpendRequest, sweepAddr string) {
@@ -1604,7 +1582,7 @@ func publishTxAndConfirmSweep(ht *lntemp.HarnessTest, node *node.HarnessNode,
// confirmAddress makes sure that a transaction in the mempool spends funds to // confirmAddress makes sure that a transaction in the mempool spends funds to
// the given address. It also checks that a confirmation notification for the // the given address. It also checks that a confirmation notification for the
// address is triggered when the transaction is mined. // address is triggered when the transaction is mined.
func confirmAddress(ht *lntemp.HarnessTest, hn *node.HarnessNode, func confirmAddress(ht *lntest.HarnessTest, hn *node.HarnessNode,
addrString string) { addrString string) {
// Wait until the tx that sends to the address is found. // Wait until the tx that sends to the address is found.
@@ -1654,7 +1632,7 @@ func confirmAddress(ht *lntemp.HarnessTest, hn *node.HarnessNode,
// deriveSigningKeys derives three signing keys and returns their descriptors, // deriveSigningKeys derives three signing keys and returns their descriptors,
// as well as the public keys in the Schnorr serialized format. // as well as the public keys in the Schnorr serialized format.
func deriveSigningKeys(ht *lntemp.HarnessTest, node *node.HarnessNode, func deriveSigningKeys(ht *lntest.HarnessTest, node *node.HarnessNode,
version signrpc.MuSig2Version) (*signrpc.KeyDescriptor, version signrpc.MuSig2Version) (*signrpc.KeyDescriptor,
*signrpc.KeyDescriptor, *signrpc.KeyDescriptor, [][]byte) { *signrpc.KeyDescriptor, *signrpc.KeyDescriptor, [][]byte) {
@@ -1700,7 +1678,7 @@ func deriveSigningKeys(ht *lntemp.HarnessTest, node *node.HarnessNode,
// combined into a single key. The same node is used for the three signing // combined into a single key. The same node is used for the three signing
// participants but a separate key is generated for each session. So the result // participants but a separate key is generated for each session. So the result
// should be the same as if it were three different nodes. // should be the same as if it were three different nodes.
func createMuSigSessions(ht *lntemp.HarnessTest, node *node.HarnessNode, func createMuSigSessions(ht *lntest.HarnessTest, node *node.HarnessNode,
taprootTweak *signrpc.TaprootTweakDesc, taprootTweak *signrpc.TaprootTweakDesc,
keyDesc1, keyDesc2, keyDesc3 *signrpc.KeyDescriptor, keyDesc1, keyDesc2, keyDesc3 *signrpc.KeyDescriptor,
allPubKeys [][]byte, version signrpc.MuSig2Version) (*btcec.PublicKey, allPubKeys [][]byte, version signrpc.MuSig2Version) (*btcec.PublicKey,
@@ -1838,7 +1816,7 @@ func createMuSigSessions(ht *lntemp.HarnessTest, node *node.HarnessNode,
// testTaprootCoopClose asserts that if both peers signal ShutdownAnySegwit, // testTaprootCoopClose asserts that if both peers signal ShutdownAnySegwit,
// then a taproot closing addr is used. Otherwise, we shouldn't expect one to // then a taproot closing addr is used. Otherwise, we shouldn't expect one to
// be used. // be used.
func testTaprootCoopClose(ht *lntemp.HarnessTest) { func testTaprootCoopClose(ht *lntest.HarnessTest) {
// We'll start by making two new nodes, and funding a channel between // We'll start by making two new nodes, and funding a channel between
// them. // them.
carol := ht.NewNode("Carol", nil) carol := ht.NewNode("Carol", nil)
@@ -1853,7 +1831,7 @@ func testTaprootCoopClose(ht *lntemp.HarnessTest) {
// We'll now open a channel between Carol and Dave. // We'll now open a channel between Carol and Dave.
chanPoint := ht.OpenChannel( chanPoint := ht.OpenChannel(
carol, dave, lntemp.OpenChannelParams{ carol, dave, lntest.OpenChannelParams{
Amt: chanAmt, Amt: chanAmt,
PushAmt: pushAmt, PushAmt: pushAmt,
SatPerVByte: satPerVbyte, SatPerVByte: satPerVbyte,
@@ -1888,7 +1866,7 @@ func testTaprootCoopClose(ht *lntemp.HarnessTest) {
// We'll now open up a chanel again between Carol and Eve. // We'll now open up a chanel again between Carol and Eve.
chanPoint = ht.OpenChannel( chanPoint = ht.OpenChannel(
carol, eve, lntemp.OpenChannelParams{ carol, eve, lntest.OpenChannelParams{
Amt: chanAmt, Amt: chanAmt,
PushAmt: pushAmt, PushAmt: pushAmt,
SatPerVByte: satPerVbyte, SatPerVByte: satPerVbyte,
@@ -1904,7 +1882,7 @@ func testTaprootCoopClose(ht *lntemp.HarnessTest) {
// testMuSig2CombineKey makes sure that combining a key with MuSig2 returns the // testMuSig2CombineKey makes sure that combining a key with MuSig2 returns the
// correct result according to the MuSig2 version specified. // correct result according to the MuSig2 version specified.
func testMuSig2CombineKey(ht *lntemp.HarnessTest, alice *node.HarnessNode, func testMuSig2CombineKey(ht *lntest.HarnessTest, alice *node.HarnessNode,
version signrpc.MuSig2Version) { version signrpc.MuSig2Version) {
testVector040Key1 := hexDecode( testVector040Key1 := hexDecode(
@@ -4,6 +4,7 @@ import (
"flag" "flag"
"fmt" "fmt"
"io" "io"
"math"
"os" "os"
"path/filepath" "path/filepath"
"runtime" "runtime"
@@ -11,9 +12,12 @@ import (
"testing" "testing"
"time" "time"
"github.com/btcsuite/btcd/chaincfg"
"github.com/btcsuite/btcd/integration/rpctest" "github.com/btcsuite/btcd/integration/rpctest"
"github.com/lightningnetwork/lnd/lntemp" "github.com/lightningnetwork/lnd/lnrpc"
"github.com/lightningnetwork/lnd/lntest" "github.com/lightningnetwork/lnd/lntest"
"github.com/lightningnetwork/lnd/lntest/node"
"github.com/lightningnetwork/lnd/lntest/wait"
"github.com/stretchr/testify/require" "github.com/stretchr/testify/require"
"google.golang.org/grpc/grpclog" "google.golang.org/grpc/grpclog"
) )
@@ -26,9 +30,25 @@ const (
// defaultRunTranche is the default index of the test cases tranche that // defaultRunTranche is the default index of the test cases tranche that
// we run. // we run.
defaultRunTranche uint = 0 defaultRunTranche uint = 0
defaultTimeout = wait.DefaultTimeout
itestLndBinary = "../lnd-itest"
// TODO(yy): remove the following defined constants and put them in the
// specific tests where they are used?
testFeeBase = 1e+6
anchorSize = 330
defaultCSV = node.DefaultCSV
noFeeLimitMsat = math.MaxInt64
AddrTypeWitnessPubkeyHash = lnrpc.AddressType_WITNESS_PUBKEY_HASH
AddrTypeNestedPubkeyHash = lnrpc.AddressType_NESTED_PUBKEY_HASH
AddrTypeTaprootPubkey = lnrpc.AddressType_TAPROOT_PUBKEY
) )
var ( var (
harnessNetParams = &chaincfg.RegressionNetParams
// testCasesSplitParts is the number of tranches the test cases should // testCasesSplitParts is the number of tranches the test cases should
// be split into. By default this is set to 1, so no splitting happens. // be split into. By default this is set to 1, so no splitting happens.
// If this value is increased, then the -runtranche flag must be // If this value is increased, then the -runtranche flag must be
@@ -49,31 +69,32 @@ var (
// dbBackendFlag specifies the backend to use. // dbBackendFlag specifies the backend to use.
dbBackendFlag = flag.String("dbbackend", "bbolt", "Database backend "+ dbBackendFlag = flag.String("dbbackend", "bbolt", "Database backend "+
"(bbolt, etcd, postgres, sqlite)") "(bbolt, etcd, postgres)")
// lndExecutable is the full path to the lnd binary.
lndExecutable = flag.String(
"lndexec", itestLndBinary, "full path to lnd binary",
)
) )
// TestLightningNetworkDaemonTemp performs a series of integration tests // TestLightningNetworkDaemon performs a series of integration tests amongst a
// amongst a programmatically driven network of lnd nodes. // programmatically driven network of lnd nodes.
func TestLightningNetworkDaemonTemp(t *testing.T) { func TestLightningNetworkDaemon(t *testing.T) {
if !*tempTest {
t.Skip("Running old tests, new tests are skipped")
}
// If no tests are registered, then we can exit early. // If no tests are registered, then we can exit early.
if len(allTestCasesTemp) == 0 { if len(allTestCases) == 0 {
t.Skip("integration tests not selected with flag 'rpctest'") t.Skip("integration tests not selected with flag 'integration'")
} }
// Get the test cases to be run in this tranche. // Get the test cases to be run in this tranche.
testCases, trancheIndex, trancheOffset := getTestCaseSplitTranche() testCases, trancheIndex, trancheOffset := getTestCaseSplitTranche()
lntest.ApplyPortOffset(uint32(trancheIndex) * 1000) node.ApplyPortOffset(uint32(trancheIndex) * 1000)
// Create a simple fee service. // Create a simple fee service.
feeService := lntemp.NewFeeService(t) feeService := lntest.NewFeeService(t)
// Get the binary path and setup the harness test. // Get the binary path and setup the harness test.
binary := getLndBinary(t) binary := getLndBinary(t)
harnessTest := lntemp.SetupHarness( harnessTest := lntest.SetupHarness(
t, binary, *dbBackendFlag, feeService, t, binary, *dbBackendFlag, feeService,
) )
defer harnessTest.Stop() defer harnessTest.Stop()
@@ -126,12 +147,16 @@ func TestLightningNetworkDaemonTemp(t *testing.T) {
break break
} }
} }
_, height := harnessTest.Miner.GetBestBlock()
t.Logf("=========> tests finished for tranche: %v, tested %d "+
"cases, end height: %d\n", trancheIndex, len(testCases), height)
} }
// getTestCaseSplitTranche returns the sub slice of the test cases that should // getTestCaseSplitTranche returns the sub slice of the test cases that should
// be run as the current split tranche as well as the index and slice offset of // be run as the current split tranche as well as the index and slice offset of
// the tranche. // the tranche.
func getTestCaseSplitTranche() ([]*lntemp.TestCase, uint, uint) { func getTestCaseSplitTranche() ([]*lntest.TestCase, uint, uint) {
numTranches := defaultSplitTranches numTranches := defaultSplitTranches
if testCasesSplitTranches != nil { if testCasesSplitTranches != nil {
numTranches = *testCasesSplitTranches numTranches = *testCasesSplitTranches
@@ -150,7 +175,7 @@ func getTestCaseSplitTranche() ([]*lntemp.TestCase, uint, uint) {
runTranche = 0 runTranche = 0
} }
numCases := uint(len(allTestCasesTemp)) numCases := uint(len(allTestCases))
testsPerTranche := numCases / numTranches testsPerTranche := numCases / numTranches
trancheOffset := runTranche * testsPerTranche trancheOffset := runTranche * testsPerTranche
trancheEnd := trancheOffset + testsPerTranche trancheEnd := trancheOffset + testsPerTranche
@@ -158,7 +183,7 @@ func getTestCaseSplitTranche() ([]*lntemp.TestCase, uint, uint) {
trancheEnd = numCases trancheEnd = numCases
} }
return allTestCasesTemp[trancheOffset:trancheEnd], threadID, return allTestCases[trancheOffset:trancheEnd], threadID,
trancheOffset trancheOffset
} }
@@ -188,7 +213,7 @@ func init() {
// Before we start any node, we need to make sure that any btcd node // Before we start any node, we need to make sure that any btcd node
// that is started through the RPC harness uses a unique port as well // that is started through the RPC harness uses a unique port as well
// to avoid any port collisions. // to avoid any port collisions.
rpctest.ListenAddressGenerator = lntest.GenerateBtcdListenerAddresses rpctest.ListenAddressGenerator = node.GenerateBtcdListenerAddresses
// Swap out grpc's default logger with out fake logger which drops the // Swap out grpc's default logger with out fake logger which drops the
// statements on the floor. // statements on the floor.
@@ -7,17 +7,17 @@ import (
"github.com/btcsuite/btcd/btcutil" "github.com/btcsuite/btcd/btcutil"
"github.com/lightningnetwork/lnd/lnrpc" "github.com/lightningnetwork/lnd/lnrpc"
"github.com/lightningnetwork/lnd/lnrpc/routerrpc" "github.com/lightningnetwork/lnd/lnrpc/routerrpc"
"github.com/lightningnetwork/lnd/lntemp" "github.com/lightningnetwork/lnd/lntest"
"github.com/stretchr/testify/require" "github.com/stretchr/testify/require"
) )
// testTrackPayments tests whether a client that calls the TrackPayments api // testTrackPayments tests whether a client that calls the TrackPayments api
// receives payment updates. // receives payment updates.
func testTrackPayments(ht *lntemp.HarnessTest) { func testTrackPayments(ht *lntest.HarnessTest) {
// Open a channel between alice and bob. // Open a channel between alice and bob.
alice, bob := ht.Alice, ht.Bob alice, bob := ht.Alice, ht.Bob
channel := ht.OpenChannel( channel := ht.OpenChannel(
alice, bob, lntemp.OpenChannelParams{ alice, bob, lntest.OpenChannelParams{
Amt: btcutil.Amount(300000), Amt: btcutil.Amount(300000),
}, },
) )
@@ -16,8 +16,8 @@ import (
"github.com/lightningnetwork/lnd/funding" "github.com/lightningnetwork/lnd/funding"
"github.com/lightningnetwork/lnd/lnrpc" "github.com/lightningnetwork/lnd/lnrpc"
"github.com/lightningnetwork/lnd/lnrpc/walletrpc" "github.com/lightningnetwork/lnd/lnrpc/walletrpc"
"github.com/lightningnetwork/lnd/lntemp" "github.com/lightningnetwork/lnd/lntest"
"github.com/lightningnetwork/lnd/lntemp/node" "github.com/lightningnetwork/lnd/lntest/node"
"github.com/lightningnetwork/lnd/lnwallet" "github.com/lightningnetwork/lnd/lnwallet"
"github.com/stretchr/testify/require" "github.com/stretchr/testify/require"
) )
@@ -51,7 +51,7 @@ func walletToLNAddrType(t *testing.T,
// newExternalAddr generates a new external address of an imported account for a // newExternalAddr generates a new external address of an imported account for a
// pair of nodes, where one acts as the funder and the other as the signer. // pair of nodes, where one acts as the funder and the other as the signer.
func newExternalAddr(ht *lntemp.HarnessTest, funder, signer *node.HarnessNode, func newExternalAddr(ht *lntest.HarnessTest, funder, signer *node.HarnessNode,
importedAccount string, addrType walletrpc.AddressType) string { importedAccount string, addrType walletrpc.AddressType) string {
// We'll generate a new address for Carol from Dave's node to receive // We'll generate a new address for Carol from Dave's node to receive
@@ -125,7 +125,7 @@ func assertOutputScriptType(t *testing.T, expType txscript.ScriptClass,
// psbtSendFromImportedAccount attempts to fund a PSBT from the given imported // psbtSendFromImportedAccount attempts to fund a PSBT from the given imported
// account, originating from the source node to the destination. // account, originating from the source node to the destination.
func psbtSendFromImportedAccount(ht *lntemp.HarnessTest, srcNode, destNode, func psbtSendFromImportedAccount(ht *lntest.HarnessTest, srcNode, destNode,
signer *node.HarnessNode, account string, signer *node.HarnessNode, account string,
accountAddrType walletrpc.AddressType) { accountAddrType walletrpc.AddressType) {
@@ -236,7 +236,7 @@ func psbtSendFromImportedAccount(ht *lntemp.HarnessTest, srcNode, destNode,
// node. To ensure the channel is operational before closing it, a test payment // node. To ensure the channel is operational before closing it, a test payment
// is made. Several balance assertions are made along the way for the sake of // is made. Several balance assertions are made along the way for the sake of
// correctness. // correctness.
func fundChanAndCloseFromImportedAccount(ht *lntemp.HarnessTest, srcNode, func fundChanAndCloseFromImportedAccount(ht *lntest.HarnessTest, srcNode,
destNode, signer *node.HarnessNode, account string, destNode, signer *node.HarnessNode, account string,
accountAddrType walletrpc.AddressType, utxoAmt, chanSize int64) { accountAddrType walletrpc.AddressType, utxoAmt, chanSize int64) {
@@ -256,7 +256,7 @@ func fundChanAndCloseFromImportedAccount(ht *lntemp.HarnessTest, srcNode,
// The source node will then fund the channel through a PSBT shim. // The source node will then fund the channel through a PSBT shim.
pendingChanID := ht.Random32Bytes() pendingChanID := ht.Random32Bytes()
chanUpdates, rawPsbt := ht.OpenChannelPsbt( chanUpdates, rawPsbt := ht.OpenChannelPsbt(
srcNode, destNode, lntemp.OpenChannelParams{ srcNode, destNode, lntest.OpenChannelParams{
Amt: btcutil.Amount(chanSize), Amt: btcutil.Amount(chanSize),
FundingShim: &lnrpc.FundingShim{ FundingShim: &lnrpc.FundingShim{
Shim: &lnrpc.FundingShim_PsbtShim{ Shim: &lnrpc.FundingShim_PsbtShim{
@@ -463,7 +463,7 @@ func fundChanAndCloseFromImportedAccount(ht *lntemp.HarnessTest, srcNode,
// testWalletImportAccount tests that an imported account can fund transactions // testWalletImportAccount tests that an imported account can fund transactions
// and channels through PSBTs, by having one node (the one with the imported // and channels through PSBTs, by having one node (the one with the imported
// account) craft the transactions and another node act as the signer. // account) craft the transactions and another node act as the signer.
func testWalletImportAccount(ht *lntemp.HarnessTest) { func testWalletImportAccount(ht *lntest.HarnessTest) {
testCases := []struct { testCases := []struct {
name string name string
addrType walletrpc.AddressType addrType walletrpc.AddressType
@@ -491,7 +491,7 @@ func testWalletImportAccount(ht *lntemp.HarnessTest) {
for _, tc := range testCases { for _, tc := range testCases {
tc := tc tc := tc
success := ht.Run(tc.name, func(tt *testing.T) { success := ht.Run(tc.name, func(tt *testing.T) {
testFunc := func(ht *lntemp.HarnessTest) { testFunc := func(ht *lntest.HarnessTest) {
testWalletImportAccountScenario( testWalletImportAccountScenario(
ht, tc.addrType, ht, tc.addrType,
) )
@@ -499,7 +499,7 @@ func testWalletImportAccount(ht *lntemp.HarnessTest) {
st := ht.Subtest(tt) st := ht.Subtest(tt)
st.RunTestCase(&lntemp.TestCase{ st.RunTestCase(&lntest.TestCase{
Name: tc.name, Name: tc.name,
TestFunc: testFunc, TestFunc: testFunc,
}) })
@@ -515,7 +515,7 @@ func testWalletImportAccount(ht *lntemp.HarnessTest) {
} }
} }
func testWalletImportAccountScenario(ht *lntemp.HarnessTest, func testWalletImportAccountScenario(ht *lntest.HarnessTest,
addrType walletrpc.AddressType) { addrType walletrpc.AddressType) {
// We'll start our test by having two nodes, Carol and Dave. Carol's // We'll start our test by having two nodes, Carol and Dave. Carol's
@@ -529,7 +529,7 @@ func testWalletImportAccountScenario(ht *lntemp.HarnessTest,
runWalletImportAccountScenario(ht, addrType, carol, dave) runWalletImportAccountScenario(ht, addrType, carol, dave)
} }
func runWalletImportAccountScenario(ht *lntemp.HarnessTest, func runWalletImportAccountScenario(ht *lntest.HarnessTest,
addrType walletrpc.AddressType, carol, dave *node.HarnessNode) { addrType walletrpc.AddressType, carol, dave *node.HarnessNode) {
const utxoAmt int64 = btcutil.SatoshiPerBitcoin const utxoAmt int64 = btcutil.SatoshiPerBitcoin
@@ -619,7 +619,7 @@ func runWalletImportAccountScenario(ht *lntemp.HarnessTest,
// testWalletImportPubKey tests that an imported public keys can fund // testWalletImportPubKey tests that an imported public keys can fund
// transactions and channels through PSBTs, by having one node (the one with the // transactions and channels through PSBTs, by having one node (the one with the
// imported account) craft the transactions and another node act as the signer. // imported account) craft the transactions and another node act as the signer.
func testWalletImportPubKey(ht *lntemp.HarnessTest) { func testWalletImportPubKey(ht *lntest.HarnessTest) {
testCases := []struct { testCases := []struct {
name string name string
addrType walletrpc.AddressType addrType walletrpc.AddressType
@@ -642,7 +642,7 @@ func testWalletImportPubKey(ht *lntemp.HarnessTest) {
for _, tc := range testCases { for _, tc := range testCases {
tc := tc tc := tc
success := ht.Run(tc.name, func(tt *testing.T) { success := ht.Run(tc.name, func(tt *testing.T) {
testFunc := func(ht *lntemp.HarnessTest) { testFunc := func(ht *lntest.HarnessTest) {
testWalletImportPubKeyScenario( testWalletImportPubKeyScenario(
ht, tc.addrType, ht, tc.addrType,
) )
@@ -650,7 +650,7 @@ func testWalletImportPubKey(ht *lntemp.HarnessTest) {
st := ht.Subtest(tt) st := ht.Subtest(tt)
st.RunTestCase(&lntemp.TestCase{ st.RunTestCase(&lntest.TestCase{
Name: tc.name, Name: tc.name,
TestFunc: testFunc, TestFunc: testFunc,
}) })
@@ -666,7 +666,7 @@ func testWalletImportPubKey(ht *lntemp.HarnessTest) {
} }
} }
func testWalletImportPubKeyScenario(ht *lntemp.HarnessTest, func testWalletImportPubKeyScenario(ht *lntest.HarnessTest,
addrType walletrpc.AddressType) { addrType walletrpc.AddressType) {
const utxoAmt int64 = btcutil.SatoshiPerBitcoin const utxoAmt int64 = btcutil.SatoshiPerBitcoin
@@ -5,12 +5,10 @@ import (
"github.com/lightningnetwork/lnd/chainreg" "github.com/lightningnetwork/lnd/chainreg"
"github.com/lightningnetwork/lnd/lnrpc" "github.com/lightningnetwork/lnd/lnrpc"
"github.com/lightningnetwork/lnd/lntemp" "github.com/lightningnetwork/lnd/lntest"
"github.com/stretchr/testify/require" "github.com/stretchr/testify/require"
) )
type pendingChan *lnrpc.PendingChannelsResponse_PendingChannel
// testWipeForwardingPackagesLocal tests that when a channel is closed, either // testWipeForwardingPackagesLocal tests that when a channel is closed, either
// through local force close, remote close, or coop close, all the forwarding // through local force close, remote close, or coop close, all the forwarding
// packages of that particular channel are deleted. The test creates a // packages of that particular channel are deleted. The test creates a
@@ -21,7 +19,7 @@ type pendingChan *lnrpc.PendingChannelsResponse_PendingChannel
// packages are wiped. // packages are wiped.
// - Bob coop closes the channel Bob->Carol, and checks from both Bob PoVs // - Bob coop closes the channel Bob->Carol, and checks from both Bob PoVs
// that the forwarding packages are wiped. // that the forwarding packages are wiped.
func testWipeForwardingPackages(ht *lntemp.HarnessTest) { func testWipeForwardingPackages(ht *lntest.HarnessTest) {
const ( const (
chanAmt = 10e6 chanAmt = 10e6
paymentAmt = 10e4 paymentAmt = 10e4
@@ -41,12 +39,12 @@ func testWipeForwardingPackages(ht *lntemp.HarnessTest) {
// Open a channel between Alice and Bob. // Open a channel between Alice and Bob.
chanPointAB := ht.OpenChannel( chanPointAB := ht.OpenChannel(
alice, bob, lntemp.OpenChannelParams{Amt: chanAmt}, alice, bob, lntest.OpenChannelParams{Amt: chanAmt},
) )
// Open a channel between Bob and Carol. // Open a channel between Bob and Carol.
chanPointBC := ht.OpenChannel( chanPointBC := ht.OpenChannel(
bob, carol, lntemp.OpenChannelParams{Amt: chanAmt}, bob, carol, lntest.OpenChannelParams{Amt: chanAmt},
) )
// Before we continue, make sure Alice has seen the channel between Bob // Before we continue, make sure Alice has seen the channel between Bob
@@ -3,7 +3,7 @@ package itest
import ( import (
"github.com/btcsuite/btcd/btcutil" "github.com/btcsuite/btcd/btcutil"
"github.com/lightningnetwork/lnd/funding" "github.com/lightningnetwork/lnd/funding"
"github.com/lightningnetwork/lnd/lntemp" "github.com/lightningnetwork/lnd/lntest"
"github.com/lightningnetwork/lnd/lnwallet" "github.com/lightningnetwork/lnd/lnwallet"
) )
@@ -11,7 +11,7 @@ import (
// acceptances will allow a wumbo channel to be created. Additionally, if a // acceptances will allow a wumbo channel to be created. Additionally, if a
// node is running with mini channels only enabled, then they should reject any // node is running with mini channels only enabled, then they should reject any
// inbound wumbo channel requests. // inbound wumbo channel requests.
func testWumboChannels(ht *lntemp.HarnessTest) { func testWumboChannels(ht *lntest.HarnessTest) {
// With all the channel types exercised, we'll now make sure the wumbo // With all the channel types exercised, we'll now make sure the wumbo
// signalling support works properly. // signalling support works properly.
// //
@@ -33,7 +33,7 @@ func testWumboChannels(ht *lntemp.HarnessTest) {
// The test should indicate a failure due to the channel being too // The test should indicate a failure due to the channel being too
// large. // large.
ht.OpenChannelAssertErr( ht.OpenChannelAssertErr(
wumboNode, miniNode, lntemp.OpenChannelParams{Amt: chanAmt}, wumboNode, miniNode, lntest.OpenChannelParams{Amt: chanAmt},
lnwallet.ErrChanTooLarge(chanAmt, funding.MaxBtcFundingAmount), lnwallet.ErrChanTooLarge(chanAmt, funding.MaxBtcFundingAmount),
) )
@@ -46,7 +46,7 @@ func testWumboChannels(ht *lntemp.HarnessTest) {
// Creating a wumbo channel between these two nodes should succeed. // Creating a wumbo channel between these two nodes should succeed.
ht.EnsureConnected(wumboNode, wumboNode2) ht.EnsureConnected(wumboNode, wumboNode2)
chanPoint := ht.OpenChannel( chanPoint := ht.OpenChannel(
wumboNode, wumboNode2, lntemp.OpenChannelParams{Amt: chanAmt}, wumboNode, wumboNode2, lntest.OpenChannelParams{Amt: chanAmt},
) )
ht.CloseChannel(wumboNode, chanPoint) ht.CloseChannel(wumboNode, chanPoint)
} }
@@ -1,7 +1,7 @@
package itest package itest
import ( import (
"context" "fmt"
"testing" "testing"
"time" "time"
@@ -13,10 +13,9 @@ import (
"github.com/lightningnetwork/lnd/chainreg" "github.com/lightningnetwork/lnd/chainreg"
"github.com/lightningnetwork/lnd/lnrpc" "github.com/lightningnetwork/lnd/lnrpc"
"github.com/lightningnetwork/lnd/lnrpc/routerrpc" "github.com/lightningnetwork/lnd/lnrpc/routerrpc"
"github.com/lightningnetwork/lnd/lntemp"
"github.com/lightningnetwork/lnd/lntemp/node"
"github.com/lightningnetwork/lnd/lntemp/rpc"
"github.com/lightningnetwork/lnd/lntest" "github.com/lightningnetwork/lnd/lntest"
"github.com/lightningnetwork/lnd/lntest/node"
"github.com/lightningnetwork/lnd/lntest/rpc"
"github.com/lightningnetwork/lnd/lntest/wait" "github.com/lightningnetwork/lnd/lntest/wait"
"github.com/lightningnetwork/lnd/lnwire" "github.com/lightningnetwork/lnd/lnwire"
"github.com/stretchr/testify/require" "github.com/stretchr/testify/require"
@@ -24,7 +23,7 @@ import (
// testZeroConfChannelOpen tests that opening a zero-conf channel works and // testZeroConfChannelOpen tests that opening a zero-conf channel works and
// sending payments also works. // sending payments also works.
func testZeroConfChannelOpen(ht *lntemp.HarnessTest) { func testZeroConfChannelOpen(ht *lntest.HarnessTest) {
// Since option-scid-alias is opt-in, the provided harness nodes will // Since option-scid-alias is opt-in, the provided harness nodes will
// not have the feature bit set. Also need to set anchors as those are // not have the feature bit set. Also need to set anchors as those are
// default-off in itests. // default-off in itests.
@@ -40,7 +39,7 @@ func testZeroConfChannelOpen(ht *lntemp.HarnessTest) {
// We'll open a regular public channel between Bob and Carol here. // We'll open a regular public channel between Bob and Carol here.
chanAmt := btcutil.Amount(1_000_000) chanAmt := btcutil.Amount(1_000_000)
p := lntemp.OpenChannelParams{ p := lntest.OpenChannelParams{
Amt: chanAmt, Amt: chanAmt,
} }
chanPoint := ht.OpenChannel(bob, carol, p) chanPoint := ht.OpenChannel(bob, carol, p)
@@ -59,7 +58,7 @@ func testZeroConfChannelOpen(ht *lntemp.HarnessTest) {
go acceptChannel(ht.T, true, acceptStream) go acceptChannel(ht.T, true, acceptStream)
// Open a private zero-conf anchors channel of 1M satoshis. // Open a private zero-conf anchors channel of 1M satoshis.
params := lntemp.OpenChannelParams{ params := lntest.OpenChannelParams{
Amt: chanAmt, Amt: chanAmt,
Private: true, Private: true,
CommitmentType: lnrpc.CommitmentType_ANCHORS, CommitmentType: lnrpc.CommitmentType_ANCHORS,
@@ -192,7 +191,7 @@ func testZeroConfChannelOpen(ht *lntemp.HarnessTest) {
// testOptionScidAlias checks that opening an option_scid_alias channel-type // testOptionScidAlias checks that opening an option_scid_alias channel-type
// channel or w/o the channel-type works properly. // channel or w/o the channel-type works properly.
func testOptionScidAlias(ht *lntemp.HarnessTest) { func testOptionScidAlias(ht *lntest.HarnessTest) {
type scidTestCase struct { type scidTestCase struct {
name string name string
@@ -235,7 +234,7 @@ func testOptionScidAlias(ht *lntemp.HarnessTest) {
} }
} }
func optionScidAliasScenario(ht *lntemp.HarnessTest, chantype, private bool) { func optionScidAliasScenario(ht *lntest.HarnessTest, chantype, private bool) {
// Option-scid-alias is opt-in, as is anchors. // Option-scid-alias is opt-in, as is anchors.
scidAliasArgs := []string{ scidAliasArgs := []string{
"--protocol.option-scid-alias", "--protocol.option-scid-alias",
@@ -257,7 +256,7 @@ func optionScidAliasScenario(ht *lntemp.HarnessTest, chantype, private bool) {
chanAmt := btcutil.Amount(1_000_000) chanAmt := btcutil.Amount(1_000_000)
params := lntemp.OpenChannelParams{ params := lntest.OpenChannelParams{
Amt: chanAmt, Amt: chanAmt,
Private: private, Private: private,
CommitmentType: lnrpc.CommitmentType_ANCHORS, CommitmentType: lnrpc.CommitmentType_ANCHORS,
@@ -283,7 +282,7 @@ func optionScidAliasScenario(ht *lntemp.HarnessTest, chantype, private bool) {
// We'll now open a regular public channel between Bob and Carol and // We'll now open a regular public channel between Bob and Carol and
// assert that Bob can pay Dave. We'll also assert that the invoice // assert that Bob can pay Dave. We'll also assert that the invoice
// Dave issues has the startingAlias as a hop hint. // Dave issues has the startingAlias as a hop hint.
p := lntemp.OpenChannelParams{ p := lntest.OpenChannelParams{
Amt: chanAmt, Amt: chanAmt,
} }
fundingPoint2 := ht.OpenChannel(bob, carol, p) fundingPoint2 := ht.OpenChannel(bob, carol, p)
@@ -313,6 +312,7 @@ func optionScidAliasScenario(ht *lntemp.HarnessTest, chantype, private bool) {
require.Len(ht, decodedReq.RouteHints, 0) require.Len(ht, decodedReq.RouteHints, 0)
payReq := daveInvoiceResp2.PaymentRequest payReq := daveInvoiceResp2.PaymentRequest
ht.CompletePaymentRequests(bob, []string{payReq}) ht.CompletePaymentRequests(bob, []string{payReq})
return return
} }
@@ -410,7 +410,7 @@ func waitForZeroConfGraphChange(hn *node.HarnessNode,
// testUpdateChannelPolicyScidAlias checks that option-scid-alias, zero-conf // testUpdateChannelPolicyScidAlias checks that option-scid-alias, zero-conf
// channel-types, and option-scid-alias feature-bit-only channels have the // channel-types, and option-scid-alias feature-bit-only channels have the
// expected graph and that payments work when updating the channel policy. // expected graph and that payments work when updating the channel policy.
func testUpdateChannelPolicyScidAlias(ht *lntemp.HarnessTest) { func testUpdateChannelPolicyScidAlias(ht *lntest.HarnessTest) {
tests := []struct { tests := []struct {
name string name string
@@ -462,7 +462,7 @@ func testUpdateChannelPolicyScidAlias(ht *lntemp.HarnessTest) {
} }
} }
func testPrivateUpdateAlias(ht *lntemp.HarnessTest, func testPrivateUpdateAlias(ht *lntest.HarnessTest,
zeroConf, scidAliasType, private bool) { zeroConf, scidAliasType, private bool) {
// We'll create a new node Eve that will not have option-scid-alias // We'll create a new node Eve that will not have option-scid-alias
@@ -495,7 +495,7 @@ func testPrivateUpdateAlias(ht *lntemp.HarnessTest,
chanAmt := btcutil.Amount(1_000_000) chanAmt := btcutil.Amount(1_000_000)
p := lntemp.OpenChannelParams{ p := lntest.OpenChannelParams{
Amt: chanAmt, Amt: chanAmt,
PushAmt: chanAmt / 2, PushAmt: chanAmt / 2,
} }
@@ -509,7 +509,7 @@ func testPrivateUpdateAlias(ht *lntemp.HarnessTest,
go acceptChannel(ht.T, zeroConf, acceptStream) go acceptChannel(ht.T, zeroConf, acceptStream)
// Open a private channel, optionally specifying a channel-type. // Open a private channel, optionally specifying a channel-type.
params := lntemp.OpenChannelParams{ params := lntest.OpenChannelParams{
Amt: chanAmt, Amt: chanAmt,
Private: private, Private: private,
CommitmentType: lnrpc.CommitmentType_ANCHORS, CommitmentType: lnrpc.CommitmentType_ANCHORS,
@@ -542,7 +542,7 @@ func testPrivateUpdateAlias(ht *lntemp.HarnessTest,
FeeRateMilliMsat: testFeeBase * feeRate, FeeRateMilliMsat: testFeeBase * feeRate,
TimeLockDelta: timeLockDelta, TimeLockDelta: timeLockDelta,
MinHtlc: 1000, // default value MinHtlc: 1000, // default value
MaxHtlcMsat: calculateMaxHtlc(chanAmt), MaxHtlcMsat: lntest.CalculateMaxHtlc(chanAmt),
} }
// Assert that Dave receives Carol's policy update. // Assert that Dave receives Carol's policy update.
@@ -568,7 +568,7 @@ func testPrivateUpdateAlias(ht *lntemp.HarnessTest,
FeeRateMilliMsat: testFeeBase * feeRate, FeeRateMilliMsat: testFeeBase * feeRate,
TimeLockDelta: timeLockDelta, TimeLockDelta: timeLockDelta,
MinHtlc: 1000, MinHtlc: 1000,
MaxHtlcMsat: calculateMaxHtlc(chanAmt), MaxHtlcMsat: lntest.CalculateMaxHtlc(chanAmt),
} }
// Assert that Carol receives Dave's policy update. // Assert that Carol receives Dave's policy update.
@@ -655,7 +655,7 @@ func testPrivateUpdateAlias(ht *lntemp.HarnessTest,
FeeRateMilliMsat: testFeeBase * feeRate, FeeRateMilliMsat: testFeeBase * feeRate,
TimeLockDelta: timeLockDelta, TimeLockDelta: timeLockDelta,
MinHtlc: 1000, MinHtlc: 1000,
MaxHtlcMsat: calculateMaxHtlc(chanAmt), MaxHtlcMsat: lntest.CalculateMaxHtlc(chanAmt),
} }
// Assert Dave receives Carol's policy update. // Assert Dave receives Carol's policy update.
@@ -744,7 +744,7 @@ func testPrivateUpdateAlias(ht *lntemp.HarnessTest,
FeeRateMilliMsat: testFeeBase * feeRate, FeeRateMilliMsat: testFeeBase * feeRate,
TimeLockDelta: timeLockDelta, TimeLockDelta: timeLockDelta,
MinHtlc: 1000, MinHtlc: 1000,
MaxHtlcMsat: calculateMaxHtlc(chanAmt), MaxHtlcMsat: lntest.CalculateMaxHtlc(chanAmt),
} }
// Assert Dave and optionally Eve receives Carol's update. // Assert Dave and optionally Eve receives Carol's update.
@@ -764,7 +764,7 @@ func testPrivateUpdateAlias(ht *lntemp.HarnessTest,
// testOptionScidUpgrade tests that toggling the option-scid-alias feature bit // testOptionScidUpgrade tests that toggling the option-scid-alias feature bit
// correctly upgrades existing channels. // correctly upgrades existing channels.
func testOptionScidUpgrade(ht *lntemp.HarnessTest) { func testOptionScidUpgrade(ht *lntest.HarnessTest) {
bob := ht.Bob bob := ht.Bob
// Start carol with anchors only. // Start carol with anchors only.
@@ -788,7 +788,7 @@ func testOptionScidUpgrade(ht *lntemp.HarnessTest) {
chanAmt := btcutil.Amount(1_000_000) chanAmt := btcutil.Amount(1_000_000)
p := lntemp.OpenChannelParams{ p := lntest.OpenChannelParams{
Amt: chanAmt, Amt: chanAmt,
PushAmt: chanAmt / 2, PushAmt: chanAmt / 2,
Private: true, Private: true,
@@ -798,7 +798,7 @@ func testOptionScidUpgrade(ht *lntemp.HarnessTest) {
// Bob will open a channel to Carol now. // Bob will open a channel to Carol now.
ht.EnsureConnected(bob, carol) ht.EnsureConnected(bob, carol)
p = lntemp.OpenChannelParams{ p = lntest.OpenChannelParams{
Amt: chanAmt, Amt: chanAmt,
} }
fundingPoint2 := ht.OpenChannel(bob, carol, p) fundingPoint2 := ht.OpenChannel(bob, carol, p)
@@ -822,25 +822,34 @@ func testOptionScidUpgrade(ht *lntemp.HarnessTest) {
var startingAlias lnwire.ShortChannelID var startingAlias lnwire.ShortChannelID
startingAlias.BlockHeight = 16_000_000 startingAlias.BlockHeight = 16_000_000
err := wait.Predicate(func() bool { // TODO(yy): Carol and Dave will attempt to connect to each other
// during restart. However, due to the race condition in peer
// connection, they may both fail. Thus we need to ensure the
// connection here. Once the race is fixed, we can remove this line.
ht.EnsureConnected(dave, carol)
err := wait.NoError(func() error {
invoiceResp := dave.RPC.AddInvoice(daveParams) invoiceResp := dave.RPC.AddInvoice(daveParams)
decodedReq := dave.RPC.DecodePayReq(invoiceResp.PaymentRequest) decodedReq := dave.RPC.DecodePayReq(invoiceResp.PaymentRequest)
if len(decodedReq.RouteHints) != 1 { if len(decodedReq.RouteHints) != 1 {
return false return fmt.Errorf("expected 1 route hint, got %v",
decodedReq.RouteHints)
} }
if len(decodedReq.RouteHints[0].HopHints) != 1 { if len(decodedReq.RouteHints[0].HopHints) != 1 {
return false return fmt.Errorf("expected 1 hop hint, got %v",
len(decodedReq.RouteHints[0].HopHints))
} }
hopHint := decodedReq.RouteHints[0].HopHints[0].ChanId hopHint := decodedReq.RouteHints[0].HopHints[0].ChanId
if startingAlias.ToUint64() == hopHint { if startingAlias.ToUint64() == hopHint {
daveInvoice = invoiceResp daveInvoice = invoiceResp
return true return nil
} }
return false return fmt.Errorf("unmatched alias, expected %v, got %v",
startingAlias.ToUint64(), hopHint)
}, defaultTimeout) }, defaultTimeout)
require.NoError(ht, err) require.NoError(ht, err)
@@ -892,15 +901,12 @@ func acceptChannel(t *testing.T, zeroConf bool, stream rpc.AcceptorClient) {
// testZeroConfReorg tests that a reorg does not cause a zero-conf channel to // testZeroConfReorg tests that a reorg does not cause a zero-conf channel to
// be deleted from the channel graph. This was previously the case due to logic // be deleted from the channel graph. This was previously the case due to logic
// in the function DisconnectBlockAtHeight. // in the function DisconnectBlockAtHeight.
func testZeroConfReorg(ht *lntemp.HarnessTest) { func testZeroConfReorg(ht *lntest.HarnessTest) {
if ht.ChainBackendName() == lntest.NeutrinoBackendName { if ht.IsNeutrinoBackend() {
ht.Skipf("skipping zero-conf reorg test for neutrino backend") ht.Skipf("skipping zero-conf reorg test for neutrino backend")
} }
var ( var temp = "temp"
ctxb = context.Background()
temp = "temp"
)
// Since zero-conf is opt in, the harness nodes provided won't be able // Since zero-conf is opt in, the harness nodes provided won't be able
// to open zero-conf channels. In that case, we just spin up new nodes. // to open zero-conf channels. In that case, we just spin up new nodes.
@@ -926,7 +932,7 @@ func testZeroConfReorg(ht *lntemp.HarnessTest) {
go acceptChannel(ht.T, true, acceptStream) go acceptChannel(ht.T, true, acceptStream)
// Open a private zero-conf anchors channel of 1M satoshis. // Open a private zero-conf anchors channel of 1M satoshis.
params := lntemp.OpenChannelParams{ params := lntest.OpenChannelParams{
Amt: btcutil.Amount(1_000_000), Amt: btcutil.Amount(1_000_000),
CommitmentType: lnrpc.CommitmentType_ANCHORS, CommitmentType: lnrpc.CommitmentType_ANCHORS,
ZeroConf: true, ZeroConf: true,
@@ -949,10 +955,9 @@ func testZeroConfReorg(ht *lntemp.HarnessTest) {
// We will now attempt to query for the alias SCID in Carol's graph. // We will now attempt to query for the alias SCID in Carol's graph.
// We will query for the starting alias, which is exported by the // We will query for the starting alias, which is exported by the
// aliasmgr package. // aliasmgr package.
_, err := carol.RPC.LN.GetChanInfo(ctxb, &lnrpc.ChanInfoRequest{ carol.RPC.GetChanInfo(&lnrpc.ChanInfoRequest{
ChanId: aliasmgr.StartingAlias.ToUint64(), ChanId: aliasmgr.StartingAlias.ToUint64(),
}) })
require.NoError(ht.T, err)
// Now we will trigger a reorg and we'll assert that the edge still // Now we will trigger a reorg and we'll assert that the edge still
// exists in the graph. // exists in the graph.
@@ -960,7 +965,7 @@ func testZeroConfReorg(ht *lntemp.HarnessTest) {
// First, we'll setup a new miner that we can use to cause a reorg. // First, we'll setup a new miner that we can use to cause a reorg.
tempLogDir := ".tempminerlogs" tempLogDir := ".tempminerlogs"
logFilename := "output-open_channel_reorg-temp_miner.log" logFilename := "output-open_channel_reorg-temp_miner.log"
tempMiner := lntemp.NewTempMiner( tempMiner := lntest.NewTempMiner(
ht.Context(), ht.T, tempLogDir, logFilename, ht.Context(), ht.T, tempLogDir, logFilename,
) )
defer tempMiner.Stop() defer tempMiner.Stop()
@@ -971,7 +976,7 @@ func testZeroConfReorg(ht *lntemp.HarnessTest) {
// We start by connecting the new miner to our original miner, such // We start by connecting the new miner to our original miner, such
// that it will sync to our original chain. // that it will sync to our original chain.
err = ht.Miner.Client.Node( err := ht.Miner.Client.Node(
btcjson.NConnect, tempMiner.P2PAddress(), &temp, btcjson.NConnect, tempMiner.P2PAddress(), &temp,
) )
require.NoError(ht.T, err, "unable to connect node") require.NoError(ht.T, err, "unable to connect node")
@@ -991,18 +996,16 @@ func testZeroConfReorg(ht *lntemp.HarnessTest) {
require.NoError(ht.T, err, "unable to remove node") require.NoError(ht.T, err, "unable to remove node")
// We now cause a fork, by letting our original miner mine 1 block and // We now cause a fork, by letting our original miner mine 1 block and
// our new miner will mine 2. // our new miner will mine 2. We also expect the funding transition to
ht.MineBlocks(1) // be mined.
_, err = tempMiner.Client.Generate(2) ht.MineBlocksAndAssertNumTxes(1, 1)
require.NoError(ht.T, err, "unable to generate blocks") tempMiner.MineEmptyBlocks(2)
// Ensure the temp miner is one block ahead. // Ensure the temp miner is one block ahead.
assertMinerBlockHeightDelta(ht, ht.Miner, tempMiner, 1) assertMinerBlockHeightDelta(ht, ht.Miner, tempMiner, 1)
// Wait for Carol to sync to the original miner's chain. // Wait for Carol to sync to the original miner's chain.
_, minerHeight, err := ht.Miner.Client.GetBestBlock() _, minerHeight := ht.Miner.GetBestBlock()
require.NoError(ht.T, err, "unable to get current blockheight")
ht.WaitForNodeBlockHeight(carol, minerHeight) ht.WaitForNodeBlockHeight(carol, minerHeight)
// Now we'll disconnect Carol's chain backend from the original miner // Now we'll disconnect Carol's chain backend from the original miner
@@ -1033,24 +1036,19 @@ func testZeroConfReorg(ht *lntemp.HarnessTest) {
ht.ConnectMiner() ht.ConnectMiner()
// This should have caused a reorg and Alice should sync to the new // This should have caused a reorg and Carol should sync to the new
// chain. // chain.
_, tempMinerHeight, err := tempMiner.Client.GetBestBlock() _, tempMinerHeight := tempMiner.GetBestBlock()
require.NoError(ht.T, err, "unable to get current blockheight")
ht.WaitForNodeBlockHeight(carol, tempMinerHeight) ht.WaitForNodeBlockHeight(carol, tempMinerHeight)
err = wait.Predicate(func() bool { // Make sure all active nodes are synced.
ctxt, _ := context.WithTimeout(ctxb, defaultTimeout) ht.AssertActiveNodesSynced()
_, err = carol.RPC.LN.GetChanInfo(ctxt, &lnrpc.ChanInfoRequest{ // Carol should have the channel once synced.
ChanId: aliasmgr.StartingAlias.ToUint64(), carol.RPC.GetChanInfo(&lnrpc.ChanInfoRequest{
}) ChanId: aliasmgr.StartingAlias.ToUint64(),
})
return err == nil
}, defaultTimeout)
require.NoError(ht.T, err, "carol doesn't have zero-conf edge")
// Mine the zero-conf funding transaction so the test doesn't fail. // Mine the zero-conf funding transaction so the test doesn't fail.
ht.MineBlocks(1) ht.MineBlocksAndAssertNumTxes(1, 1)
} }
File renamed without changes.
File renamed without changes.
-3
View File
@@ -1,6 +1,3 @@
//go:build !rpctest
// +build !rpctest
package lncfg package lncfg
import ( import (
+1 -2
View File
@@ -1,5 +1,4 @@
//go:build !rpctest //go:build !integration
// +build !rpctest
package lncfg package lncfg
@@ -1,5 +1,4 @@
//go:build rpctest //go:build integration
// +build rpctest
package lncfg package lncfg
@@ -7,6 +6,8 @@ package lncfg
// compatibility of protocol additions, while defaulting to the latest within // compatibility of protocol additions, while defaulting to the latest within
// lnd, or to enable experimental protocol changes. // lnd, or to enable experimental protocol changes.
// //
// TODO(yy): delete this build flag to unify with `lncfg/protocol.go`.
//
//nolint:lll //nolint:lll
type ProtocolOptions struct { type ProtocolOptions struct {
// LegacyProtocol is a sub-config that houses all the legacy protocol // LegacyProtocol is a sub-config that houses all the legacy protocol
-140
View File
@@ -1,140 +0,0 @@
package lntemp
import (
"context"
"encoding/json"
"fmt"
"io"
"net/http"
"sync"
"testing"
"github.com/lightningnetwork/lnd/lntest"
"github.com/lightningnetwork/lnd/lnwallet/chainfee"
"github.com/stretchr/testify/require"
)
// 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 `--feeurl` and uses the customized fee
// estimator.
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)
}
const (
// feeServiceTarget is the confirmation target for which a fee estimate
// is returned. Requests for higher confirmation targets will fall back
// to this.
feeServiceTarget = 1
// DefaultFeeRateSatPerKw specifies the default fee rate used in the
// tests.
DefaultFeeRateSatPerKw = 12500
)
// FeeService runs a web service that provides fee estimation information.
type FeeService struct {
*testing.T
feeRateMap map[uint32]uint32
url string
srv *http.Server
wg sync.WaitGroup
lock sync.Mutex
}
// Compile-time check for the WebFeeService interface.
var _ WebFeeService = (*FeeService)(nil)
// Start spins up a go-routine to serve fee estimates.
func NewFeeService(t *testing.T) *FeeService {
port := lntest.NextAvailablePort()
f := FeeService{
T: t,
url: fmt.Sprintf(
"http://localhost:%v/fee-estimates.json", port,
),
}
// Initialize default fee estimate.
f.feeRateMap = map[uint32]uint32{
feeServiceTarget: DefaultFeeRateSatPerKw,
}
listenAddr := fmt.Sprintf(":%v", port)
mux := http.NewServeMux()
mux.HandleFunc("/fee-estimates.json", f.handleRequest)
f.srv = &http.Server{
Addr: listenAddr,
Handler: mux,
}
return &f
}
// Start starts the web server.
func (f *FeeService) Start() error {
f.wg.Add(1)
go func() {
defer f.wg.Done()
if err := f.srv.ListenAndServe(); err != http.ErrServerClosed {
require.NoErrorf(f, err, "cannot start fee api")
}
}()
return nil
}
// handleRequest handles a client request for fee estimates.
func (f *FeeService) handleRequest(w http.ResponseWriter, r *http.Request) {
f.lock.Lock()
defer f.lock.Unlock()
bytes, err := json.Marshal(
struct {
Fees map[uint32]uint32 `json:"fee_by_block_target"`
}{
Fees: f.feeRateMap,
},
)
require.NoErrorf(f, err, "cannot serialize estimates")
_, err = io.WriteString(w, string(bytes))
require.NoError(f, err, "cannot send estimates")
}
// Stop stops the web server.
func (f *FeeService) Stop() error {
err := f.srv.Shutdown(context.Background())
require.NoError(f, err, "cannot stop fee api")
f.wg.Wait()
return nil
}
// SetFeeRate sets a fee for the given confirmation target.
func (f *FeeService) SetFeeRate(fee chainfee.SatPerKWeight, conf uint32) {
f.lock.Lock()
defer f.lock.Unlock()
f.feeRateMap[conf] = uint32(fee.FeePerKVByte())
}
// URL returns the service endpoint.
func (f *FeeService) URL() string {
return f.url
}
-438
View File
@@ -1,438 +0,0 @@
package lntemp
import (
"bytes"
"context"
"fmt"
"io/ioutil"
"os"
"path/filepath"
"strings"
"testing"
"time"
"github.com/btcsuite/btcd/btcjson"
"github.com/btcsuite/btcd/btcutil"
"github.com/btcsuite/btcd/chaincfg"
"github.com/btcsuite/btcd/chaincfg/chainhash"
"github.com/btcsuite/btcd/integration/rpctest"
"github.com/btcsuite/btcd/rpcclient"
"github.com/btcsuite/btcd/wire"
"github.com/lightningnetwork/lnd/lntest"
"github.com/lightningnetwork/lnd/lntest/wait"
"github.com/stretchr/testify/require"
)
const (
// minerLogFilename is the default log filename for the miner node.
minerLogFilename = "output_btcd_miner.log"
// minerLogDir is the default log dir for the miner node.
minerLogDir = ".minerlogs"
// slowMineDelay defines a wait period between mining new blocks.
slowMineDelay = 100 * time.Millisecond
)
var harnessNetParams = &chaincfg.RegressionNetParams
type HarnessMiner struct {
*testing.T
*rpctest.Harness
// runCtx is a context with cancel method. It's used to signal when the
// node needs to quit, and used as the parent context when spawning
runCtx context.Context
cancel context.CancelFunc
// logPath is the directory path of the miner's logs.
logPath string
// logFilename is the saved log filename of the miner node.
logFilename string
}
// NewMiner creates a new miner using btcd backend with the default log file
// dir and name.
func NewMiner(ctxt context.Context, t *testing.T) *HarnessMiner {
return newMiner(ctxt, t, minerLogDir, minerLogFilename)
}
// NewTempMiner creates a new miner using btcd backend with the specified log
// file dir and name.
func NewTempMiner(ctxt context.Context, t *testing.T,
tempDir, tempLogFilename string) *HarnessMiner {
t.Helper()
return newMiner(ctxt, t, tempDir, tempLogFilename)
}
// newMiner creates a new miner using btcd's rpctest.
func newMiner(ctxb context.Context, t *testing.T, minerDirName,
logFilename string) *HarnessMiner {
handler := &rpcclient.NotificationHandlers{}
btcdBinary := lntest.GetBtcdBinary()
baseLogPath := fmt.Sprintf("%s/%s", lntest.GetLogDir(), minerDirName)
args := []string{
"--rejectnonstd",
"--txindex",
"--nowinservice",
"--nobanning",
"--debuglevel=debug",
"--logdir=" + baseLogPath,
"--trickleinterval=100ms",
// Don't disconnect if a reply takes too long.
"--nostalldetect",
}
miner, err := rpctest.New(harnessNetParams, handler, args, btcdBinary)
require.NoError(t, err, "unable to create mining node")
ctxt, cancel := context.WithCancel(ctxb)
return &HarnessMiner{
T: t,
Harness: miner,
runCtx: ctxt,
cancel: cancel,
logPath: baseLogPath,
logFilename: logFilename,
}
}
// saveLogs copies the node logs and save it to the file specified by
// h.logFilename.
func (h *HarnessMiner) saveLogs() {
// After shutting down the miner, we'll make a copy of the log files
// before deleting the temporary log dir.
path := fmt.Sprintf("%s/%s", h.logPath, harnessNetParams.Name)
files, err := ioutil.ReadDir(path)
require.NoError(h, err, "unable to read log directory")
for _, file := range files {
newFilename := strings.Replace(
file.Name(), "btcd.log", h.logFilename, 1,
)
copyPath := fmt.Sprintf("%s/../%s", h.logPath, newFilename)
logFile := fmt.Sprintf("%s/%s", path, file.Name())
err := CopyFile(filepath.Clean(copyPath), logFile)
require.NoError(h, err, "unable to copy file")
}
err = os.RemoveAll(h.logPath)
require.NoErrorf(h, err, "cannot remove dir %s", h.logPath)
}
// Stop shuts down the miner and saves its logs.
func (h *HarnessMiner) Stop() {
h.cancel()
require.NoError(h, h.TearDown(), "tear down miner got error")
h.saveLogs()
}
// GetBestBlock makes a RPC request to miner and asserts.
func (h *HarnessMiner) GetBestBlock() (*chainhash.Hash, int32) {
blockHash, height, err := h.Client.GetBestBlock()
require.NoError(h, err, "failed to GetBestBlock")
return blockHash, height
}
// GetRawMempool makes a RPC call to the miner's GetRawMempool and
// asserts.
func (h *HarnessMiner) GetRawMempool() []*chainhash.Hash {
mempool, err := h.Client.GetRawMempool()
require.NoError(h, err, "unable to get mempool")
return mempool
}
// GenerateBlocks mine 'num' of blocks and returns them.
func (h *HarnessMiner) GenerateBlocks(num uint32) []*chainhash.Hash {
blockHashes, err := h.Client.Generate(num)
require.NoError(h, err, "unable to generate blocks")
require.Len(h, blockHashes, int(num), "wrong num of blocks generated")
return blockHashes
}
// GetBlock gets a block using its block hash.
func (h *HarnessMiner) GetBlock(blockHash *chainhash.Hash) *wire.MsgBlock {
block, err := h.Client.GetBlock(blockHash)
require.NoError(h, err, "unable to get block")
return block
}
// MineBlocks mine 'num' of blocks and check that blocks are present in
// node blockchain.
func (h *HarnessMiner) MineBlocks(num uint32) []*wire.MsgBlock {
blocks := make([]*wire.MsgBlock, num)
blockHashes := h.GenerateBlocks(num)
for i, blockHash := range blockHashes {
block := h.GetBlock(blockHash)
blocks[i] = block
}
return blocks
}
// 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 (h *HarnessMiner) AssertNumTxsInMempool(n int) []*chainhash.Hash {
var (
mem []*chainhash.Hash
err error
)
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.
mem = h.GetRawMempool()
if len(mem) == n {
return nil
}
return fmt.Errorf("want %v, got %v in mempool: %v",
n, len(mem), mem)
}, lntest.MinerMempoolTimeout)
require.NoError(h, err, "assert tx in mempool timeout")
return mem
}
// AssertTxInBlock asserts that a given txid can be found in the passed block.
func (h *HarnessMiner) AssertTxInBlock(block *wire.MsgBlock,
txid *chainhash.Hash) {
blockTxes := make([]chainhash.Hash, 0)
for _, tx := range block.Transactions {
sha := tx.TxHash()
blockTxes = append(blockTxes, sha)
if bytes.Equal(txid[:], sha[:]) {
return
}
}
require.Failf(h, "tx was not included in block", "tx:%v, block has:%v",
txid, blockTxes)
}
// 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 (h *HarnessMiner) MineBlocksAndAssertNumTxes(num uint32,
numTxs int) []*wire.MsgBlock {
// If we expect transactions to be included in the blocks we'll mine,
// we wait here until they are seen in the miner's mempool.
txids := h.AssertNumTxsInMempool(numTxs)
// Mine blocks.
blocks := h.MineBlocks(num)
// Finally, assert that all the transactions were included in the first
// block.
for _, txid := range txids {
h.AssertTxInBlock(blocks[0], txid)
}
return blocks
}
// GetRawTransaction makes a RPC call to the miner's GetRawTransaction and
// asserts.
func (h *HarnessMiner) GetRawTransaction(txid *chainhash.Hash) *btcutil.Tx {
tx, err := h.Client.GetRawTransaction(txid)
require.NoErrorf(h, err, "failed to get raw tx: %v", txid)
return tx
}
// GetRawTransactionVerbose makes a RPC call to the miner's
// GetRawTransactionVerbose and asserts.
func (h *HarnessMiner) GetRawTransactionVerbose(
txid *chainhash.Hash) *btcjson.TxRawResult {
tx, err := h.Client.GetRawTransactionVerbose(txid)
require.NoErrorf(h, err, "failed to get raw tx verbose: %v", txid)
return tx
}
// AssertTxInMempool asserts a given transaction can be found in the mempool.
func (h *HarnessMiner) AssertTxInMempool(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 *memTx == *txid {
return nil
}
}
return fmt.Errorf("txid %v not found in mempool: %v", txid,
mempool)
}, lntest.MinerMempoolTimeout)
require.NoError(h, err, "timeout checking mempool")
return msgTx
}
// SendOutputsWithoutChange uses the miner to send the given outputs using the
// specified fee rate and returns the txid.
func (h *HarnessMiner) SendOutputsWithoutChange(outputs []*wire.TxOut,
feeRate btcutil.Amount) *chainhash.Hash {
txid, err := h.Harness.SendOutputsWithoutChange(
outputs, feeRate,
)
require.NoErrorf(h, err, "failed to send output")
return txid
}
// CreateTransaction uses the miner to create a transaction using the given
// outputs using the specified fee rate and returns the transaction.
func (h *HarnessMiner) CreateTransaction(outputs []*wire.TxOut,
feeRate btcutil.Amount) *wire.MsgTx {
tx, err := h.Harness.CreateTransaction(outputs, feeRate, false)
require.NoErrorf(h, err, "failed to create transaction")
return tx
}
// SendOutput creates, signs, and finally broadcasts a transaction spending
// the harness' available mature coinbase outputs to create the new output.
func (h *HarnessMiner) SendOutput(newOutput *wire.TxOut,
feeRate btcutil.Amount) *chainhash.Hash {
hash, err := h.Harness.SendOutputs([]*wire.TxOut{newOutput}, feeRate)
require.NoErrorf(h, err, "failed to send outputs")
return hash
}
// MineBlocksSlow mines 'num' of blocks. Between each mined block an artificial
// delay is introduced to give all network participants time to catch up.
func (h *HarnessMiner) MineBlocksSlow(num uint32) []*wire.MsgBlock {
blocks := make([]*wire.MsgBlock, num)
blockHashes := make([]*chainhash.Hash, 0, num)
for i := uint32(0); i < num; i++ {
generatedHashes := h.GenerateBlocks(1)
blockHashes = append(blockHashes, generatedHashes...)
time.Sleep(slowMineDelay)
}
for i, blockHash := range blockHashes {
block, err := h.Client.GetBlock(blockHash)
require.NoError(h, err, "get blocks")
blocks[i] = block
}
return blocks
}
// AssertOutpointInMempool asserts a given outpoint can be found in the mempool.
func (h *HarnessMiner) AssertOutpointInMempool(op wire.OutPoint) *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 _, txid := range mempool {
// We require the RPC call to be succeeded and won't
// wait for it as it's an unexpected behavior.
tx := h.GetRawTransaction(txid)
msgTx = tx.MsgTx()
for _, txIn := range msgTx.TxIn {
if txIn.PreviousOutPoint == op {
return nil
}
}
}
return fmt.Errorf("outpoint %v not found in mempool", op)
}, lntest.MinerMempoolTimeout)
require.NoError(h, err, "timeout checking mempool")
return msgTx
}
// GetNumTxsFromMempool polls until finding the desired number of transactions
// in the miner's mempool and returns the full transactions to the caller.
func (h *HarnessMiner) GetNumTxsFromMempool(n int) []*wire.MsgTx {
txids := h.AssertNumTxsInMempool(n)
var txes []*wire.MsgTx
for _, txid := range txids {
tx := h.GetRawTransaction(txid)
txes = append(txes, tx.MsgTx())
}
return txes
}
// NewMinerAddress creates a new address for the miner and asserts.
func (h *HarnessMiner) NewMinerAddress() btcutil.Address {
addr, err := h.NewAddress()
require.NoError(h, err, "failed to create new miner address")
return addr
}
// MineBlocksWithTxes mines a single block to include the specifies
// transactions only.
func (h *HarnessMiner) MineBlockWithTxes(txes []*btcutil.Tx) *wire.MsgBlock {
var emptyTime time.Time
// Generate a block.
b, err := h.GenerateAndSubmitBlock(txes, -1, emptyTime)
require.NoError(h, err, "unable to mine block")
block, err := h.Client.GetBlock(b.Hash())
require.NoError(h, err, "unable to get block")
return block
}
// MineEmptyBlocks mines a given number of empty blocks.
func (h *HarnessMiner) MineEmptyBlocks(num int) []*wire.MsgBlock {
var emptyTime time.Time
blocks := make([]*wire.MsgBlock, num)
for i := 0; i < num; i++ {
// Generate an empty block.
b, err := h.GenerateAndSubmitBlock(nil, -1, emptyTime)
require.NoError(h, err, "unable to mine empty block")
block := h.GetBlock(b.Hash())
blocks[i] = block
}
return blocks
}
+21
View File
@@ -93,3 +93,24 @@ 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 further validates the current test case has no dangling uncleaned states, such
as transactions left in mempool, open channels, etc. 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.checkPeerFundingLockInterval`, which is used when we wait for the
peer to send us `FundingLocked`. 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.
+11 -8
View File
@@ -14,6 +14,7 @@ import (
"github.com/btcsuite/btcd/chaincfg" "github.com/btcsuite/btcd/chaincfg"
"github.com/btcsuite/btcd/rpcclient" "github.com/btcsuite/btcd/rpcclient"
"github.com/lightningnetwork/lnd/lntest/node"
) )
// logDirPattern is the pattern of the name of the temporary log directory. // logDirPattern is the pattern of the name of the temporary log directory.
@@ -37,7 +38,7 @@ type BitcoindBackendConfig struct {
// A compile time assertion to ensure BitcoindBackendConfig meets the // A compile time assertion to ensure BitcoindBackendConfig meets the
// BackendConfig interface. // BackendConfig interface.
var _ BackendConfig = (*BitcoindBackendConfig)(nil) var _ node.BackendConfig = (*BitcoindBackendConfig)(nil)
// GenArgs returns the arguments needed to be passed to LND at startup for // GenArgs returns the arguments needed to be passed to LND at startup for
// using this node as a chain backend. // using this node as a chain backend.
@@ -89,7 +90,7 @@ func (b BitcoindBackendConfig) Name() string {
func newBackend(miner string, netParams *chaincfg.Params, extraArgs []string, func newBackend(miner string, netParams *chaincfg.Params, extraArgs []string,
rpcPolling bool) (*BitcoindBackendConfig, func() error, error) { rpcPolling bool) (*BitcoindBackendConfig, func() error, error) {
baseLogDir := fmt.Sprintf(logDirPattern, GetLogDir()) baseLogDir := fmt.Sprintf(logDirPattern, node.GetLogDir())
if netParams != &chaincfg.RegressionNetParams { if netParams != &chaincfg.RegressionNetParams {
return nil, nil, fmt.Errorf("only regtest supported") return nil, nil, fmt.Errorf("only regtest supported")
} }
@@ -109,10 +110,12 @@ func newBackend(miner string, netParams *chaincfg.Params, extraArgs []string,
fmt.Errorf("unable to create temp directory: %v", err) fmt.Errorf("unable to create temp directory: %v", err)
} }
zmqBlockAddr := fmt.Sprintf("tcp://127.0.0.1:%d", NextAvailablePort()) zmqBlockAddr := fmt.Sprintf("tcp://127.0.0.1:%d",
zmqTxAddr := fmt.Sprintf("tcp://127.0.0.1:%d", NextAvailablePort()) node.NextAvailablePort())
rpcPort := NextAvailablePort() zmqTxAddr := fmt.Sprintf("tcp://127.0.0.1:%d",
p2pPort := NextAvailablePort() node.NextAvailablePort())
rpcPort := node.NextAvailablePort()
p2pPort := node.NextAvailablePort()
cmdArgs := []string{ cmdArgs := []string{
"-datadir=" + tempBitcoindDir, "-datadir=" + tempBitcoindDir,
@@ -146,9 +149,9 @@ func newBackend(miner string, netParams *chaincfg.Params, extraArgs []string,
// After shutting down the chain backend, we'll make a copy of // After shutting down the chain backend, we'll make a copy of
// the log file before deleting the temporary log dir. // the log file before deleting the temporary log dir.
logDestination := fmt.Sprintf( logDestination := fmt.Sprintf(
"%s/output_bitcoind_chainbackend.log", GetLogDir(), "%s/output_bitcoind_chainbackend.log", node.GetLogDir(),
) )
err := CopyFile(logDestination, logFile) err := node.CopyFile(logDestination, logFile)
if err != nil { if err != nil {
errStr += fmt.Sprintf("unable to copy file: %v\n", err) errStr += fmt.Sprintf("unable to copy file: %v\n", err)
} }
+23 -11
View File
@@ -15,6 +15,7 @@ import (
"github.com/btcsuite/btcd/chaincfg" "github.com/btcsuite/btcd/chaincfg"
"github.com/btcsuite/btcd/integration/rpctest" "github.com/btcsuite/btcd/integration/rpctest"
"github.com/btcsuite/btcd/rpcclient" "github.com/btcsuite/btcd/rpcclient"
"github.com/lightningnetwork/lnd/lntest/node"
) )
// logDirPattern is the pattern of the name of the temporary log directory. // logDirPattern is the pattern of the name of the temporary log directory.
@@ -41,7 +42,7 @@ type BtcdBackendConfig struct {
// A compile time assertion to ensure BtcdBackendConfig meets the BackendConfig // A compile time assertion to ensure BtcdBackendConfig meets the BackendConfig
// interface. // interface.
var _ BackendConfig = (*BtcdBackendConfig)(nil) var _ node.BackendConfig = (*BtcdBackendConfig)(nil)
// GenArgs returns the arguments needed to be passed to LND at startup for // GenArgs returns the arguments needed to be passed to LND at startup for
// using this node as a chain backend. // using this node as a chain backend.
@@ -83,7 +84,7 @@ func (b BtcdBackendConfig) Name() string {
func NewBackend(miner string, netParams *chaincfg.Params) ( func NewBackend(miner string, netParams *chaincfg.Params) (
*BtcdBackendConfig, func() error, error) { *BtcdBackendConfig, func() error, error) {
baseLogDir := fmt.Sprintf(logDirPattern, GetLogDir()) baseLogDir := fmt.Sprintf(logDirPattern, node.GetLogDir())
args := []string{ args := []string{
"--rejectnonstd", "--rejectnonstd",
"--txindex", "--txindex",
@@ -98,9 +99,12 @@ func NewBackend(miner string, netParams *chaincfg.Params) (
// Don't disconnect if a reply takes too long. // Don't disconnect if a reply takes too long.
"--nostalldetect", "--nostalldetect",
} }
chainBackend, err := rpctest.New(netParams, nil, args, GetBtcdBinary()) chainBackend, err := rpctest.New(
netParams, nil, args, node.GetBtcdBinary(),
)
if err != nil { if err != nil {
return nil, nil, fmt.Errorf("unable to create btcd node: %v", err) return nil, nil, fmt.Errorf("unable to create btcd node: %w",
err)
} }
// We want to overwrite some of the connection settings to make the // We want to overwrite some of the connection settings to make the
@@ -108,11 +112,17 @@ func NewBackend(miner string, netParams *chaincfg.Params) (
// are already blocks present, which will take a bit longer than the // are already blocks present, which will take a bit longer than the
// 1 second the default settings amount to. Doubling both values will // 1 second the default settings amount to. Doubling both values will
// give us retries up to 4 seconds. // give us retries up to 4 seconds.
chainBackend.MaxConnRetries = rpctest.DefaultMaxConnectionRetries * 2 const (
chainBackend.ConnectionRetryTimeout = rpctest.DefaultConnectionRetryTimeout * 2 maxConnRetries = rpctest.DefaultMaxConnectionRetries * 2
connRetryTimeout = rpctest.DefaultConnectionRetryTimeout * 2
)
chainBackend.MaxConnRetries = maxConnRetries
chainBackend.ConnectionRetryTimeout = connRetryTimeout
if err := chainBackend.SetUp(false, 0); err != nil { if err := chainBackend.SetUp(false, 0); err != nil {
return nil, nil, fmt.Errorf("unable to set up btcd backend: %v", err) return nil, nil, fmt.Errorf("unable to set up btcd backend: %w",
err)
} }
bd := &BtcdBackendConfig{ bd := &BtcdBackendConfig{
@@ -141,14 +151,16 @@ func NewBackend(miner string, netParams *chaincfg.Params) (
for _, file := range files { for _, file := range files {
logFile := fmt.Sprintf("%s/%s", logDir, file.Name()) logFile := fmt.Sprintf("%s/%s", logDir, file.Name())
newFilename := strings.Replace( newFilename := strings.Replace(
file.Name(), "btcd.log", "output_btcd_chainbackend.log", 1, file.Name(), "btcd.log",
"output_btcd_chainbackend.log", 1,
) )
logDestination := fmt.Sprintf( logDestination := fmt.Sprintf(
"%s/%s", GetLogDir(), newFilename, "%s/%s", node.GetLogDir(), newFilename,
) )
err := CopyFile(logDestination, logFile) err := node.CopyFile(logDestination, logFile)
if err != nil { if err != nil {
errStr += fmt.Sprintf("unable to copy file: %v\n", err) errStr += fmt.Sprintf("unable to copy file: "+
"%v\n", err)
} }
} }
+76 -46
View File
@@ -9,45 +9,72 @@ import (
"sync" "sync"
"testing" "testing"
"github.com/lightningnetwork/lnd/lntest/node"
"github.com/lightningnetwork/lnd/lnwallet/chainfee" "github.com/lightningnetwork/lnd/lnwallet/chainfee"
"github.com/stretchr/testify/require"
) )
// 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 `--feeurl` and uses the customized fee
// estimator.
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)
}
const ( const (
// feeServiceTarget is the confirmation target for which a fee estimate // feeServiceTarget is the confirmation target for which a fee estimate
// is returned. Requests for higher confirmation targets will fall back // is returned. Requests for higher confirmation targets will fall back
// to this. // to this.
feeServiceTarget = 1 feeServiceTarget = 1
// DefaultFeeRateSatPerKw specifies the default fee rate used in the
// tests.
DefaultFeeRateSatPerKw = 12500
) )
// feeService runs a web service that provides fee estimation information. // FeeService runs a web service that provides fee estimation information.
type feeService struct { type FeeService struct {
feeEstimates *testing.T
t *testing.T feeRateMap map[uint32]uint32
url string
srv *http.Server
wg sync.WaitGroup
url string
srv *http.Server
wg sync.WaitGroup
lock sync.Mutex lock sync.Mutex
} }
// feeEstimates contains the current fee estimates. // Compile-time check for the WebFeeService interface.
type feeEstimates struct { var _ WebFeeService = (*FeeService)(nil)
Fees map[uint32]uint32 `json:"fee_by_block_target"`
}
// startFeeService spins up a go-routine to serve fee estimates. // Start spins up a go-routine to serve fee estimates.
func startFeeService(t *testing.T) *feeService { func NewFeeService(t *testing.T) *FeeService {
port := NextAvailablePort() t.Helper()
f := feeService{
t: t, port := node.NextAvailablePort()
url: fmt.Sprintf("http://localhost:%v/fee-estimates.json", port), f := FeeService{
T: t,
url: fmt.Sprintf(
"http://localhost:%v/fee-estimates.json", port,
),
} }
// Initialize default fee estimate. // Initialize default fee estimate.
f.Fees = map[uint32]uint32{feeServiceTarget: 50000} f.feeRateMap = map[uint32]uint32{
feeServiceTarget: DefaultFeeRateSatPerKw,
}
listenAddr := fmt.Sprintf(":%v", port) listenAddr := fmt.Sprintf(":%v", port)
mux := http.NewServeMux() mux := http.NewServeMux()
@@ -58,57 +85,60 @@ func startFeeService(t *testing.T) *feeService {
Handler: mux, Handler: mux,
} }
return &f
}
// Start starts the web server.
func (f *FeeService) Start() error {
f.wg.Add(1) f.wg.Add(1)
go func() { go func() {
defer f.wg.Done() defer f.wg.Done()
if err := f.srv.ListenAndServe(); err != http.ErrServerClosed { if err := f.srv.ListenAndServe(); err != http.ErrServerClosed {
f.t.Errorf("error: cannot start fee api: %v", err) require.NoErrorf(f, err, "cannot start fee api")
} }
}() }()
return &f return nil
} }
// handleRequest handles a client request for fee estimates. // handleRequest handles a client request for fee estimates.
func (f *feeService) handleRequest(w http.ResponseWriter, r *http.Request) { func (f *FeeService) handleRequest(w http.ResponseWriter, r *http.Request) {
f.lock.Lock() f.lock.Lock()
defer f.lock.Unlock() defer f.lock.Unlock()
bytes, err := json.Marshal(f.feeEstimates) bytes, err := json.Marshal(
if err != nil { struct {
f.t.Errorf("error: cannot serialize estimates: %v", err) Fees map[uint32]uint32 `json:"fee_by_block_target"`
}{
return Fees: f.feeRateMap,
} },
)
require.NoErrorf(f, err, "cannot serialize estimates")
_, err = io.WriteString(w, string(bytes)) _, err = io.WriteString(w, string(bytes))
if err != nil { require.NoError(f, err, "cannot send estimates")
f.t.Errorf("error: cannot send estimates: %v", err)
}
} }
// stop stops the web server. // Stop stops the web server.
func (f *feeService) stop() { func (f *FeeService) Stop() error {
if err := f.srv.Shutdown(context.Background()); err != nil { err := f.srv.Shutdown(context.Background())
f.t.Errorf("error: cannot stop fee api: %v", err) require.NoError(f, err, "cannot stop fee api")
}
f.wg.Wait() f.wg.Wait()
return nil
} }
// setFee changes the current fee estimate for the fixed confirmation target. // SetFeeRate sets a fee for the given confirmation target.
func (f *feeService) setFee(fee chainfee.SatPerKWeight) { func (f *FeeService) SetFeeRate(fee chainfee.SatPerKWeight, conf uint32) {
f.lock.Lock() f.lock.Lock()
defer f.lock.Unlock() defer f.lock.Unlock()
f.Fees[feeServiceTarget] = uint32(fee.FeePerKVByte()) f.feeRateMap[conf] = uint32(fee.FeePerKVByte())
} }
// setFeeWithConf sets a fee for the given confirmation target. // URL returns the service endpoint.
func (f *feeService) setFeeWithConf(fee chainfee.SatPerKWeight, conf uint32) { func (f *FeeService) URL() string {
f.lock.Lock() return f.url
defer f.lock.Unlock()
f.Fees[conf] = uint32(fee.FeePerKVByte())
} }
-39
View File
@@ -1,39 +0,0 @@
package lntest
import (
"io/ioutil"
"net/http"
"testing"
"time"
"github.com/stretchr/testify/require"
)
// TestFeeService tests the itest fee estimating web service.
func TestFeeService(t *testing.T) {
service := startFeeService(t)
defer service.stop()
service.setFee(5000)
// Wait for service to start accepting connections.
var resp *http.Response
require.Eventually(
t,
func() bool {
var err error
resp, err = http.Get(service.url) // nolint:bodyclose
return err == nil
},
10*time.Second, time.Second,
)
defer resp.Body.Close()
body, err := ioutil.ReadAll(resp.Body)
require.NoError(t, err)
require.Equal(
t, "{\"fee_by_block_target\":{\"1\":20000}}", string(body),
)
}
+60 -27
View File
@@ -1,4 +1,4 @@
package lntemp package lntest
import ( import (
"context" "context"
@@ -17,9 +17,8 @@ import (
"github.com/lightningnetwork/lnd/lnrpc" "github.com/lightningnetwork/lnd/lnrpc"
"github.com/lightningnetwork/lnd/lnrpc/routerrpc" "github.com/lightningnetwork/lnd/lnrpc/routerrpc"
"github.com/lightningnetwork/lnd/lnrpc/walletrpc" "github.com/lightningnetwork/lnd/lnrpc/walletrpc"
"github.com/lightningnetwork/lnd/lntemp/node" "github.com/lightningnetwork/lnd/lntest/node"
"github.com/lightningnetwork/lnd/lntemp/rpc" "github.com/lightningnetwork/lnd/lntest/rpc"
"github.com/lightningnetwork/lnd/lntest"
"github.com/lightningnetwork/lnd/lntest/wait" "github.com/lightningnetwork/lnd/lntest/wait"
"github.com/lightningnetwork/lnd/lnwallet/chainfee" "github.com/lightningnetwork/lnd/lnwallet/chainfee"
"github.com/lightningnetwork/lnd/lnwire" "github.com/lightningnetwork/lnd/lnwire"
@@ -38,6 +37,10 @@ const (
// numBlocksOpenChannel specifies the number of blocks mined when // numBlocksOpenChannel specifies the number of blocks mined when
// opening a channel. // opening a channel.
numBlocksOpenChannel = 6 numBlocksOpenChannel = 6
// lndErrorChanSize specifies the buffer size used to receive errors
// from lnd process.
lndErrorChanSize = 10
) )
// TestCase defines a test case that's been used in the integration test. // TestCase defines a test case that's been used in the integration test.
@@ -85,7 +88,7 @@ type HarnessTest struct {
// runCtx is a context with cancel method. It's used to signal when the // runCtx is a context with cancel method. It's used to signal when the
// node needs to quit, and used as the parent context when spawning // node needs to quit, and used as the parent context when spawning
// children contexts for RPC requests. // children contexts for RPC requests.
runCtx context.Context runCtx context.Context //nolint:containedctx
cancel context.CancelFunc cancel context.CancelFunc
// stopChainBackend points to the cleanup function returned by the // stopChainBackend points to the cleanup function returned by the
@@ -100,12 +103,15 @@ type HarnessTest struct {
// NewHarnessTest creates a new instance of a harnessTest from a regular // NewHarnessTest creates a new instance of a harnessTest from a regular
// testing.T instance. // testing.T instance.
func NewHarnessTest(t *testing.T, lndBinary string, feeService WebFeeService, func NewHarnessTest(t *testing.T, lndBinary string, feeService WebFeeService,
dbBackend lntest.DatabaseBackend) *HarnessTest { dbBackend node.DatabaseBackend) *HarnessTest {
t.Helper()
// Create the run context. // Create the run context.
ctxt, cancel := context.WithCancel(context.Background()) ctxt, cancel := context.WithCancel(context.Background())
manager := newNodeManager(lndBinary, dbBackend) manager := newNodeManager(lndBinary, dbBackend)
return &HarnessTest{ return &HarnessTest{
T: t, T: t,
manager: manager, manager: manager,
@@ -114,7 +120,7 @@ func NewHarnessTest(t *testing.T, lndBinary string, feeService WebFeeService,
cancel: cancel, cancel: cancel,
// We need to use buffered channel here as we don't want to // We need to use buffered channel here as we don't want to
// block sending errors. // block sending errors.
lndErrorChan: make(chan error, 10), lndErrorChan: make(chan error, lndErrorChanSize),
} }
} }
@@ -180,21 +186,18 @@ func (h *HarnessTest) SetupStandbyNodes() {
h.Alice = h.NewNode("Alice", lndArgs) h.Alice = h.NewNode("Alice", lndArgs)
h.Bob = h.NewNode("Bob", lndArgs) h.Bob = h.NewNode("Bob", lndArgs)
// First, make a connection between the two nodes. This will wait until
// both nodes are fully started since the Connect RPC is guarded behind
// the server.Started() flag that waits for all subsystems to be ready.
h.ConnectNodes(h.Alice, h.Bob)
addrReq := &lnrpc.NewAddressRequest{ addrReq := &lnrpc.NewAddressRequest{
Type: lnrpc.AddressType_WITNESS_PUBKEY_HASH, Type: lnrpc.AddressType_WITNESS_PUBKEY_HASH,
} }
// Load up the wallets of the seeder nodes with 10 outputs of 10 BTC const initialFund = 1 * btcutil.SatoshiPerBitcoin
// Load up the wallets of the seeder nodes with 100 outputs of 1 BTC
// each. // each.
nodes := []*node.HarnessNode{h.Alice, h.Bob} nodes := []*node.HarnessNode{h.Alice, h.Bob}
for _, hn := range nodes { for _, hn := range nodes {
h.manager.standbyNodes[hn.Cfg.NodeID] = hn h.manager.standbyNodes[hn.Cfg.NodeID] = hn
for i := 0; i < 10; i++ { for i := 0; i < 100; i++ {
resp := hn.RPC.NewAddress(addrReq) resp := hn.RPC.NewAddress(addrReq)
addr, err := btcutil.DecodeAddress( addr, err := btcutil.DecodeAddress(
@@ -207,7 +210,7 @@ func (h *HarnessTest) SetupStandbyNodes() {
output := &wire.TxOut{ output := &wire.TxOut{
PkScript: addrScript, PkScript: addrScript,
Value: 10 * btcutil.SatoshiPerBitcoin, Value: initialFund,
} }
h.Miner.SendOutput(output, defaultMinerFeeRate) h.Miner.SendOutput(output, defaultMinerFeeRate)
} }
@@ -215,7 +218,7 @@ func (h *HarnessTest) SetupStandbyNodes() {
// We generate several blocks in order to give the outputs created // We generate several blocks in order to give the outputs created
// above a good number of confirmations. // above a good number of confirmations.
const totalTxes = 20 const totalTxes = 200
h.MineBlocksAndAssertNumTxes(numBlocksSendOutput, totalTxes) h.MineBlocksAndAssertNumTxes(numBlocksSendOutput, totalTxes)
// Now we want to wait for the nodes to catch up. // Now we want to wait for the nodes to catch up.
@@ -223,7 +226,7 @@ func (h *HarnessTest) SetupStandbyNodes() {
h.WaitForBlockchainSync(h.Bob) h.WaitForBlockchainSync(h.Bob)
// Now block until both wallets have fully synced up. // Now block until both wallets have fully synced up.
expectedBalance := int64(btcutil.SatoshiPerBitcoin * 100) const expectedBalance = 100 * initialFund
err := wait.NoError(func() error { err := wait.NoError(func() error {
aliceResp := h.Alice.RPC.WalletBalance() aliceResp := h.Alice.RPC.WalletBalance()
bobResp := h.Bob.RPC.WalletBalance() bobResp := h.Bob.RPC.WalletBalance()
@@ -286,6 +289,8 @@ func (h *HarnessTest) RunTestCase(testCase *TestCase) {
// resetStandbyNodes resets all standby nodes by attaching the new testing.T // resetStandbyNodes resets all standby nodes by attaching the new testing.T
// and restarting them with the original config. // and restarting them with the original config.
func (h *HarnessTest) resetStandbyNodes(t *testing.T) { func (h *HarnessTest) resetStandbyNodes(t *testing.T) {
t.Helper()
for _, hn := range h.manager.standbyNodes { for _, hn := range h.manager.standbyNodes {
// Inherit the testing.T. // Inherit the testing.T.
h.T = t h.T = t
@@ -313,7 +318,7 @@ func (h *HarnessTest) Subtest(t *testing.T) *HarnessTest {
Miner: h.Miner, Miner: h.Miner,
standbyNodes: h.standbyNodes, standbyNodes: h.standbyNodes,
feeService: h.feeService, feeService: h.feeService,
lndErrorChan: make(chan error, 10), lndErrorChan: make(chan error, lndErrorChanSize),
} }
// Inherit context from the main test. // Inherit context from the main test.
@@ -341,6 +346,7 @@ func (h *HarnessTest) Subtest(t *testing.T) *HarnessTest {
// Don't bother run the cleanups if the test is failed. // Don't bother run the cleanups if the test is failed.
if st.Failed() { if st.Failed() {
st.Log("test failed, skipped cleanup") st.Log("test failed, skipped cleanup")
st.shutdownAllNodes()
return return
} }
@@ -381,10 +387,21 @@ func (h *HarnessTest) Subtest(t *testing.T) *HarnessTest {
// shutdownNonStandbyNodes will shutdown any non-standby nodes. // shutdownNonStandbyNodes will shutdown any non-standby nodes.
func (h *HarnessTest) shutdownNonStandbyNodes() { func (h *HarnessTest) shutdownNonStandbyNodes() {
h.shutdownNodes(true)
}
// shutdownAllNodes will shutdown all running nodes.
func (h *HarnessTest) shutdownAllNodes() {
h.shutdownNodes(false)
}
// shutdownNodes will shutdown any non-standby nodes. If skipStandby is false,
// all the standby nodes will be shutdown too.
func (h *HarnessTest) shutdownNodes(skipStandby bool) {
for nid, node := range h.manager.activeNodes { for nid, node := range h.manager.activeNodes {
// If it's a standby node, skip. // If it's a standby node, skip.
_, ok := h.manager.standbyNodes[nid] _, ok := h.manager.standbyNodes[nid]
if ok { if ok && skipStandby {
continue continue
} }
@@ -394,7 +411,11 @@ func (h *HarnessTest) shutdownNonStandbyNodes() {
err := wait.NoError(func() error { err := wait.NoError(func() error {
return h.manager.shutdownNode(node) return h.manager.shutdownNode(node)
}, DefaultTimeout) }, DefaultTimeout)
require.NoErrorf(h, err, "unable to shutdown %s", node.Name())
// Instead of returning the error, we will log it instead. This
// is needed so other nodes can continue their shutdown
// processes.
h.Logf("unable to shutdown %s, got err: %v", node.Name(), err)
} }
} }
@@ -636,7 +657,7 @@ func (h *HarnessTest) NewNodeEtcd(name string, etcdCfg *etcd.Config,
leaderSessionTTL int) *node.HarnessNode { leaderSessionTTL int) *node.HarnessNode {
// We don't want to use the embedded etcd instance. // We don't want to use the embedded etcd instance.
h.manager.dbBackend = lntest.BackendBbolt h.manager.dbBackend = node.BackendBbolt
extraArgs := node.ExtraArgsEtcd( extraArgs := node.ExtraArgsEtcd(
etcdCfg, name, cluster, leaderSessionTTL, etcdCfg, name, cluster, leaderSessionTTL,
@@ -659,7 +680,7 @@ func (h *HarnessTest) NewNodeWithSeedEtcd(name string, etcdCfg *etcd.Config,
leaderSessionTTL int) (*node.HarnessNode, []string, []byte) { leaderSessionTTL int) (*node.HarnessNode, []string, []byte) {
// We don't want to use the embedded etcd instance. // We don't want to use the embedded etcd instance.
h.manager.dbBackend = lntest.BackendBbolt h.manager.dbBackend = node.BackendBbolt
// Create a request to generate a new aezeed. The new seed will have // Create a request to generate a new aezeed. The new seed will have
// the same password as the internal wallet. // the same password as the internal wallet.
@@ -1082,7 +1103,19 @@ func (h *HarnessTest) CloseChannelAssertPending(hn *node.HarnessNode,
// transaction to be broadcast, then wait for the closing tx to be seen // transaction to be broadcast, then wait for the closing tx to be seen
// within the network. // within the network.
event, err := h.ReceiveCloseChannelUpdate(stream) event, err := h.ReceiveCloseChannelUpdate(stream)
require.NoError(h, err) if err != nil {
// TODO(yy): remove the sleep once the following bug is fixed.
// We may receive the error `cannot co-op close channel with
// active htlcs` or `link failed to shutdown` if we close the
// channel. We need to investigate the order of settling the
// payments and updating commitments to properly fix it.
time.Sleep(2 * time.Second)
// Give it another chance.
stream = hn.RPC.CloseChannel(closeReq)
event, err = h.ReceiveCloseChannelUpdate(stream)
require.NoError(h, err)
}
pendingClose, ok := event.Update.(*lnrpc.CloseStatusUpdate_ClosePending) pendingClose, ok := event.Update.(*lnrpc.CloseStatusUpdate_ClosePending)
require.Truef(h, ok, "expected channel close update, instead got %v", require.Truef(h, ok, "expected channel close update, instead got %v",
@@ -1277,7 +1310,7 @@ func (h *HarnessTest) completePaymentRequestsAssertStatus(hn *node.HarnessNode,
send := func(payReq string) { send := func(payReq string) {
req := &routerrpc.SendPaymentRequest{ req := &routerrpc.SendPaymentRequest{
PaymentRequest: payReq, PaymentRequest: payReq,
TimeoutSeconds: defaultPaymentTimeout, TimeoutSeconds: int32(wait.PaymentTimeout.Seconds()),
FeeLimitMsat: noFeeLimitMsat, FeeLimitMsat: noFeeLimitMsat,
} }
stream := hn.RPC.SendPayment(req) stream := hn.RPC.SendPayment(req)
@@ -1293,7 +1326,7 @@ func (h *HarnessTest) completePaymentRequestsAssertStatus(hn *node.HarnessNode,
} }
// Wait for all payments to report the expected status. // Wait for all payments to report the expected status.
timer := time.After(DefaultTimeout) timer := time.After(wait.PaymentTimeout)
select { select {
case stream := <-results: case stream := <-results:
h.AssertPaymentStatusFromStream(stream, status) h.AssertPaymentStatusFromStream(stream, status)
@@ -1402,7 +1435,7 @@ func (h *HarnessTest) CleanupForceClose(hn *node.HarnessNode,
// //
// The commit sweep resolver is able to broadcast the sweep tx up to // The commit sweep resolver is able to broadcast the sweep tx up to
// one block before the CSV elapses, so wait until defaulCSV-1. // one block before the CSV elapses, so wait until defaulCSV-1.
h.MineBlocks(lntest.DefaultCSV - 1) h.MineBlocks(node.DefaultCSV - 1)
// The node should now sweep the funds, clean up by mining the sweeping // The node should now sweep the funds, clean up by mining the sweeping
// tx. // tx.
@@ -1686,7 +1719,7 @@ func (h *HarnessTest) OpenMultiChannelsAsync(
case cp := <-r.result: case cp := <-r.result:
channelPoints = append(channelPoints, cp) channelPoints = append(channelPoints, cp)
case <-time.After(lntest.ChannelOpenTimeout): case <-time.After(wait.ChannelOpenTimeout):
require.Failf(h, "timeout", "wait channel point "+ require.Failf(h, "timeout", "wait channel point "+
"timeout for channel %s=>%s", r.Local.Name(), "timeout for channel %s=>%s", r.Local.Name(),
r.Remote.Name()) r.Remote.Name())
@@ -1,4 +1,4 @@
package lntemp package lntest
import ( import (
"bytes" "bytes"
@@ -23,8 +23,8 @@ import (
"github.com/lightningnetwork/lnd/lnrpc/invoicesrpc" "github.com/lightningnetwork/lnd/lnrpc/invoicesrpc"
"github.com/lightningnetwork/lnd/lnrpc/routerrpc" "github.com/lightningnetwork/lnd/lnrpc/routerrpc"
"github.com/lightningnetwork/lnd/lnrpc/walletrpc" "github.com/lightningnetwork/lnd/lnrpc/walletrpc"
"github.com/lightningnetwork/lnd/lntemp/node" "github.com/lightningnetwork/lnd/lntest/node"
"github.com/lightningnetwork/lnd/lntemp/rpc" "github.com/lightningnetwork/lnd/lntest/rpc"
"github.com/lightningnetwork/lnd/lntest/wait" "github.com/lightningnetwork/lnd/lntest/wait"
"github.com/lightningnetwork/lnd/lntypes" "github.com/lightningnetwork/lnd/lntypes"
"github.com/stretchr/testify/require" "github.com/stretchr/testify/require"
@@ -38,6 +38,7 @@ func (h *HarnessTest) WaitForBlockchainSync(hn *node.HarnessNode) {
if resp.SyncedToChain { if resp.SyncedToChain {
return nil return nil
} }
return fmt.Errorf("%s is not synced to chain", hn.Name()) return fmt.Errorf("%s is not synced to chain", hn.Name())
}, DefaultTimeout) }, DefaultTimeout)
@@ -145,6 +146,12 @@ func (h *HarnessTest) EnsureConnected(a, b *node.HarnessNode) {
// connected to the peer. // connected to the peer.
errConnectionRequested := "connection request in progress" errConnectionRequested := "connection request in progress"
// windowsErr is an error we've seen from windows build where
// connecting to an already connected node gives such error from the
// receiver side.
windowsErr := "An established connection was aborted by the software " +
"in your host machine."
tryConnect := func(a, b *node.HarnessNode) error { tryConnect := func(a, b *node.HarnessNode) error {
bInfo := b.RPC.GetInfo() bInfo := b.RPC.GetInfo()
@@ -165,17 +172,21 @@ func (h *HarnessTest) EnsureConnected(a, b *node.HarnessNode) {
return nil return nil
} }
// If the connection is in process, we return no error.
if strings.Contains(err.Error(), errConnectionRequested) {
return nil
}
// If the two are already connected, we return early with no // If the two are already connected, we return early with no
// error. // error.
if strings.Contains(err.Error(), "already connected to peer") { if strings.Contains(err.Error(), "already connected to peer") {
return nil return nil
} }
// Otherwise we log the error to console.
h.Logf("EnsureConnected %s=>%s got err: %v", a.Name(),
b.Name(), err)
// If the connection is in process, we return no error.
if strings.Contains(err.Error(), errConnectionRequested) {
return nil
}
// We may get connection refused error if we happens to be in // We may get connection refused error if we happens to be in
// the middle of a previous node disconnection, e.g., a restart // the middle of a previous node disconnection, e.g., a restart
// from one of the nodes. // from one of the nodes.
@@ -183,6 +194,16 @@ func (h *HarnessTest) EnsureConnected(a, b *node.HarnessNode) {
return nil return nil
} }
// Check for windows error. If Alice connects to Bob, Alice
// will throw "i/o timeout" and Bob will give windowsErr.
if strings.Contains(err.Error(), windowsErr) {
return nil
}
if strings.Contains(err.Error(), "i/o timeout") {
return nil
}
return err return err
} }
@@ -231,8 +252,10 @@ func (h *HarnessTest) AssertNumEdges(hn *node.HarnessNode,
// slice. // slice.
edges = chanGraph.Edges[old:] edges = chanGraph.Edges[old:]
} }
return nil return nil
} }
return errNumNotMatched(hn.Name(), "num of channel edges", return errNumNotMatched(hn.Name(), "num of channel edges",
expected, total-old, total, old) expected, total-old, total, old)
}, DefaultTimeout) }, DefaultTimeout)
@@ -925,7 +948,9 @@ func (h *HarnessTest) AssertNodesNumPendingOpenChannels(a, b *node.HarnessNode,
func (h *HarnessTest) AssertPaymentStatusFromStream(stream rpc.PaymentClient, func (h *HarnessTest) AssertPaymentStatusFromStream(stream rpc.PaymentClient,
status lnrpc.Payment_PaymentStatus) *lnrpc.Payment { status lnrpc.Payment_PaymentStatus) *lnrpc.Payment {
return h.assertPaymentStatusWithTimeout(stream, status, DefaultTimeout) return h.assertPaymentStatusWithTimeout(
stream, status, wait.PaymentTimeout,
)
} }
// AssertPaymentSucceedWithTimeout asserts that a payment is succeeded within // AssertPaymentSucceedWithTimeout asserts that a payment is succeeded within
@@ -1166,7 +1191,9 @@ func (h *HarnessTest) AssertActiveHtlcs(hn *node.HarnessNode,
h := hex.EncodeToString(htlc.HashLock) h := hex.EncodeToString(htlc.HashLock)
_, ok := htlcHashes[h] _, ok := htlcHashes[h]
if ok { if ok {
return fmt.Errorf("duplicate HashLock") return fmt.Errorf("duplicate HashLock "+
"in PendingHtlcs: %v",
ch.PendingHtlcs)
} }
htlcHashes[h] = struct{}{} htlcHashes[h] = struct{}{}
} }
@@ -1732,7 +1759,8 @@ func (h *HarnessTest) AssertNumPayments(hn *node.HarnessNode,
return errNumNotMatched(hn.Name(), "num of payments", return errNumNotMatched(hn.Name(), "num of payments",
num, len(payments), have+len(payments), have) num, len(payments), have+len(payments), have)
}, DefaultTimeout) }, DefaultTimeout)
require.NoError(h, err, "timeout checking num of payments") require.NoError(h, err, "%s: timeout checking num of payments",
hn.Name())
return payments return payments
} }
@@ -1745,7 +1773,8 @@ func (h *HarnessTest) AssertNumNodeAnns(hn *node.HarnessNode,
// We will get the current number of channel updates first and add it // We will get the current number of channel updates first and add it
// to our expected number of newly created channel updates. // to our expected number of newly created channel updates.
anns, err := hn.Watcher.WaitForNumNodeUpdates(pubkey, num) anns, err := hn.Watcher.WaitForNumNodeUpdates(pubkey, num)
require.NoError(h, err, "failed to assert num of channel updates") require.NoError(h, err, "%s: failed to assert num of node anns",
hn.Name())
return anns return anns
} }
@@ -1757,7 +1786,8 @@ func (h *HarnessTest) AssertNumChannelUpdates(hn *node.HarnessNode,
op := h.OutPointFromChannelPoint(chanPoint) op := h.OutPointFromChannelPoint(chanPoint)
err := hn.Watcher.WaitForNumChannelUpdates(op, num) err := hn.Watcher.WaitForNumChannelUpdates(op, num)
require.NoError(h, err, "failed to assert num of channel updates") require.NoError(h, err, "%s: failed to assert num of channel updates",
hn.Name())
} }
// CreateBurnAddr creates a random burn address of the given type. // CreateBurnAddr creates a random burn address of the given type.
+350 -56
View File
@@ -1,18 +1,26 @@
package lntest package lntest
import ( import (
"bytes"
"context" "context"
"fmt" "fmt"
"io/ioutil" "io/ioutil"
"os" "os"
"path/filepath" "path/filepath"
"strings" "strings"
"testing"
"time" "time"
"github.com/btcsuite/btcd/btcjson"
"github.com/btcsuite/btcd/btcutil"
"github.com/btcsuite/btcd/chaincfg" "github.com/btcsuite/btcd/chaincfg"
"github.com/btcsuite/btcd/chaincfg/chainhash" "github.com/btcsuite/btcd/chaincfg/chainhash"
"github.com/btcsuite/btcd/integration/rpctest" "github.com/btcsuite/btcd/integration/rpctest"
"github.com/btcsuite/btcd/rpcclient" "github.com/btcsuite/btcd/rpcclient"
"github.com/btcsuite/btcd/wire"
"github.com/lightningnetwork/lnd/lntest/node"
"github.com/lightningnetwork/lnd/lntest/wait"
"github.com/stretchr/testify/require"
) )
const ( const (
@@ -21,16 +29,21 @@ const (
// minerLogDir is the default log dir for the miner node. // minerLogDir is the default log dir for the miner node.
minerLogDir = ".minerlogs" minerLogDir = ".minerlogs"
// slowMineDelay defines a wait period between mining new blocks.
slowMineDelay = 100 * time.Millisecond
) )
var harnessNetParams = &chaincfg.RegressionNetParams var harnessNetParams = &chaincfg.RegressionNetParams
type HarnessMiner struct { type HarnessMiner struct {
*testing.T
*rpctest.Harness *rpctest.Harness
// runCtx is a context with cancel method. It's used to signal when the // runCtx is a context with cancel method. It's used to signal when the
// node needs to quit, and used as the parent context when spawning // node needs to quit, and used as the parent context when spawning
runCtx context.Context // children contexts for RPC requests.
runCtx context.Context //nolint:containedctx
cancel context.CancelFunc cancel context.CancelFunc
// logPath is the directory path of the miner's logs. // logPath is the directory path of the miner's logs.
@@ -42,21 +55,30 @@ type HarnessMiner struct {
// NewMiner creates a new miner using btcd backend with the default log file // NewMiner creates a new miner using btcd backend with the default log file
// dir and name. // dir and name.
func NewMiner() (*HarnessMiner, error) { func NewMiner(ctxt context.Context, t *testing.T) *HarnessMiner {
return newMiner(minerLogDir, minerLogFilename) t.Helper()
return newMiner(ctxt, t, minerLogDir, minerLogFilename)
} }
// NewTempMiner creates a new miner using btcd backend with the specified log // NewTempMiner creates a new miner using btcd backend with the specified log
// file dir and name. // file dir and name.
func NewTempMiner(tempDir, tempLogFilename string) (*HarnessMiner, error) { func NewTempMiner(ctxt context.Context, t *testing.T,
return newMiner(tempDir, tempLogFilename) tempDir, tempLogFilename string) *HarnessMiner {
t.Helper()
return newMiner(ctxt, t, tempDir, tempLogFilename)
} }
// newMiner creates a new miner using btcd's rpctest. // newMiner creates a new miner using btcd's rpctest.
func newMiner(minerDirName, logFilename string) (*HarnessMiner, error) { func newMiner(ctxb context.Context, t *testing.T, minerDirName,
logFilename string) *HarnessMiner {
t.Helper()
handler := &rpcclient.NotificationHandlers{} handler := &rpcclient.NotificationHandlers{}
btcdBinary := GetBtcdBinary() btcdBinary := node.GetBtcdBinary()
baseLogPath := fmt.Sprintf("%s/%s", GetLogDir(), minerDirName) baseLogPath := fmt.Sprintf("%s/%s", node.GetLogDir(), minerDirName)
args := []string{ args := []string{
"--rejectnonstd", "--rejectnonstd",
@@ -71,42 +93,28 @@ func newMiner(minerDirName, logFilename string) (*HarnessMiner, error) {
} }
miner, err := rpctest.New(harnessNetParams, handler, args, btcdBinary) miner, err := rpctest.New(harnessNetParams, handler, args, btcdBinary)
if err != nil { require.NoError(t, err, "unable to create mining node")
return nil, fmt.Errorf("unable to create mining node: %v", err)
}
ctxt, cancel := context.WithCancel(context.Background()) ctxt, cancel := context.WithCancel(ctxb)
m := &HarnessMiner{
return &HarnessMiner{
T: t,
Harness: miner, Harness: miner,
runCtx: ctxt, runCtx: ctxt,
cancel: cancel, cancel: cancel,
logPath: baseLogPath, logPath: baseLogPath,
logFilename: logFilename, logFilename: logFilename,
} }
return m, nil
}
// Stop shuts down the miner and saves its logs.
func (h *HarnessMiner) Stop() error {
h.cancel()
if err := h.TearDown(); err != nil {
return fmt.Errorf("tear down miner got error: %s", err)
}
return h.saveLogs()
} }
// saveLogs copies the node logs and save it to the file specified by // saveLogs copies the node logs and save it to the file specified by
// h.logFilename. // h.logFilename.
func (h *HarnessMiner) saveLogs() error { func (h *HarnessMiner) saveLogs() {
// After shutting down the miner, we'll make a copy of the log files // After shutting down the miner, we'll make a copy of the log files
// before deleting the temporary log dir. // before deleting the temporary log dir.
path := fmt.Sprintf("%s/%s", h.logPath, harnessNetParams.Name) path := fmt.Sprintf("%s/%s", h.logPath, harnessNetParams.Name)
files, err := ioutil.ReadDir(path) files, err := ioutil.ReadDir(path)
if err != nil { require.NoError(h, err, "unable to read log directory")
return fmt.Errorf("unable to read log directory: %v", err)
}
for _, file := range files { for _, file := range files {
newFilename := strings.Replace( newFilename := strings.Replace(
@@ -116,46 +124,332 @@ func (h *HarnessMiner) saveLogs() error {
logFile := fmt.Sprintf("%s/%s", path, file.Name()) logFile := fmt.Sprintf("%s/%s", path, file.Name())
err := CopyFile(filepath.Clean(copyPath), logFile) err := CopyFile(filepath.Clean(copyPath), logFile)
if err != nil { require.NoError(h, err, "unable to copy file")
return fmt.Errorf("unable to copy file: %v", err) }
err = os.RemoveAll(h.logPath)
require.NoErrorf(h, err, "cannot remove dir %s", h.logPath)
}
// Stop shuts down the miner and saves its logs.
func (h *HarnessMiner) Stop() {
h.cancel()
require.NoError(h, h.TearDown(), "tear down miner got error")
h.saveLogs()
}
// GetBestBlock makes a RPC request to miner and asserts.
func (h *HarnessMiner) GetBestBlock() (*chainhash.Hash, int32) {
blockHash, height, err := h.Client.GetBestBlock()
require.NoError(h, err, "failed to GetBestBlock")
return blockHash, height
}
// GetRawMempool makes a RPC call to the miner's GetRawMempool and
// asserts.
func (h *HarnessMiner) GetRawMempool() []*chainhash.Hash {
mempool, err := h.Client.GetRawMempool()
require.NoError(h, err, "unable to get mempool")
return mempool
}
// GenerateBlocks mine 'num' of blocks and returns them.
func (h *HarnessMiner) GenerateBlocks(num uint32) []*chainhash.Hash {
blockHashes, err := h.Client.Generate(num)
require.NoError(h, err, "unable to generate blocks")
require.Len(h, blockHashes, int(num), "wrong num of blocks generated")
return blockHashes
}
// GetBlock gets a block using its block hash.
func (h *HarnessMiner) GetBlock(blockHash *chainhash.Hash) *wire.MsgBlock {
block, err := h.Client.GetBlock(blockHash)
require.NoError(h, err, "unable to get block")
return block
}
// MineBlocks mine 'num' of blocks and check that blocks are present in
// node blockchain.
func (h *HarnessMiner) MineBlocks(num uint32) []*wire.MsgBlock {
blocks := make([]*wire.MsgBlock, num)
blockHashes := h.GenerateBlocks(num)
for i, blockHash := range blockHashes {
block := h.GetBlock(blockHash)
blocks[i] = block
}
return blocks
}
// 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 (h *HarnessMiner) AssertNumTxsInMempool(n int) []*chainhash.Hash {
var (
mem []*chainhash.Hash
err error
)
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.
mem = h.GetRawMempool()
if len(mem) == n {
return nil
}
return fmt.Errorf("want %v, got %v in mempool: %v",
n, len(mem), mem)
}, wait.MinerMempoolTimeout)
require.NoError(h, err, "assert tx in mempool timeout")
return mem
}
// AssertTxInBlock asserts that a given txid can be found in the passed block.
func (h *HarnessMiner) AssertTxInBlock(block *wire.MsgBlock,
txid *chainhash.Hash) {
blockTxes := make([]chainhash.Hash, 0)
for _, tx := range block.Transactions {
sha := tx.TxHash()
blockTxes = append(blockTxes, sha)
if bytes.Equal(txid[:], sha[:]) {
return
} }
} }
if err = os.RemoveAll(h.logPath); err != nil { require.Failf(h, "tx was not included in block", "tx:%v, block has:%v",
return fmt.Errorf("cannot remove dir %s: %v", h.logPath, err) txid, blockTxes)
}
return nil
} }
// waitForTxInMempool blocks until the target txid is seen in the mempool. If // MineBlocksAndAssertNumTxes mine 'num' of blocks and check that blocks are
// the transaction isn't seen within the network before the passed timeout, // present in node blockchain. numTxs should be set to the number of
// then an error is returned. // transactions (excluding the coinbase) we expect to be included in the first
func (h *HarnessMiner) waitForTxInMempool(txid chainhash.Hash) error { // mined block.
ticker := time.NewTicker(50 * time.Millisecond) func (h *HarnessMiner) MineBlocksAndAssertNumTxes(num uint32,
defer ticker.Stop() numTxs int) []*wire.MsgBlock {
var mempool []*chainhash.Hash // If we expect transactions to be included in the blocks we'll mine,
for { // we wait here until they are seen in the miner's mempool.
select { txids := h.AssertNumTxsInMempool(numTxs)
case <-h.runCtx.Done():
return fmt.Errorf("NetworkHarness has been torn down")
case <-time.After(DefaultTimeout):
return fmt.Errorf("wanted %v, found %v txs "+
"in mempool: %v", txid, len(mempool), mempool)
case <-ticker.C: // Mine blocks.
var err error blocks := h.MineBlocks(num)
mempool, err = h.Client.GetRawMempool()
// Finally, assert that all the transactions were included in the first
// block.
for _, txid := range txids {
h.AssertTxInBlock(blocks[0], txid)
}
return blocks
}
// GetRawTransaction makes a RPC call to the miner's GetRawTransaction and
// asserts.
func (h *HarnessMiner) GetRawTransaction(txid *chainhash.Hash) *btcutil.Tx {
tx, err := h.Client.GetRawTransaction(txid)
require.NoErrorf(h, err, "failed to get raw tx: %v", txid)
return tx
}
// GetRawTransactionVerbose makes a RPC call to the miner's
// GetRawTransactionVerbose and asserts.
func (h *HarnessMiner) GetRawTransactionVerbose(
txid *chainhash.Hash) *btcjson.TxRawResult {
tx, err := h.Client.GetRawTransactionVerbose(txid)
require.NoErrorf(h, err, "failed to get raw tx verbose: %v", txid)
return tx
}
// AssertTxInMempool asserts a given transaction can be found in the mempool.
func (h *HarnessMiner) AssertTxInMempool(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 *memTx == *txid {
return nil
}
}
return fmt.Errorf("txid %v not found in mempool: %v", txid,
mempool)
}, wait.MinerMempoolTimeout)
require.NoError(h, err, "timeout checking mempool")
return msgTx
}
// SendOutputsWithoutChange uses the miner to send the given outputs using the
// specified fee rate and returns the txid.
func (h *HarnessMiner) SendOutputsWithoutChange(outputs []*wire.TxOut,
feeRate btcutil.Amount) *chainhash.Hash {
txid, err := h.Harness.SendOutputsWithoutChange(
outputs, feeRate,
)
require.NoErrorf(h, err, "failed to send output")
return txid
}
// CreateTransaction uses the miner to create a transaction using the given
// outputs using the specified fee rate and returns the transaction.
func (h *HarnessMiner) CreateTransaction(outputs []*wire.TxOut,
feeRate btcutil.Amount) *wire.MsgTx {
tx, err := h.Harness.CreateTransaction(outputs, feeRate, false)
require.NoErrorf(h, err, "failed to create transaction")
return tx
}
// SendOutput creates, signs, and finally broadcasts a transaction spending
// the harness' available mature coinbase outputs to create the new output.
func (h *HarnessMiner) SendOutput(newOutput *wire.TxOut,
feeRate btcutil.Amount) *chainhash.Hash {
hash, err := h.Harness.SendOutputs([]*wire.TxOut{newOutput}, feeRate)
require.NoErrorf(h, err, "failed to send outputs")
return hash
}
// MineBlocksSlow mines 'num' of blocks. Between each mined block an artificial
// delay is introduced to give all network participants time to catch up.
func (h *HarnessMiner) MineBlocksSlow(num uint32) []*wire.MsgBlock {
blocks := make([]*wire.MsgBlock, num)
blockHashes := make([]*chainhash.Hash, 0, num)
for i := uint32(0); i < num; i++ {
generatedHashes := h.GenerateBlocks(1)
blockHashes = append(blockHashes, generatedHashes...)
time.Sleep(slowMineDelay)
}
for i, blockHash := range blockHashes {
block, err := h.Client.GetBlock(blockHash)
require.NoError(h, err, "get blocks")
blocks[i] = block
}
return blocks
}
// AssertOutpointInMempool asserts a given outpoint can be found in the mempool.
func (h *HarnessMiner) AssertOutpointInMempool(op wire.OutPoint) *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 _, txid := range mempool {
// We don't use `ht.Miner.GetRawTransaction` which
// asserts a txid must be found. While iterating here,
// the actual mempool state might have been changed,
// causing a given txid being removed and cannot be
// found. For instance, the aggregation logic used in
// sweeping HTLC outputs will update the mempool by
// replacing the HTLC spending txes with a single one.
tx, err := h.Client.GetRawTransaction(txid)
if err != nil { if err != nil {
return err return err
} }
for _, mempoolTx := range mempool { msgTx = tx.MsgTx()
if *mempoolTx == txid { for _, txIn := range msgTx.TxIn {
if txIn.PreviousOutPoint == op {
return nil return nil
} }
} }
} }
}
return fmt.Errorf("outpoint %v not found in mempool", op)
}, wait.MinerMempoolTimeout)
require.NoError(h, err, "timeout checking mempool")
return msgTx
}
// GetNumTxsFromMempool polls until finding the desired number of transactions
// in the miner's mempool and returns the full transactions to the caller.
func (h *HarnessMiner) GetNumTxsFromMempool(n int) []*wire.MsgTx {
txids := h.AssertNumTxsInMempool(n)
var txes []*wire.MsgTx
for _, txid := range txids {
tx := h.GetRawTransaction(txid)
txes = append(txes, tx.MsgTx())
}
return txes
}
// NewMinerAddress creates a new address for the miner and asserts.
func (h *HarnessMiner) NewMinerAddress() btcutil.Address {
addr, err := h.NewAddress()
require.NoError(h, err, "failed to create new miner address")
return addr
}
// MineBlocksWithTxes mines a single block to include the specifies
// transactions only.
func (h *HarnessMiner) MineBlockWithTxes(txes []*btcutil.Tx) *wire.MsgBlock {
var emptyTime time.Time
// Generate a block.
b, err := h.GenerateAndSubmitBlock(txes, -1, emptyTime)
require.NoError(h, err, "unable to mine block")
block, err := h.Client.GetBlock(b.Hash())
require.NoError(h, err, "unable to get block")
return block
}
// MineEmptyBlocks mines a given number of empty blocks.
func (h *HarnessMiner) MineEmptyBlocks(num int) []*wire.MsgBlock {
var emptyTime time.Time
blocks := make([]*wire.MsgBlock, num)
for i := 0; i < num; i++ {
// Generate an empty block.
b, err := h.GenerateAndSubmitBlock(nil, -1, emptyTime)
require.NoError(h, err, "unable to mine empty block")
block := h.GetBlock(b.Hash())
blocks[i] = block
}
return blocks
} }
File diff suppressed because it is too large. Load diff
File diff suppressed because it is too large. Load diff
@@ -1,4 +1,4 @@
package lntemp package lntest
import ( import (
"context" "context"
@@ -8,8 +8,7 @@ import (
"testing" "testing"
"github.com/lightningnetwork/lnd/lnrpc" "github.com/lightningnetwork/lnd/lnrpc"
"github.com/lightningnetwork/lnd/lntemp/node" "github.com/lightningnetwork/lnd/lntest/node"
"github.com/lightningnetwork/lnd/lntest"
"github.com/lightningnetwork/lnd/lntest/wait" "github.com/lightningnetwork/lnd/lntest/wait"
) )
@@ -30,7 +29,7 @@ type nodeManager struct {
lndBinary string lndBinary string
// dbBackend sets the database backend to use. // dbBackend sets the database backend to use.
dbBackend lntest.DatabaseBackend dbBackend node.DatabaseBackend
// activeNodes is a map of all running nodes, format: // activeNodes is a map of all running nodes, format:
// {pubkey: *HarnessNode}. // {pubkey: *HarnessNode}.
@@ -50,7 +49,7 @@ type nodeManager struct {
// newNodeManager creates a new node manager instance. // newNodeManager creates a new node manager instance.
func newNodeManager(lndBinary string, func newNodeManager(lndBinary string,
dbBackend lntest.DatabaseBackend) *nodeManager { dbBackend node.DatabaseBackend) *nodeManager {
return &nodeManager{ return &nodeManager{
lndBinary: lndBinary, lndBinary: lndBinary,
@@ -80,7 +79,7 @@ func (nm *nodeManager) newNode(t *testing.T, name string, extraArgs []string,
BackendCfg: nm.chainBackend, BackendCfg: nm.chainBackend,
ExtraArgs: extraArgs, ExtraArgs: extraArgs,
FeeURL: nm.feeServiceURL, FeeURL: nm.feeServiceURL,
DbBackend: nm.dbBackend, DBBackend: nm.dbBackend,
NodeID: nm.nextNodeID(), NodeID: nm.nextNodeID(),
LndBinary: nm.lndBinary, LndBinary: nm.lndBinary,
NetParams: harnessNetParams, NetParams: harnessNetParams,
@@ -1,4 +1,4 @@
package lntemp package lntest
import ( import (
"context" "context"
@@ -6,7 +6,7 @@ import (
"testing" "testing"
"github.com/btcsuite/btcd/integration/rpctest" "github.com/btcsuite/btcd/integration/rpctest"
"github.com/lightningnetwork/lnd/lntest" "github.com/lightningnetwork/lnd/lntest/node"
"github.com/stretchr/testify/require" "github.com/stretchr/testify/require"
) )
@@ -23,11 +23,11 @@ func SetupHarness(t *testing.T, binaryPath, dbBackendName string,
t.Log("Setting up HarnessTest...") t.Log("Setting up HarnessTest...")
// Parse testing flags that influence our test execution. // Parse testing flags that influence our test execution.
logDir := lntest.GetLogDir() logDir := node.GetLogDir()
require.NoError(t, os.MkdirAll(logDir, 0700), "create log dir failed") require.NoError(t, os.MkdirAll(logDir, 0700), "create log dir failed")
// Parse database backend // Parse database backend
dbBackend := prepareDbBackend(t, dbBackendName) dbBackend := prepareDBBackend(t, dbBackendName)
// Create a new HarnessTest. // Create a new HarnessTest.
ht := NewHarnessTest(t, binaryPath, feeService, dbBackend) ht := NewHarnessTest(t, binaryPath, feeService, dbBackend)
@@ -82,9 +82,9 @@ func prepareMiner(ctxt context.Context, t *testing.T) *HarnessMiner {
// prepareChainBackend creates a new chain backend. // prepareChainBackend creates a new chain backend.
func prepareChainBackend(t *testing.T, func prepareChainBackend(t *testing.T,
minerAddr string) (lntest.BackendConfig, func()) { minerAddr string) (node.BackendConfig, func()) {
chainBackend, cleanUp, err := lntest.NewBackend( chainBackend, cleanUp, err := NewBackend(
minerAddr, harnessNetParams, minerAddr, harnessNetParams,
) )
require.NoError(t, err, "new backend") require.NoError(t, err, "new backend")
@@ -94,23 +94,23 @@ func prepareChainBackend(t *testing.T,
} }
} }
// prepareDbBackend parses a DatabaseBackend based on the name given. // prepareDBBackend parses a DatabaseBackend based on the name given.
func prepareDbBackend(t *testing.T, func prepareDBBackend(t *testing.T,
dbBackendName string) lntest.DatabaseBackend { dbBackendName string) node.DatabaseBackend {
var dbBackend lntest.DatabaseBackend var dbBackend node.DatabaseBackend
switch dbBackendName { switch dbBackendName {
case "bbolt": case "bbolt":
dbBackend = lntest.BackendBbolt dbBackend = node.BackendBbolt
case "etcd": case "etcd":
dbBackend = lntest.BackendEtcd dbBackend = node.BackendEtcd
case "postgres": case "postgres":
dbBackend = lntest.BackendPostgres dbBackend = node.BackendPostgres
case "sqlite": case "sqlite":
dbBackend = lntest.BackendSqlite dbBackend = node.BackendSqlite
default: default:
require.Fail(t, "unknown db backend") require.Fail(t, "unknown db backend")
File diff suppressed because it is too large. Load diff
-9
View File
@@ -1,9 +0,0 @@
//go:build !rpctest
// +build !rpctest
package itest
import "github.com/lightningnetwork/lnd/lntemp"
// TODO(yy): remove the temp.
var allTestCasesTemp = []*lntemp.TestCase{}
-241
View File
@@ -1,241 +0,0 @@
package itest
import (
"flag"
"fmt"
"os"
"strings"
"testing"
"time"
"github.com/btcsuite/btcd/integration/rpctest"
"github.com/lightningnetwork/lnd/lntest"
"github.com/stretchr/testify/require"
)
var (
// tempTest is a flag used to mark whether we should run the old or the
// new test cases. Used here so we can transit smoothly during our new
// itest construction.
//
// TODO(yy): remove temp flag.
tempTest = flag.Bool("temptest", false, "run the new tests(temp)")
)
// getTestCaseSplitTranche returns the sub slice of the test cases that should
// be run as the current split tranche as well as the index and slice offset of
// the tranche.
func getTestCaseSplitTrancheOld() ([]*testCase, uint, uint) {
numTranches := defaultSplitTranches
if testCasesSplitTranches != nil {
numTranches = *testCasesSplitTranches
}
runTranche := defaultRunTranche
if testCasesRunTranche != nil {
runTranche = *testCasesRunTranche
}
// There's a special flake-hunt mode where we run the same test multiple
// times in parallel. In that case the tranche index is equal to the
// thread ID, but we need to actually run all tests for the regex
// selection to work.
threadID := runTranche
if numTranches == 1 {
runTranche = 0
}
numCases := uint(len(allTestCases))
testsPerTranche := numCases / numTranches
trancheOffset := runTranche * testsPerTranche
trancheEnd := trancheOffset + testsPerTranche
if trancheEnd > numCases || runTranche == numTranches-1 {
trancheEnd = numCases
}
return allTestCases[trancheOffset:trancheEnd], threadID, trancheOffset
}
// TestLightningNetworkDaemon performs a series of integration tests amongst a
// programmatically driven network of lnd nodes.
func TestLightningNetworkDaemon(t *testing.T) {
if *tempTest {
t.Skip("Running new tests, old tests are skipped")
}
// If no tests are registered, then we can exit early.
if len(allTestCases) == 0 {
t.Skip("integration tests not selected with flag 'rpctest'")
}
// Parse testing flags that influence our test execution.
logDir := lntest.GetLogDir()
require.NoError(t, os.MkdirAll(logDir, 0700))
testCases, trancheIndex, trancheOffset := getTestCaseSplitTrancheOld()
lntest.ApplyPortOffset(uint32(trancheIndex) * 1000)
// Before we start any node, we need to make sure that any btcd node
// that is started through the RPC harness uses a unique port as well to
// avoid any port collisions.
rpctest.ListenAddressGenerator = lntest.GenerateBtcdListenerAddresses
// Declare the network harness here to gain access to its
// 'OnTxAccepted' call back.
var lndHarness *lntest.NetworkHarness
// Create an instance of the btcd's rpctest.Harness that will act as
// the miner for all tests. This will be used to fund the wallets of
// the nodes within the test network and to drive blockchain related
// events within the network. Revert the default setting of accepting
// non-standard transactions on simnet to reject them. Transactions on
// the lightning network should always be standard to get better
// guarantees of getting included in to blocks.
//
// We will also connect it to our chain backend.
miner, err := lntest.NewMiner()
require.NoError(t, err, "failed to create new miner")
defer func() {
require.NoError(t, miner.Stop(), "failed to stop miner")
}()
// Start a chain backend.
chainBackend, cleanUp, err := lntest.NewBackend(
miner.P2PAddress(), harnessNetParams,
)
require.NoError(t, err, "new backend")
defer func() {
require.NoError(t, cleanUp(), "cleanup")
}()
// Before we start anything, we want to overwrite some of the connection
// settings to make the tests more robust. We might need to restart the
// miner while there are already blocks present, which will take a bit
// longer than the 1 second the default settings amount to. Doubling
// both values will give us retries up to 4 seconds.
miner.MaxConnRetries = rpctest.DefaultMaxConnectionRetries * 2
miner.ConnectionRetryTimeout = rpctest.DefaultConnectionRetryTimeout * 2
// Set up miner and connect chain backend to it.
require.NoError(t, miner.SetUp(true, 50))
require.NoError(t, miner.Client.NotifyNewTransactions(false))
require.NoError(t, chainBackend.ConnectMiner(), "connect miner")
// Parse database backend
var dbBackend lntest.DatabaseBackend
switch *dbBackendFlag {
case "bbolt":
dbBackend = lntest.BackendBbolt
case "etcd":
dbBackend = lntest.BackendEtcd
case "postgres":
dbBackend = lntest.BackendPostgres
case "sqlite":
dbBackend = lntest.BackendSqlite
default:
require.Fail(t, "unknown db backend")
}
// Now we can set up our test harness (LND instance), with the chain
// backend we just created.
ht := newHarnessTest(t, nil)
binary := ht.getLndBinary()
lndHarness, err = lntest.NewNetworkHarness(
miner, chainBackend, binary, dbBackend,
)
if err != nil {
ht.Fatalf("unable to create lightning network harness: %v", err)
}
defer lndHarness.Stop()
// Spawn a new goroutine to watch for any fatal errors that any of the
// running lnd processes encounter. If an error occurs, then the test
// case should naturally as a result and we log the server error here to
// help debug.
go func() {
for {
select {
case err, more := <-lndHarness.ProcessErrors():
if !more {
return
}
ht.Logf("lnd finished with error (stderr):\n%v",
err)
}
}
}()
// Next mine enough blocks in order for segwit and the CSV package
// soft-fork to activate on SimNet.
numBlocks := harnessNetParams.MinerConfirmationWindow * 2
if _, err := miner.Client.Generate(numBlocks); err != nil {
ht.Fatalf("unable to generate blocks: %v", err)
}
// With the btcd harness created, we can now complete the
// initialization of the network. args - list of lnd arguments,
// example: "--debuglevel=debug"
// TODO(roasbeef): create master balanced channel with all the monies?
aliceBobArgs := []string{
"--default-remote-max-htlcs=483",
"--dust-threshold=5000000",
}
// Run the subset of the test cases selected in this tranche.
for idx, testCase := range testCases {
testCase := testCase
name := fmt.Sprintf("tranche%02d/%02d-of-%d/%s/%s",
trancheIndex, trancheOffset+uint(idx)+1,
len(allTestCases), chainBackend.Name(), testCase.name)
success := t.Run(name, func(t1 *testing.T) {
cleanTestCaseName := strings.ReplaceAll(
testCase.name, " ", "_",
)
err = lndHarness.SetUp(
t1, cleanTestCaseName, aliceBobArgs,
)
require.NoError(t1,
err, "unable to set up test lightning network",
)
defer func() {
require.NoError(t1, lndHarness.TearDown())
}()
lndHarness.EnsureConnected(
t1, lndHarness.Alice, lndHarness.Bob,
)
logLine := fmt.Sprintf(
"STARTING ============ %v ============\n",
testCase.name,
)
lndHarness.Alice.AddToLogf(logLine)
lndHarness.Bob.AddToLogf(logLine)
// Start every test with the default static fee estimate.
lndHarness.SetFeeEstimate(12500)
// Create a separate harness test for the testcase to
// avoid overwriting the external harness test that is
// tied to the parent test.
ht := newHarnessTest(t1, lndHarness)
ht.RunTestCase(testCase)
})
// Stop at the first failure. Mimic behavior of original test
// framework.
if !success {
// Log failure time to help relate the lnd logs to the
// failure.
t.Logf("Failure time: %v", time.Now().Format(
"2006-01-02 15:04:05.000",
))
break
}
}
}
-6
View File
@@ -1,6 +0,0 @@
//go:build !rpctest
// +build !rpctest
package itest
var allTestCases = []*testCase{}
-11
View File
@@ -1,11 +0,0 @@
//go:build rpctest
// +build rpctest
package itest
var allTestCases = []*testCase{
{
name: "async bidirectional payments",
test: testBidirectionalAsyncPayments,
},
}
-302
View File
@@ -1,302 +0,0 @@
<time> [ERR] BRAR: Unable to broadcast justice tx: Transaction rejected: output already spent
<time> [ERR] BRAR: Unable to check for spentness of outpoint=<chan_point>: TxNotifier is exiting
<time> [ERR] BRAR: Unable to register for conf for txid(<hex>): TxNotifier is exiting
<time> [ERR] BRAR: Unable to register for block notifications: chainntnfs: system interrupt while attempting to register for block epoch notification.
<time> [ERR] BTCN: Broadcast attempt failed: rejected by <ip>: replacement transaction <hex> has an insufficient absolute fee: needs <amt>, has <amt>
<time> [ERR] BTCN: Broadcast attempt failed: rejected by <ip>: replacement transaction <hex> has an insufficient fee rate: needs more than <amt>, has <amt>
<time> [ERR] BTCN: Broadcast attempt failed: rejected by <ip>: transaction already exists
<time> [ERR] BTCN: Can't accept connection: unable to accept connection from <ip>: chacha20poly1305: message authentication failed
<time> [ERR] BTCN: Can't accept connection: unable to accept connection from <ip>: EOF
<time> [ERR] BTCN: Can't accept connection: unable to accept connection from <ip>: read tcp <ip>-><ip>: i/o timeout
<time> [ERR] BTCN: Query failed with 0 out of 1 filters received
<time> [ERR] BTCN: unable to get filter for hash=<hex>, retrying: neutrino shutting down
<time> [ERR] BTCN: unable to get filter for hash=<hex>, retrying: unable to fetch cfilter
<time> [ERR] BTCN: Unable to process block connected (height=<height>, hash=<hex>): out of order block <hex>: expected PrevBlock <hex>, got <hex>
<time> [ERR] BTCN: Unknown connid=<id>
<time> [ERR] CHAC: Received an error: rpc error: code = Canceled desc = context canceled, shutting down
<time> [ERR] CHFT: Close channel <chan_point> unknown to store
<time> [ERR] CNCT: ChannelArbitrator(<chan_point>): unable to advance state: channel not found
<time> [ERR] CNCT: ChannelArbitrator(<chan_point>): unable to broadcast close tx: Transaction rejected: output already spent
<time> [ERR] CNCT: ChannelArbitrator(<chan_point>): unable to force close: channel not found
<time> [ERR] CNCT: ChannelArbitrator(<chan_point>): unable to mark commitment broadcasted: channel not found
<time> [ERR] CNCT: ChannelArbitrator(<chan_point>): unable to progress *contractcourt.commitSweepResolver: remote party swept utxo
<time> [ERR] CNCT: ChannelArbitrator(<chan_point>): unable to progress *contractcourt.commitSweepResolver: chainntnfs: system interrupt while attempting to register for block epoch notification.
<time> [ERR] CNCT: ChannelArbitrator(<chan_point>): unable to progress *contractcourt.htlcOutgoingContestResolver: chain notifier shutting down
<time> [ERR] CNCT: ChannelArbitrator(<chan_point>): unable to progress *contractcourt.htlcOutgoingContestResolver: chainntnfs: system interrupt while attempting to register for block epoch notification.
<time> [ERR] CNCT: ChannelArbitrator(<chan_point>): unable to progress *contractcourt.htlcOutgoingContestResolver: resolver canceled
<time> [ERR] CNCT: ChannelArbitrator(<chan_point>): unable to progress *contractcourt.htlcOutgoingContestResolver: the client has been shutdown
<time> [ERR] CNCT: ChannelArbitrator(<chan_point>): unable to progress *contractcourt.htlcOutgoingContestResolver: unable to create pre-image from witness: invalid preimage length of 33, want 32
<time> [ERR] CNCT: ChannelArbitrator(<chan_point>): unable to progress *contractcourt.htlcSuccessResolver: Transaction rejected: output already spent
<time> [ERR] CNCT: ChannelArbitrator(<chan_point>): unable to progress *contractcourt.htlcTimeoutResolver: htlcswitch shutting down
<time> [ERR] CNCT: ChannelArbitrator(<chan_point>): unable to progress *contractcourt.htlcTimeoutResolver: TxNotifier is exiting
<time> [ERR] CNCT: ChannelArbitrator(<chan_point>): unexpected local commitment confirmed while in StateDefault
<time> [ERR] CNCT: ChannelArbitrator(<chan_point>): unexpected local on-chain channel close
<time> [ERR] CNCT: *contractcourt.commitSweepResolver(<chan_point>): unable to sweep input: remote party swept utxo
<time> [ERR] CNCT: Unable to advance state: channel not found
<time> [ERR] CNCT: unable to hand breached contract off to breachArbiter: server is shutting down
<time> [ERR] CNCT: unable to handle channel breach for chan_point=<chan_point>: server is shutting down
<time> [ERR] CNCT: Unable to handle known remote state: unable to handle channel breach for chan_point=<chan_point>: server is shutting down
<time> [ERR] CRTR: Channel update of ourselves received
<time> [ERR] CRTR: Error collecting result for shard <number> for payment <hex>: shard handler exiting
<time> [ERR] CRTR: Error encountered during rescan: rescan exited
<time> [ERR] CRTR: Failed sending attempt <number> for payment <hex> to switch: could not add downstream htlc
<time> [ERR] CRTR: Failed sending attempt <number> for payment <hex> to switch: insufficient bandwidth to route htlc
<time> [ERR] CRTR: Failed sending attempt <number> for payment <hex> to switch: UnknownNextPeer
<time> [ERR] CRTR: out of order block: expecting height=<height>, got height=<height>
<time> [ERR] CRTR: Payment <hex> failed: error
<time> [ERR] CRTR: Payment <hex> failed: incorrect_payment_details
<time> [ERR] CRTR: Payment <hex> failed: insufficient_balance
<time> [ERR] CRTR: Payment <hex> failed: no_route
<time> [ERR] CRTR: Payment <hex> failed: router shutting down
<time> [ERR] CRTR: Payment <hex> failed: timeout
<time> [ERR] CRTR: Resuming payment <hex> failed: error.
<time> [ERR] CRTR: Resuming payment <hex> failed: incorrect_payment_details.
<time> [ERR] CRTR: Resuming payment <hex> failed: no_route.
<time> [ERR] CRTR: Resuming payment <hex> failed: router shutting down.
<time> [ERR] CRTR: unable to add channel: edge not found
<time> [ERR] CRTR: Unable to retrieve channel by id: edge not found
<time> [ERR] DISC: channel announcement proof for short_chan_id=<cid> isn't valid: can't verify first bitcoin signature
<time> [ERR] DISC: router shutting down
<time> [ERR] DISC: unable add proof to the channel chanID=<hex>: edge marked as zombie
<time> [ERR] DISC: unable add proof to the channel chanID=<hex>: edge not found
<time> [ERR] DISC: unable to add channel: edge not found
<time> [ERR] DISC: Unable to reply to peer query: set tcp <ip>: use of closed network connection
<time> [ERR] DISC: Unable to reply to peer query: write tcp <ip>-><ip>: use of closed network connection
<time> [ERR] DISC: Unable to reply to peer query: write tcp <ip>-><ip>: write: broken pipe
<time> [ERR] DISC: Unable to reply to peer query: write tcp <ip>-><ip>: write: connection reset by peer
<time> [ERR] FNDG: received funding error from <hex>: chan_id=<hex>, err=channel too large
<time> [ERR] FNDG: received funding error from <hex>: chan_id=<hex>, err=chan size of 0.16777216 BTC exceeds maximum chan size of 0.16777215 BTC
<time> [ERR] FNDG: received funding error from <hex>: chan_id=<hex>, err=chan size of 10.00000001 BTC exceeds maximum chan size of 0.16777215 BTC
<time> [ERR] FNDG: received funding error from <hex>: chan_id=<hex>, err=chan size of 10.00000001 BTC exceeds maximum chan size of 10 BTC
<time> [ERR] FNDG: received funding error from <hex>: chan_id=<hex>, err=Number of pending channels exceed maximum
<time> [ERR] FNDG: received funding error from <hex>: chan_id=<hex>, err=Synchronizing blockchain
<time> [ERR] FNDG: received funding error from <hex>: chan_id=<hex>, err=chan size of 0.001 BTC is below min chan size of 0.002 BTC
<time> [ERR] FNDG: received funding error from <hex>: chan_id=<hex>, err=funding failed due to internal error
<time> [ERR] FNDG: Unable to add new channel <chan_point> with peer <hex>: canceled adding new channel
<time> [ERR] FNDG: Unable to add new channel <chan_point> with peer <hex>: peer exiting
<time> [ERR] FNDG: Unable to add new channel <chan_point> with peer <hex>: unable to get best block: the client has been shutdown
<time> [ERR] FNDG: Unable to advance pending state of ChannelPoint(<chan_point>): error waiting for funding confirmation for ChannelPoint(<chan_point>): epoch client shutting down
<time> [ERR] FNDG: Unable to advance pending state of ChannelPoint(<chan_point>): error waiting for funding confirmation for ChannelPoint(<chan_point>): funding manager shutting down
<time> [ERR] FNDG: Unable to advance pending state of ChannelPoint(<chan_point>): error waiting for funding confirmation for ChannelPoint(<chan_point>): waiting for fundingconfirmation failed
<time> [ERR] FNDG: Unable to advance state(<chan_point>): error sending channel announcement: ChainNotifier shutting down, cannot complete funding flow for ChannelPoint(<chan_point>)
<time> [ERR] FNDG: Unable to advance state(<chan_point>): error sending channel announcement: channel announcement failed: channel announcement proof for short_chan_id=<cid> isn't valid: can't verify first bitcoin signature
<time> [ERR] FNDG: Unable to advance state(<chan_point>): error sending channel announcement: channel announcement failed: funding manager shutting down
<time> [ERR] FNDG: Unable to advance state(<chan_point>): error sending channel announcement: channel announcement failed: gossiper is shutting down
<time> [ERR] FNDG: Unable to advance state(<chan_point>): error sending channel announcement: channel announcement failed: router shutting down
<time> [ERR] FNDG: Unable to advance state(<chan_point>): error sending channel announcement: channel announcement failed: unable add proof to the channel chanID=<hex>: edge marked as zombie
<time> [ERR] FNDG: Unable to advance state(<chan_point>): error sending channel announcement: channel announcement failed: unable add proof to the channel chanID=<hex>: edge not found
<time> [ERR] FNDG: Unable to advance state(<chan_point>): error sending channel announcement: unable to register for confirmation of ChannelPoint(<chan_point>): chain notifier shutting down
<time> [ERR] FNDG: Unable to advance state(<chan_point>): error sending channel announcement: unable to register for confirmation of ChannelPoint(<chan_point>): TxNotifier is exiting
<time> [ERR] FNDG: Unable to advance state(<chan_point>): failed adding to router graph: error sending channel announcement: gossiper is shutting down
<time> [ERR] FNDG: Unable to advance state(<chan_point>): failed adding to router graph: error sending channel announcement: router shutting down
<time> [ERR] FNDG: Unable to advance state(<chan_point>): failed adding to router graph: error sending channel update: router shutting down
<time> [ERR] FNDG: Unable to advance state(<chan_point>): failed adding to router graph: funding manager shutting down
<time> [ERR] FNDG: Unable to advance state(<chan_point>): failed sending fundingLocked: funding manager shutting down
<time> [ERR] FNDG: Unable to advance state(<chan_point>): funding manager shutting down
<time> [ERR] FNDG: unable to cancel reservation: no active reservations for peer(<hex>)
<time> [ERR] FNDG: Unable to handle funding accept message for peer_key=<hex>, pending_chan_id=<hex>: aborting PSBT flow: user canceled funding
<time> [ERR] FNDG: unable to report short chan id: link <hex> not found
<time> [ERR] FNDG: Unable to send channel proof: channel announcement proof for short_chan_id=<cid> isn't valid: can't verify first bitcoin signature
<time> [ERR] FNDG: Unable to send channel proof: gossiper is shutting down
<time> [ERR] FNDG: Unable to send channel proof: unable add proof to the channel chanID=<hex>: edge marked as zombie
<time> [ERR] FNDG: Unable to send channel proof: unable add proof to the channel chanID=<hex>: edge not found
<time> [ERR] FNDG: Unable to send node announcement: gossiper is shutting down
<time> [ERR] FNDG: Unable to send node announcement: router shutting down
<time> [ERR] FNDG: unable to open channel to NodeKey(<hex>): remote canceled funding, possibly timed out: received funding error from <hex>: chan_id=<hex>, err=chan size of 0.001 BTC is below min chan size of 0.002 BTC
<time> [ERR] HSWC: AmountBelowMinimum(amt=<amt>, update=(lnwire.ChannelUpdate) {
<time> [ERR] HSWC: ChannelLink(<chan_point>): failing link: ChannelPoint(<chan_point>): received error from peer: chan_id=<hex>, err=internal error with error: remote error
<time> [ERR] HSWC: ChannelLink(<chan_point>): failing link: ChannelPoint(<chan_point>): received error from peer: chan_id=<hex>, err=invalid update with error: remote error
<time> [ERR] HSWC: ChannelLink(<chan_point>): failing link: ChannelPoint(<chan_point>): received error from peer: chan_id=<hex>, err=sync error with error: remote error
<time> [ERR] HSWC: ChannelLink(<chan_point>): failing link: ChannelPoint(<chan_point>): received error from peer: chan_id=<hex>, err=unable to resume channel, recovery required with error: remote error
<time> [ERR] HSWC: ChannelLink(<chan_point>): failing link: unable to handle upstream settle HTLC: Invalid payment preimage <hex> for hash <hex> with error: invalid update
<time> [ERR] HSWC: ChannelLink(<chan_point>): failing link: unable to synchronize channel states: ChannelPoint(<chan_point>) with CommitPoint(<hex>) had possible local commitment state data loss with error: unable to resume channel, recovery required
<time> [ERR] HSWC: ChannelLink(<chan_point>): failing link: unable to synchronize channel states: possible remote commitment state data loss with error: sync error
<time> [ERR] HSWC: ChannelLink(<chan_point>): failing link: unable to synchronize channel states: Unable to send chan sync message for ChannelPoint(<chan_point>): peer exiting with error: unable to resume channel, recovery required
<time> [ERR] HSWC: ChannelLink(<chan_point>): failing link: unable to synchronize channel states: unable to send chan sync message for ChannelPoint(<chan_point>): set tcp <ip>: use of closed network connection with error: unable to resume channel, recovery required
<time> [ERR] HSWC: ChannelLink(<chan_point>): failing link: unable to synchronize channel states: unable to send chan sync message for ChannelPoint(<chan_point>): set tcp <ip>: use of closed network connection with error: unable to resume channel, recovery required
<time> [ERR] HSWC: ChannelLink(<chan_point>): failing link: unable to synchronize channel states: Unable to send chan sync message for ChannelPoint(<chan_point>): write tcp <ip>-><ip>: use of closed network connection with error: unable to resume channel, recovery required
<time> [ERR] HSWC: ChannelLink(<chan_point>): failing link: unable to synchronize channel states: Unable to send chan sync message for ChannelPoint(<chan_point>): write tcp <ip>-><ip>: write: broken pipe with error: unable to resume channel, recovery required
<time> [ERR] HSWC: ChannelLink(<chan_point>): failing link: unable to synchronize channel states: unable to send chan sync message for ChannelPoint(<chan_point>): write tcp <ip>-><ip>: write: connection reset by peer with error: unable to resume channel, recovery required
<time> [ERR] HSWC: ChannelLink(<chan_point>): failing link: unable to update commitment: link shutting down with error: internal error
<time> [ERR] HSWC: ChannelLink(<chan_point>): link failed, exiting htlcManager
<time> [ERR] HSWC: ChannelLink(<chan_point>): unable to cancel incoming HTLC for circuit-key=(Chan ID=<chan>, HTLC ID=0): HTLC with ID 0 has already been failed
<time> [ERR] HSWC: ChannelLink(<chan_point>): unable to decode onion hop iterator: TemporaryChannelFailure
<time> [ERR] HSWC: ChannelLink(<chan_point>): unable to update signals
<time> [ERR] HSWC: ChannelLink(<chan_point>): unhandled error while forwarding htlc packet over htlcswitch: AmountBelowMinimum(amt=4000 mSAT, update=(lnwire.ChannelUpdate) {
<time> [ERR] HSWC: ChannelLink(<chan_point>): unhandled error while forwarding htlc packet over htlcswitch: circuit has already been closed
<time> [ERR] HSWC: ChannelLink(<chan_point>): unhandled error while forwarding htlc packet over htlcswitch: insufficient bandwidth to route htlc
<time> [ERR] HSWC: ChannelLink(<chan_point>): unhandled error while forwarding htlc packet over htlcswitch: node configured to disallow forwards
<time> [ERR] HSWC: ChannelLink(<chan_point>): unhandled error while forwarding htlc packet over htlcswitch: UnknownNextPeer
<time> [ERR] HSWC: FeeInsufficient(htlc_amt==<amt>, update=(lnwire.ChannelUpdate) {
<time> [ERR] HSWC: insufficient bandwidth to route htlc
<time> [ERR] HSWC: Link <chan> not found
<time> [ERR] HSWC: Link <chan> policy for local forward not satisfied
<time> [ERR] HSWC: node configured to disallow forwards
<time> [ERR] HSWC: unable to de-obfuscate onion failure (hash=<hex>, pid=<pid>): invalid error length: expected 292 got 0
<time> [ERR] HSWC: unable to find target channel for HTLC fail: channel ID = <chan>, HTLC ID = <id>
<time> [ERR] HSWC: Unable to forward resolution msg: unable to find target channel for HTLC fail: channel ID = <chan>, HTLC ID = <id>
<time> [ERR] HSWC: unable to process onion packet: sphinx packet replay attempted
<time> [ERR] HSWC: Unhandled error while reforwarding htlc settle/fail over htlcswitch: AmountBelowMinimum(amt=<amt>, update=(lnwire.ChannelUpdate) {
<time> [ERR] HSWC: Unhandled error while reforwarding htlc settle/fail over htlcswitch: circuit has already been closed
<time> [ERR] HSWC: Unhandled error while reforwarding htlc settle/fail over htlcswitch: FeeInsufficient(htlc_amt==<amt>, update=(lnwire.ChannelUpdate) {
<time> [ERR] HSWC: Unhandled error while reforwarding htlc settle/fail over htlcswitch: insufficient bandwidth to route htlc
<time> [ERR] HSWC: Unhandled error while reforwarding htlc settle/fail over htlcswitch: node configured to disallow forwards
<time> [ERR] HSWC: Unhandled error while reforwarding htlc settle/fail over htlcswitch: UnknownNextPeer
<time> [ERR] HSWC: UnknownNextPeer
<time> [ERR] LNWL: ChannelPoint(<chan_point>): sync failed: remote believes our tail height is <height>, while we have <height>!
<time> [ERR] LNWL: ChannelPoint(<chan_point>): sync failed: remote's next commit height is <height>, while we believe it is <height>!
<time> [ERR] LNWL: ChannelPoint(<chan_point>): sync failed with local data loss: remote believes our tail height is <height>, while we have <height>!
<time> [ERR] LNWL: Neutrino rescan ended with error: rescan exited
<time> [ERR] LNWL: Notifying unmined tx notification (<hex>) while creating notification for blocks
<time> [ERR] LNWL: Rescan for <num> addresses failed: the client has been shutdown
<time> [ERR] LTND: Unable to lookup witness: no witnesses
<time> [ERR] NANN: Unable to retrieve chan status for Channel(<chan_point>): edge not found
<time> [ERR] NANN: Unable to retrieve chan status for Channel(<chan_point>): unable to extract ChannelUpdate for channel <chan_point>
<time> [ERR] NANN: Unable to sign update disabling channel(<chan_point>): edge not found
<time> [ERR] NTFN: chain notifier shutting down
<time> [ERR] NTFN: Error during rescan: rescan exited
<time> [ERR] NTFN: Failed getting UTXO: get utxo request cancelled
<time> [ERR] NTFN: Rescan to determine the spend details of <chan_point> failed: the client has been shutdown
<time> [ERR] NTFN: Unable to fetch block header: the client has been shutdown
<time> [ERR] NTFN: unable to find blockhash for height=<height>: -1: Block number out of range
<time> [ERR] NTFN: unable to get block: Post "http://<ip>": dial tcp <ip>: connect: connection refused
<time> [ERR] NTFN: unable to get block: Post "http://<ip>": dial tcp <ip>: connect: connection reset by peer
<time> [ERR] NTFN: unable to get block: Post "http://<ip>": read tcp <ip>-><ip>: read: connection reset by peer
<time> [ERR] NTFN: unable to get block: the client has been shutdown
<time> [ERR] NTFN: unable to get hash from block with height 790
<time> [ERR] NTFN: unable to get missed blocks: starting height <height> is greater than ending height <height>
<time> [ERR] NTFN: Unable to rewind chain from height <height> to height <height>: unable to find blockhash for disconnected height=<height>: -1: Block number out of range
<time> [ERR] NTFN: Unable to rewind chain from height <height> to height <height>: unable to find blockhash for disconnected height=<height>: -8: Block height out of range
<time> [ERR] NTNF: unable to get hash from block with height <height>
<time> [ERR] PEER: Allowed test error from <ip> (inbound): ReadMessage: unhandled command [sendaddrv2]
<time> [ERR] PEER: resend failed: unable to fetch channel sync messages for peer <hex>@<ip>: unable to find closed channel summary
<time> [ERR] PEER: unable to close channel, ChannelID(<hex>) is unknown
<time> [ERR] PEER: unable to force close link(<chan>): ChainArbitrator exiting
<time> [ERR] PEER: unable to force close link(<chan>): channel not found
<time> [ERR] PEER: unable to force close link(<chan>): unable to find arbitrator
<time> [ERR] PEER: unable to get best block: the client has been shutdown
<time> [ERR] PEER: unable to send msg to remote peer: peer exiting
<time> [ERR] PEER: unable to send msg to remote peer: write tcp <ip>-><ip>: write: broken pipe
<time> [ERR] PEER: unable to send msg to remote peer: write tcp <ip>-><ip>: write: connection reset by peer
<time> [ERR] RPCS: [/chainrpc.ChainNotifier/RegisterBlockEpochNtfn]: chain notifier shutting down
<time> [ERR] RPCS: [/chainrpc.ChainNotifier/RegisterBlockEpochNtfn]: context canceled
<time> [ERR] RPCS: [closechannel] unable to close ChannelPoint(<chan_point>): chain notifier shutting down
<time> [ERR] RPCS: [connectpeer]: error connecting to peer: already connected to peer: <hex>@<ip>
<time> [ERR] RPCS: [connectpeer]: error connecting to peer: dial tcp <ip>: i/o timeout
<time> [ERR] RPCS: [connectpeer]: error connecting to peer: dial tcp <ip>: i/o timeout
<time> [ERR] RPCS: [connectpeer]: error connecting to peer: read tcp <ip>-><ip>: i/o timeout
<time> [ERR] RPCS: Failed receiving from stream: rpc error: code = Canceled desc = context canceled
<time> [ERR] RPCS: Failed receiving from stream: rpc error: code = DeadlineExceeded desc = context deadline exceeded
<time> [ERR] RPCS: Failed sending error response: rpc error: code = Canceled desc = context canceled
<time> [ERR] RPCS: Failed sending error response: rpc error: code = Internal desc = transport: transport: the stream is done or WriteHeader was already called
<time> [ERR] RPCS: Failed sending response: rpc error: code = Canceled desc = context canceled
<time> [ERR] RPCS: Failed sending response: rpc error: code = Internal desc = transport: transport: the stream is done or WriteHeader was already called
<time> [ERR] RPCS: [/invoicesrpc.Invoices/SubscribeSingleInvoice]: rpc error: code = Canceled desc = context canceled
<time> [ERR] RPCS: [/lnrpc.Lightning/BatchOpenChannel]: batch funding failed: error batch opening channel, initial negotiation failed: remote canceled funding, possibly timed out: received funding error from <hex>: chan_id=<hex>, err=chan size of 0.001 BTC is below min chan size of 0.002 BTC
<time> [ERR] RPCS: [/lnrpc.Lightning/BakeMacaroon]: invalid permission action. supported actions are [read write generate], supported entities are [onchain offchain address message peers info invoices signer macaroon uri]
<time> [ERR] RPCS: [/lnrpc.Lightning/BakeMacaroon]: invalid permission entity. supported actions are [read write generate], supported entities are [onchain offchain address message peers info invoices signer macaroon uri]
<time> [ERR] RPCS: [/lnrpc.Lightning/BakeMacaroon]: permission list cannot be empty. specify at least one action/entity pair. supported actions are [read write generate], supported entities are [onchain offchain address message peers info invoices signer macaroon uri]
<time> [ERR] RPCS: [/lnrpc.Lightning/ChannelAcceptor]: rpc error: code = Canceled desc = context canceled
<time> [ERR] RPCS: [/lnrpc.Lightning/CloseChannel]: cannot close channel with state: ChanStatusRestored
<time> [ERR] RPCS: [/lnrpc.Lightning/CloseChannel]: cannot co-op close frozen channel as initiator until height=3059, (current_height=3055)
<time> [ERR] RPCS: [/lnrpc.Lightning/CloseChannel]: cannot co-op close frozen channel as initiator until height=<height>, (current_height=<height>)
<time> [ERR] RPCS: [/lnrpc.Lightning/CloseChannel]: chain notifier shutting down
<time> [ERR] RPCS: [/lnrpc.Lightning/CloseChannel]: must specify channel point in close channel
<time> [ERR] RPCS: [/lnrpc.Lightning/CloseChannel]: rpc error: code = DeadlineExceeded desc = context deadline exceeded
<time> [ERR] RPCS: [/lnrpc.Lightning/CloseChannel]: server is still in the process of starting
<time> [ERR] RPCS: [/lnrpc.Lightning/ConnectPeer]: already connected to peer: <hex>@<ip>
<time> [ERR] RPCS: [/lnrpc.Lightning/ConnectPeer]: dial tcp <ip>: i/o timeout
<time> [ERR] RPCS: [/lnrpc.Lightning/ConnectPeer]: dial tcp <ip>: i/o timeout
<time> [ERR] RPCS: [/lnrpc.Lightning/ConnectPeer]: read tcp <ip>-><ip>: i/o timeout
<time> [ERR] RPCS: [/lnrpc.Lightning/ConnectPeer]: server is still in the process of starting
<time> [ERR] RPCS: [/lnrpc.Lightning/DeleteMacaroonID]: the specified ID cannot be deleted
<time> [ERR] RPCS: [/lnrpc.Lightning/FundingStateStep]: pendingChanID(<hex>) already has intent registered
<time> [ERR] RPCS: [/lnrpc.Lightning/GetChanInfo]: edge marked as zombie
<time> [ERR] RPCS: [/lnrpc.Lightning/GetChanInfo]: edge not found
<time> [ERR] RPCS: [/lnrpc.Lightning/OpenChannel]: channels cannot be created before the wallet is fully synced
<time> [ERR] RPCS: [/lnrpc.Lightning/OpenChannel]: received funding error from <hex>: chan_id=<hex>, err=channel too large
<time> [ERR] RPCS: [/lnrpc.Lightning/OpenChannel]: received funding error from <hex>: chan_id=<hex>, err=chan size of 0.16777216 BTC exceeds maximum chan size of 0.16777215 BTC
<time> [ERR] RPCS: [/lnrpc.Lightning/OpenChannel]: received funding error from <hex>: chan_id=<hex>, err=chan size of 10.00000001 BTC exceeds maximum chan size of 0.16777215 BTC
<time> [ERR] RPCS: [/lnrpc.Lightning/OpenChannel]: received funding error from <hex>: chan_id=<hex>, err=chan size of 10.00000001 BTC exceeds maximum chan size of 10 BTC
<time> [ERR] RPCS: [/lnrpc.Lightning/OpenChannel]: received funding error from <hex>: chan_id=<hex>, err=Number of pending channels exceed maximum
<time> [ERR] RPCS: [/lnrpc.Lightning/OpenChannel]: received funding error from <hex>: chan_id=<hex>, err=Synchronizing blockchain
<time> [ERR] RPCS: [/lnrpc.Lightning/PendingChannels]: unable to find arbitrator
<time> [ERR] RPCS: [/lnrpc.Lightning/SendCoins]: address: tb1qfc8fusa98jx8uvnhzavxccqlzvg749tvjw82tg is not valid for this network: regtest
<time> [ERR] RPCS: [/lnrpc.Lightning/SendCoins]: amount set while SendAll is active
<time> [ERR] RPCS: [/lnrpc.Lightning/SendCoins]: cannot send coins to pubkeys
<time> [ERR] RPCS: [/lnrpc.Lightning/SendCoins]: unknown address type
<time> [ERR] RPCS: [/lnrpc.Lightning/SendPayment]: rpc error: code = Canceled desc = context canceled
<time> [ERR] RPCS: [/lnrpc.Lightning/SendPayment]: rpc error: code = DeadlineExceeded desc = context deadline exceeded
<time> [ERR] RPCS: [/lnrpc.Lightning/SendPayment]: rpc server shutting down
<time> [ERR] RPCS: [/lnrpc.Lightning/SendToRoute]: rpc error: code = Canceled desc = context canceled
<time> [ERR] RPCS: [/lnrpc.Lightning/SendToRoute]: rpc error: code = DeadlineExceeded desc = context deadline exceeded
<time> [ERR] RPCS: [/lnrpc.Lightning/SendToRoute]: rpc server shutting down
<time> [ERR] RPCS: [/lnrpc.Lightning/SubscribeChannelEvents]: rpc error: code = Canceled desc = context canceled
<time> [ERR] RPCS: [/lnrpc.Lightning/SubscribeChannelGraph]: ChannelRouter shutting down
<time> [ERR] RPCS: [/lnrpc.Lightning/SubscribeChannelGraph]: router not started
<time> [ERR] RPCS: [/lnrpc.Lightning/SubscribeChannelGraph]: rpc error: code = Canceled desc = context canceled
<time> [ERR] RPCS: [/lnrpc.Lightning/SubscribeChannelGraph]: rpc error: code = DeadlineExceeded desc = context deadline exceeded
<time> [ERR] RPCS: [/lnrpc.Lightning/SubscribeChannelGraph]: rpc error: code = Internal desc = transport: transport: the stream is done or WriteHeader was already called
<time> [ERR] RPCS: [/lnrpc.Lightning/SubscribeInvoices]: rpc error: code = Canceled desc = context canceled
<time> [ERR] RPCS: [/routerrpc.Router/HtlcInterceptor]: rpc error: code = Canceled desc = context canceled
<time> [ERR] RPCS: [/routerrpc.Router/SendPayment]: routerrpc server shutting down
<time> [ERR] RPCS: [/routerrpc.Router/SendPaymentV2]: context canceled
<time> [ERR] RPCS: [/routerrpc.Router/SendPaymentV2]: context deadline exceeded
<time> [ERR] RPCS: [/routerrpc.Router/SendPaymentV2]: routerrpc server shutting down
<time> [ERR] RPCS: [/routerrpc.Router/SubscribeHtlcEvents]: context canceled
<time> [ERR] RPCS: [/routerrpc.Router/SubscribeHtlcEvents]: htlc event subscription terminated
<time> [ERR] RPCS: [/routerrpc.Router/SubscribeHtlcEvents]: context deadline exceeded
<time> [ERR] RPCS: [/routerrpc.Route<time> [INF] LTND: Listening on the p2p interface is disabled!
<time> [ERR] RPCS: [/signrpc.Signer/DeriveSharedKey]: must provide ephemeral pubkey
<time> [ERR] RPCS: [/signrpc.Signer/DeriveSharedKey]: use either key_desc or key_loc
<time> [ERR] RPCS: [/signrpc.Signer/DeriveSharedKey]: use either raw_key_bytes or key_index
<time> [ERR] RPCS: [/signrpc.Signer/DeriveSharedKey]: when setting key_desc the field key_desc.key_loc must also be set
<time> [ERR] RPCS: [/lnrpc.Lightning/BakeMacaroon]: permission denied
<time> [ERR] RPCS: [/lnrpc.Lightning/GetInfo]: cannot retrieve macaroon: cannot get macaroon: root key with id doesn't exist
<time> [ERR] RPCS: [/lnrpc.Lightning/GetInfo]: caveat "ipaddr 1.1.1.1" not satisfied: macaroon locked to different IP address
<time> [ERR] RPCS: [/lnrpc.Lightning/GetInfo]: caveat "time-before <time>" not satisfied: macaroon has expired
<time> [ERR] RPCS: [/lnrpc.Lightning/GetInfo]: expected 1 macaroon, got 0
<time> [ERR] RPCS: [/lnrpc.Lightning/GetInfo]: permission denied
<time> [ERR] RPCS: [/lnrpc.Lightning/GetInfo]: the RPC server is in the process of starting up, but not yet ready to accept calls
<time> [ERR] RPCS: [/lnrpc.Lightning/GetInfo]: wallet locked, unlock it to enable full RPC access
<time> [ERR] RPCS: [/lnrpc.Lightning/ListMacaroonIDs]: cannot retrieve macaroon: cannot get macaroon: root key with id 1 doesn't exist
<time> [ERR] RPCS: [/lnrpc.Lightning/NewAddress]: permission denied
<time> [ERR] RPCS: unable to open channel to NodeKey(<hex>): received funding error from <hex>: chan_id=<hex>, err=channel too large
<time> [ERR] RPCS: unable to open channel to NodeKey(<hex>): received funding error from <hex>: chan_id=<hex>, err=chan size of 0.16777216 BTC exceeds maximum chan size of 0.16777215 BTC
<time> [ERR] RPCS: unable to open channel to NodeKey(<hex>): received funding error from <hex>: chan_id=<hex>, err=chan size of 10.00000001 BTC exceeds maximum chan size of 0.16777215 BTC
<time> [ERR] RPCS: unable to open channel to NodeKey(<hex>): received funding error from <hex>: chan_id=<hex>, err=chan size of 10.00000001 BTC exceeds maximum chan size of 10 BTC
<time> [ERR] RPCS: unable to open channel to NodeKey(<hex>): received funding error from <hex>: chan_id=<hex>, err=Number of pending channels exceed maximum
<time> [ERR] RPCS: unable to open channel to NodeKey(<hex>): received funding error from <hex>: chan_id=<hex>, err=Synchronizing blockchain
<time> [ERR] RPCS: [/walletrpc.WalletKit/LabelTransaction]: cannot label transaction with empty label
<time> [ERR] RPCS: [/walletrpc.WalletKit/LabelTransaction]: transaction already labelled
<time> [ERR] RPCS: Websocket receive error from <ip>: read tcp4 <ip>-><ip>: use of closed network connection
<time> [ERR] RPCS: Websocket receive error from <ip>: websocket: close 1006 unexpected EOF
<time> [ERR] RPCS: WS: error closing upgraded conn: write tcp4 <ip>-><ip>: write: connection reset by peer
<time> [ERR] SRVR: Unable to connect to <hex>@<ip>: dial tcp <ip>: i/o timeout
<time> [ERR] SRVR: Unable to connect to <hex>@<ip>: dial tcp <ip>: i/o timeout
<time> [ERR] SRVR: Unable to connect to <hex>@<ip>: read tcp <ip>-><ip>: i/o timeout
<time> [ERR] SRVR: Unable to retrieve advertised address for node <hex>: no advertised addresses found
<time> [ERR] SRVR: Unable to retrieve advertised address for node <hex>: unable to find node
<time> [ERR] UTXN: error while graduating class at height=<height>: TxNotifier is exiting
<time> [ERR] UTXN: Failed to sweep first-stage HTLC (CLTV-delayed) output <chan_point>
<time> [ERR] UTXN: Notification chan closed, can't advance output <chan_point>
<time> [ERR] DISC: Unable to rebroadcast stale announcements: unable to retrieve outgoing channels: channel from self node has no policy
<time> [ERR] RPCS: [/lnrpc.Lightning/OpenChannel]: reserved wallet balance invalidated: transaction would leave insufficient funds for fee bumping anchor channel closings (see debug log for details)
<time> [ERR] RPCS: [/lnrpc.Lightning/SendCoins]: reserved wallet balance invalidated: transaction would leave insufficient funds for fee bumping anchor channel closings (see debug log for details)
<time> [ERR] RPCS: unable to open channel to NodeKey(<hex>): reserved wallet balance invalidated: transaction would leave insufficient funds for fee bumping anchor channel closings (see debug log for details)
<time> [ERR] NANN: Unable to retrieve chan status for Channel(<chan_point>): unable to extract ChannelUpdate
<time> [ERR] NTFN: Unable to rewind chain from height 1 to height -1: unable to find blockhash for disconnected height=<height>: -8: Block height out of range
<time> [ERR] RPCS: WS: error writing message: websocket: close sent
<time> [ERR] RPCS: [/routerrpc.Router/XImportMissionControl]: pair: <hex> -> <hex>: invalid failure: msat: <amt> and sat: 0.0000002 BTC values not equal
<time> [ERR] BTCN: utxo scan failed: neutrino shutting down
<time> [ERR] RPCS: [/lnrpc.Lightning/SubscribeChannelGraph]: context canceled
<time> [ERR] RPCS: [/lnrpc.Lightning/SubscribeInvoices]: context canceled
<time> [ERR] RPCS: [/lnrpc.Lightning/SubscribeChannelGraph]: context deadline exceeded
<time> [ERR] RPCS: [/invoicesrpc.Invoices/SubscribeSingleInvoice]: context canceled
<time> [ERR] RPCS: [/lnrpc.State/SubscribeState]: context canceled
<time> [ERR] NTFN: Failed to update rescan progress: database not open
<time> [ERR] HSWC: ChannelLink(<chan_point>): failing link: process hodl queue: unable to update commitment: link shutting down with error: internal error
<time> [ERR] INVC: SettleHodlInvoice with preimage <hex>: invoice already canceled
<time> [ERR] RPCS: [/invoicesrpc.Invoices/SettleInvoice]: invoice already canceled
<time> [ERR] HSWC: ChannelLink(<chan_point>): outgoing htlc(<hex>) has insufficient fee: expected 33000, got 1020
<time> [ERR] RPCS: [/lnrpc.Lightning/CloseChannel]: rpc error: code = Canceled desc = context canceled
-351
View File
@@ -1,351 +0,0 @@
package itest
import (
"bytes"
"context"
"flag"
"fmt"
"math"
"os"
"path/filepath"
"runtime"
"testing"
"time"
"github.com/btcsuite/btcd/chaincfg"
"github.com/btcsuite/btcd/chaincfg/chainhash"
"github.com/btcsuite/btcd/rpcclient"
"github.com/btcsuite/btcd/wire"
"github.com/go-errors/errors"
"github.com/lightningnetwork/lnd/lnrpc"
"github.com/lightningnetwork/lnd/lnrpc/walletrpc"
"github.com/lightningnetwork/lnd/lntest"
"github.com/lightningnetwork/lnd/lntest/wait"
"github.com/stretchr/testify/require"
)
var (
harnessNetParams = &chaincfg.RegressionNetParams
// lndExecutable is the full path to the lnd binary.
lndExecutable = flag.String(
"lndexec", itestLndBinary, "full path to lnd binary",
)
slowMineDelay = 20 * time.Millisecond
)
const (
testFeeBase = 1e+6
defaultCSV = lntest.DefaultCSV
defaultTimeout = lntest.DefaultTimeout
minerMempoolTimeout = lntest.MinerMempoolTimeout
channelCloseTimeout = lntest.ChannelCloseTimeout
itestLndBinary = "../../lnd-itest"
anchorSize = 330
noFeeLimitMsat = math.MaxInt64
AddrTypeWitnessPubkeyHash = lnrpc.AddressType_WITNESS_PUBKEY_HASH
AddrTypeNestedPubkeyHash = lnrpc.AddressType_NESTED_PUBKEY_HASH
AddrTypeTaprootPubkey = lnrpc.AddressType_TAPROOT_PUBKEY
)
// harnessTest wraps a regular testing.T providing enhanced error detection
// and propagation. All error will be augmented with a full stack-trace in
// order to aid in debugging. Additionally, any panics caused by active
// test cases will also be handled and represented as fatals.
type harnessTest struct {
t *testing.T
// testCase is populated during test execution and represents the
// current test case.
testCase *testCase
// lndHarness is a reference to the current network harness. Will be
// nil if not yet set up.
lndHarness *lntest.NetworkHarness
}
// newHarnessTest creates a new instance of a harnessTest from a regular
// testing.T instance.
func newHarnessTest(t *testing.T, net *lntest.NetworkHarness) *harnessTest {
return &harnessTest{t, nil, net}
}
// Skipf calls the underlying testing.T's Skip method, causing the current test
// to be skipped.
func (h *harnessTest) Skipf(format string, args ...interface{}) {
h.t.Skipf(format, args...)
}
// Fatalf causes the current active test case to fail with a fatal error. All
// integration tests should mark test failures solely with this method due to
// the error stack traces it produces.
func (h *harnessTest) Fatalf(format string, a ...interface{}) {
if h.lndHarness != nil {
h.lndHarness.SaveProfilesPages(h.t)
}
stacktrace := errors.Wrap(fmt.Sprintf(format, a...), 1).ErrorStack()
if h.testCase != nil {
h.t.Fatalf("Failed: (%v): exited with error: \n"+
"%v", h.testCase.name, stacktrace)
} else {
h.t.Fatalf("Error outside of test: %v", stacktrace)
}
}
// RunTestCase executes a harness test case. Any errors or panics will be
// represented as fatal.
func (h *harnessTest) RunTestCase(testCase *testCase) {
h.testCase = testCase
defer func() {
h.testCase = nil
}()
defer func() {
if err := recover(); err != nil {
description := errors.Wrap(err, 2).ErrorStack()
h.t.Fatalf("Failed: (%v) panicked with: \n%v",
h.testCase.name, description)
}
}()
testCase.test(h.lndHarness, h)
}
func (h *harnessTest) Logf(format string, args ...interface{}) {
h.t.Logf(format, args...)
}
func (h *harnessTest) Log(args ...interface{}) {
h.t.Log(args...)
}
func (h *harnessTest) getLndBinary() string {
binary := itestLndBinary
lndExec := ""
if lndExecutable != nil && *lndExecutable != "" {
lndExec = *lndExecutable
}
if lndExec == "" && runtime.GOOS == "windows" {
// Windows (even in a bash like environment like git bash as on
// Travis) doesn't seem to like relative paths to exe files...
currentDir, err := os.Getwd()
if err != nil {
h.Fatalf("unable to get working directory: %v", err)
}
targetPath := filepath.Join(currentDir, "../../lnd-itest.exe")
binary, err = filepath.Abs(targetPath)
if err != nil {
h.Fatalf("unable to get absolute path: %v", err)
}
} else if lndExec != "" {
binary = lndExec
}
return binary
}
type testCase struct {
name string
test func(net *lntest.NetworkHarness, t *harnessTest)
}
// waitForTxInMempool polls until finding one transaction in the provided
// miner's mempool. An error is returned if *one* transaction isn't found within
// the given timeout.
func waitForTxInMempool(miner *rpcclient.Client,
timeout time.Duration) (*chainhash.Hash, error) {
txs, err := waitForNTxsInMempool(miner, 1, timeout)
if err != nil {
return nil, err
}
return txs[0], err
}
// waitForNTxsInMempool polls until finding the desired number of transactions
// in the provided miner's mempool. An error is returned if this number is not
// met after the given timeout.
func waitForNTxsInMempool(miner *rpcclient.Client, n int,
timeout time.Duration) ([]*chainhash.Hash, error) {
breakTimeout := time.After(timeout)
ticker := time.NewTicker(50 * time.Millisecond)
defer ticker.Stop()
var err error
var mempool []*chainhash.Hash
for {
select {
case <-breakTimeout:
return nil, fmt.Errorf("wanted %v, found %v txs "+
"in mempool: %v", n, len(mempool), mempool)
case <-ticker.C:
mempool, err = miner.GetRawMempool()
if err != nil {
return nil, err
}
if len(mempool) == n {
return mempool, nil
}
}
}
}
// mineBlocks 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 mineBlocksFast(t *harnessTest, net *lntest.NetworkHarness,
num uint32, numTxs int) []*wire.MsgBlock {
// If we expect transactions to be included in the blocks we'll mine,
// we wait here until they are seen in the miner's mempool.
var txids []*chainhash.Hash
var err error
if numTxs > 0 {
txids, err = waitForNTxsInMempool(
net.Miner.Client, numTxs, minerMempoolTimeout,
)
if err != nil {
t.Fatalf("unable to find txns in mempool: %v", err)
}
}
blocks := make([]*wire.MsgBlock, num)
blockHashes, err := net.Miner.Client.Generate(num)
if err != nil {
t.Fatalf("unable to generate blocks: %v", err)
}
for i, blockHash := range blockHashes {
block, err := net.Miner.Client.GetBlock(blockHash)
if err != nil {
t.Fatalf("unable to get block: %v", err)
}
blocks[i] = block
}
// Finally, assert that all the transactions were included in the first
// block.
for _, txid := range txids {
assertTxInBlock(t, blocks[0], txid)
}
return blocks
}
// mineBlocksSlow mines 'num' of blocks and checks that blocks are present in
// the mining node's blockchain. numTxs should be set to the number of
// transactions (excluding the coinbase) we expect to be included in the first
// mined block. Between each mined block an artificial delay is introduced to
// give all network participants time to catch up.
//
// NOTE: This function currently is just an alias for mineBlocksSlow.
func mineBlocks(t *harnessTest, net *lntest.NetworkHarness,
num uint32, numTxs int) []*wire.MsgBlock {
return mineBlocksSlow(t, net, num, numTxs)
}
// mineBlocksSlow mines 'num' of blocks and checks that blocks are present in
// the mining node's blockchain. numTxs should be set to the number of
// transactions (excluding the coinbase) we expect to be included in the first
// mined block. Between each mined block an artificial delay is introduced to
// give all network participants time to catch up.
func mineBlocksSlow(t *harnessTest, net *lntest.NetworkHarness,
num uint32, numTxs int) []*wire.MsgBlock {
t.t.Helper()
// If we expect transactions to be included in the blocks we'll mine,
// we wait here until they are seen in the miner's mempool.
var txids []*chainhash.Hash
var err error
if numTxs > 0 {
txids, err = waitForNTxsInMempool(
net.Miner.Client, numTxs, minerMempoolTimeout,
)
require.NoError(t.t, err, "unable to find txns in mempool")
}
blocks := make([]*wire.MsgBlock, num)
blockHashes := make([]*chainhash.Hash, 0, num)
for i := uint32(0); i < num; i++ {
generatedHashes, err := net.Miner.Client.Generate(1)
require.NoError(t.t, err, "generate blocks")
blockHashes = append(blockHashes, generatedHashes...)
time.Sleep(slowMineDelay)
}
for i, blockHash := range blockHashes {
block, err := net.Miner.Client.GetBlock(blockHash)
require.NoError(t.t, err, "get blocks")
blocks[i] = block
}
// Finally, assert that all the transactions were included in the first
// block.
for _, txid := range txids {
assertTxInBlock(t, blocks[0], txid)
}
return blocks
}
func assertTxInBlock(t *harnessTest, block *wire.MsgBlock, txid *chainhash.Hash) {
for _, tx := range block.Transactions {
sha := tx.TxHash()
if bytes.Equal(txid[:], sha[:]) {
return
}
}
t.Fatalf("tx was not included in block")
}
func assertWalletUnspent(t *harnessTest, node *lntest.HarnessNode,
out *lnrpc.OutPoint, account string) {
t.t.Helper()
ctxb := context.Background()
err := wait.NoError(func() error {
ctxt, cancel := context.WithTimeout(ctxb, defaultTimeout)
defer cancel()
unspent, err := node.WalletKitClient.ListUnspent(
ctxt, &walletrpc.ListUnspentRequest{
Account: account,
},
)
if err != nil {
return err
}
err = errors.New("tx with wanted txhash never found")
for _, utxo := range unspent.Utxos {
if !bytes.Equal(utxo.Outpoint.TxidBytes, out.TxidBytes) {
continue
}
err = errors.New("wanted output is not a wallet utxo")
if utxo.Outpoint.OutputIndex != out.OutputIndex {
continue
}
return nil
}
return err
}, defaultTimeout)
require.NoError(t.t, err)
}
-468
View File
@@ -1,468 +0,0 @@
package itest
import (
"context"
"crypto/rand"
"fmt"
"io"
"time"
"github.com/btcsuite/btcd/btcutil"
"github.com/btcsuite/btcd/rpcclient"
"github.com/btcsuite/btcd/wire"
"github.com/go-errors/errors"
"github.com/lightningnetwork/lnd/input"
"github.com/lightningnetwork/lnd/lnrpc"
"github.com/lightningnetwork/lnd/lnrpc/routerrpc"
"github.com/lightningnetwork/lnd/lntemp"
"github.com/lightningnetwork/lnd/lntest"
"github.com/lightningnetwork/lnd/lntest/wait"
"github.com/lightningnetwork/lnd/lnwallet"
"github.com/lightningnetwork/lnd/lnwallet/chainfee"
"github.com/lightningnetwork/lnd/lnwire"
"github.com/stretchr/testify/require"
)
// completePaymentRequests sends payments from a lightning node to complete all
// payment requests. If the awaitResponse parameter is true, this function
// does not return until all payments successfully complete without errors.
func completePaymentRequests(client lnrpc.LightningClient,
routerClient routerrpc.RouterClient, paymentRequests []string,
awaitResponse bool) error {
ctxb := context.Background()
ctx, cancel := context.WithTimeout(ctxb, defaultTimeout)
defer cancel()
// We start by getting the current state of the client's channels. This
// is needed to ensure the payments actually have been committed before
// we return.
req := &lnrpc.ListChannelsRequest{}
listResp, err := client.ListChannels(ctx, req)
if err != nil {
return err
}
// send sends a payment and returns an error if it doesn't succeeded.
send := func(payReq string) error {
ctxc, cancel := context.WithCancel(ctx)
defer cancel()
payStream, err := routerClient.SendPaymentV2(
ctxc,
&routerrpc.SendPaymentRequest{
PaymentRequest: payReq,
TimeoutSeconds: 60,
FeeLimitMsat: noFeeLimitMsat,
},
)
if err != nil {
return err
}
resp, err := getPaymentResult(payStream)
if err != nil {
return err
}
if resp.Status != lnrpc.Payment_SUCCEEDED {
return errors.New(resp.FailureReason)
}
return nil
}
// Launch all payments simultaneously.
results := make(chan error)
for _, payReq := range paymentRequests {
go func(payReq string) {
err := send(payReq)
if awaitResponse {
results <- err
}
}(payReq)
}
// If awaiting a response, verify that all payments succeeded.
if awaitResponse {
for range paymentRequests {
err := <-results
if err != nil {
return err
}
}
return nil
}
// We are not waiting for feedback in the form of a response, but we
// should still wait long enough for the server to receive and handle
// the send before cancelling the request. We wait for the number of
// updates to one of our channels has increased before we return.
err = wait.Predicate(func() bool {
newListResp, err := client.ListChannels(ctx, req)
if err != nil {
return false
}
// If the number of open channels is now lower than before
// attempting the payments, it means one of the payments
// triggered a force closure (for example, due to an incorrect
// preimage). Return early since it's clear the payment was
// attempted.
if len(newListResp.Channels) < len(listResp.Channels) {
return true
}
for _, c1 := range listResp.Channels {
for _, c2 := range newListResp.Channels {
if c1.ChannelPoint != c2.ChannelPoint {
continue
}
// If this channel has an increased numbr of
// updates, we assume the payments are
// committed, and we can return.
if c2.NumUpdates > c1.NumUpdates {
return true
}
}
}
return false
}, defaultTimeout)
if err != nil {
return err
}
return nil
}
// makeFakePayHash creates random pre image hash.
func makeFakePayHash(t *harnessTest) []byte {
randBuf := make([]byte, 32)
if _, err := rand.Read(randBuf); err != nil {
t.Fatalf("internal error, cannot generate random string: %v", err)
}
return randBuf
}
// createPayReqs is a helper method that will create a slice of payment
// requests for the given node.
func createPayReqs(node *lntest.HarnessNode, paymentAmt btcutil.Amount,
numInvoices int) ([]string, [][]byte, []*lnrpc.Invoice, error) {
payReqs := make([]string, numInvoices)
rHashes := make([][]byte, numInvoices)
invoices := make([]*lnrpc.Invoice, numInvoices)
for i := 0; i < numInvoices; i++ {
preimage := make([]byte, 32)
_, err := rand.Read(preimage)
if err != nil {
return nil, nil, nil, fmt.Errorf("unable to generate "+
"preimage: %v", err)
}
invoice := &lnrpc.Invoice{
Memo: "testing",
RPreimage: preimage,
Value: int64(paymentAmt),
}
ctxt, _ := context.WithTimeout(
context.Background(), defaultTimeout,
)
resp, err := node.AddInvoice(ctxt, invoice)
if err != nil {
return nil, nil, nil, fmt.Errorf("unable to add "+
"invoice: %v", err)
}
// Set the payment address in the invoice so the caller can
// properly use it.
invoice.PaymentAddr = resp.PaymentAddr
payReqs[i] = resp.PaymentRequest
rHashes[i] = resp.RHash
invoices[i] = invoice
}
return payReqs, rHashes, invoices, nil
}
// getChanInfo is a helper method for getting channel info for a node's sole
// channel.
func getChanInfo(node *lntest.HarnessNode) (*lnrpc.Channel, error) {
ctxb := context.Background()
ctx, cancel := context.WithTimeout(ctxb, defaultTimeout)
defer cancel()
req := &lnrpc.ListChannelsRequest{}
channelInfo, err := node.ListChannels(ctx, req)
if err != nil {
return nil, err
}
if len(channelInfo.Channels) != 1 {
return nil, fmt.Errorf("node should only have a single "+
"channel, instead it has %v", len(channelInfo.Channels))
}
return channelInfo.Channels[0], nil
}
// commitTypeHasAnchors returns whether commitType uses anchor outputs.
func commitTypeHasAnchors(commitType lnrpc.CommitmentType) bool {
switch commitType {
case lnrpc.CommitmentType_ANCHORS,
lnrpc.CommitmentType_SCRIPT_ENFORCED_LEASE:
return true
default:
return false
}
}
// nodeArgsForCommitType returns the command line flag to supply to enable this
// commitment type.
func nodeArgsForCommitType(commitType lnrpc.CommitmentType) []string {
switch commitType {
case lnrpc.CommitmentType_LEGACY:
return []string{"--protocol.legacy.committweak"}
case lnrpc.CommitmentType_STATIC_REMOTE_KEY:
return []string{}
case lnrpc.CommitmentType_ANCHORS:
return []string{"--protocol.anchors"}
case lnrpc.CommitmentType_SCRIPT_ENFORCED_LEASE:
return []string{
"--protocol.anchors",
"--protocol.script-enforced-lease",
}
}
return nil
}
// 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 calcStaticFee(c lnrpc.CommitmentType, numHTLCs int) btcutil.Amount {
const htlcWeight = input.HTLCWeight
var (
feePerKw = chainfee.SatPerKWeight(
lntemp.DefaultFeeRateSatPerKw,
)
commitWeight = input.CommitWeight
anchors = btcutil.Amount(0)
)
// The anchor commitment type is slightly heavier, and we must also add
// the value of the two anchors to the resulting fee the initiator
// pays. In addition the fee rate is capped at 10 sat/vbyte for anchor
// channels.
if commitTypeHasAnchors(c) {
feePerKw = chainfee.SatPerKVByte(
lnwallet.DefaultAnchorsCommitMaxFeeRateSatPerVByte * 1000,
).FeePerKWeight()
commitWeight = input.AnchorCommitWeight
anchors = 2 * anchorSize
}
return feePerKw.FeeForWeight(int64(commitWeight+htlcWeight*numHTLCs)) +
anchors
}
// channelCommitType retrieves the active channel commitment type for the given
// chan point.
func channelCommitType(node *lntest.HarnessNode,
chanPoint *lnrpc.ChannelPoint) (lnrpc.CommitmentType, error) {
ctxb := context.Background()
ctxt, _ := context.WithTimeout(ctxb, defaultTimeout)
req := &lnrpc.ListChannelsRequest{}
channels, err := node.ListChannels(ctxt, req)
if err != nil {
return 0, fmt.Errorf("listchannels failed: %v", err)
}
for _, c := range channels.Channels {
if c.ChannelPoint == txStr(chanPoint) {
return c.CommitmentType, nil
}
}
return 0, fmt.Errorf("channel point %v not found", chanPoint)
}
// 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 calculateMaxHtlc(chanCap btcutil.Amount) uint64 {
reserve := lnwire.NewMSatFromSatoshis(chanCap / 100)
max := lnwire.NewMSatFromSatoshis(chanCap) - reserve
return uint64(max)
}
// waitForNodeBlockHeight queries the node for its current block height until
// it reaches the passed height.
func waitForNodeBlockHeight(node *lntest.HarnessNode, height int32) error {
ctxb := context.Background()
ctx, cancel := context.WithTimeout(ctxb, defaultTimeout)
defer cancel()
var predErr error
err := wait.Predicate(func() bool {
info, err := node.GetInfo(ctx, &lnrpc.GetInfoRequest{})
if err != nil {
predErr = err
return false
}
if int32(info.BlockHeight) != height {
predErr = fmt.Errorf("expected block height to "+
"be %v, was %v", height, info.BlockHeight)
return false
}
return true
}, defaultTimeout)
if err != nil {
return predErr
}
return nil
}
// getNTxsFromMempool polls until finding the desired number of transactions in
// the provided miner's mempool and returns the full transactions to the caller.
func getNTxsFromMempool(miner *rpcclient.Client, n int,
timeout time.Duration) ([]*wire.MsgTx, error) {
txids, err := waitForNTxsInMempool(miner, n, timeout)
if err != nil {
return nil, err
}
var txes []*wire.MsgTx
for _, txid := range txids {
tx, err := miner.GetRawTransaction(txid)
if err != nil {
return nil, err
}
txes = append(txes, tx.MsgTx())
}
return txes, nil
}
// getTxFee retrieves parent transactions and reconstructs the fee paid.
func getTxFee(miner *rpcclient.Client, tx *wire.MsgTx) (btcutil.Amount, error) {
var balance btcutil.Amount
for _, in := range tx.TxIn {
parentHash := in.PreviousOutPoint.Hash
rawTx, err := miner.GetRawTransaction(&parentHash)
if err != nil {
return 0, err
}
parent := rawTx.MsgTx()
balance += btcutil.Amount(
parent.TxOut[in.PreviousOutPoint.Index].Value,
)
}
for _, out := range tx.TxOut {
balance -= btcutil.Amount(out.Value)
}
return balance, nil
}
// channelSubscription houses the proxied update and error chans for a node's
// channel subscriptions.
type channelSubscription struct {
updateChan chan *lnrpc.ChannelEventUpdate
errChan chan error
quit chan struct{}
}
// subscribeChannelNotifications subscribes to channel updates and launches a
// goroutine that forwards these to the returned channel.
func subscribeChannelNotifications(ctxb context.Context, t *harnessTest,
node *lntest.HarnessNode) channelSubscription {
// We'll first start by establishing a notification client which will
// send us notifications upon channels becoming active, inactive or
// closed.
req := &lnrpc.ChannelEventSubscription{}
ctx, cancelFunc := context.WithCancel(ctxb)
chanUpdateClient, err := node.SubscribeChannelEvents(ctx, req)
if err != nil {
t.Fatalf("unable to create channel update client: %v", err)
}
// We'll launch a goroutine that will be responsible for proxying all
// notifications recv'd from the client into the channel below.
errChan := make(chan error, 1)
quit := make(chan struct{})
chanUpdates := make(chan *lnrpc.ChannelEventUpdate, 20)
go func() {
defer cancelFunc()
for {
select {
case <-quit:
return
default:
chanUpdate, err := chanUpdateClient.Recv()
select {
case <-quit:
return
default:
}
if err == io.EOF {
return
} else if err != nil {
select {
case errChan <- err:
case <-quit:
}
return
}
select {
case chanUpdates <- chanUpdate:
case <-quit:
return
}
}
}
}()
return channelSubscription{
updateChan: chanUpdates,
errChan: errChan,
quit: quit,
}
}
// findTxAtHeight 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 findTxAtHeight(t *harnessTest, height int32,
target string, node *lntest.HarnessNode) *lnrpc.Transaction {
ctxb := context.Background()
ctx, cancel := context.WithTimeout(ctxb, defaultTimeout)
defer cancel()
txns, err := node.LightningClient.GetTransactions(
ctx, &lnrpc.GetTransactionsRequest{
StartHeight: height,
EndHeight: height,
},
)
require.NoError(t.t, err, "could not get transactions")
for _, tx := range txns.Transactions {
if tx.TxHash == target {
return tx
}
}
return nil
}
+2 -1
View File
@@ -7,6 +7,7 @@ import (
"fmt" "fmt"
"github.com/btcsuite/btcd/chaincfg" "github.com/btcsuite/btcd/chaincfg"
"github.com/lightningnetwork/lnd/lntest/node"
) )
// NeutrinoBackendConfig is an implementation of the BackendConfig interface // NeutrinoBackendConfig is an implementation of the BackendConfig interface
@@ -17,7 +18,7 @@ type NeutrinoBackendConfig struct {
// A compile time assertion to ensure NeutrinoBackendConfig meets the // A compile time assertion to ensure NeutrinoBackendConfig meets the
// BackendConfig interface. // BackendConfig interface.
var _ BackendConfig = (*NeutrinoBackendConfig)(nil) var _ node.BackendConfig = (*NeutrinoBackendConfig)(nil)
// GenArgs returns the arguments needed to be passed to LND at startup for // GenArgs returns the arguments needed to be passed to LND at startup for
// using this node as a chain backend. // using this node as a chain backend.
+149 -20
View File
@@ -1,20 +1,63 @@
package node package node
import ( import (
"flag"
"fmt" "fmt"
"io"
"net"
"os"
"path" "path"
"path/filepath" "path/filepath"
"sync/atomic"
"github.com/btcsuite/btcd/chaincfg" "github.com/btcsuite/btcd/chaincfg"
"github.com/lightningnetwork/lnd/chanbackup" "github.com/lightningnetwork/lnd/chanbackup"
"github.com/lightningnetwork/lnd/kvdb/etcd" "github.com/lightningnetwork/lnd/kvdb/etcd"
"github.com/lightningnetwork/lnd/lntest" "github.com/lightningnetwork/lnd/lntest/wait"
) )
const ( const (
// ListenerFormat is the format string that is used to generate local // ListenerFormat is the format string that is used to generate local
// listener addresses. // listener addresses.
ListenerFormat = "127.0.0.1:%d" ListenerFormat = "127.0.0.1:%d"
// DefaultCSV is the CSV delay (remotedelay) we will start our test
// nodes with.
DefaultCSV = 4
// defaultNodePort is the start of the range for listening ports of
// harness nodes. Ports are monotonically increasing starting from this
// number and are determined by the results of NextAvailablePort().
defaultNodePort = 5555
)
var (
// lastPort is the last port determined to be free for use by a new
// node. It should be used atomically.
lastPort uint32 = defaultNodePort
// logOutput is a flag that can be set to append the output from the
// seed nodes to log files.
logOutput = flag.Bool("logoutput", false,
"log output from node n to file output-n.log")
// logSubDir is the default directory where the logs are written to if
// logOutput is true.
logSubDir = flag.String("logdir", ".", "default dir to write logs to")
// btcdExecutable is the full path to the btcd binary.
btcdExecutable = flag.String(
"btcdexec", "", "full path to btcd binary",
)
)
type DatabaseBackend int
const (
BackendBbolt DatabaseBackend = iota
BackendEtcd
BackendPostgres
BackendSqlite
) )
// Option is a function for updating a node's configuration. // Option is a function for updating a node's configuration.
@@ -73,7 +116,7 @@ type BaseNodeConfig struct {
FeeURL string FeeURL string
DbBackend lntest.DatabaseBackend DBBackend DatabaseBackend
PostgresDsn string PostgresDsn string
// NodeID is a unique ID used to identify the node. // NodeID is a unique ID used to identify the node.
@@ -83,12 +126,12 @@ type BaseNodeConfig struct {
// compiled with all required itest flags. // compiled with all required itest flags.
LndBinary string LndBinary string
// backupDbDir is the path where a database backup is stored, if any. // backupDBDir is the path where a database backup is stored, if any.
backupDbDir string backupDBDir string
// postgresDbName is the name of the postgres database where lnd data // postgresDBName is the name of the postgres database where lnd data
// is stored in. // is stored in.
postgresDbName string postgresDBName string
} }
func (cfg BaseNodeConfig) P2PAddr() string { func (cfg BaseNodeConfig) P2PAddr() string {
@@ -126,16 +169,16 @@ func (cfg BaseNodeConfig) ChanBackupPath() string {
// current lightning network test. // current lightning network test.
func (cfg *BaseNodeConfig) GenerateListeningPorts() { func (cfg *BaseNodeConfig) GenerateListeningPorts() {
if cfg.P2PPort == 0 { if cfg.P2PPort == 0 {
cfg.P2PPort = lntest.NextAvailablePort() cfg.P2PPort = NextAvailablePort()
} }
if cfg.RPCPort == 0 { if cfg.RPCPort == 0 {
cfg.RPCPort = lntest.NextAvailablePort() cfg.RPCPort = NextAvailablePort()
} }
if cfg.RESTPort == 0 { if cfg.RESTPort == 0 {
cfg.RESTPort = lntest.NextAvailablePort() cfg.RESTPort = NextAvailablePort()
} }
if cfg.ProfilePort == 0 { if cfg.ProfilePort == 0 {
cfg.ProfilePort = lntest.NextAvailablePort() cfg.ProfilePort = NextAvailablePort()
} }
} }
@@ -169,8 +212,7 @@ func (cfg *BaseNodeConfig) GenArgs() []string {
"--accept-keysend", "--accept-keysend",
"--keep-failed-payment-attempts", "--keep-failed-payment-attempts",
fmt.Sprintf("--db.batch-commit-interval=%v", commitInterval), fmt.Sprintf("--db.batch-commit-interval=%v", commitInterval),
fmt.Sprintf("--bitcoin.defaultremotedelay=%v", fmt.Sprintf("--bitcoin.defaultremotedelay=%v", DefaultCSV),
lntest.DefaultCSV),
fmt.Sprintf("--rpclisten=%v", cfg.RPCAddr()), fmt.Sprintf("--rpclisten=%v", cfg.RPCAddr()),
fmt.Sprintf("--restlisten=%v", cfg.RESTAddr()), fmt.Sprintf("--restlisten=%v", cfg.RESTAddr()),
fmt.Sprintf("--restcors=https://%v", cfg.RESTAddr()), fmt.Sprintf("--restcors=https://%v", cfg.RESTAddr()),
@@ -182,7 +224,6 @@ func (cfg *BaseNodeConfig) GenArgs() []string {
fmt.Sprintf("--invoicemacaroonpath=%v", cfg.InvoiceMacPath), fmt.Sprintf("--invoicemacaroonpath=%v", cfg.InvoiceMacPath),
fmt.Sprintf("--trickledelay=%v", trickleDelay), fmt.Sprintf("--trickledelay=%v", trickleDelay),
fmt.Sprintf("--profile=%d", cfg.ProfilePort), fmt.Sprintf("--profile=%d", cfg.ProfilePort),
fmt.Sprintf("--caches.rpc-graph-cache-duration=%d", 0),
// Use a small batch window so we can broadcast our sweep // Use a small batch window so we can broadcast our sweep
// transactions faster. // transactions faster.
@@ -191,27 +232,32 @@ func (cfg *BaseNodeConfig) GenArgs() []string {
// Use a small batch delay so we can broadcast the // Use a small batch delay so we can broadcast the
// announcements quickly in the tests. // announcements quickly in the tests.
"--gossip.sub-batch-delay=5ms", "--gossip.sub-batch-delay=5ms",
// Use a small cache duration so the `DescribeGraph` can be
// updated quicker.
"--caches.rpc-graph-cache-duration=100ms",
} }
args = append(args, nodeArgs...) args = append(args, nodeArgs...)
if cfg.Password == nil { if cfg.Password == nil {
args = append(args, "--noseedbackup") args = append(args, "--noseedbackup")
} }
switch cfg.DbBackend { switch cfg.DBBackend {
case lntest.BackendEtcd: case BackendEtcd:
args = append(args, "--db.backend=etcd") args = append(args, "--db.backend=etcd")
args = append(args, "--db.etcd.embedded") args = append(args, "--db.etcd.embedded")
args = append( args = append(
args, fmt.Sprintf( args, fmt.Sprintf(
"--db.etcd.embedded_client_port=%v", "--db.etcd.embedded_client_port=%v",
lntest.NextAvailablePort(), NextAvailablePort(),
), ),
) )
args = append( args = append(
args, fmt.Sprintf( args, fmt.Sprintf(
"--db.etcd.embedded_peer_port=%v", "--db.etcd.embedded_peer_port=%v",
lntest.NextAvailablePort(), NextAvailablePort(),
), ),
) )
args = append( args = append(
@@ -221,14 +267,14 @@ func (cfg *BaseNodeConfig) GenArgs() []string {
), ),
) )
case lntest.BackendPostgres: case BackendPostgres:
args = append(args, "--db.backend=postgres") args = append(args, "--db.backend=postgres")
args = append(args, "--db.postgres.dsn="+cfg.PostgresDsn) args = append(args, "--db.postgres.dsn="+cfg.PostgresDsn)
case lntest.BackendSqlite: case BackendSqlite:
args = append(args, "--db.backend=sqlite") args = append(args, "--db.backend=sqlite")
args = append(args, fmt.Sprintf("--db.sqlite.busytimeout=%v", args = append(args, fmt.Sprintf("--db.sqlite.busytimeout=%v",
lntest.SqliteBusyTimeout)) wait.SqliteBusyTimeout))
} }
if cfg.FeeURL != "" { if cfg.FeeURL != "" {
@@ -272,3 +318,86 @@ func ExtraArgsEtcd(etcdCfg *etcd.Config, name string, cluster bool,
return extraArgs return extraArgs
} }
// NextAvailablePort returns the first port that is available for listening by
// a new node. It panics if no port is found and the maximum available TCP port
// is reached.
func NextAvailablePort() int {
port := atomic.AddUint32(&lastPort, 1)
for port < 65535 {
// If there are no errors while attempting to listen on this
// port, close the socket and return it as available. While it
// could be the case that some other process picks up this port
// between the time the socket is closed and it's reopened in
// the harness node, in practice in CI servers this seems much
// less likely than simply some other process already being
// bound at the start of the tests.
addr := fmt.Sprintf(ListenerFormat, port)
l, err := net.Listen("tcp4", addr)
if err == nil {
err := l.Close()
if err == nil {
return int(port)
}
}
port = atomic.AddUint32(&lastPort, 1)
}
// No ports available? Must be a mistake.
panic("no ports available for listening")
}
// GetLogDir returns the passed --logdir flag or the default value if it wasn't
// set.
func GetLogDir() string {
if logSubDir != nil && *logSubDir != "" {
return *logSubDir
}
return "."
}
// CopyFile copies the file src to dest.
func CopyFile(dest, src string) error {
s, err := os.Open(src)
if err != nil {
return err
}
defer s.Close()
d, err := os.Create(dest)
if err != nil {
return err
}
if _, err := io.Copy(d, s); err != nil {
d.Close()
return err
}
return d.Close()
}
// GetBtcdBinary returns the full path to the binary of the custom built btcd
// executable or an empty string if none is set.
func GetBtcdBinary() string {
if btcdExecutable != nil {
return *btcdExecutable
}
return ""
}
// GenerateBtcdListenerAddresses is a function that returns two listener
// addresses with unique ports and should be used to overwrite rpctest's
// default generator which is prone to use colliding ports.
func GenerateBtcdListenerAddresses() (string, string) {
return fmt.Sprintf(ListenerFormat, NextAvailablePort()),
fmt.Sprintf(ListenerFormat, NextAvailablePort())
}
// ApplyPortOffset adds the given offset to the lastPort variable, making it
// possible to run the tests in parallel without colliding on the same ports.
func ApplyPortOffset(offset uint32) {
_ = atomic.AddUint32(&lastPort, offset)
}
@@ -18,8 +18,7 @@ import (
"github.com/jackc/pgx/v4/pgxpool" "github.com/jackc/pgx/v4/pgxpool"
"github.com/lightningnetwork/lnd/lnrpc" "github.com/lightningnetwork/lnd/lnrpc"
"github.com/lightningnetwork/lnd/lntemp/rpc" "github.com/lightningnetwork/lnd/lntest/rpc"
"github.com/lightningnetwork/lnd/lntest"
"github.com/lightningnetwork/lnd/lntest/wait" "github.com/lightningnetwork/lnd/lntest/wait"
"github.com/lightningnetwork/lnd/macaroons" "github.com/lightningnetwork/lnd/macaroons"
"google.golang.org/grpc" "google.golang.org/grpc"
@@ -81,7 +80,7 @@ type HarnessNode struct {
// runCtx is a context with cancel method. It's used to signal when the // runCtx is a context with cancel method. It's used to signal when the
// node needs to quit, and used as the parent context when spawning // node needs to quit, and used as the parent context when spawning
// children contexts for RPC requests. // children contexts for RPC requests.
runCtx context.Context runCtx context.Context //nolint:containedctx
cancel context.CancelFunc cancel context.CancelFunc
// filename is the log file's name. // filename is the log file's name.
@@ -117,9 +116,9 @@ func NewHarnessNode(t *testing.T, cfg *BaseNodeConfig) (*HarnessNode, error) {
// Create temporary database. // Create temporary database.
var dbName string var dbName string
if cfg.DbBackend == lntest.BackendPostgres { if cfg.DBBackend == BackendPostgres {
var err error var err error
dbName, err = createTempPgDb() dbName, err = createTempPgDB()
if err != nil { if err != nil {
return nil, err return nil, err
} }
@@ -127,7 +126,7 @@ func NewHarnessNode(t *testing.T, cfg *BaseNodeConfig) (*HarnessNode, error) {
} }
cfg.OriginalExtraArgs = cfg.ExtraArgs cfg.OriginalExtraArgs = cfg.ExtraArgs
cfg.postgresDbName = dbName cfg.postgresDBName = dbName
return &HarnessNode{ return &HarnessNode{
T: t, T: t,
@@ -324,7 +323,7 @@ func (hn *HarnessNode) ConnectRPCWithMacaroon(mac *macaroon.Macaroon) (
hn.Cfg.TLSCertPath, "", hn.Cfg.TLSCertPath, "",
) )
return err return err
}, DefaultTimeout) }, wait.DefaultTimeout)
if err != nil { if err != nil {
return nil, fmt.Errorf("error reading TLS cert: %v", err) return nil, fmt.Errorf("error reading TLS cert: %v", err)
} }
@@ -334,7 +333,7 @@ func (hn *HarnessNode) ConnectRPCWithMacaroon(mac *macaroon.Macaroon) (
grpc.WithTransportCredentials(tlsCreds), grpc.WithTransportCredentials(tlsCreds),
} }
ctx, cancel := context.WithTimeout(hn.runCtx, DefaultTimeout) ctx, cancel := context.WithTimeout(hn.runCtx, wait.DefaultTimeout)
defer cancel() defer cancel()
if mac == nil { if mac == nil {
@@ -354,7 +353,7 @@ func (hn *HarnessNode) ConnectRPCWithMacaroon(mac *macaroon.Macaroon) (
func (hn *HarnessNode) ConnectRPC() (*grpc.ClientConn, error) { func (hn *HarnessNode) ConnectRPC() (*grpc.ClientConn, error) {
// If we should use a macaroon, always take the admin macaroon as a // If we should use a macaroon, always take the admin macaroon as a
// default. // default.
mac, err := hn.ReadMacaroon(hn.Cfg.AdminMacPath, DefaultTimeout) mac, err := hn.ReadMacaroon(hn.Cfg.AdminMacPath, wait.DefaultTimeout)
if err != nil { if err != nil {
return nil, err return nil, err
} }
@@ -375,7 +374,7 @@ func (hn *HarnessNode) StartLndCmd(ctxb context.Context) error {
hn.runCtx, hn.cancel = context.WithCancel(ctxb) hn.runCtx, hn.cancel = context.WithCancel(ctxb)
args := hn.Cfg.GenArgs() args := hn.Cfg.GenArgs()
hn.cmd = exec.Command(hn.Cfg.LndBinary, args...) //nolint:gosec hn.cmd = exec.Command(hn.Cfg.LndBinary, args...)
// Redirect stderr output to buffer // Redirect stderr output to buffer
var errb bytes.Buffer var errb bytes.Buffer
@@ -383,7 +382,7 @@ func (hn *HarnessNode) StartLndCmd(ctxb context.Context) error {
// If the logoutput flag is passed, redirect output from the nodes to // If the logoutput flag is passed, redirect output from the nodes to
// log files. // log files.
if *lntest.LogOutput { if *logOutput {
err := addLogFile(hn) err := addLogFile(hn)
if err != nil { if err != nil {
return err return err
@@ -540,7 +539,7 @@ func (hn *HarnessNode) waitTillServerState(
for { for {
select { select {
case <-time.After(lntest.NodeStartTimeout): case <-time.After(wait.NodeStartTimeout):
return fmt.Errorf("timeout waiting for server state") return fmt.Errorf("timeout waiting for server state")
case err := <-errChan: case err := <-errChan:
return fmt.Errorf("receive server state err: %v", err) return fmt.Errorf("receive server state err: %v", err)
@@ -581,7 +580,7 @@ func (hn *HarnessNode) initLightningClient() error {
"got err: %v", err) "got err: %v", err)
} }
case <-time.After(DefaultTimeout): case <-time.After(wait.DefaultTimeout):
return fmt.Errorf("timeout creating topology client stream") return fmt.Errorf("timeout creating topology client stream")
} }
@@ -615,8 +614,8 @@ func (hn *HarnessNode) attachPubKey() error {
// cleanup cleans up all the temporary files created by the node's process. // cleanup cleans up all the temporary files created by the node's process.
func (hn *HarnessNode) cleanup() error { func (hn *HarnessNode) cleanup() error {
if hn.Cfg.backupDbDir != "" { if hn.Cfg.backupDBDir != "" {
err := os.RemoveAll(hn.Cfg.backupDbDir) err := os.RemoveAll(hn.Cfg.backupDBDir)
if err != nil { if err != nil {
return fmt.Errorf("unable to remove backup dir: %v", return fmt.Errorf("unable to remove backup dir: %v",
err) err)
@@ -650,9 +649,10 @@ func (hn *HarnessNode) waitForProcessExit() {
// Otherwise, we print the error, break the select and save // Otherwise, we print the error, break the select and save
// logs. // logs.
hn.printErrf("wait process exit got err: %v", err) hn.printErrf("wait process exit got err: %v", err)
break break
case <-time.After(DefaultTimeout * 2): case <-time.After(wait.DefaultTimeout):
hn.printErrf("timeout waiting for process to exit") hn.printErrf("timeout waiting for process to exit")
} }
@@ -705,7 +705,7 @@ func (hn *HarnessNode) Stop() error {
default: default:
return nil return nil
} }
}, DefaultTimeout) }, wait.DefaultTimeout)
if err != nil { if err != nil {
return err return err
} }
@@ -720,7 +720,7 @@ func (hn *HarnessNode) Stop() error {
// If the goroutines fail to finish before timeout, we'll print // If the goroutines fail to finish before timeout, we'll print
// the error to console and continue. // the error to console and continue.
select { select {
case <-time.After(DefaultTimeout): case <-time.After(wait.DefaultTimeout):
hn.printErrf("timeout on wait group") hn.printErrf("timeout on wait group")
case <-done: case <-done:
} }
@@ -784,23 +784,23 @@ func (hn *HarnessNode) Kill() error {
// printErrf prints an error to the console. // printErrf prints an error to the console.
func (hn *HarnessNode) printErrf(format string, a ...interface{}) { func (hn *HarnessNode) printErrf(format string, a ...interface{}) {
fmt.Printf("itest error from [%s:%s]: %s\n", // nolint:forbidigo fmt.Printf("itest error from [%s:%s]: %s\n", //nolint:forbidigo
hn.Cfg.LogFilenamePrefix, hn.Cfg.Name, hn.Cfg.LogFilenamePrefix, hn.Cfg.Name,
fmt.Sprintf(format, a...)) fmt.Sprintf(format, a...))
} }
// BackupDB creates a backup of the current database. // BackupDB creates a backup of the current database.
func (hn *HarnessNode) BackupDB() error { func (hn *HarnessNode) BackupDB() error {
if hn.Cfg.backupDbDir != "" { if hn.Cfg.backupDBDir != "" {
return fmt.Errorf("backup already created") return fmt.Errorf("backup already created")
} }
if hn.Cfg.postgresDbName != "" { if hn.Cfg.postgresDBName != "" {
// Backup database. // Backup database.
backupDBName := hn.Cfg.postgresDbName + "_backup" backupDBName := hn.Cfg.postgresDBName + "_backup"
err := executePgQuery( err := executePgQuery(
"CREATE DATABASE " + backupDBName + " WITH TEMPLATE " + "CREATE DATABASE " + backupDBName + " WITH TEMPLATE " +
hn.Cfg.postgresDbName, hn.Cfg.postgresDBName,
) )
if err != nil { if err != nil {
return err return err
@@ -818,7 +818,7 @@ func (hn *HarnessNode) BackupDB() error {
err) err)
} }
hn.Cfg.backupDbDir = tempDir hn.Cfg.backupDBDir = tempDir
} }
return nil return nil
@@ -826,39 +826,39 @@ func (hn *HarnessNode) BackupDB() error {
// RestoreDB restores a database backup. // RestoreDB restores a database backup.
func (hn *HarnessNode) RestoreDB() error { func (hn *HarnessNode) RestoreDB() error {
if hn.Cfg.postgresDbName != "" { if hn.Cfg.postgresDBName != "" {
// Restore database. // Restore database.
backupDBName := hn.Cfg.postgresDbName + "_backup" backupDBName := hn.Cfg.postgresDBName + "_backup"
err := executePgQuery( err := executePgQuery(
"DROP DATABASE " + hn.Cfg.postgresDbName, "DROP DATABASE " + hn.Cfg.postgresDBName,
) )
if err != nil { if err != nil {
return err return err
} }
err = executePgQuery( err = executePgQuery(
"ALTER DATABASE " + backupDBName + " RENAME TO " + "ALTER DATABASE " + backupDBName + " RENAME TO " +
hn.Cfg.postgresDbName, hn.Cfg.postgresDBName,
) )
if err != nil { if err != nil {
return err return err
} }
} else { } else {
// Restore files. // Restore files.
if hn.Cfg.backupDbDir == "" { if hn.Cfg.backupDBDir == "" {
return fmt.Errorf("no database backup created") return fmt.Errorf("no database backup created")
} }
err := copyAll(hn.Cfg.DBDir(), hn.Cfg.backupDbDir) err := copyAll(hn.Cfg.DBDir(), hn.Cfg.backupDBDir)
if err != nil { if err != nil {
return fmt.Errorf("unable to copy database files: %w", return fmt.Errorf("unable to copy database files: %w",
err) err)
} }
if err := os.RemoveAll(hn.Cfg.backupDbDir); err != nil { if err := os.RemoveAll(hn.Cfg.backupDBDir); err != nil {
return fmt.Errorf("unable to remove backup dir: %w", return fmt.Errorf("unable to remove backup dir: %w",
err) err)
} }
hn.Cfg.backupDbDir = "" hn.Cfg.backupDBDir = ""
} }
return nil return nil
@@ -868,8 +868,8 @@ func postgresDatabaseDsn(dbName string) string {
return fmt.Sprintf(postgresDsn, dbName) return fmt.Sprintf(postgresDsn, dbName)
} }
// createTempPgDb creates a temp postgres database. // createTempPgDB creates a temp postgres database.
func createTempPgDb() (string, error) { func createTempPgDB() (string, error) {
// Create random database name. // Create random database name.
randBytes := make([]byte, 8) randBytes := make([]byte, 8)
_, err := rand.Read(randBytes) _, err := rand.Read(randBytes)
@@ -918,10 +918,8 @@ func getFinalizedLogFilePrefix(hn *HarnessNode) string {
hn.PubKey[:logPubKeyBytes], hn.PubKey[:logPubKeyBytes],
) )
return fmt.Sprintf("%s/%d-%s-%s-%s", return fmt.Sprintf("%s/%d-%s-%s-%s", GetLogDir(), hn.Cfg.NodeID,
lntest.GetLogDir(), hn.Cfg.NodeID, hn.Cfg.LogFilenamePrefix, hn.Cfg.Name, pubKeyHex)
hn.Cfg.LogFilenamePrefix,
hn.Cfg.Name, pubKeyHex)
} }
// finalizeLogfile makes sure the log file cleanup function is initialized, // finalizeLogfile makes sure the log file cleanup function is initialized,
@@ -935,7 +933,7 @@ func finalizeLogfile(hn *HarnessNode) {
hn.logFile.Close() hn.logFile.Close()
// If logoutput flag is not set, return early. // If logoutput flag is not set, return early.
if !*lntest.LogOutput { if !*logOutput {
return return
} }
@@ -948,7 +946,7 @@ func finalizeLogfile(hn *HarnessNode) {
// finalizeEtcdLog saves the etcd log files when test ends. // finalizeEtcdLog saves the etcd log files when test ends.
func finalizeEtcdLog(hn *HarnessNode) { func finalizeEtcdLog(hn *HarnessNode) {
// Exit early if this is not etcd backend. // Exit early if this is not etcd backend.
if hn.Cfg.DbBackend != lntest.BackendEtcd { if hn.Cfg.DBBackend != BackendEtcd {
return return
} }
@@ -964,7 +962,7 @@ func finalizeEtcdLog(hn *HarnessNode) {
func addLogFile(hn *HarnessNode) error { func addLogFile(hn *HarnessNode) error {
var fileName string var fileName string
dir := lntest.GetLogDir() dir := GetLogDir()
fileName = fmt.Sprintf("%s/%d-%s-%s-%s.log", dir, hn.Cfg.NodeID, fileName = fmt.Sprintf("%s/%d-%s-%s-%s.log", dir, hn.Cfg.NodeID,
hn.Cfg.LogFilenamePrefix, hn.Cfg.Name, hn.Cfg.LogFilenamePrefix, hn.Cfg.Name,
hex.EncodeToString(hn.PubKey[:logPubKeyBytes])) hex.EncodeToString(hn.PubKey[:logPubKeyBytes]))
@@ -1028,7 +1026,7 @@ func copyAll(dstDir, srcDir string) error {
if err != nil { if err != nil {
return err return err
} }
} else if err := lntest.CopyFile(dstPath, srcPath); err != nil { } else if err := CopyFile(dstPath, srcPath); err != nil {
return err return err
} }
} }
@@ -9,7 +9,7 @@ import (
"github.com/btcsuite/btcd/wire" "github.com/btcsuite/btcd/wire"
"github.com/lightningnetwork/lnd/lnrpc" "github.com/lightningnetwork/lnd/lnrpc"
"github.com/lightningnetwork/lnd/lnrpc/walletrpc" "github.com/lightningnetwork/lnd/lnrpc/walletrpc"
"github.com/lightningnetwork/lnd/lntemp/rpc" "github.com/lightningnetwork/lnd/lntest/rpc"
"github.com/lightningnetwork/lnd/lnutils" "github.com/lightningnetwork/lnd/lnutils"
) )
@@ -11,8 +11,7 @@ import (
"github.com/btcsuite/btcd/wire" "github.com/btcsuite/btcd/wire"
"github.com/lightningnetwork/lnd/lnrpc" "github.com/lightningnetwork/lnd/lnrpc"
"github.com/lightningnetwork/lnd/lntemp/rpc" "github.com/lightningnetwork/lnd/lntest/rpc"
"github.com/lightningnetwork/lnd/lntest"
"github.com/lightningnetwork/lnd/lntest/wait" "github.com/lightningnetwork/lnd/lntest/wait"
"github.com/lightningnetwork/lnd/lnutils" "github.com/lightningnetwork/lnd/lnutils"
) )
@@ -31,9 +30,6 @@ const (
// watchPolicyUpdate specifies that this is a request to watch a policy // watchPolicyUpdate specifies that this is a request to watch a policy
// update event. // update event.
watchPolicyUpdate watchPolicyUpdate
// TODO(yy): remove once temp tests is finished.
DefaultTimeout = lntest.DefaultTimeout
) )
// chanWatchRequest is a request to the lightningNetworkWatcher to be notified // chanWatchRequest is a request to the lightningNetworkWatcher to be notified
@@ -123,7 +119,7 @@ func (nw *nodeWatcher) WaitForNumChannelUpdates(op wire.OutPoint,
"want %d, got %d", expected, num) "want %d, got %d", expected, num)
} }
return wait.NoError(checkNumUpdates, DefaultTimeout) return wait.NoError(checkNumUpdates, wait.DefaultTimeout)
} }
// WaitForNumNodeUpdates will block until a given number of node updates has // WaitForNumNodeUpdates will block until a given number of node updates has
@@ -142,8 +138,7 @@ func (nw *nodeWatcher) WaitForNumNodeUpdates(pubkey string,
return fmt.Errorf("timeout waiting for num node updates, "+ return fmt.Errorf("timeout waiting for num node updates, "+
"want %d, got %d", expected, num) "want %d, got %d", expected, num)
} }
err := wait.NoError(checkNumUpdates, wait.DefaultTimeout)
err := wait.NoError(checkNumUpdates, DefaultTimeout)
return updates, err return updates, err
} }
@@ -161,7 +156,7 @@ func (nw *nodeWatcher) WaitForChannelOpen(chanPoint *lnrpc.ChannelPoint) error {
chanWatchType: watchOpenChannel, chanWatchType: watchOpenChannel,
} }
timer := time.After(DefaultTimeout) timer := time.After(wait.DefaultTimeout)
select { select {
case <-eventChan: case <-eventChan:
return nil return nil
@@ -192,7 +187,7 @@ func (nw *nodeWatcher) WaitForChannelClose(
chanWatchType: watchCloseChannel, chanWatchType: watchCloseChannel,
} }
timer := time.After(DefaultTimeout) timer := time.After(wait.DefaultTimeout)
select { select {
case <-eventChan: case <-eventChan:
closedChan, ok := nw.state.closedChans.Load(op) closedChan, ok := nw.state.closedChans.Load(op)
@@ -218,7 +213,7 @@ func (nw *nodeWatcher) WaitForChannelPolicyUpdate(
op := nw.rpc.MakeOutpoint(chanPoint) op := nw.rpc.MakeOutpoint(chanPoint)
ticker := time.NewTicker(wait.PollInterval) ticker := time.NewTicker(wait.PollInterval)
timer := time.After(DefaultTimeout) timer := time.After(wait.DefaultTimeout)
defer ticker.Stop() defer ticker.Stop()
eventChan := make(chan struct{}) eventChan := make(chan struct{})
Loaded 100 of 134 files, more files were not shown because too many files have changed in this diff. Show more