-
Notifications
You must be signed in to change notification settings - Fork 575
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Create watch-only address managers and accounts #667
Conversation
9221af9
to
82c55fc
Compare
waddrmgr/manager.go
Outdated
// particular coin type and BIP0043 purpose. This is useful as it enables | ||
// callers to create an arbitrary BIP0043 like schema with a stand alone | ||
// manager. | ||
func (m *Manager) NewWatchingOnlyScopedKeyManager(ns walletdb.ReadWriteBucket, scope KeyScope, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This could be merged with NewScopedKeyManager
, with a conditional on watchingOnly
. WDYT?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
SGTM, there's a ton of duplication as is.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yes, that would definitely be preferable. You could split the content into multiple smaller methods and call them depending on the flag. This would avoid large chunks of code inside if conditions.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Fixed.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Let us know if looks good.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
After meditating on this a bit more, I realized that non of the restrictions (well most of them) that I previously thought were present actually exists. As a result, I think this PR takes a step towards putting some scaffolding in places to address both of our respective goals and more!
I've completed an initial pass through this PR, thanks again for getting this rolling!
waddrmgr/manager.go
Outdated
// particular coin type and BIP0043 purpose. This is useful as it enables | ||
// callers to create an arbitrary BIP0043 like schema with a stand alone | ||
// manager. | ||
func (m *Manager) NewWatchingOnlyScopedKeyManager(ns walletdb.ReadWriteBucket, scope KeyScope, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
SGTM, there's a ton of duplication as is.
@@ -859,6 +860,9 @@ func fetchLastAccount(ns walletdb.ReadBucket, scope *KeyScope) (uint32, error) { | |||
metaBucket := scopedBucket.NestedReadBucket(metaBucketName) | |||
|
|||
val := metaBucket.Get(lastAccountName) | |||
if val == nil { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Why wasn't this needed before? Or is this for the case where we create the new wallet as pure watch-only?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think this only occurs when the wallet is created as pure watch-only.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Ah, because no default accounts are created, right.
cc @guggero |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thank you for the PR, nice work! This does indeed look like what we need for our use case in lnd.
My comments are also mainly around code duplication and putting everything behind a flag (which will also make it easier for us to use the code in lnd).
waddrmgr/manager.go
Outdated
// particular coin type and BIP0043 purpose. This is useful as it enables | ||
// callers to create an arbitrary BIP0043 like schema with a stand alone | ||
// manager. | ||
func (m *Manager) NewWatchingOnlyScopedKeyManager(ns walletdb.ReadWriteBucket, scope KeyScope, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yes, that would definitely be preferable. You could split the content into multiple smaller methods and call them depending on the flag. This would avoid large chunks of code inside if conditions.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This looks much better without the code duplication, thanks!
Maybe it's a bit late to suggest this, but while figuring out how exactly one would use this new functionality I couldn't help but wonder if it wouldn't be possible to create a new manager with the master xpub directly instead of later adding accounts.
So perhaps creating a new CreateWatchingOnly
function and keeping the old one for compatibility but internally all routing it to a non-exported function that has all the logic.
Something like:
func CreateWatchingOnly(ns walletdb.ReadWriteBucket,
pubKey, pubPassphrase []byte,
chainParams *chaincfg.Params, config *ScryptOptions,
birthday time.Time) error {
return create(
ns, pubKey, pubPassphrase, nil, chainParams, config,
birthday, true,
)
}
func Create(ns walletdb.ReadWriteBucket,
seed, pubPassphrase, privPassphrase []byte,
chainParams *chaincfg.Params, config *ScryptOptions,
birthday time.Time) error {
return create(
ns, seed, pubPassphrase, privPassphrase, chainParams, config,
birthday, false,
)
}
func create(ns walletdb.ReadWriteBucket,
seedOrPubKey, pubPassphrase, privPassphrase []byte,
chainParams *chaincfg.Params, config *ScryptOptions,
birthday time.Time, isWatchingOnly bool) error {
// logic for parsing the pubKey as a neutered master key and initializing the default accounts with it.
}
This could also be done in a follow-up PR if we want to push forward with this.
@@ -859,6 +860,9 @@ func fetchLastAccount(ns walletdb.ReadBucket, scope *KeyScope) (uint32, error) { | |||
metaBucket := scopedBucket.NestedReadBucket(metaBucketName) | |||
|
|||
val := metaBucket.Get(lastAccountName) | |||
if val == nil { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Ah, because no default accounts are created, right.
Account derivation is hardened, so it's not possible to derive account xpubs from the parent(s). |
Right, I didn't remember that. Then I think the current design of the PR makes a lot of sense 👍 |
I think everything is addressed, pls let me know if I missed something ... |
Thanks, looks better now! Just one last question: I started implementing something on top of this and noticed that currently there is no way to create a new wallet wit a |
No, the idea is definitely to create the wallet without a seed and add accounts using XPUB from the remote signer. Investigating ... |
Oliver, I think we missed that. We'll add mechanism to create an empty watch-only wallet to this PR straightaway. Thanks for catching! |
Did a force push to rebase on master, fixes coming ... |
Ok, I've added |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thanks, looks good to me!
Just two small nits, but they aren't blocking in my opinion.
Force pushed rebase onto master, about to fix nits ... |
ping, everything look ok with this? |
cc @Roasbeef. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
LGTM 💎
// except that the manager is created normally with a seed. This test | ||
// shows that watch-only accounts can be added to managers with | ||
// non-watch-only accounts. | ||
func TestNewRawAccountHybrid(t *testing.T) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
👍
Y'all can follow the progress for the remaining |
This PR allows the creation of managers and accounts that are watch-only. The state of the database after creation would be identical to the state after calling
Manager.ConvertToWatchingOnly
, assuming accounts with the right xpubs were created in the former case.Of course, creating a watch-only database is safer, since you don't have to worry about private data ending up in a swap file or the system having been compromised before creation.