-
Notifications
You must be signed in to change notification settings - Fork 88
feat(compile): compile taproot descriptor with randomized unspendable internal key #225
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
base: master
Are you sure you want to change the base?
feat(compile): compile taproot descriptor with randomized unspendable internal key #225
Conversation
- Add basic tests validating that taproot results contain 'r' field while sh results do not - Fix test execution by enabling 'compiler' feature - Add error message validation for invalid cases Future iterations will include more comprehensive test coverage.
Pull Request Test Coverage Report for Build 20901459542Warning: This coverage report may be inaccurate.This pull request's base commit is no longer the HEAD commit of its target branch. This means it includes changes from outside the original pull request, including, potentially, unrelated coverage changes.
Details
💛 - Coveralls |
tvpeter
left a comment
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 for working on this @va-an
I have left a few comments.
110CodingP
left a comment
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.
Refactoring the tests to usestd::process::Command instead of calling the internal function handle_compile_subcommand make the tests vulnerable to the state of environment variables and makes debugging harder in my opinion. But I have no strong disagreement to the approach in the PR.
My main idea is to have integration tests, not just unit tests, because that's the closest to how users actually interact with it. As for the environment variable state concern — we could remove related env vars to isolate integration tests, for example for compile tests: let output = Command::new("cargo")
.args(args)
.env_remove("NETWORK")
.env_remove("DATADIR")
.env_remove("POLICY")
.env_remove("TYPE")
.output()
.unwrap();This way we can isolate tests from the environment. Maintaining such tests might be a bit less convenient, but I promise to keep an eye on it :) |
That definitely makes sense.
Thanks! I did not know that we could remove them. I agree this could be helpful. Do you think it should be done in a separate PR though? maybe one that also refactors |
I would prefer to keep this PR as is, since @tvpeter has already looked at these changes. |
|
@110CodingP I decided to add the code for removing env vars in tests, as we discussed, so we don't forget to do this in future PRs. I verified locally that this works as expected — the command process will not receive these env vars from the parent process. use std::{env, process::Command};
fn main() {
unsafe {
env::set_var("FOO", "1");
env::set_var("BAR", "2");
env::set_var("BAZ", "3");
}
let cmd = Command::new("printenv")
.env_remove("FOO")
.env_remove("BAR")
.output()
.unwrap();
let stdout = String::from_utf8_lossy(&cmd.stdout);
assert!(!stdout.contains("FOO"), "FOO should be removed");
assert!(!stdout.contains("BAR"), "BAR should be removed");
assert!(stdout.contains("BAZ"), "BAZ should still be present");
println!("it's all good man");
}Please take a look — afc76aa. |
tvpeter
left a comment
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 updating the PR @va-an
Once you address the little comments, I will do a final test.
| .table() | ||
| .display() | ||
| .map_err(|e| Error::Generic(e.to_string()))?; | ||
| let mut rows = vec![vec!["Descriptor".cell().bold(true), descriptor.cell()]]; |
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.
the descriptor value is quite long, can you apply the [shorten](https://github.com/bitcoindevkit/bdk-cli/blob/fb7f6c60ca4ac1ad80750391435bbafd7346c714/src/utils.rs#L381) fn so it displays better?
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! I also used shorten() for r.
I extracted shorten description into a variable to shorten only the internal key and leave the rest of the descriptor as is.
without pretty:
-> % cargo run --all-features -- compile "pk(ABC)" -t tr
{
"descriptor": "tr(1985c2a86e01bbcdb1b5806422531a73c77e568ecfdd6d2863c158a76628ea50,pk(ABC))#6qsjh5q3",
"r": "e38caa40d0db7cae7037336c982278a7fc6b770e7a80f8bbce0d79976a14d5e1"
}with pretty:
-> % cargo run --all-features -- compile "pk(ABC)" -t tr --pretty
+------------+----------------------------------+
| Descriptor | tr(ccb4...b1d0,pk(ABC))#qrk923py |
+------------+----------------------------------+
| r | a129...7a14 |
+------------+----------------------------------+| let output = Command::new("cargo") | ||
| .args(args) | ||
| .env_remove("NETWORK") | ||
| .env_remove("DATADIR") |
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.
nit: ig removing DATADIR env variable is not required? Since the compile command does not use it?
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're right, DATADIR isn't used in compile command.
I'm planning to reuse this command execution code in other tests, so I preemptively cleared all env vars.
| .map_err(|e| Error::Generic(e.to_string()))?; | ||
| let descriptor = shorten_descriptor.unwrap_or(descriptor); | ||
|
|
||
| let mut rows = vec![vec!["Descriptor".cell().bold(true), descriptor.cell()]]; |
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 mut rows = vec![vec!["Descriptor".cell().bold(true), descriptor.cell()]]; | |
| let mut rows = vec![vec!["Descriptor".cell().bold(true), shorten(descriptor, 32, 29).cell()]]; |
you can remove: 908, 931-934, 946
you can also revert 951; it should size most screens comfortably.
tvpeter
left a comment
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.
Hi @va-an,
Could you please squash your commits into two or three commits and fix the shortening approach?
Aside from that, it looks good to go. Thank you.
Description
Resolves #218 (part 1/2).
Implements randomization of the unspendable internal key for taproot descriptors. This is the first part of #218, which consists of two parts:
Split into separate PRs for easier review and iteration, and to allow independent discussion of the verification command implementation, as one of the possible approaches could introduce breaking changes.
Notes to the reviewers
The
compilecommand now returns an additionalrfield for taproot descriptors (-t tr), containing the randomly generated internal key. Each compilation will produce a different internal key instead of using a fixed NUMS key.Example output for taproot (first execution):
Same descriptor compiled again produces different
rand internal key:Other descriptor types remain unchanged:
Tests for
compilecommand have been moved fromhandlers.rsto thetestsdirectory. Since taproot descriptors now generate a random internal key on each invocation, the test for thecompilecommand has been simplified. I plan to enhance this test in a follow-up PR once the verification command is implemented.Changelog notice
Checklists
All Submissions:
cargo fmtandcargo clippybefore committingNew Features:
CHANGELOG.md