Skip to content

Commit

Permalink
Merge 65cdb12 into 3be894b
Browse files Browse the repository at this point in the history
  • Loading branch information
Roasbeef committed Mar 5, 2019
2 parents 3be894b + 65cdb12 commit 42273e0
Show file tree
Hide file tree
Showing 8 changed files with 713 additions and 579 deletions.
1,147 changes: 577 additions & 570 deletions lnrpc/rpc.pb.go

Large diffs are not rendered by default.

2 changes: 2 additions & 0 deletions lnrpc/rpc.proto
Expand Up @@ -900,6 +900,8 @@ message ListUnspentResponse {
enum AddressType {
WITNESS_PUBKEY_HASH = 0;
NESTED_PUBKEY_HASH = 1;
UNUSED_WITNESS_PUBKEY_HASH = 2;
UNUSED_NESTED_PUBKEY_HASH = 3;
}

message NewAddressRequest {
Expand Down
8 changes: 6 additions & 2 deletions lnrpc/rpc.swagger.json
Expand Up @@ -793,7 +793,9 @@
"type": "string",
"enum": [
"WITNESS_PUBKEY_HASH",
"NESTED_PUBKEY_HASH"
"NESTED_PUBKEY_HASH",
"UNUSED_WITNESS_PUBKEY_HASH",
"UNUSED_NESTED_PUBKEY_HASH"
],
"default": "WITNESS_PUBKEY_HASH"
}
Expand Down Expand Up @@ -1289,7 +1291,9 @@
"type": "string",
"enum": [
"WITNESS_PUBKEY_HASH",
"NESTED_PUBKEY_HASH"
"NESTED_PUBKEY_HASH",
"UNUSED_WITNESS_PUBKEY_HASH",
"UNUSED_NESTED_PUBKEY_HASH"
],
"default": "WITNESS_PUBKEY_HASH",
"description": "- `p2wkh`: Pay to witness key hash (`WITNESS_PUBKEY_HASH` = 0)\n- `np2wkh`: Pay to nested witness key hash (`NESTED_PUBKEY_HASH` = 1)",
Expand Down
23 changes: 23 additions & 0 deletions lnwallet/btcwallet/btcwallet.go
Expand Up @@ -254,6 +254,29 @@ func (b *BtcWallet) NewAddress(t lnwallet.AddressType, change bool) (btcutil.Add
return b.wallet.NewAddress(defaultAccount, keyScope)
}

// LastUnusedAddress returns the last *unused* address known by the wallet. An
// address is unused if it hasn't received any payments. This can be useful in
// UIs in order to continually show the "freshest" address without having to
// worry about "address inflation" caused by continual refreshing. Similar to
// NewAddress it can derive a specified address type, and also optionally a
// change address.
func (b *BtcWallet) LastUnusedAddress(addrType lnwallet.AddressType) (
btcutil.Address, error) {

var keyScope waddrmgr.KeyScope

switch addrType {
case lnwallet.WitnessPubKey:
keyScope = waddrmgr.KeyScopeBIP0084
case lnwallet.NestedWitnessPubKey:
keyScope = waddrmgr.KeyScopeBIP0049Plus
default:
return nil, fmt.Errorf("unknown address type")
}

return b.wallet.CurrentAddress(defaultAccount, keyScope)
}

// IsOurAddress checks if the passed address belongs to this wallet
//
// This is a part of the WalletController interface.
Expand Down
8 changes: 8 additions & 0 deletions lnwallet/interface.go
Expand Up @@ -150,6 +150,14 @@ type WalletController interface {
// p2wsh, etc.
NewAddress(addrType AddressType, change bool) (btcutil.Address, error)

// LastUnusedAddress returns the last *unused* address known by the
// wallet. An address is unused if it hasn't received any payments.
// This can be useful in UIs in order to continually show the
// "freshest" address without having to worry about "address inflation"
// caused by continual refreshing. Similar to NewAddress it can derive
// a specified address type. By default, this is a non-change address.
LastUnusedAddress(addrType AddressType) (btcutil.Address, error)

// IsOurAddress checks if the passed address belongs to this wallet
IsOurAddress(a btcutil.Address) bool

Expand Down
60 changes: 60 additions & 0 deletions lnwallet/interface_test.go
Expand Up @@ -2165,6 +2165,62 @@ func testChangeOutputSpendConfirmation(r *rpctest.Harness,
}
}

// testLastUnusedAddr tests that the LastUnusedAddress returns the address if
// it isn't used, and also that once the address becomes used, then it's
// properly rotated.
func testLastUnusedAddr(miner *rpctest.Harness,
alice, bob *lnwallet.LightningWallet, t *testing.T) {

if _, err := miner.Node.Generate(1); err != nil {
t.Fatalf("unable to generate block: %v", err)
}

// We'll repeat this test for each address type to ensure they're all
// rotated properly.
addrTypes := []lnwallet.AddressType{
lnwallet.WitnessPubKey, lnwallet.NestedWitnessPubKey,
}
for _, addrType := range addrTypes {
addr1, err := alice.LastUnusedAddress(addrType)
if err != nil {
t.Fatalf("unable to get addr: %v", err)
}
addr2, err := alice.LastUnusedAddress(addrType)
if err != nil {
t.Fatalf("unable to get addr: %v", err)
}

// If we generate two addresses back to back, then we should
// get the same addr, as none of them have been used yet.
if addr1.String() != addr2.String() {
t.Fatalf("addresses changed w/o use: %v vs %v", addr1, addr2)
}

// Next, we'll have Bob pay to Alice's new address. This should
// trigger address rotation at the backend wallet.
addrScript, err := txscript.PayToAddrScript(addr1)
if err != nil {
t.Fatalf("unable to convert addr to script: %v", err)
}
feeRate := lnwallet.SatPerKWeight(2500)
output := &wire.TxOut{
Value: 1000000,
PkScript: addrScript,
}
sendCoins(t, miner, bob, alice, output, feeRate)

// If we make a new address, then it should be brand new, as
// the prior address has been used.
addr3, err := alice.LastUnusedAddress(addrType)
if err != nil {
t.Fatalf("unable to get addr: %v", err)
}
if addr1.String() == addr3.String() {
t.Fatalf("address should have changed but didn't")
}
}
}

type walletTestCase struct {
name string
test func(miner *rpctest.Harness, alice, bob *lnwallet.LightningWallet,
Expand Down Expand Up @@ -2219,6 +2275,10 @@ var walletTests = []walletTestCase{
name: "test cancel non-existent reservation",
test: testCancelNonExistentReservation,
},
{
name: "last unused addr",
test: testLastUnusedAddr,
},
{
name: "reorg wallet balance",
test: testReorgWalletBalance,
Expand Down
5 changes: 5 additions & 0 deletions mock.go
Expand Up @@ -226,6 +226,11 @@ func (m *mockWalletController) NewAddress(addrType lnwallet.AddressType,
m.rootKey.PubKey().SerializeCompressed(), &chaincfg.MainNetParams)
return addr, nil
}
func (*mockWalletController) LastUnusedAddress(addrType lnwallet.AddressType) (
btcutil.Address, error) {
return nil, nil
}

func (*mockWalletController) IsOurAddress(a btcutil.Address) bool {
return false
}
Expand Down
39 changes: 32 additions & 7 deletions rpcserver.go
Expand Up @@ -932,17 +932,42 @@ func (r *rpcServer) NewAddress(ctx context.Context,

// Translate the gRPC proto address type to the wallet controller's
// available address types.
var addrType lnwallet.AddressType
var (
addr btcutil.Address
err error
)
switch in.Type {
case lnrpc.AddressType_WITNESS_PUBKEY_HASH:
addrType = lnwallet.WitnessPubKey
addr, err = r.server.cc.wallet.NewAddress(
lnwallet.WitnessPubKey, false,
)
if err != nil {
return nil, err
}

case lnrpc.AddressType_NESTED_PUBKEY_HASH:
addrType = lnwallet.NestedWitnessPubKey
}
addr, err = r.server.cc.wallet.NewAddress(
lnwallet.NestedWitnessPubKey, false,
)
if err != nil {
return nil, err
}

addr, err := r.server.cc.wallet.NewAddress(addrType, false)
if err != nil {
return nil, err
case lnrpc.AddressType_UNUSED_WITNESS_PUBKEY_HASH:
addr, err = r.server.cc.wallet.LastUnusedAddress(
lnwallet.WitnessPubKey,
)
if err != nil {
return nil, err
}

case lnrpc.AddressType_UNUSED_NESTED_PUBKEY_HASH:
addr, err = r.server.cc.wallet.LastUnusedAddress(
lnwallet.NestedWitnessPubKey,
)
if err != nil {
return nil, err
}
}

rpcsLog.Infof("[newaddress] addr=%v", addr.String())
Expand Down

0 comments on commit 42273e0

Please sign in to comment.