-
Notifications
You must be signed in to change notification settings - Fork 809
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
Adds descriptor module with getdescriptorinfo rpc #1152
Conversation
Codecov ReportPatch coverage:
Additional details and impacted files@@ Coverage Diff @@
## master #1152 +/- ##
==========================================
+ Coverage 69.56% 70.26% +0.69%
==========================================
Files 159 174 +15
Lines 26607 27367 +760
==========================================
+ Hits 18509 19229 +720
- Misses 8098 8138 +40
☔ View full report in Codecov by Sentry. |
918ed8c
to
e47a36c
Compare
baa629e
to
1c28e9d
Compare
4ec0130
to
474641d
Compare
e33ac76
to
2bb70a0
Compare
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.
code review ACK 2bb70a0
The commits look super clean now THANK YOU, this was very easy to read and review. I left quite a few nits and questions below. I think everything is looking really good, just some clean up and some ideas about making your base classes more abstract.
While you address those comments I'm going to review the test vectors more closely and then play with the actual RPC feature and library functions and try to break them ;-)
GREAT WORK, keep it up! Almost done. <3
lib/hd/keyorigininfo.js
Outdated
fromOptions(options) { | ||
assert(options, 'requires options'); | ||
|
||
if (options.fingerPrint !== null) { |
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 these need to be !=
so that undefined
and null
are treated the same
lib/hd/common.js
Outdated
* @param {Boolean} hard | ||
* @returns {Number[]} | ||
* @returns {Array} |
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 change this? isn't Number[]
correct?
lib/hd/keyorigininfo.js
Outdated
const fingerPrint = isValidFingerPrint(slashSplit[0]); | ||
this.fingerPrint = fingerPrint; |
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.
could just be...
const fingerPrint = isValidFingerPrint(slashSplit[0]); | |
this.fingerPrint = fingerPrint; | |
this.fingerPrint = isValidFingerPrint(slashSplit[0]); |
lib/hd/keyorigininfo.js
Outdated
* @returns {Number} | ||
*/ | ||
|
||
function isValidFingerPrint(str) { |
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.
maybe call this validateFingerprint()
? since it doesn't return a boolean like most is...()
functions
test/keyorigininfo-test.js
Outdated
/* eslint-disable quotes */ | ||
/* eslint-disable no-unused-vars */ |
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.
nits:
- I dont think you need no-unsued-vars
- but you should set
/* eslint-env mocha */
- I understand you want to use double quotes because there's so many single-quotes in the test vectors, I think that is ok. Still looks ugly to me in the first 5 lines though
lib/descriptor/type/combo.js
Outdated
|
||
this.network = Network.get(options.network); | ||
|
||
for (const keyProvider of options.keyProviders) { |
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.
didn't you just assert there will only be one of these? Same with pk()
maybe others...
lib/descriptor/type/multisig.js
Outdated
super(); | ||
this.name = types.MULTI; | ||
this.isSorted = false; | ||
this.threshold = null; |
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 should initialize as 0
for type optimization ?
} | ||
|
||
this.network = Network.get(options.network); | ||
this.script = options.script; |
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.
should have init value in constructor
lib/descriptor/descriptor.js
Outdated
class Descriptor { | ||
/** | ||
* Create a descriptor | ||
* @constructor | ||
*/ | ||
|
||
constructor() { | ||
this.name = null; | ||
this.keyProviders = []; | ||
this.subdescriptors = []; | ||
this.network = null; | ||
} |
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.
See my comment about making AbstractKeyProvider
- I think more stuff can be moved to the base class, like parsing some of the common options like network. keyProviders
must always be an array so that can be checked in base class, then each extended class can check those array lengths, etc.
lib/node/rpc.js
Outdated
@@ -2765,6 +2769,26 @@ class RPC extends RPCBase { | |||
}; | |||
} | |||
|
|||
async getDescriptorInfo(args, help) { |
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.
lets put this function after the setloglevel
implementation (up on line 2328 or so). Down here is for helper functions
02796a5
to
e96f319
Compare
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.
code review ACK e96f319
Everything looks awesome, just a few picky nits and we can land this beast!
lib/hd/keyorigininfo.js
Outdated
fromOptions(options) { | ||
assert(options, 'requires options'); | ||
|
||
if (options.fingerPrint) { |
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.
if (options.fingerPrint) { | |
if (options.fingerPrint != null) { |
See for example ChainOptions.fromOptions()
in chain.js L2639
lib/hd/common.js
Outdated
* @param {Boolean} hard | ||
* @returns {Number[]} | ||
*/ | ||
|
||
common.parsePath = function parsePath(path, hard) { | ||
assert(typeof path === 'string'); | ||
common.parsePathToArray = function parsePathToArray(path, hard) { |
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.
Should this be parsePathFromArray()
?
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.
Actually this function parses path from String so maybe I can rename it to parsePathFromString?
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.
does it?
assert(Array.isArray(path), 'Path must be an array.');
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.
Ohh sorry I thought you were mentioning parsePath function. I'll change parsePathToArray to parsePathFromArray
lib/hd/keyorigininfo.js
Outdated
toJSON() { | ||
return { | ||
fingerPrint: this.format().fingerPrint, | ||
path: this.format().path | ||
}; | ||
} |
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.
should this just return this.format()
? And so only call it once?
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 no need. Good catch.
@@ -0,0 +1,27 @@ | |||
/*! |
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.
Lets add a link to this module in lib/bcoin.js
as well
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.
Yeah should have done this way earlier. Thanks for pointing this out :). Also added KeyOriginInfo in HD here.
lib/descriptor/common.js
Outdated
|
||
common.isHex = function isHex(str) { | ||
assert(typeof str === 'string'); | ||
return /^[0-9a-fA-F]+$/.test(str); |
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 should also probably ensure an even number of characters
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'm a bit unsure whether this function should exist. I only found 1 usage in keyprovider.js
L87. I think we can remove this function from here.
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 we can have it for now . People could use it instead of calling the external dependencies. (base16)
lib/descriptor/keyprovider.js
Outdated
parseOptions(options) { | ||
this.ring = options.ring; | ||
this.pos = options.pos; | ||
this.originInfo = options.originInfo; | ||
this.hardenedMarker = options.hardenedMarker; | ||
this.network = Network.get(options.network); | ||
} |
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.
Don't we still need to do input validation here of the passed-in options?
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 don't think it's required to do that here since we are already parsing and validating the inputs by the parsing functions of KeyProvider class.
isRange() { | ||
return false; | ||
} |
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.
If these functions all return null
because direct instances of the abstract KeyProvider
class shouldn't be used, these methods should probably throw errors. See the methods in blockstore/abstract.js
options.script = desc.script; | ||
options.network = desc.network; | ||
|
||
switch (type) { |
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.
You already have parser.parse()
is there a reason to implement that again here?
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.
parser.parse() parses descriptor only when it is in string form. To parse descriptor from options object this function is needed.
lib/descriptor/type/addr.js
Outdated
if (options.subdescriptors) { | ||
assert(options.subdescriptors.length === 0); | ||
} | ||
|
||
if (options.keyProviders) { | ||
assert(options.keyProviders.length === 0); | ||
} |
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 you can drop the if's and just assert. Because of the abstractdescriptor constructor, we know those arrays will exist, we just need to ensure that they are empty.
lib/descriptor/abstractdescriptor.js
Outdated
*/ | ||
|
||
constructor() { | ||
this.name = null; |
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 should be this.type
in all the classes, sorry I shouldve caught that sooner
1b87d14
to
e94d8cb
Compare
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.
ACK e94d8cb
Excellent work on the PR! Just a few small nits to fix before we can merge.
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.
Tested ACK 5b09c3f
This pr implements getdescriptorinfo rpc by adding a descriptor module.
If the argument string of getdescriptorinfo() rpc is a valid string it is parsed into a AbstractDescriptor object.
Along with that various parts of the string, such as origin information, keys (Public/Private), and derivation path (along with hardened or unhardened information) are parsed into PubKeyProvider object respectively. If the descriiptor string contains a checksum it will be validiated and if a checksum is not present we will calculate one.
Note: The input descriptor string doesn't require checksum to be present.
The AbstractDescriptor class has PKDescriptor, PKHDescriptor, WPKHDescriptor, AddressDescriptor, MultisigDescriptor, WSHDescriptor, SHDescriptor, RawDescriptor, ComboDescriptor as its subclasses.
The KeyProvider class will have ConstPubkeyProvider (for parsing constant keys with/without origin info) and HDKeyProvider (for parsing extended (hd - bip32) keys with/without origin info) as its subclasses.
Functions for parsing descriptor string will be present as global function in parser.js.
Checksum functions are implemented in common.js.
Functions checking isRange(), isSolvable(), hasPrivateKeys() etc. will be present in the AbstractDescriptor class.