Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
47 changes: 46 additions & 1 deletion .github/workflows/main.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -461,7 +461,52 @@ jobs:
format: 'golang'
parallel: true

# Integration tests on Postgres backend.
########################
# run integration tests with lnd remote-signer
########################
integration-test-lnd-remote-signer:
name: run itests with lnd remote-signer
runs-on: ubuntu-latest
steps:
- name: cleanup space
run: rm -rf /opt/hostedtoolcache

- name: git checkout
uses: actions/checkout@v5

- name: Setup go ${{ env.GO_VERSION }}
uses: actions/setup-go@v5
with:
go-version: '${{ env.GO_VERSION }}'

- name: run itest
run: make itest icase='(mint_assets|basic_send_unidirectional)' remotesigning=1

- name: Zip log files on failure
if: ${{ failure() }}
run: 7z a logs-itest-lnd-remotesigner.zip itest/regtest/logs-tranche*/*.log

- name: Upload log files on failure
uses: actions/upload-artifact@v7
if: ${{ failure() }}
with:
name: logs-itest-lnd-remotesigner
path: logs-itest-lnd-remotesigner.zip
retention-days: 5

- name: Send coverage
uses: coverallsapp/github-action@v2
if: ${{ success() }}
continue-on-error: true
with:
file: itest/coverage.txt
flag-name: 'itest-remotesigner'
format: 'golang'
parallel: true

########################
# run integration tests with Postgres backend
########################
integration-test-postgres:
name: run itests postgres
runs-on: ubuntu-latest
Expand Down
7 changes: 7 additions & 0 deletions docs/release-notes/release-notes-0.8.0.md
Original file line number Diff line number Diff line change
Expand Up @@ -484,6 +484,13 @@
Add sell-side constraint rejection unit tests for
TestResolveRequest.

- [PR#1694](https://github.com/lightninglabs/taproot-assets/pull/1694)
Add a CI sanity job that runs a small subset of itests (mint +
send/receive) against an `lnd` backend in remote-signing (watch-only)
mode, paired with a separate signer `lnd` node. Guards against
regressions in tapd's support for watch-only `lnd` deployments while
keeping CI cost low.

## Database

- [forwards table](https://github.com/lightninglabs/taproot-assets/pull/1921):
Expand Down
12 changes: 6 additions & 6 deletions itest/mint_fund_seal_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -599,18 +599,18 @@ func testMintExternalGroupKeyChantools(t *harnessTest) {
func deriveRandomKey(t *testing.T, ctxt context.Context,
keyRing *lndservices.LndRpcKeyRing) keychain.KeyDescriptor {

// The random key family is capped to MaxInt8 to stay inside the range
// of accounts known to the watch-only signer set up by the remote
// signing itest mode. The cap also keeps the family safely below
// asset.TaprootAssetsKeyFamily, so no explicit collision check is
// needed.
var (
randFam = test.RandInt31n(math.MaxInt32)
randFam = test.RandInt31n(math.MaxInt8)
randInd = test.RandInt31n(255)
desc keychain.KeyDescriptor
err error
)

// Ensure that we use a different key family from tapd.
for randFam == asset.TaprootAssetsKeyFamily {
randFam = test.RandInt31n(math.MaxInt32)
}

desc, err = keyRing.DeriveNextKey(
ctxt, keychain.KeyFamily(randFam),
)
Expand Down
2 changes: 1 addition & 1 deletion itest/multi_send_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -371,7 +371,7 @@ func testAnchorMultipleVirtualTransactions(t *harnessTest) {
)

btcPacket = signPacket(t.t, aliceLnd, btcPacket)
btcPacket = FinalizePacket(t.t, aliceLnd.RPC, btcPacket)
btcPacket = FinalizeFullySigned(t.t, btcPacket)
sendResp = PublishAndLogTransfer(
t.t, aliceTapd, btcPacket, activeAssets, passiveAssets,
commitResp,
Expand Down
21 changes: 19 additions & 2 deletions itest/multisig.go
Original file line number Diff line number Diff line change
Expand Up @@ -466,22 +466,39 @@ func CommitVirtualPsbts(t *testing.T, funder commands.RpcClientsBundle,
func FinalizePacket(t *testing.T, lnd *rpc.HarnessRPC,
pkt *psbt.Packet) *psbt.Packet {

// We sign and locally finalize instead of calling lnd's FinalizePsbt
// RPC because the latter is broken for p2tr inputs when lnd runs in
// watch-only / remote-signing mode (it fails with "is not a p2wkh or
// np2wkh address" while trying to compute the input script). SignPsbt
// + local MaybeFinalizeAll is equivalent and works in both modes.
var buf bytes.Buffer
err := pkt.Serialize(&buf)
require.NoError(t, err)

finalizeResp := lnd.FinalizePsbt(&walletrpc.FinalizePsbtRequest{
signResp := lnd.SignPsbt(&walletrpc.SignPsbtRequest{
FundedPsbt: buf.Bytes(),
})

signedPacket, err := psbt.NewFromRawBytes(
bytes.NewReader(finalizeResp.SignedPsbt), false,
bytes.NewReader(signResp.SignedPsbt), false,
)
require.NoError(t, err)

err = psbt.MaybeFinalizeAll(signedPacket)
require.NoError(t, err)

return signedPacket
}

// FinalizeFullySigned is a helper function that finalizes a PSBT packet
// that is already fully signed. It will return the finalized packet.
func FinalizeFullySigned(t *testing.T, pkt *psbt.Packet) *psbt.Packet {
err := psbt.MaybeFinalizeAll(pkt)
require.NoError(t, err)

return pkt
}

// PublishAndLogTransferOption defines a functional option for
// PublishAndLogTransfer.
type PublishAndLogTransferOption func(*publishAndLogTransferOptions)
Expand Down
36 changes: 8 additions & 28 deletions itest/psbt_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -839,7 +839,7 @@ func runPsbtInteractiveMarkerV0MixedVersions(ctxt context.Context,
require.NoError(t.t, err)

btcPkt = signPacket(t.t, sender.cfg.LndNode, btcPkt)
btcPkt = FinalizePacket(t.t, sender.cfg.LndNode.RPC, btcPkt)
btcPkt = FinalizeFullySigned(t.t, btcPkt)
PublishAndLogTransfer(
t.t, sender, btcPkt, activePkt, passivePkt, commitResp,
withExpectedErr("error validating input assets: mixed virtual "+
Expand Down Expand Up @@ -1254,7 +1254,7 @@ func testPsbtInteractiveAltLeafAnchoring(t *harnessTest) {
require.NoError(t.t, err)

commitPacket = signPacket(t.t, senderLnd, commitPacket)
commitPacket = FinalizePacket(t.t, senderLnd.RPC, commitPacket)
commitPacket = FinalizeFullySigned(t.t, commitPacket)
publishResp := PublishAndLogTransfer(
t.t, sender, commitPacket, []*tappsbt.VPacket{activePacket},
[]*tappsbt.VPacket{passivePacket}, commitResp,
Expand Down Expand Up @@ -2526,7 +2526,7 @@ func testPsbtTrustlessSwap(t *harnessTest) {
require.Equal(t.t, bobInputIdx, signResp.SignedInputs[0])
require.NoError(t.t, finalPsbt.SanityCheck())

signedPkt := finalizePacket(t.t, lndBob, finalPsbt)
signedPkt := FinalizeFullySigned(t.t, finalPsbt)
require.True(t.t, signedPkt.IsComplete())

logResp := PublishAndLogTransfer(
Expand Down Expand Up @@ -2866,7 +2866,7 @@ func testPsbtExternalCommit(t *harnessTest) {
t.Logf("Committed transaction: %v", toJSON(t.t, commitResp))

btcPacket = signPacket(t.t, aliceLnd, btcPacket)
btcPacket = FinalizePacket(t.t, aliceLnd.RPC, btcPacket)
btcPacket = FinalizeFullySigned(t.t, btcPacket)

transferLabel := "itest-psbt-external-commit"

Expand Down Expand Up @@ -3119,7 +3119,7 @@ func testPsbtLockTimeSend(t *harnessTest) {
t.t, bob, btcPacket, vPackets, nil, -1,
)
btcPacket = signPacket(t.t, bobLnd, btcPacket)
btcPacket = FinalizePacket(t.t, bobLnd.RPC, btcPacket)
btcPacket = FinalizeFullySigned(t.t, btcPacket)
spendTx, err := psbt.Extract(btcPacket)
require.NoError(t.t, err)

Expand Down Expand Up @@ -3332,7 +3332,7 @@ func testPsbtRelativeLockTimeSend(t *harnessTest) {
t.t, bob, btcPacket, vPackets, nil, -1,
)
btcPacket = signPacket(t.t, lndBob, btcPacket)
btcPacket = FinalizePacket(t.t, lndBob.RPC, btcPacket)
btcPacket = FinalizeFullySigned(t.t, btcPacket)
spendTx, err := psbt.Extract(btcPacket)
require.NoError(t.t, err)

Expand Down Expand Up @@ -3547,9 +3547,7 @@ func testPsbtRelativeLockTimeSendProofFail(t *harnessTest) {
t.t, bob, btcPacket, vPackets, nil, -1,
)
btcPacketTimeLocked := signPacket(t.t, lndBob, btcPacket)
btcPacketTimeLocked = FinalizePacket(
t.t, lndBob.RPC, btcPacketTimeLocked,
)
btcPacketTimeLocked = FinalizeFullySigned(t.t, btcPacketTimeLocked)
spendTxTimeLocked, err := psbt.Extract(btcPacketTimeLocked)
require.NoError(t.t, err)

Expand All @@ -3573,7 +3571,7 @@ func testPsbtRelativeLockTimeSendProofFail(t *harnessTest) {
}

btcPacket = signPacket(t.t, lndBob, btcPacket)
btcPacket = FinalizePacket(t.t, lndBob.RPC, btcPacket)
btcPacket = FinalizeFullySigned(t.t, btcPacket)
spendTxTimeLocked, err = psbt.Extract(btcPacket)
require.NoError(t.t, err)

Expand Down Expand Up @@ -3742,24 +3740,6 @@ func signPacket(t *testing.T, lnd *node.HarnessNode,
return signedPacket
}

func finalizePacket(t *testing.T, lnd *node.HarnessNode,
pkt *psbt.Packet) *psbt.Packet {

pktBytes, err := fn.Serialize(pkt)
require.NoError(t, err)

finalizeResp := lnd.RPC.FinalizePsbt(&walletrpc.FinalizePsbtRequest{
FundedPsbt: pktBytes,
})

signedPacket, err := psbt.NewFromRawBytes(
bytes.NewReader(finalizeResp.SignedPsbt), false,
)
require.NoError(t, err)

return signedPacket
}

// getAddressBip32Derivation returns the PSBT BIP-0032 derivation info of an
// address.
func getAddressBip32Derivation(t testing.TB, addr string,
Expand Down
70 changes: 65 additions & 5 deletions itest/test_harness.go
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,8 @@ import (
"github.com/lightninglabs/taproot-assets/taprpc"
unirpc "github.com/lightninglabs/taproot-assets/taprpc/universerpc"
"github.com/lightningnetwork/lnd/build"
"github.com/lightningnetwork/lnd/lnrpc"
"github.com/lightningnetwork/lnd/lnrpc/walletrpc"
"github.com/lightningnetwork/lnd/lntest"
"github.com/lightningnetwork/lnd/lntest/miner"
"github.com/lightningnetwork/lnd/lntest/node"
Expand All @@ -38,13 +40,24 @@ var (

// noDelete is a command line flag for disabling deleting the tapd
// data directories.
noDelete = flag.Bool("nodelete", false, "Set to true to keep all "+
"tapd data directories after completing the tests")
noDelete = flag.Bool(
"nodelete", false, "Set to true to keep all tapd data "+
"directories after completing the tests",
)

// logLevel is a command line flag for setting the log level of the
// integration test output.
logLevel = flag.String("loglevel", "info", "Set the log level of the "+
"integration test output")
logLevel = flag.String(
"loglevel", "info", "Set the log level of the integration "+
"test output",
)

// lndRemoteSigner is a command line flag that indicates whether the
// lnd instances should be set up to use a remote signer.
lndRemoteSigner = flag.Bool(
"lndremotesigner", false, "if true, the lnd instances will "+
"be set up to use a remote signer",
)
)

const (
Expand Down Expand Up @@ -294,7 +307,54 @@ func setupHarnesses(t *testing.T, ht *harnessTest,
proofCourier = universeServer
}

alice := lndHarness.NewNodeWithCoins("Alice", nil)
var alice *node.HarnessNode
if *lndRemoteSigner {
signer := lndHarness.NewNode("Signer", nil)

// AccountsToWatchOnly only exports accounts that already exist
// on the signer. Tapd's own key family
// (asset.TaprootAssetsKeyFamily) is not pre-created on a fresh
// lnd node and is therefore not in this snapshot. Itests work
// today because lnd's watch-only path tolerates derivations in
// families that weren't in the snapshot for this scope; if
// that ever changes, the signer node would need an explicit
// DeriveNextKey call for that family before this snapshot is
// taken.
rpcAccts := signer.RPC.ListAccounts(
&walletrpc.ListAccountsRequest{},
)

watchOnlyAccounts, err := walletrpc.AccountsToWatchOnly(
rpcAccts.Accounts,
)
require.NoError(t, err)
alice = lndHarness.NewNodeRemoteSigner(
"WatchOnly", []string{
"--remotesigner.enable",
fmt.Sprintf(
"--remotesigner.rpchost=localhost:%d",
signer.Cfg.RPCPort,
),
fmt.Sprintf(
"--remotesigner.tlscertpath=%s",
signer.Cfg.TLSCertPath,
),
fmt.Sprintf(
"--remotesigner.macaroonpath=%s",
signer.Cfg.AdminMacPath,
),
},
[]byte("itestpassword"), &lnrpc.WatchOnly{
MasterKeyBirthdayTimestamp: 0,
MasterKeyFingerprint: nil,
Accounts: watchOnlyAccounts,
},
)

lndHarness.FundNumCoins(alice, 5)
} else {
alice = lndHarness.NewNodeWithCoins("Alice", nil)
}

// Create a tapd that uses Alice and connect it to the universe server.
tapdHarness := setupTapdHarness(
Expand Down
5 changes: 5 additions & 0 deletions make/testing_flags.mk
Original file line number Diff line number Diff line change
Expand Up @@ -87,6 +87,11 @@ ifneq ($(nodelete),)
ITEST_FLAGS += -nodelete
endif

# Run the lnd node in remote signing mode.
ifneq ($(remotesigning),)
ITEST_FLAGS += -lndremotesigner
endif

# Run the optional tests.
ifneq ($(optional),)
ITEST_FLAGS += -optional -postgrestimeout=240m
Expand Down