Merge pull request #3419 from Roasbeef/sign-create-key-if-not-found
lnwallet: when signing create account if not found
This commit is contained in:
commit
216d1e8017
@ -83,6 +83,25 @@ func (b *BtcWallet) fetchOutputAddr(script []byte) (waddrmgr.ManagedAddress, err
|
|||||||
return nil, lnwallet.ErrNotMine
|
return nil, lnwallet.ErrNotMine
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// deriveFromKeyLoc attempts to derive a private key using a fully specified
|
||||||
|
// KeyLocator.
|
||||||
|
func deriveFromKeyLoc(scopedMgr *waddrmgr.ScopedKeyManager,
|
||||||
|
addrmgrNs walletdb.ReadWriteBucket,
|
||||||
|
keyLoc keychain.KeyLocator) (*btcec.PrivateKey, error) {
|
||||||
|
|
||||||
|
path := waddrmgr.DerivationPath{
|
||||||
|
Account: uint32(keyLoc.Family),
|
||||||
|
Branch: 0,
|
||||||
|
Index: uint32(keyLoc.Index),
|
||||||
|
}
|
||||||
|
addr, err := scopedMgr.DeriveFromKeyPath(addrmgrNs, path)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return addr.(waddrmgr.ManagedPubKeyAddress).PrivKey()
|
||||||
|
}
|
||||||
|
|
||||||
// deriveKeyByLocator attempts to derive a key stored in the wallet given a
|
// deriveKeyByLocator attempts to derive a key stored in the wallet given a
|
||||||
// valid key locator.
|
// valid key locator.
|
||||||
func (b *BtcWallet) deriveKeyByLocator(keyLoc keychain.KeyLocator) (*btcec.PrivateKey, error) {
|
func (b *BtcWallet) deriveKeyByLocator(keyLoc keychain.KeyLocator) (*btcec.PrivateKey, error) {
|
||||||
@ -95,20 +114,31 @@ func (b *BtcWallet) deriveKeyByLocator(keyLoc keychain.KeyLocator) (*btcec.Priva
|
|||||||
}
|
}
|
||||||
|
|
||||||
var key *btcec.PrivateKey
|
var key *btcec.PrivateKey
|
||||||
err = walletdb.View(b.db, func(tx walletdb.ReadTx) error {
|
err = walletdb.Update(b.db, func(tx walletdb.ReadWriteTx) error {
|
||||||
addrmgrNs := tx.ReadBucket(waddrmgrNamespaceKey)
|
addrmgrNs := tx.ReadWriteBucket(waddrmgrNamespaceKey)
|
||||||
|
|
||||||
path := waddrmgr.DerivationPath{
|
key, err = deriveFromKeyLoc(scopedMgr, addrmgrNs, keyLoc)
|
||||||
Account: uint32(keyLoc.Family),
|
if waddrmgr.IsError(err, waddrmgr.ErrAccountNotFound) {
|
||||||
Branch: 0,
|
// If we've reached this point, then the account
|
||||||
Index: uint32(keyLoc.Index),
|
// doesn't yet exist, so we'll create it now to ensure
|
||||||
}
|
// we can sign.
|
||||||
addr, err := scopedMgr.DeriveFromKeyPath(addrmgrNs, path)
|
acctErr := scopedMgr.NewRawAccount(
|
||||||
if err != nil {
|
addrmgrNs, uint32(keyLoc.Family),
|
||||||
return err
|
)
|
||||||
|
if acctErr != nil {
|
||||||
|
return acctErr
|
||||||
|
}
|
||||||
|
|
||||||
|
// Now that we know the account exists, we'll attempt
|
||||||
|
// to re-derive the private key.
|
||||||
|
key, err = deriveFromKeyLoc(
|
||||||
|
scopedMgr, addrmgrNs, keyLoc,
|
||||||
|
)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
key, err = addr.(waddrmgr.ManagedPubKeyAddress).PrivKey()
|
|
||||||
return err
|
return err
|
||||||
})
|
})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
@ -2427,6 +2427,48 @@ func testCreateSimpleTx(r *rpctest.Harness, w *lnwallet.LightningWallet,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// testSignOutputCreateAccount tests that we're able to properly sign for an
|
||||||
|
// output if the target account hasn't yet been created on disk. In this case,
|
||||||
|
// we'll create the account, then sign.
|
||||||
|
func testSignOutputCreateAccount(r *rpctest.Harness, w *lnwallet.LightningWallet,
|
||||||
|
_ *lnwallet.LightningWallet, t *testing.T) {
|
||||||
|
|
||||||
|
// First, we'll create a sign desc that references a non-default key
|
||||||
|
// family. Under the hood, key families are actually accounts, so this
|
||||||
|
// should force create of the account so we can sign with it.
|
||||||
|
fakeTx := wire.NewMsgTx(2)
|
||||||
|
fakeTx.AddTxIn(&wire.TxIn{
|
||||||
|
PreviousOutPoint: wire.OutPoint{
|
||||||
|
Hash: chainhash.Hash{},
|
||||||
|
Index: 0,
|
||||||
|
},
|
||||||
|
})
|
||||||
|
signDesc := &input.SignDescriptor{
|
||||||
|
KeyDesc: keychain.KeyDescriptor{
|
||||||
|
KeyLocator: keychain.KeyLocator{
|
||||||
|
Family: 99,
|
||||||
|
Index: 1,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
WitnessScript: []byte{},
|
||||||
|
Output: &wire.TxOut{
|
||||||
|
Value: 1000,
|
||||||
|
},
|
||||||
|
HashType: txscript.SigHashAll,
|
||||||
|
SigHashes: txscript.NewTxSigHashes(fakeTx),
|
||||||
|
InputIndex: 0,
|
||||||
|
}
|
||||||
|
|
||||||
|
// We'll now sign and expect this to succeed, as even though the
|
||||||
|
// account doesn't exist atm, it should be created in order to process
|
||||||
|
// the inbound signing request.
|
||||||
|
_, err := w.Cfg.Signer.SignOutputRaw(fakeTx, signDesc)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("unable to sign for output with non-existent "+
|
||||||
|
"account: %v", err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
type walletTestCase struct {
|
type walletTestCase struct {
|
||||||
name string
|
name string
|
||||||
test func(miner *rpctest.Harness, alice, bob *lnwallet.LightningWallet,
|
test func(miner *rpctest.Harness, alice, bob *lnwallet.LightningWallet,
|
||||||
@ -2493,6 +2535,10 @@ var walletTests = []walletTestCase{
|
|||||||
name: "create simple tx",
|
name: "create simple tx",
|
||||||
test: testCreateSimpleTx,
|
test: testCreateSimpleTx,
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
name: "test sign create account",
|
||||||
|
test: testSignOutputCreateAccount,
|
||||||
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
func clearWalletStates(a, b *lnwallet.LightningWallet) error {
|
func clearWalletStates(a, b *lnwallet.LightningWallet) error {
|
||||||
|
Loading…
Reference in New Issue
Block a user