Merge pull request #6006 from guggero/remote-signer-no-chain

Allow remote signer to run without chain backend
This commit is contained in:
Olaoluwa Osuntokun authored and GitHub committed 2022-01-07 17:37:16 -08:00
commit fd63301dc5
40 files changed
+2960 -934

No files matched your search

+195 -38
View File
@@ -6,12 +6,15 @@ import (
"crypto/rand"
"fmt"
"github.com/btcsuite/btcd/btcec"
"github.com/btcsuite/btcd/txscript"
"github.com/btcsuite/btcd/wire"
"github.com/btcsuite/btcutil"
"github.com/btcsuite/btcutil/hdkeychain"
"github.com/btcsuite/btcutil/psbt"
"github.com/lightningnetwork/lnd/funding"
"github.com/lightningnetwork/lnd/lnrpc"
"github.com/lightningnetwork/lnd/lnrpc/signrpc"
"github.com/lightningnetwork/lnd/lnrpc/walletrpc"
"github.com/lightningnetwork/lnd/lntest"
"github.com/stretchr/testify/require"
@@ -40,6 +43,12 @@ func runPsbtChanFunding(net *lntest.NetworkHarness, t *harnessTest, carol,
dave *lntest.HarnessNode) {
ctxb := context.Background()
// Everything we do here should be done within a second or two, so we
// can just keep a single timeout context around for all calls.
ctxt, cancel := context.WithTimeout(ctxb, defaultTimeout)
defer cancel()
const chanSize = funding.MaxBtcFundingAmount
net.SendCoins(t.t, btcutil.SatoshiPerBitcoin, dave)
@@ -63,8 +72,6 @@ func runPsbtChanFunding(net *lntest.NetworkHarness, t *harnessTest, carol,
// Now that we have the pending channel ID, Carol will open the channel
// by specifying a PSBT shim. We use the NoPublish flag here to avoid
// publishing the whole batch TX too early.
ctxt, cancel := context.WithTimeout(ctxb, defaultTimeout)
defer cancel()
chanUpdates, tempPsbt, err := openChannelPsbt(
ctxt, carol, dave, lntest.OpenChannelParams{
Amt: chanSize,
@@ -83,8 +90,6 @@ func runPsbtChanFunding(net *lntest.NetworkHarness, t *harnessTest, carol,
// Let's add a second channel to the batch. This time between Carol and
// Alice. We will publish the batch TX once this channel funding is
// complete.
ctxt, cancel = context.WithTimeout(ctxb, defaultTimeout)
defer cancel()
chanUpdates2, psbtBytes2, err := openChannelPsbt(
ctxt, carol, net.Alice, lntest.OpenChannelParams{
Amt: chanSize,
@@ -104,8 +109,6 @@ func runPsbtChanFunding(net *lntest.NetworkHarness, t *harnessTest, carol,
// We'll now ask Dave's wallet to fund the PSBT for us. This will return
// a packet with inputs and outputs set but without any witness data.
// This is exactly what we need for the next step.
ctxt, cancel = context.WithTimeout(ctxb, defaultTimeout)
defer cancel()
fundReq := &walletrpc.FundPsbtRequest{
Template: &walletrpc.FundPsbtRequest_Psbt{
Psbt: psbtBytes2,
@@ -140,8 +143,6 @@ func runPsbtChanFunding(net *lntest.NetworkHarness, t *harnessTest, carol,
// Now we'll ask Dave's wallet to sign the PSBT so we can finish the
// funding flow.
ctxt, cancel = context.WithTimeout(ctxb, defaultTimeout)
defer cancel()
finalizeReq := &walletrpc.FinalizePsbtRequest{
FundedPsbt: fundResp.FundedPsbt,
}
@@ -161,8 +162,6 @@ func runPsbtChanFunding(net *lntest.NetworkHarness, t *harnessTest, carol,
// Consume the "channel pending" update. This waits until the funding
// transaction was fully compiled.
ctxt, cancel = context.WithTimeout(ctxb, defaultTimeout)
defer cancel()
updateResp, err := receiveChanUpdate(ctxt, chanUpdates)
require.NoError(t.t, err)
upd, ok := updateResp.Update.(*lnrpc.OpenStatusUpdate_ChanPending)
@@ -195,8 +194,6 @@ func runPsbtChanFunding(net *lntest.NetworkHarness, t *harnessTest, carol,
// Consume the "channel pending" update for the second channel. This
// waits until the funding transaction was fully compiled and in this
// case published.
ctxt, cancel = context.WithTimeout(ctxb, defaultTimeout)
defer cancel()
updateResp2, err := receiveChanUpdate(ctxt, chanUpdates2)
require.NoError(t.t, err)
upd2, ok := updateResp2.Update.(*lnrpc.OpenStatusUpdate_ChanPending)
@@ -225,8 +222,6 @@ func runPsbtChanFunding(net *lntest.NetworkHarness, t *harnessTest, carol,
// With the channel open, ensure that it is counted towards Carol's
// total channel balance.
balReq := &lnrpc.ChannelBalanceRequest{}
ctxt, cancel = context.WithTimeout(ctxb, defaultTimeout)
defer cancel()
balRes, err := carol.ChannelBalance(ctxt, balReq)
require.NoError(t.t, err)
require.NotEqual(t.t, int64(0), balRes.LocalBalance.Sat)
@@ -238,7 +233,6 @@ func runPsbtChanFunding(net *lntest.NetworkHarness, t *harnessTest, carol,
Memo: "new chans",
Value: int64(payAmt),
}
ctxt, _ = context.WithTimeout(ctxb, defaultTimeout)
resp, err := dave.AddInvoice(ctxt, invoice)
require.NoError(t.t, err)
err = completePaymentRequests(
@@ -261,6 +255,11 @@ func testPsbtChanFundingExternal(net *lntest.NetworkHarness, t *harnessTest) {
ctxb := context.Background()
const chanSize = funding.MaxBtcFundingAmount
// Everything we do here should be done within a second or two, so we
// can just keep a single timeout context around for all calls.
ctxt, cancel := context.WithTimeout(ctxb, defaultTimeout)
defer cancel()
// First, we'll create two new nodes that we'll use to open channels
// between for this test. Both these nodes have an empty wallet as Alice
// will be funding the channel.
@@ -290,8 +289,6 @@ func testPsbtChanFundingExternal(net *lntest.NetworkHarness, t *harnessTest) {
// Now that we have the pending channel ID, Carol will open the channel
// by specifying a PSBT shim. We use the NoPublish flag here to avoid
// publishing the whole batch TX too early.
ctxt, cancel := context.WithTimeout(ctxb, defaultTimeout)
defer cancel()
chanUpdates, tempPsbt, err := openChannelPsbt(
ctxt, carol, dave, lntest.OpenChannelParams{
Amt: chanSize,
@@ -310,8 +307,6 @@ func testPsbtChanFundingExternal(net *lntest.NetworkHarness, t *harnessTest) {
// Let's add a second channel to the batch. This time between Carol and
// Alice. We will publish the batch TX once this channel funding is
// complete.
ctxt, cancel = context.WithTimeout(ctxb, defaultTimeout)
defer cancel()
chanUpdates2, psbtBytes2, err := openChannelPsbt(
ctxt, carol, net.Alice, lntest.OpenChannelParams{
Amt: chanSize,
@@ -331,8 +326,6 @@ func testPsbtChanFundingExternal(net *lntest.NetworkHarness, t *harnessTest) {
// We'll now ask Alice's wallet to fund the PSBT for us. This will
// return a packet with inputs and outputs set but without any witness
// data. This is exactly what we need for the next step.
ctxt, cancel = context.WithTimeout(ctxb, defaultTimeout)
defer cancel()
fundReq := &walletrpc.FundPsbtRequest{
Template: &walletrpc.FundPsbtRequest_Psbt{
Psbt: psbtBytes2,
@@ -375,8 +368,6 @@ func testPsbtChanFundingExternal(net *lntest.NetworkHarness, t *harnessTest) {
// Consume the "channel pending" update. This waits until the funding
// transaction was fully compiled for both channels.
ctxt, cancel = context.WithTimeout(ctxb, defaultTimeout)
defer cancel()
updateResp, err := receiveChanUpdate(ctxt, chanUpdates)
require.NoError(t.t, err)
upd, ok := updateResp.Update.(*lnrpc.OpenStatusUpdate_ChanPending)
@@ -403,8 +394,6 @@ func testPsbtChanFundingExternal(net *lntest.NetworkHarness, t *harnessTest) {
// Now we'll ask Alice's wallet to sign the PSBT so we can finish the
// funding flow.
ctxt, cancel = context.WithTimeout(ctxb, defaultTimeout)
defer cancel()
finalizeReq := &walletrpc.FinalizePsbtRequest{
FundedPsbt: fundResp.FundedPsbt,
}
@@ -439,8 +428,6 @@ func testPsbtChanFundingExternal(net *lntest.NetworkHarness, t *harnessTest) {
// With the channel open, ensure that it is counted towards Carol's
// total channel balance.
balReq := &lnrpc.ChannelBalanceRequest{}
ctxt, cancel = context.WithTimeout(ctxb, defaultTimeout)
defer cancel()
balRes, err := carol.ChannelBalance(ctxt, balReq)
require.NoError(t.t, err)
require.NotEqual(t.t, int64(0), balRes.LocalBalance.Sat)
@@ -452,7 +439,6 @@ func testPsbtChanFundingExternal(net *lntest.NetworkHarness, t *harnessTest) {
Memo: "new chans",
Value: int64(payAmt),
}
ctxt, _ = context.WithTimeout(ctxb, defaultTimeout)
resp, err := dave.AddInvoice(ctxt, invoice)
require.NoError(t.t, err)
err = completePaymentRequests(
@@ -476,6 +462,11 @@ func testPsbtChanFundingSingleStep(net *lntest.NetworkHarness, t *harnessTest) {
ctxb := context.Background()
const chanSize = funding.MaxBtcFundingAmount
// Everything we do here should be done within a second or two, so we
// can just keep a single timeout context around for all calls.
ctxt, cancel := context.WithTimeout(ctxb, defaultTimeout)
defer cancel()
args := nodeArgsForCommitType(lnrpc.CommitmentType_ANCHORS)
// First, we'll create two new nodes that we'll use to open channels
@@ -513,8 +504,6 @@ func testPsbtChanFundingSingleStep(net *lntest.NetworkHarness, t *harnessTest) {
// Now that we have the pending channel ID, Carol will open the channel
// by specifying a PSBT shim.
ctxt, cancel := context.WithTimeout(ctxb, defaultTimeout)
defer cancel()
chanUpdates, tempPsbt, err := openChannelPsbt(
ctxt, carol, dave, lntest.OpenChannelParams{
Amt: chanSize,
@@ -547,8 +536,6 @@ func testPsbtChanFundingSingleStep(net *lntest.NetworkHarness, t *harnessTest) {
err = decodedPsbt.Serialize(&psbtBytes)
require.NoError(t.t, err)
ctxt, cancel = context.WithTimeout(ctxb, defaultTimeout)
defer cancel()
fundReq := &walletrpc.FundPsbtRequest{
Template: &walletrpc.FundPsbtRequest_Psbt{
Psbt: psbtBytes.Bytes(),
@@ -583,8 +570,6 @@ func testPsbtChanFundingSingleStep(net *lntest.NetworkHarness, t *harnessTest) {
// Now we'll ask Alice's wallet to sign the PSBT so we can finish the
// funding flow.
ctxt, cancel = context.WithTimeout(ctxb, defaultTimeout)
defer cancel()
finalizeReq := &walletrpc.FinalizePsbtRequest{
FundedPsbt: fundResp.FundedPsbt,
}
@@ -604,8 +589,6 @@ func testPsbtChanFundingSingleStep(net *lntest.NetworkHarness, t *harnessTest) {
// Consume the "channel pending" update. This waits until the funding
// transaction was fully compiled.
ctxt, cancel = context.WithTimeout(ctxb, defaultTimeout)
defer cancel()
updateResp, err := receiveChanUpdate(ctxt, chanUpdates)
require.NoError(t.t, err)
upd, ok := updateResp.Update.(*lnrpc.OpenStatusUpdate_ChanPending)
@@ -634,8 +617,6 @@ func testPsbtChanFundingSingleStep(net *lntest.NetworkHarness, t *harnessTest) {
Memo: "new chans",
Value: int64(payAmt),
}
ctxt, cancel = context.WithTimeout(ctxb, defaultTimeout)
defer cancel()
resp, err := dave.AddInvoice(ctxt, invoice)
require.NoError(t.t, err)
err = completePaymentRequests(
@@ -651,6 +632,182 @@ func testPsbtChanFundingSingleStep(net *lntest.NetworkHarness, t *harnessTest) {
closeChannelAndAssert(t, net, carol, chanPoint, false)
}
// runSignPsbt tests that the SignPsbt RPC works correctly.
func testSignPsbt(net *lntest.NetworkHarness, t *harnessTest) {
runSignPsbt(t, net, net.Alice)
}
// runSignPsbt tests that the SignPsbt RPC works correctly.
func runSignPsbt(t *harnessTest, net *lntest.NetworkHarness,
alice *lntest.HarnessNode) {
ctxb := context.Background()
// Everything we do here should be done within a second or two, so we
// can just keep a single timeout context around for all calls.
ctxt, cancel := context.WithTimeout(ctxb, defaultTimeout)
defer cancel()
// 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
// derive an address manually that the wallet won't be watching on
// chain. We can do that by exporting the account xpub of lnd's main
// account.
accounts, err := alice.WalletKitClient.ListAccounts(
ctxt, &walletrpc.ListAccountsRequest{},
)
require.NoError(t.t, err)
require.NotEmpty(t.t, accounts.Accounts)
// We also need to parse the accounts, so we have easy access to the
// parsed derivation paths.
parsedAccounts, err := walletrpc.AccountsToWatchOnly(accounts.Accounts)
require.NoError(t.t, err)
account := parsedAccounts[0]
xpub, err := hdkeychain.NewKeyFromString(account.Xpub)
require.NoError(t.t, err)
const (
changeIndex = 1
addrIndex = 1337
)
fullDerivationPath := []uint32{
hdkeychain.HardenedKeyStart + account.Purpose,
hdkeychain.HardenedKeyStart + account.CoinType,
hdkeychain.HardenedKeyStart + account.Account,
changeIndex,
addrIndex,
}
// Let's simulate a change address.
change, err := xpub.DeriveNonStandard(changeIndex) // nolint:staticcheck
require.NoError(t.t, err)
// At an index that we are certainly not watching in the wallet.
addrKey, err := change.DeriveNonStandard(addrIndex) // nolint:staticcheck
require.NoError(t.t, err)
addrPubKey, err := addrKey.ECPubKey()
require.NoError(t.t, err)
pubKeyHash := btcutil.Hash160(addrPubKey.SerializeCompressed())
witnessAddr, err := btcutil.NewAddressWitnessPubKeyHash(
pubKeyHash, harnessNetParams,
)
require.NoError(t.t, err)
pkScript, err := txscript.PayToAddrScript(witnessAddr)
require.NoError(t.t, err)
// Let's send some coins to that address now.
utxo := &wire.TxOut{
Value: 600_000,
PkScript: pkScript,
}
resp, err := alice.WalletKitClient.SendOutputs(
ctxt, &walletrpc.SendOutputsRequest{
Outputs: []*signrpc.TxOut{{
Value: utxo.Value,
PkScript: utxo.PkScript,
}},
MinConfs: 0,
SpendUnconfirmed: true,
SatPerKw: 2500,
},
)
require.NoError(t.t, err)
prevTx := wire.NewMsgTx(2)
err = prevTx.Deserialize(bytes.NewReader(resp.RawTx))
require.NoError(t.t, err)
prevOut := -1
for idx, txOut := range prevTx.TxOut {
if bytes.Equal(txOut.PkScript, pkScript) {
prevOut = idx
}
}
require.Greater(t.t, prevOut, -1)
// Okay, we have everything we need to create a PSBT now.
pendingTx := &wire.MsgTx{
Version: 2,
TxIn: []*wire.TxIn{{
PreviousOutPoint: wire.OutPoint{
Hash: prevTx.TxHash(),
Index: uint32(prevOut),
},
}},
// We send to the same address again, but deduct some fees.
TxOut: []*wire.TxOut{{
Value: utxo.Value - 600,
PkScript: utxo.PkScript,
}},
}
packet, err := psbt.NewFromUnsignedTx(pendingTx)
require.NoError(t.t, err)
// Now let's add the meta information that we need for signing.
packet.Inputs[0].Bip32Derivation = []*psbt.Bip32Derivation{{
PubKey: addrPubKey.SerializeCompressed(),
Bip32Path: fullDerivationPath,
}}
packet.Inputs[0].WitnessUtxo = utxo
packet.Inputs[0].NonWitnessUtxo = prevTx
packet.Inputs[0].SighashType = txscript.SigHashAll
// That's it, we should be able to sign the PSBT now.
var buf bytes.Buffer
err = packet.Serialize(&buf)
require.NoError(t.t, err)
signResp, err := alice.WalletKitClient.SignPsbt(
ctxt, &walletrpc.SignPsbtRequest{
FundedPsbt: buf.Bytes(),
},
)
require.NoError(t.t, err)
// Let's make sure we have a partial signature.
signedPacket, err := psbt.NewFromRawBytes(
bytes.NewReader(signResp.SignedPsbt), false,
)
require.NoError(t.t, err)
require.Len(t.t, signedPacket.Inputs, 1)
require.Len(t.t, signedPacket.Inputs[0].PartialSigs, 1)
partialSig := signedPacket.Inputs[0].PartialSigs[0]
require.Equal(t.t, partialSig.PubKey, addrPubKey.SerializeCompressed())
require.Greater(t.t, len(partialSig.Signature), btcec.MinSigLen)
// We should be able to finalize the PSBT and extract the final TX now.
err = psbt.MaybeFinalizeAll(signedPacket)
require.NoError(t.t, err)
finalTx, err := psbt.Extract(signedPacket)
require.NoError(t.t, err)
buf.Reset()
err = finalTx.Serialize(&buf)
require.NoError(t.t, err)
// Publish the second transaction and then mine both of them.
_, err = alice.WalletKitClient.PublishTransaction(
ctxt, &walletrpc.Transaction{
TxHex: buf.Bytes(),
},
)
require.NoError(t.t, err)
// Mine one block which should contain two transactions.
block := mineBlocks(t, net, 1, 2)[0]
firstTxHash := prevTx.TxHash()
secondTxHash := finalTx.TxHash()
assertTxInBlock(t, block, &firstTxHash)
assertTxInBlock(t, block, &secondTxHash)
}
// 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
+55 -75
View File
@@ -6,6 +6,7 @@ import (
"testing"
"github.com/btcsuite/btcutil"
"github.com/btcsuite/btcutil/hdkeychain"
"github.com/btcsuite/btcwallet/waddrmgr"
"github.com/lightningnetwork/lnd/keychain"
"github.com/lightningnetwork/lnd/lnrpc"
@@ -39,76 +40,6 @@ var (
Xpub: "tpubDDWAWrSLRSFrG1KdqXMQQyTKYGSKLKaY7gxpvK7RdV3e3Dkhvu" +
"W2GgsFvsPN4RGmuoYtUgZ1LHZE8oftz7T4mzc1BxGt5rt8zJcVQi" +
"KTPPV",
}, {
Purpose: keychain.BIP0043Purpose,
CoinType: harnessNetParams.HDCoinType,
Account: uint32(keychain.KeyFamilyMultiSig),
Xpub: "tpubDDXFHr67Ro2tHKVWG2gNjjijKUH1Lyv5NKFYdJnuaLGVNBVwyV" +
"5AbykhR43iy8wYozEMbw2QfmAqZhb8gnuL5mm9sZh8YsR6FjGAbe" +
"w1xoT",
}, {
Purpose: keychain.BIP0043Purpose,
CoinType: harnessNetParams.HDCoinType,
Account: uint32(keychain.KeyFamilyRevocationBase),
Xpub: "tpubDDXFHr67Ro2tKkccDqNfDqZpd5wCs2n6XRV2Uh185DzCTbkDaE" +
"d9v7P837zZTYBNVfaRriuxgGVgxbGjDui4CKxyzBzwz4aAZxjn2P" +
"hNcQy",
}, {
Purpose: keychain.BIP0043Purpose,
CoinType: harnessNetParams.HDCoinType,
Account: uint32(keychain.KeyFamilyHtlcBase),
Xpub: "tpubDDXFHr67Ro2tNH4KH41i4oTsWfRjFigoH1Ee7urvHow51opH9x" +
"J7mu1qSPMPVtkVqQZ5tE4NTuFJPrbDqno7TQietyUDmPTwyVviJb" +
"GCwXk",
}, {
Purpose: keychain.BIP0043Purpose,
CoinType: harnessNetParams.HDCoinType,
Account: uint32(keychain.KeyFamilyPaymentBase),
Xpub: "tpubDDXFHr67Ro2tQj5Zvav2ALhkU6dRQAhEtNPnYJVBC8hs2U1A9e" +
"cqxRY3XTiJKBDD7e8tudhmTRs8aGWJAiAXJN5kXy3Hi6cmiwGWjX" +
"K5Cv5",
}, {
Purpose: keychain.BIP0043Purpose,
CoinType: harnessNetParams.HDCoinType,
Account: uint32(keychain.KeyFamilyDelayBase),
Xpub: "tpubDDXFHr67Ro2tSSR2LLBJtotxx2U45cuESLWKA72YT9td3SzVKH" +
"AptzDEx5chsUNZ4WRMY5h6HJxRSebjRatxQKX1uUsux1LvKS1wsf" +
"NJ2PH",
}, {
Purpose: keychain.BIP0043Purpose,
CoinType: harnessNetParams.HDCoinType,
Account: uint32(keychain.KeyFamilyRevocationRoot),
Xpub: "tpubDDXFHr67Ro2tTwzfWvNoMoPpZbxdMEfe1WhbXJxvXikGixPa4g" +
"gSRZeGx6T5yxVHTVT3rjVh35Veqsowj7emX8SZfXKDKDKcLduXCe" +
"WPUU3",
}, {
Purpose: keychain.BIP0043Purpose,
CoinType: harnessNetParams.HDCoinType,
Account: uint32(keychain.KeyFamilyNodeKey),
Xpub: "tpubDDXFHr67Ro2tYEDS2EByRedfsUoEwBtrzVbS1qdPrX6sAkUYGL" +
"rZWvMmQv8KZDZ4zd9r8WzM9bJ2nGp7XuNVC4w2EBtWg7i76gbrmu" +
"EWjQh",
}, {
Purpose: keychain.BIP0043Purpose,
CoinType: harnessNetParams.HDCoinType,
Account: uint32(keychain.KeyFamilyStaticBackup),
Xpub: "tpubDDXFHr67Ro2tYpwnFJEQaM8eAPM2UV5uY6gFgXeSzS5aC5T9Tf" +
"zXuawYKBbQMZJn8qHXLafY4tAutoda1aKP5h6Nbgy3swPbnhWbFj" +
"S5wnX",
}, {
Purpose: keychain.BIP0043Purpose,
CoinType: harnessNetParams.HDCoinType,
Account: uint32(keychain.KeyFamilyTowerSession),
Xpub: "tpubDDXFHr67Ro2tddKpAjUegXqt7EGxRXnHkeLbUkfuFMGbLJYgRp" +
"G4ew5pMmGg2nmcGmHFQ29w3juNhd8N5ZZ8HwJdymC4f5ukQLJ4yg" +
"9rEr3",
}, {
Purpose: keychain.BIP0043Purpose,
CoinType: harnessNetParams.HDCoinType,
Account: uint32(keychain.KeyFamilyTowerID),
Xpub: "tpubDDXFHr67Ro2tgE89V8ZdgMytC2Jq1iT9ttGhdzR1X7haQJNBmX" +
"t8kau6taC6DGASYzbrjmo9z9w6JQFcaLNqbhS2h2PVSzKf79j265" +
"Zi8hF",
}}
)
@@ -166,6 +97,7 @@ func testRemoteSigner(net *lntest.NetworkHarness, t *harnessTest) {
name: "psbt",
fn: func(tt *harnessTest, wo, carol *lntest.HarnessNode) {
runPsbtChanFunding(net, tt, carol, wo)
runSignPsbt(tt, net, wo)
},
}}
@@ -180,7 +112,7 @@ func testRemoteSigner(net *lntest.NetworkHarness, t *harnessTest) {
password := []byte("itestpassword")
var (
signerNodePubKey = nodePubKey
watchOnlyAccounts = accounts
watchOnlyAccounts = deriveCustomScopeAccounts(t.t)
signer *lntest.HarnessNode
err error
)
@@ -237,10 +169,6 @@ func testRemoteSigner(net *lntest.NetworkHarness, t *harnessTest) {
if subTest.sendCoins {
net.SendCoins(t.t, btcutil.SatoshiPerBitcoin, watchOnly)
assertAccountBalance(
t.t, signer, "default",
btcutil.SatoshiPerBitcoin, 0,
)
assertAccountBalance(
t.t, watchOnly, "default",
btcutil.SatoshiPerBitcoin, 0,
@@ -264,3 +192,55 @@ func testRemoteSigner(net *lntest.NetworkHarness, t *harnessTest) {
}
}
}
// deriveCustomScopeAccounts derives the first 255 default accounts of the custom lnd
// internal key scope.
func deriveCustomScopeAccounts(t *testing.T) []*lnrpc.WatchOnlyAccount {
allAccounts := make([]*lnrpc.WatchOnlyAccount, 0, 255+len(accounts))
allAccounts = append(allAccounts, accounts...)
extendedRootKey, err := hdkeychain.NewKeyFromString(rootKey)
require.NoError(t, err)
path := []uint32{
keychain.BIP0043Purpose + hdkeychain.HardenedKeyStart,
harnessNetParams.HDCoinType + hdkeychain.HardenedKeyStart,
}
coinTypeKey, err := derivePath(extendedRootKey, path)
require.NoError(t, err)
for idx := uint32(0); idx <= 255; idx++ {
accountPath := []uint32{idx + hdkeychain.HardenedKeyStart}
accountKey, err := derivePath(coinTypeKey, accountPath)
require.NoError(t, err)
accountXPub, err := accountKey.Neuter()
require.NoError(t, err)
allAccounts = append(allAccounts, &lnrpc.WatchOnlyAccount{
Purpose: keychain.BIP0043Purpose,
CoinType: harnessNetParams.HDCoinType,
Account: idx,
Xpub: accountXPub.String(),
})
}
return allAccounts
}
// derivePath derives the given path from an extended key.
func derivePath(key *hdkeychain.ExtendedKey, path []uint32) (
*hdkeychain.ExtendedKey, error) {
var (
currentKey = key
err error
)
for _, pathPart := range path {
currentKey, err = currentKey.Derive(pathPart)
if err != nil {
return nil, err
}
}
return currentKey, nil
}
+4
View File
@@ -283,6 +283,10 @@ var allTestCases = []*testCase{
name: "psbt channel funding external",
test: testPsbtChanFundingExternal,
},
{
name: "sign psbt",
test: testSignPsbt,
},
{
name: "batch channel funding",
test: testBatchChanFunding,
+40 -21
View File
@@ -53,15 +53,25 @@ func (w *WalletController) FetchInputInfo(
return utxo, nil
}
// ScriptForOutput returns the address, witness program and redeem script for a
// given UTXO. An error is returned if the UTXO does not belong to our wallet or
// it is not a managed pubKey address.
func (w *WalletController) ScriptForOutput(*wire.TxOut) (
waddrmgr.ManagedPubKeyAddress, []byte, []byte, error) {
return nil, nil, nil, nil
}
// ConfirmedBalance currently returns dummy values.
func (w *WalletController) ConfirmedBalance(confs int32,
_ string) (btcutil.Amount, error) {
func (w *WalletController) ConfirmedBalance(int32, string) (btcutil.Amount,
error) {
return 0, nil
}
// NewAddress is called to get new addresses for delivery, change etc.
func (w *WalletController) NewAddress(addrType lnwallet.AddressType,
change bool, _ string) (btcutil.Address, error) {
func (w *WalletController) NewAddress(lnwallet.AddressType, bool,
string) (btcutil.Address, error) {
addr, _ := btcutil.NewAddressPubKey(
w.RootKey.PubKey().SerializeCompressed(), &chaincfg.MainNetParams,
@@ -70,19 +80,21 @@ func (w *WalletController) NewAddress(addrType lnwallet.AddressType,
}
// LastUnusedAddress currently returns dummy values.
func (w *WalletController) LastUnusedAddress(addrType lnwallet.AddressType,
_ string) (btcutil.Address, error) {
func (w *WalletController) LastUnusedAddress(lnwallet.AddressType,
string) (btcutil.Address, error) {
return nil, nil
}
// IsOurAddress currently returns a dummy value.
func (w *WalletController) IsOurAddress(a btcutil.Address) bool {
func (w *WalletController) IsOurAddress(btcutil.Address) bool {
return false
}
// ListAccounts currently returns a dummy value.
func (w *WalletController) ListAccounts(_ string,
_ *waddrmgr.KeyScope) ([]*waddrmgr.AccountProperties, error) {
func (w *WalletController) ListAccounts(string,
*waddrmgr.KeyScope) ([]*waddrmgr.AccountProperties, error) {
return nil, nil
}
@@ -90,33 +102,35 @@ func (w *WalletController) ListAccounts(_ string,
func (w *WalletController) ImportAccount(string, *hdkeychain.ExtendedKey,
uint32, *waddrmgr.AddressType, bool) (*waddrmgr.AccountProperties,
[]btcutil.Address, []btcutil.Address, error) {
return nil, nil, nil, nil
}
// ImportPublicKey currently returns a dummy value.
func (w *WalletController) ImportPublicKey(*btcec.PublicKey,
waddrmgr.AddressType) error {
return nil
}
// SendOutputs currently returns dummy values.
func (w *WalletController) SendOutputs(outputs []*wire.TxOut,
_ chainfee.SatPerKWeight, _ int32, _ string) (*wire.MsgTx, error) {
func (w *WalletController) SendOutputs([]*wire.TxOut,
chainfee.SatPerKWeight, int32, string) (*wire.MsgTx, error) {
return nil, nil
}
// CreateSimpleTx currently returns dummy values.
func (w *WalletController) CreateSimpleTx(outputs []*wire.TxOut,
_ chainfee.SatPerKWeight, _ int32, _ bool) (*txauthor.AuthoredTx, error) {
func (w *WalletController) CreateSimpleTx([]*wire.TxOut,
chainfee.SatPerKWeight, int32, bool) (*txauthor.AuthoredTx, error) {
return nil, nil
}
// ListUnspentWitness is called by the wallet when doing coin selection. We just
// need one unspent for the funding transaction.
func (w *WalletController) ListUnspentWitness(minConfs,
maxConfs int32, _ string) ([]*lnwallet.Utxo, error) {
func (w *WalletController) ListUnspentWitness(int32, int32,
string) ([]*lnwallet.Utxo, error) {
// If the mock already has a list of utxos, return it.
if w.Utxos != nil {
@@ -140,8 +154,8 @@ func (w *WalletController) ListUnspentWitness(minConfs,
}
// ListTransactionDetails currently returns dummy values.
func (w *WalletController) ListTransactionDetails(_,
_ int32, _ string) ([]*lnwallet.TransactionDetail, error) {
func (w *WalletController) ListTransactionDetails(int32, int32,
string) ([]*lnwallet.TransactionDetail, error) {
return nil, nil
}
@@ -169,12 +183,17 @@ func (w *WalletController) ListLeasedOutputs() ([]*wtxmgr.LockedOutput, error) {
}
// FundPsbt currently does nothing.
func (w *WalletController) FundPsbt(_ *psbt.Packet, _ int32,
_ chainfee.SatPerKWeight, _ string) (int32, error) {
func (w *WalletController) FundPsbt(*psbt.Packet, int32, chainfee.SatPerKWeight,
string) (int32, error) {
return 0, nil
}
// SignPsbt currently does nothing.
func (w *WalletController) SignPsbt(*psbt.Packet) error {
return nil
}
// FinalizePsbt currently does nothing.
func (w *WalletController) FinalizePsbt(_ *psbt.Packet, _ string) error {
return nil
@@ -187,8 +206,8 @@ func (w *WalletController) PublishTransaction(tx *wire.MsgTx, _ string) error {
}
// LabelTransaction currently does nothing.
func (w *WalletController) LabelTransaction(_ chainhash.Hash, _ string,
_ bool) error {
func (w *WalletController) LabelTransaction(chainhash.Hash, string,
bool) error {
return nil
}