-
Notifications
You must be signed in to change notification settings - Fork 2.1k
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
Adding path derivation #538
Conversation
ping @jprichardson, merge here, then extract to |
@@ -281,6 +281,24 @@ HDNode.prototype.deriveHardened = function (index) { | |||
return this.derive(index + HDNode.HIGHEST_BIT) | |||
} | |||
|
|||
// number + ' (e.g. 234') as a string -> hardened | |||
HDNode.prototype.derivePath = function (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.
Any reason why this just doesn't take a string
as input?
IMHO, I think I don't think there is much value in adding an |
We also intend to break out See #508 (comment) I'm not sure if adding these API's flies in the face of that or not. |
ad array based API: My original thinking for using Array was "What if someone puts there an array that is not a path, or that is wrongly formatted? Do I have to trim spaces around the slashes? Does it have to start with 'm/' or not? What if the node is not a master and is a sub-node, the 'm/' doesn't make sense", and that by using Array I just go around all these problems. Then I also thought about the function accepting both array and string, but that would be really ugly. ad splitting: |
@dcousens Yep, I don't see any harm in adding it at the moment. Agreed on not needing the array API. |
how exactly would you do the string-based API? Should it start with 'm/', or should it be "relative"? So for example, |
I think |
By "we", you mean the code in the library, or the user of the API? |
We, the developers of this library. |
Exactly. But then, I don't know how to make it unambiguous and non-sucky. And I don't also want to totally abandon it either. 😓 |
@Runn1ng I think if an Thoughts? |
Sorry for the delay. OK, that sounds reasonable |
Done :) |
splitPath = splitPath.slice(1) | ||
} else { | ||
throw new Error('Not a master node') | ||
} |
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 (this.parentFingerprint) throw new Error('Not a master node')
splitPath = splitPath.slice(1)
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 am not sure standard allow if block without curly braces :) but yeah I got you. Ok, will do tomorrow
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.
done
The argument is path of either numbers or strings. String with "'" at the end signifies hardened path.
I am taking description field for the path.
Maybe overdoing it a bit :)
I have done some cosmetic changes and rebased. The failing check has nothing to do with my code. |
Sounds good, will review asap :) |
@Runn1ng why unary plus instead return splitPath.reduce(function (prevHd, indexStr) {
if (indexStr.slice(-1) !== "'") return prevHd.derive(parseInt(indexStr, 10))
return prevHd.deriveHardened(parseInt(indexStr.slice(0, -1), 10))
}, this) |
Good catch. |
+ can cause issues - +"" is 0. parseInt("", 10) is NaN, which is better (since it causes typeforce to throw).
Just thinking.... if you put in path with decimal points ("m/0.5/1") by some mistake, using "parseInt" will silently truncate it instead of throwing errors. But I am not sure that is worth caring about. |
As option, you can check that result of return splitPath.reduce(function (prevHd, indexStr) {
var derive = prevHd.derive
if (indexStr.slice(-1) === "'") {
derive = prevHd.deriveHardened
indexStr = indexStr.slice(0, -1)
}
var index = parseInt(indexStr, 10)
if (index.toString() !== indexStr) throw new Error(...)
return derive.call(prevHd, index)
}, this) |
I am also thinking if things like I will probably do what you suggest. Alternatively, I can just test the index with regexp if it's only numbers. |
/([m]\/)?([0-9]+[']?\/)*([0-9]+[']?)/ |
Well, I wanted to test indices one by one after splitting, which is more readable and easily debuggable, but it's true that testing the parameter at the start of a function is more in line with the rest of the code. |
Again through typeforce
I have added path validation to typeforce types. |
@@ -26,6 +26,11 @@ function UInt53 (value) { | |||
Math.floor(value) === value | |||
} | |||
|
|||
function Path (value) { |
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.
BIP32Path
? shrug
It's private anyway, so I'm not worried too much.
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.
+1 for BIP32Path
or BIP32DerivePath
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.
Ok
Only thing I haven't been able to do is to add "undefined" to fixtures. So I could not properly test that node.derivePath() properly fails as it should. However, I added "null" there, and "null" and "undefined" behave in similar way in JavaScript, so that should catch that.
OK, feedback was put in |
ACK |
ACK 👍 |
😎 great |
@@ -109,7 +109,7 @@ | |||
"address": "19EuDJdgfRkwCmRzbzVBHZWQG9QNWhftbZ" | |||
}, | |||
{ | |||
"description": "m/0/2147483647", | |||
"description": "m/0/2147483647'", |
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 might rename this to 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.
That would be great
Thanks for merging, I kind of forgot about this PR :) |
Now this might be a bit controversial, but I found something like that to be really useful.
What will be controversial, I think: