From 38eaa36d90ff1a91caac7ce1f2a0e2f1840f7367 Mon Sep 17 00:00:00 2001 From: yyforyongyu Date: Thu, 11 Aug 2022 15:56:06 +0800 Subject: [PATCH] lntemp+itest: refactor `testRemoteSigner` --- lntemp/harness.go | 26 ++ lntemp/node/harness_node.go | 6 +- lntest/itest/list_on_test.go | 4 + lntest/itest/lnd_remote_signer_test.go | 340 ++++++++++++------------- lntest/itest/lnd_test_list_on_test.go | 4 - 5 files changed, 201 insertions(+), 179 deletions(-) diff --git a/lntemp/harness.go b/lntemp/harness.go index 6b8d8cb40..68817eea4 100644 --- a/lntemp/harness.go +++ b/lntemp/harness.go @@ -675,6 +675,32 @@ func (h *HarnessTest) NewNodeWithSeedEtcd(name string, etcdCfg *etcd.Config, return h.newNodeWithSeed(name, extraArgs, req, statelessInit) } +// NewNodeRemoteSigner creates a new remote signer node and asserts its +// creation. +func (h *HarnessTest) NewNodeRemoteSigner(name string, extraArgs []string, + password []byte, watchOnly *lnrpc.WatchOnly) *node.HarnessNode { + + hn, err := h.manager.newNode(h.T, name, extraArgs, password, true) + require.NoErrorf(h, err, "unable to create new node for %s", name) + + err = hn.StartWithNoAuth(h.runCtx) + require.NoError(h, err, "failed to start node %s", name) + + // With the seed created, construct the init request to the node, + // including the newly generated seed. + initReq := &lnrpc.InitWalletRequest{ + WalletPassword: password, + WatchOnly: watchOnly, + } + + // Pass the init request via rpc to finish unlocking the node. This + // will also initialize the macaroon-authenticated LightningClient. + _, err = h.manager.initWalletAndNode(hn, initReq) + require.NoErrorf(h, err, "failed to init node %s", name) + + return hn +} + // KillNode kills the node (but won't wait for the node process to stop). func (h *HarnessTest) KillNode(hn *node.HarnessNode) { require.NoErrorf(h, hn.Kill(), "%s: kill got error", hn.Name()) diff --git a/lntemp/node/harness_node.go b/lntemp/node/harness_node.go index 1dc484bed..bdd0fc744 100644 --- a/lntemp/node/harness_node.go +++ b/lntemp/node/harness_node.go @@ -164,11 +164,11 @@ func (hn *HarnessNode) String() string { type nodeCfg struct { LogFilenamePrefix string ExtraArgs []string - HasSeed bool + SkipUnlock bool + Password []byte P2PPort int RPCPort int RESTPort int - ProfilePort int AcceptKeySend bool FeeURL string } @@ -185,6 +185,8 @@ func (hn *HarnessNode) String() string { PubKey: hn.PubKeyStr, State: hn.State, NodeCfg: nodeCfg{ + SkipUnlock: hn.Cfg.SkipUnlock, + Password: hn.Cfg.Password, LogFilenamePrefix: hn.Cfg.LogFilenamePrefix, ExtraArgs: hn.Cfg.ExtraArgs, P2PPort: hn.Cfg.P2PPort, diff --git a/lntest/itest/list_on_test.go b/lntest/itest/list_on_test.go index 6b3758e2e..decc87250 100644 --- a/lntest/itest/list_on_test.go +++ b/lntest/itest/list_on_test.go @@ -481,4 +481,8 @@ var allTestCasesTemp = []*lntemp.TestCase{ Name: "async payments benchmark", TestFunc: testAsyncPayments, }, + { + Name: "remote signer", + TestFunc: testRemoteSigner, + }, } diff --git a/lntest/itest/lnd_remote_signer_test.go b/lntest/itest/lnd_remote_signer_test.go index 92e729df5..032301340 100644 --- a/lntest/itest/lnd_remote_signer_test.go +++ b/lntest/itest/lnd_remote_signer_test.go @@ -1,13 +1,17 @@ package itest import ( + "fmt" "testing" + "github.com/btcsuite/btcd/btcutil" "github.com/btcsuite/btcd/btcutil/hdkeychain" "github.com/btcsuite/btcwallet/waddrmgr" "github.com/lightningnetwork/lnd/keychain" "github.com/lightningnetwork/lnd/lnrpc" - "github.com/lightningnetwork/lnd/lntest" + "github.com/lightningnetwork/lnd/lnrpc/walletrpc" + "github.com/lightningnetwork/lnd/lntemp" + "github.com/lightningnetwork/lnd/lntemp/node" "github.com/stretchr/testify/require" ) @@ -50,192 +54,182 @@ var ( // testRemoteSigner tests that a watch-only wallet can use a remote signing // wallet to perform any signing or ECDH operations. -func testRemoteSigner(net *lntest.NetworkHarness, t *harnessTest) { - // ctxb := context.Background() +func testRemoteSigner(ht *lntemp.HarnessTest) { + type testCase struct { + name string + randomSeed bool + sendCoins bool + fn func(tt *lntemp.HarnessTest, + wo, carol *node.HarnessNode) + } - // subTests := []struct { - // name string - // randomSeed bool - // sendCoins bool - // fn func(tt *harnessTest, wo, carol *lntest.HarnessNode) - // }{{ - // name: "random seed", - // randomSeed: true, - // fn: func(tt *harnessTest, wo, carol *lntest.HarnessNode) { - // // Nothing more to test here. - // }, - // }, { - // name: "account import", - // fn: func(tt *harnessTest, wo, carol *lntest.HarnessNode) { - // runWalletImportAccountScenario( - // net, tt, - // walletrpc.AddressType_WITNESS_PUBKEY_HASH, - // carol, wo, - // ) - // }, - // }, { - // name: "basic channel open close", - // sendCoins: true, - // fn: func(tt *harnessTest, wo, carol *lntest.HarnessNode) { - // runBasicChannelCreationAndUpdates( - // net, tt, wo, carol, - // ) - // }, - // }, { - // name: "async payments", - // sendCoins: true, - // fn: func(tt *harnessTest, wo, carol *lntest.HarnessNode) { - // runAsyncPayments(net, tt, wo, carol) - // }, - // }, { - // name: "shared key", - // fn: func(tt *harnessTest, wo, carol *lntest.HarnessNode) { - // runDeriveSharedKey(tt, wo) - // }, - // }, { - // name: "cpfp", - // sendCoins: true, - // fn: func(tt *harnessTest, wo, carol *lntest.HarnessNode) { - // runCPFP(net, tt, wo, carol) - // }, - // }, { - // name: "psbt", - // randomSeed: true, - // fn: func(tt *harnessTest, wo, carol *lntest.HarnessNode) { - // runPsbtChanFunding(net, tt, carol, wo) - // runSignPsbtSegWitV0P2WKH(tt, net, wo) - // runSignPsbtSegWitV1KeySpendBip86(tt, net, wo) - // runSignPsbtSegWitV1KeySpendRootHash(tt, net, wo) - // runSignPsbtSegWitV1ScriptSpend(tt, net, wo) - // }, - // }, { - // name: "sign output raw", - // sendCoins: true, - // fn: func(tt *harnessTest, wo, carol *lntest.HarnessNode) { - // runSignOutputRaw(tt, net, wo) - // }, - // }, { - // name: "sign verify msg", - // sendCoins: true, - // fn: func(tt *harnessTest, wo, carol *lntest.HarnessNode) { - // runSignVerifyMessage(tt, net, wo) - // }, - // }, { - // name: "taproot", - // sendCoins: true, - // randomSeed: true, - // fn: func(tt *harnessTest, wo, carol *lntest.HarnessNode) { - // ctxt, cancel := context.WithTimeout( - // ctxb, 3*defaultTimeout, - // ) - // defer cancel() + subTests := []testCase{{ + name: "random seed", + randomSeed: true, + fn: func(tt *lntemp.HarnessTest, wo, carol *node.HarnessNode) { + // Nothing more to test here. + }, + }, { + name: "account import", + fn: func(tt *lntemp.HarnessTest, wo, carol *node.HarnessNode) { + runWalletImportAccountScenario( + tt, walletrpc.AddressType_WITNESS_PUBKEY_HASH, + carol, wo, + ) + }, + }, { + name: "basic channel open close", + sendCoins: true, + fn: func(tt *lntemp.HarnessTest, wo, carol *node.HarnessNode) { + runBasicChannelCreationAndUpdates(tt, wo, carol) + }, + }, { + name: "async payments", + sendCoins: true, + fn: func(tt *lntemp.HarnessTest, wo, carol *node.HarnessNode) { + runAsyncPayments(tt, wo, carol) + }, + }, { + name: "shared key", + fn: func(tt *lntemp.HarnessTest, wo, carol *node.HarnessNode) { + runDeriveSharedKey(tt, wo) + }, + }, { + name: "cpfp", + sendCoins: true, + fn: func(tt *lntemp.HarnessTest, wo, carol *node.HarnessNode) { + runCPFP(tt, wo, carol) + }, + }, { + name: "psbt", + randomSeed: true, + fn: func(tt *lntemp.HarnessTest, wo, carol *node.HarnessNode) { + runPsbtChanFunding(tt, carol, wo) + runSignPsbtSegWitV0P2WKH(tt, wo) + runSignPsbtSegWitV1KeySpendBip86(tt, wo) + runSignPsbtSegWitV1KeySpendRootHash(tt, wo) + runSignPsbtSegWitV1ScriptSpend(tt, wo) + }, + }, { + name: "sign output raw", + sendCoins: true, + fn: func(tt *lntemp.HarnessTest, wo, carol *node.HarnessNode) { + runSignOutputRaw(tt, wo) + }, + }, { + name: "sign verify msg", + sendCoins: true, + fn: func(tt *lntemp.HarnessTest, wo, carol *node.HarnessNode) { + runSignVerifyMessage(tt, wo) + }, + }, { + name: "taproot", + sendCoins: true, + randomSeed: true, + fn: func(tt *lntemp.HarnessTest, wo, carol *node.HarnessNode) { + testTaprootSendCoinsKeySpendBip86(tt, wo) + testTaprootComputeInputScriptKeySpendBip86(tt, wo) + testTaprootSignOutputRawScriptSpend(tt, wo) + testTaprootSignOutputRawKeySpendBip86(tt, wo) + testTaprootSignOutputRawKeySpendRootHash(tt, wo) + testTaprootMuSig2KeySpendRootHash(tt, wo) + testTaprootMuSig2ScriptSpend(tt, wo) + testTaprootMuSig2KeySpendBip86(tt, wo) + testTaprootMuSig2CombinedLeafKeySpend(tt, wo) + }, + }} - // testTaprootSendCoinsKeySpendBip86(ctxt, tt, wo, net) - // testTaprootComputeInputScriptKeySpendBip86( - // ctxt, tt, wo, net, - // ) - // testTaprootSignOutputRawScriptSpend(ctxt, tt, wo, net) - // testTaprootSignOutputRawKeySpendBip86(ctxt, tt, wo, net) - // testTaprootSignOutputRawKeySpendRootHash( - // ctxt, tt, wo, net, - // ) - // testTaprootMuSig2KeySpendRootHash(ctxt, tt, wo, net) - // testTaprootMuSig2ScriptSpend(ctxt, tt, wo, net) - // testTaprootMuSig2KeySpendBip86(ctxt, tt, wo, net) - // testTaprootMuSig2CombinedLeafKeySpend(ctxt, tt, wo, net) - // }, - // }} + prepareTest := func(st *lntemp.HarnessTest, + subTest testCase) (*node.HarnessNode, + *node.HarnessNode, *node.HarnessNode) { - // for _, st := range subTests { - // subTest := st + // Signer is our signing node and has the wallet with the full + // master private key. We test that we can create the watch-only + // wallet from the exported accounts but also from a static key + // to make sure the derivation of the account public keys is + // correct in both cases. + password := []byte("itestpassword") + var ( + signerNodePubKey = nodePubKey + watchOnlyAccounts = deriveCustomScopeAccounts(ht.T) + signer *node.HarnessNode + err error + ) + if !subTest.randomSeed { + signer = st.RestoreNodeWithSeed( + "Signer", nil, password, nil, rootKey, 0, nil, + ) + } else { + signer = st.NewNode("Signer", nil) + signerNodePubKey = signer.PubKeyStr - // // Signer is our signing node and has the wallet with the full - // // master private key. We test that we can create the watch-only - // // wallet from the exported accounts but also from a static key - // // to make sure the derivation of the account public keys is - // // correct in both cases. - // password := []byte("itestpassword") - // var ( - // signerNodePubKey = nodePubKey - // watchOnlyAccounts = deriveCustomScopeAccounts(t.t) - // signer *lntest.HarnessNode - // err error - // ) - // if !subTest.randomSeed { - // signer, err = net.RestoreNodeWithSeed( - // "Signer", nil, password, nil, rootKey, 0, nil, - // ) - // require.NoError(t.t, err) - // } else { - // signer = net.NewNode(t.t, "Signer", nil) - // signerNodePubKey = signer.PubKeyStr + rpcAccts := signer.RPC.ListAccounts( + &walletrpc.ListAccountsRequest{}, + ) - // rpcAccts, err := signer.WalletKitClient.ListAccounts( - // ctxb, &walletrpc.ListAccountsRequest{}, - // ) - // require.NoError(t.t, err) + watchOnlyAccounts, err = walletrpc.AccountsToWatchOnly( + rpcAccts.Accounts, + ) + require.NoError(st, err) + } - // watchOnlyAccounts, err = walletrpc.AccountsToWatchOnly( - // rpcAccts.Accounts, - // ) - // require.NoError(t.t, err) - // } + // WatchOnly is the node that has a watch-only wallet and uses + // the Signer node for any operation that requires access to + // private keys. + watchOnly := st.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, + ), + }, password, &lnrpc.WatchOnly{ + MasterKeyBirthdayTimestamp: 0, + MasterKeyFingerprint: nil, + Accounts: watchOnlyAccounts, + }, + ) - // // WatchOnly is the node that has a watch-only wallet and uses - // // the Signer node for any operation that requires access to - // // private keys. - // watchOnly, err := net.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, - // ), - // }, password, &lnrpc.WatchOnly{ - // MasterKeyBirthdayTimestamp: 0, - // MasterKeyFingerprint: nil, - // Accounts: watchOnlyAccounts, - // }, - // ) - // require.NoError(t.t, err) + resp := watchOnly.RPC.GetInfo() + require.Equal(st, signerNodePubKey, resp.IdentityPubkey) - // resp, err := watchOnly.GetInfo(ctxb, &lnrpc.GetInfoRequest{}) - // require.NoError(t.t, err) + if subTest.sendCoins { + st.FundCoins(btcutil.SatoshiPerBitcoin, watchOnly) + ht.AssertWalletAccountBalance( + watchOnly, "default", + btcutil.SatoshiPerBitcoin, 0, + ) + } - // require.Equal(t.t, signerNodePubKey, resp.IdentityPubkey) + carol := st.NewNode("carol", nil) + st.EnsureConnected(watchOnly, carol) - // if subTest.sendCoins { - // net.SendCoins(t.t, btcutil.SatoshiPerBitcoin, watchOnly) - // assertAccountBalance( - // t.t, watchOnly, "default", - // btcutil.SatoshiPerBitcoin, 0, - // ) - // } + return signer, watchOnly, carol + } - // carol := net.NewNode(t.t, "carol", nil) - // net.EnsureConnected(t.t, watchOnly, carol) + for _, testCase := range subTests { + subTest := testCase - // success := t.t.Run(subTest.name, func(tt *testing.T) { - // ht := newHarnessTest(tt, net) - // subTest.fn(ht, watchOnly, carol) - // }) + success := ht.Run(subTest.name, func(tt *testing.T) { + // Skip the cleanup here as no standby node is used. + st := ht.Subtest(tt) - // shutdownAndAssert(net, t, carol) - // shutdownAndAssert(net, t, watchOnly) - // shutdownAndAssert(net, t, signer) + _, watchOnly, carol := prepareTest(st, subTest) + subTest.fn(st, watchOnly, carol) + }) - // if !success { - // return - // } - // } + if !success { + return + } + } } // deriveCustomScopeAccounts derives the first 255 default accounts of the custom lnd diff --git a/lntest/itest/lnd_test_list_on_test.go b/lntest/itest/lnd_test_list_on_test.go index 29ac80e97..7e502c64e 100644 --- a/lntest/itest/lnd_test_list_on_test.go +++ b/lntest/itest/lnd_test_list_on_test.go @@ -8,10 +8,6 @@ var allTestCases = []*testCase{ name: "async bidirectional payments", test: testBidirectionalAsyncPayments, }, - { - name: "remote signer", - test: testRemoteSigner, - }, { name: "taproot coop close", test: testTaprootCoopClose,