Allow enabling at most one blockchain client feature - #38

Merged
notmandatory merged 10 commits into
bitcoindevkit:masterfrom
notmandatory:single_blockchain_feature
Aug 13, 2021
Merged

Allow enabling at most one blockchain client feature#38
notmandatory merged 10 commits into
bitcoindevkit:masterfrom
notmandatory:single_blockchain_feature

Conversation

@notmandatory

@notmandatorynotmandatory commented Aug 5, 2021

Copy link
Copy Markdown
Member

Description

Allow at most one blockchain client feature be enabled at a time for builds. If no blockchain client feature is enabled then online wallet commands are disabled. This will simplify the options shown to the user and make adding new blockchain clients (such as #36) easier. Electrum is still the default, to make a build with a different blockchain client the --no-default-features build option will need to be used. No blockchain client is included in the default features, so if one is needed it must be specified with --features. I also added a default esplora server url so the user doesn't need to specify one if selecting that client, which is how the electrum and compact_filters clients work.

Notes to the reviewers

I changed the server option for both electrum and esplora to --server or -s since that now won't cause a conflict. I also simplified the CHANGELOG to focus on what a user would see as a change while using the bin.

I've also added a build.rs file to prevent more than one blockchain client feature from being enabled.

Checklists

All Submissions:

  • I've signed all my commits
  • I followed the contribution guidelines
  • I ran cargo fmt and cargo clippy before committing

New Features:

  • I've added tests for the new feature
  • I've added docs for the new feature
  • I've updated CHANGELOG.md

Bugfixes:

  • This pull request breaks the existing API
  • I've added tests to reproduce the issue which are now passing
  • I'm linking the issue being fixed by this PR

@notmandatory
notmandatoryforce-pushed the single_blockchain_feature branch 4 times, most recently from 65729b9 to 47e0962CompareAugust 5, 2021 06:15
@notmandatorynotmandatory changed the title Single blockchain featureOnly allow enabling at most one blockchain client featureAug 5, 2021
@notmandatorynotmandatory changed the title Only allow enabling at most one blockchain client featureAllow enabling at most one blockchain client featureAug 5, 2021
@notmandatory
notmandatoryforce-pushed the single_blockchain_feature branch 2 times, most recently from f9cd936 to c81a99eCompareAugust 5, 2021 06:42
@notmandatory
notmandatory marked this pull request as ready for review August 5, 2021 06:43

@rajarshimaitrarajarshimaitra left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks @notmandatory for the PR, we are close almost. I just have a few more comments.

Is there any specific use of Repl mode here?

bdk-cli/src/lib.rs

Lines 258 to 262 in 378b33a

#[structopt(long_about = "REPL command loop mode")]
Repl{
#[structopt(flatten)]
wallet_opts:WalletOpts,
},

It just seems to be duplicating WalletOpts and no commands. If not we can remove this, it seems redundant.

One problem here is using --no-default-features will turn off repl too, which is required dep for the binary, so it will not compile any binary. This has been the crux of the problem because cargo doesn't let us selectively disable features. So if we disable default, it disables everything in default.

I think the only way to solve this problem is by having a very minimal default with only the stuffs that we need to create the minimal possible binary. And then add stuff to it with features flag. This will also remove the use of --no-default-feature if we only want esplora but not electrum.

So I propose something like this:

[features]
default = ["repl"]
repl = ["bdk/key-value-db", "clap", "dirs-next", "env_logger", "regex", "rustyline"]
electrum = ["bdk/electrum"]
esplora = ["bdk/esplora"]
compiler = ["bdk/compiler"]
async-interface = ["bdk/async-interface"]
compact_filters = ["bdk/compact_filters"]
[[bin]]
name = "bdk-cli"
path = "src/bdk_cli.rs"
required-features = ["repl"]

This will create the following builds

cargo build : build only repl stuffs, no backend
cargo build --features [backend] : build repl + [backend] blockchain.

I don't think there's any adverse effect of not having a blockchain by default. the only method we have with blockchain is sync and broadcast, everything else can be done without a blockchain. So it's safe to remove it in default.

@rajarshimaitra

rajarshimaitra commented Aug 5, 2021

Copy link
Copy Markdown
Contributor

Also, I am not sure if we should silently ignore "no binary built" scenarios in CI.

run: cargo build --features ${{ matrix.features }} --no-default-features

with current changes for example cargo build --features esplora --no-default-features will not build any binary, but the CI doesn't complain.

you can check that locally with

$ cargo clean
$ cargo build --features esplora --no-default-features
$ ./target/debug/bdk-cli wallet --help
bash: ./target/debug/bdk-cli: No such file or directory

I am not sure how then it's passing the tests without a binary.

@notmandatory

notmandatory commented Aug 6, 2021

Copy link
Copy Markdown
MemberAuthor

I think tests were passing because they only needed a lib build to run. But I agree it would be nice to not have to use the --no-default-features flag. I did the following to try and address this:

  1. split the repl feature into cli for the required dependencies to build the cli bin, and repl to enable the cli repl commands, then made the cli feature required to build the cli bin, but the cli and repl features on by default.
  2. added cfg statements so someone could build the cli without the repl command if they want fewer dependencies and use the --no-default-features flag
  3. update the CI to test with the default (no blockchain client) features, or each blockchain client, or the 'compiler' feature

@rajarshimaitrarajarshimaitra left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Code review ACK. This simplifies the issue.

I had the following observation. It seems if we compile the library using cargo build --features cli --no-default-features, that produces a binary that is perfectly workable with non backend wallet. It has functionality like this

$ ./target/debug/bdk-cli wallet --help
bdk-cli-wallet 0.2.1-dev
Wallet mode
USAGE:
bdk-cli wallet [FLAGS] [OPTIONS] --descriptor <DESCRIPTOR> <SUBCOMMAND>
FLAGS:
-v, --verbose Adds verbosity, returns PSBT in JSON format alongside serialized
-h, --help Prints help information
-V, --version Prints version information
OPTIONS:
-c, --change_descriptor <CHANGE_DESCRIPTOR> Sets the descriptor to use for internal addresses
-d, --descriptor <DESCRIPTOR> Sets the descriptor to use for the external addresses
-w, --wallet <WALLET_NAME> Selects the wallet to use [default: main]
SUBCOMMANDS:
bump_fee Bumps the fees of an RBF transaction
combine_psbt Combines multiple PSBTs into one
create_tx Creates a new unsigned transaction
extract_psbt Extracts a raw transaction from a PSBT
finalize_psbt Finalizes a PSBT
get_balance Returns the current wallet balance
get_new_address Generates a new external address
help Prints this message or the help of the given subcommand(s)
list_transactions Lists all the incoming and outgoing transactions of the wallet
list_unspent Lists the available spendable UTXOs
policies Returns the available spending policies for the descriptor
public_descriptor Returns the public version of the wallet's descriptor(s)
sign Signs and tries to finalize a PSBT

So that begs the question I had before, what do we need the repl thing for?

Also from here https://github.com/notmandatory/bdk-cli/blob/69b1d80bcd4715a3b78af4aafacebe2fc5ca2b88/src/bdk_cli.rs#L318-L331
it seems all a repl does is to perse existing commands and use them with either wallet or key functions. Maybe I am missing something, but I am not seeing any use of having the same methods called twice in different ways.

If two features cli and repl that does the same thing, it seems confusing to me.

Comment threadsrc/bdk_cli.rs Outdated
feature = "esplora",
any(feature = "electrum", feature = "compact_filters")
))]
compile_error!("Only one blockchain client feature can be enabled at a time.");

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It seems for every combination of electrum, esplora and compact_filters, this error is being duplicated with the one defined few lines below.

Instead, if we write it like this

#[cfg(all(
any( feature = "electrum", feature = "esplora", feature = "compact_filters"),
any( feature = "electrum", feature = "esplora", feature = "compact_filters")
))]

this will activate for any combination of the above three. And we won't need to specify compiler_error! multiple times.

Also for future extension, if we just add a new backend to the list above, that will taker care of multiple backend activation errors.

@notmandatorynotmandatoryAug 6, 2021

Copy link
Copy Markdown
MemberAuthor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Unfortunately the cfg all any any approach doesn't work, when I added this code:

#[cfg(all(any( feature = "electrum", feature = "esplora", feature = "compact_filters"),any( feature = "electrum", feature = "esplora", feature = "compact_filters")))]compile_error!("Only one blockchain client feature can be enabled at a time.");

I get the error even with only one blockchain client feature enabled (ie. cargo build --features esplora).

Looks like other's have had this same problem and are proposing a Rust RFC to allow a set of features to provide another feature in a mutually exclusive way.

Until mutually exclusive features are possible I can fix this in a simplistic way in the build.rs file as below or just leave it as it.. What do you think?

fnmain(){let electrum = env::var_os("CARGO_FEATURE_ELECTRUM").map(|_| "electrum".to_string());let esplora = env::var_os("CARGO_FEATURE_ESPLORA").map(|_| "esplora".to_string());let compact_filters = env::var_os("CARGO_FEATURE_COMPACT_FILTERS").map(|_| "compact_filters".to_string());let blockchain_features :Vec<String> = vec!(electrum, esplora, compact_filters).iter().map(|f| f.to_owned()).flatten().collect();if blockchain_features.len() > 1{panic!("At most one blockchain client feature can be enabled but these features were enabled: {:?}", blockchain_features)}}

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ah ok.. I thought it would work because my analyzer didn't throw. Yes there should be a way to handle mutually exclusive features in cargo itself.

I like the build script approach. It's clear and concise. Till it's available in cargo we can use a guard like above.

@rajarshimaitra

Copy link
Copy Markdown
Contributor

The following structure and function call could use feature guard. They exist in binary compiled without a backend, but are never used.

https://github.com/notmandatory/bdk-cli/blob/69b1d80bcd4715a3b78af4aafacebe2fc5ca2b88/src/lib.rs#L892

https://github.com/notmandatory/bdk-cli/blob/69b1d80bcd4715a3b78af4aafacebe2fc5ca2b88/src/lib.rs#L638

@notmandatory
notmandatoryforce-pushed the single_blockchain_feature branch from d3c0af3 to 9bb1c60CompareAugust 7, 2021 00:27

@rajarshimaitrarajarshimaitra left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

tACK 9bb1c60

With some minor nits.

Comment threadCHANGELOG.md Outdated
Comment threadCargo.toml
name = "bdk-cli"
path = "src/bdk_cli.rs"
required-features = ["repl", "electrum"]
required-features = ["cli"]

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is this required-features value necessary? By putting cli in default we are ensuring that the build will always include cli. (we also removed any necessity of using --no-default-features).

Copy link
Copy Markdown
MemberAuthor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think we still need cli as required to force anyone building the bin without repl (using --no-default-features) to still include cli.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ya makes sense.

Comment threadREADME.md Outdated
Comment threadREADME.md

```shell
cargo run -- wallet --descriptor "wpkh(tpubEBr4i6yk5nf5DAaJpsi9N2pPYBeJ7fZ5Z9rmN4977iYLCGco1VyjB9tvvuvYtfZzjD5A8igzgw3HeWeeKFmanHYqksqZXYXGsw5zjnj7KM9/*)" sync
cargo run --features electrum -- wallet --descriptor "wpkh(tpubEBr4i6yk5nf5DAaJpsi9N2pPYBeJ7fZ5Z9rmN4977iYLCGco1VyjB9tvvuvYtfZzjD5A8igzgw3HeWeeKFmanHYqksqZXYXGsw5zjnj7KM9/*)" sync

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Few lines ago we mentioned how to install bdk-cli with cargo.

Instructing to use cargo run here will build the local files instead of using the installed binary. So if someone is in their cloned repo, using cargo run they will actually build and then run the master branch instead of the release binary he just installed (this might be an unexpected behavior for the user, unless he knows cargo stuffs).

Even worse if someone didn't clone the repo, cargo run will not run anything, even if they have bdk-cli binary installed (and we don't have that instruction anywhere).

I think in the "bdk-cli bin usage examples" section, we should just instruct to use bdk-cli binary instead of crago run, which will make the instruction simpler also.

This doesn't have to be fixed here. Just mentioned as it occurred to me.

Copy link
Copy Markdown
MemberAuthor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I agree we should probably update the README to focus on installing with different features, and then usage with an installed version instead of using cargo run since anyone making local changes should already know how to use cargo. But let's do that cleanup in a different PR.

Comment threadsrc/lib.rs
@rajarshimaitra

Copy link
Copy Markdown
Contributor

ACK 062542a

@notmandatory
notmandatoryforce-pushed the single_blockchain_feature branch from 062542a to 7c4f5e7CompareAugust 12, 2021 14:13

@rajarshimaitrarajarshimaitra left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Code review with testing ACK 4fd39b7

@notmandatory
notmandatory merged commit 4fd39b7 into bitcoindevkit:masterAug 13, 2021
@notmandatory

Copy link
Copy Markdown
MemberAuthor

Thanks for the suggestions and review on this @rajarshimaitra, all ready to rebase your #36 PR.

Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants

@notmandatory@rajarshimaitra
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Add copy buttons to all
 blocks\n(function() {\n function addCopyButtons() {\n document.querySelectorAll('pre code').forEach(function(codeBlock) {\n if (codeBlock.parentElement.hasAttribute('data-copy-added')) return;\n codeBlock.parentElement.setAttribute('data-copy-added', 'true');\n \n var btn = document.createElement('button');\n btn.textContent = 'Copy';\n btn.style.cssText = 'position:absolute;top:4px;right:4px;padding:2px 8px;font-size:11px;background:#4ecdc4;border:none;border-radius:4px;color:#1a1a2e;cursor:pointer;opacity:0.7;transition:opacity 0.2s;';\n btn.onmouseover = function() { this.style.opacity = '1'; };\n btn.onmouseout = function() { this.style.opacity = '0.7'; };\n btn.onclick = function() {\n navigator.clipboard.writeText(codeBlock.textContent).then(function() {\n btn.textContent = 'Copied!';\n setTimeout(function() { btn.textContent = 'Copy'; }, 1500);\n });\n };\n codeBlock.parentElement.style.position = 'relative';\n codeBlock.parentElement.appendChild(btn);\n });\n }\n \n addCopyButtons();\n \n // Re-run on dynamic content\n var observer = new MutationObserver(addCopyButtons);\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "Add Copy Buttons to Code Blocks");
}
} catch(__e) { console.warn('[Userscript:Add Copy Buttons to Code Blocks]', __e); }
})();
(function(){
try {
var __m = "github.com";
var __re = new RegExp('^' + "github\\.com" + '
Skip to content

Allow enabling at most one blockchain client feature - #38

Merged
notmandatory merged 10 commits into
bitcoindevkit:masterfrom
notmandatory:single_blockchain_feature
Aug 13, 2021
Merged

Allow enabling at most one blockchain client feature#38
notmandatory merged 10 commits into
bitcoindevkit:masterfrom
notmandatory:single_blockchain_feature

Conversation

@notmandatory

@notmandatorynotmandatory commented Aug 5, 2021

Copy link
Copy Markdown
Member

Description

Allow at most one blockchain client feature be enabled at a time for builds. If no blockchain client feature is enabled then online wallet commands are disabled. This will simplify the options shown to the user and make adding new blockchain clients (such as #36) easier. Electrum is still the default, to make a build with a different blockchain client the --no-default-features build option will need to be used. No blockchain client is included in the default features, so if one is needed it must be specified with --features. I also added a default esplora server url so the user doesn't need to specify one if selecting that client, which is how the electrum and compact_filters clients work.

Notes to the reviewers

I changed the server option for both electrum and esplora to --server or -s since that now won't cause a conflict. I also simplified the CHANGELOG to focus on what a user would see as a change while using the bin.

I've also added a build.rs file to prevent more than one blockchain client feature from being enabled.

Checklists

All Submissions:

  • I've signed all my commits
  • I followed the contribution guidelines
  • I ran cargo fmt and cargo clippy before committing

New Features:

  • I've added tests for the new feature
  • I've added docs for the new feature
  • I've updated CHANGELOG.md

Bugfixes:

  • This pull request breaks the existing API
  • I've added tests to reproduce the issue which are now passing
  • I'm linking the issue being fixed by this PR

@notmandatory
notmandatoryforce-pushed the single_blockchain_feature branch 4 times, most recently from 65729b9 to 47e0962CompareAugust 5, 2021 06:15
@notmandatorynotmandatory changed the title Single blockchain featureOnly allow enabling at most one blockchain client featureAug 5, 2021
@notmandatorynotmandatory changed the title Only allow enabling at most one blockchain client featureAllow enabling at most one blockchain client featureAug 5, 2021
@notmandatory
notmandatoryforce-pushed the single_blockchain_feature branch 2 times, most recently from f9cd936 to c81a99eCompareAugust 5, 2021 06:42
@notmandatory
notmandatory marked this pull request as ready for review August 5, 2021 06:43

@rajarshimaitrarajarshimaitra left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks @notmandatory for the PR, we are close almost. I just have a few more comments.

Is there any specific use of Repl mode here?

bdk-cli/src/lib.rs

Lines 258 to 262 in 378b33a

#[structopt(long_about = "REPL command loop mode")]
Repl{
#[structopt(flatten)]
wallet_opts:WalletOpts,
},

It just seems to be duplicating WalletOpts and no commands. If not we can remove this, it seems redundant.

One problem here is using --no-default-features will turn off repl too, which is required dep for the binary, so it will not compile any binary. This has been the crux of the problem because cargo doesn't let us selectively disable features. So if we disable default, it disables everything in default.

I think the only way to solve this problem is by having a very minimal default with only the stuffs that we need to create the minimal possible binary. And then add stuff to it with features flag. This will also remove the use of --no-default-feature if we only want esplora but not electrum.

So I propose something like this:

[features]
default = ["repl"]
repl = ["bdk/key-value-db", "clap", "dirs-next", "env_logger", "regex", "rustyline"]
electrum = ["bdk/electrum"]
esplora = ["bdk/esplora"]
compiler = ["bdk/compiler"]
async-interface = ["bdk/async-interface"]
compact_filters = ["bdk/compact_filters"]
[[bin]]
name = "bdk-cli"
path = "src/bdk_cli.rs"
required-features = ["repl"]

This will create the following builds

cargo build : build only repl stuffs, no backend
cargo build --features [backend] : build repl + [backend] blockchain.

I don't think there's any adverse effect of not having a blockchain by default. the only method we have with blockchain is sync and broadcast, everything else can be done without a blockchain. So it's safe to remove it in default.

@rajarshimaitra

rajarshimaitra commented Aug 5, 2021

Copy link
Copy Markdown
Contributor

Also, I am not sure if we should silently ignore "no binary built" scenarios in CI.

run: cargo build --features ${{ matrix.features }} --no-default-features

with current changes for example cargo build --features esplora --no-default-features will not build any binary, but the CI doesn't complain.

you can check that locally with

$ cargo clean
$ cargo build --features esplora --no-default-features
$ ./target/debug/bdk-cli wallet --help
bash: ./target/debug/bdk-cli: No such file or directory

I am not sure how then it's passing the tests without a binary.

@notmandatory

notmandatory commented Aug 6, 2021

Copy link
Copy Markdown
MemberAuthor

I think tests were passing because they only needed a lib build to run. But I agree it would be nice to not have to use the --no-default-features flag. I did the following to try and address this:

  1. split the repl feature into cli for the required dependencies to build the cli bin, and repl to enable the cli repl commands, then made the cli feature required to build the cli bin, but the cli and repl features on by default.
  2. added cfg statements so someone could build the cli without the repl command if they want fewer dependencies and use the --no-default-features flag
  3. update the CI to test with the default (no blockchain client) features, or each blockchain client, or the 'compiler' feature

@rajarshimaitrarajarshimaitra left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Code review ACK. This simplifies the issue.

I had the following observation. It seems if we compile the library using cargo build --features cli --no-default-features, that produces a binary that is perfectly workable with non backend wallet. It has functionality like this

$ ./target/debug/bdk-cli wallet --help
bdk-cli-wallet 0.2.1-dev
Wallet mode
USAGE:
bdk-cli wallet [FLAGS] [OPTIONS] --descriptor <DESCRIPTOR> <SUBCOMMAND>
FLAGS:
-v, --verbose Adds verbosity, returns PSBT in JSON format alongside serialized
-h, --help Prints help information
-V, --version Prints version information
OPTIONS:
-c, --change_descriptor <CHANGE_DESCRIPTOR> Sets the descriptor to use for internal addresses
-d, --descriptor <DESCRIPTOR> Sets the descriptor to use for the external addresses
-w, --wallet <WALLET_NAME> Selects the wallet to use [default: main]
SUBCOMMANDS:
bump_fee Bumps the fees of an RBF transaction
combine_psbt Combines multiple PSBTs into one
create_tx Creates a new unsigned transaction
extract_psbt Extracts a raw transaction from a PSBT
finalize_psbt Finalizes a PSBT
get_balance Returns the current wallet balance
get_new_address Generates a new external address
help Prints this message or the help of the given subcommand(s)
list_transactions Lists all the incoming and outgoing transactions of the wallet
list_unspent Lists the available spendable UTXOs
policies Returns the available spending policies for the descriptor
public_descriptor Returns the public version of the wallet's descriptor(s)
sign Signs and tries to finalize a PSBT

So that begs the question I had before, what do we need the repl thing for?

Also from here https://github.com/notmandatory/bdk-cli/blob/69b1d80bcd4715a3b78af4aafacebe2fc5ca2b88/src/bdk_cli.rs#L318-L331
it seems all a repl does is to perse existing commands and use them with either wallet or key functions. Maybe I am missing something, but I am not seeing any use of having the same methods called twice in different ways.

If two features cli and repl that does the same thing, it seems confusing to me.

Comment threadsrc/bdk_cli.rs Outdated
feature = "esplora",
any(feature = "electrum", feature = "compact_filters")
))]
compile_error!("Only one blockchain client feature can be enabled at a time.");

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It seems for every combination of electrum, esplora and compact_filters, this error is being duplicated with the one defined few lines below.

Instead, if we write it like this

#[cfg(all(
any( feature = "electrum", feature = "esplora", feature = "compact_filters"),
any( feature = "electrum", feature = "esplora", feature = "compact_filters")
))]

this will activate for any combination of the above three. And we won't need to specify compiler_error! multiple times.

Also for future extension, if we just add a new backend to the list above, that will taker care of multiple backend activation errors.

@notmandatorynotmandatoryAug 6, 2021

Copy link
Copy Markdown
MemberAuthor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Unfortunately the cfg all any any approach doesn't work, when I added this code:

#[cfg(all(any( feature = "electrum", feature = "esplora", feature = "compact_filters"),any( feature = "electrum", feature = "esplora", feature = "compact_filters")))]compile_error!("Only one blockchain client feature can be enabled at a time.");

I get the error even with only one blockchain client feature enabled (ie. cargo build --features esplora).

Looks like other's have had this same problem and are proposing a Rust RFC to allow a set of features to provide another feature in a mutually exclusive way.

Until mutually exclusive features are possible I can fix this in a simplistic way in the build.rs file as below or just leave it as it.. What do you think?

fnmain(){let electrum = env::var_os("CARGO_FEATURE_ELECTRUM").map(|_| "electrum".to_string());let esplora = env::var_os("CARGO_FEATURE_ESPLORA").map(|_| "esplora".to_string());let compact_filters = env::var_os("CARGO_FEATURE_COMPACT_FILTERS").map(|_| "compact_filters".to_string());let blockchain_features :Vec<String> = vec!(electrum, esplora, compact_filters).iter().map(|f| f.to_owned()).flatten().collect();if blockchain_features.len() > 1{panic!("At most one blockchain client feature can be enabled but these features were enabled: {:?}", blockchain_features)}}

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ah ok.. I thought it would work because my analyzer didn't throw. Yes there should be a way to handle mutually exclusive features in cargo itself.

I like the build script approach. It's clear and concise. Till it's available in cargo we can use a guard like above.

@rajarshimaitra

Copy link
Copy Markdown
Contributor

The following structure and function call could use feature guard. They exist in binary compiled without a backend, but are never used.

https://github.com/notmandatory/bdk-cli/blob/69b1d80bcd4715a3b78af4aafacebe2fc5ca2b88/src/lib.rs#L892

https://github.com/notmandatory/bdk-cli/blob/69b1d80bcd4715a3b78af4aafacebe2fc5ca2b88/src/lib.rs#L638

@notmandatory
notmandatoryforce-pushed the single_blockchain_feature branch from d3c0af3 to 9bb1c60CompareAugust 7, 2021 00:27

@rajarshimaitrarajarshimaitra left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

tACK 9bb1c60

With some minor nits.

Comment threadCHANGELOG.md Outdated
Comment threadCargo.toml
name = "bdk-cli"
path = "src/bdk_cli.rs"
required-features = ["repl", "electrum"]
required-features = ["cli"]

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is this required-features value necessary? By putting cli in default we are ensuring that the build will always include cli. (we also removed any necessity of using --no-default-features).

Copy link
Copy Markdown
MemberAuthor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think we still need cli as required to force anyone building the bin without repl (using --no-default-features) to still include cli.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ya makes sense.

Comment threadREADME.md Outdated
Comment threadREADME.md

```shell
cargo run -- wallet --descriptor "wpkh(tpubEBr4i6yk5nf5DAaJpsi9N2pPYBeJ7fZ5Z9rmN4977iYLCGco1VyjB9tvvuvYtfZzjD5A8igzgw3HeWeeKFmanHYqksqZXYXGsw5zjnj7KM9/*)" sync
cargo run --features electrum -- wallet --descriptor "wpkh(tpubEBr4i6yk5nf5DAaJpsi9N2pPYBeJ7fZ5Z9rmN4977iYLCGco1VyjB9tvvuvYtfZzjD5A8igzgw3HeWeeKFmanHYqksqZXYXGsw5zjnj7KM9/*)" sync

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Few lines ago we mentioned how to install bdk-cli with cargo.

Instructing to use cargo run here will build the local files instead of using the installed binary. So if someone is in their cloned repo, using cargo run they will actually build and then run the master branch instead of the release binary he just installed (this might be an unexpected behavior for the user, unless he knows cargo stuffs).

Even worse if someone didn't clone the repo, cargo run will not run anything, even if they have bdk-cli binary installed (and we don't have that instruction anywhere).

I think in the "bdk-cli bin usage examples" section, we should just instruct to use bdk-cli binary instead of crago run, which will make the instruction simpler also.

This doesn't have to be fixed here. Just mentioned as it occurred to me.

Copy link
Copy Markdown
MemberAuthor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I agree we should probably update the README to focus on installing with different features, and then usage with an installed version instead of using cargo run since anyone making local changes should already know how to use cargo. But let's do that cleanup in a different PR.

Comment threadsrc/lib.rs
@rajarshimaitra

Copy link
Copy Markdown
Contributor

ACK 062542a

@notmandatory
notmandatoryforce-pushed the single_blockchain_feature branch from 062542a to 7c4f5e7CompareAugust 12, 2021 14:13

@rajarshimaitrarajarshimaitra left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Code review with testing ACK 4fd39b7

@notmandatory
notmandatory merged commit 4fd39b7 into bitcoindevkit:masterAug 13, 2021
@notmandatory

Copy link
Copy Markdown
MemberAuthor

Thanks for the suggestions and review on this @rajarshimaitra, all ready to rebase your #36 PR.

Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants

@notmandatory@rajarshimaitra
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Force GitHub README to respect dark mode\n(function() {\n var style = document.createElement('style');\n style.textContent = '\n .markdown-body {\n color-scheme: dark light;\n }\n .markdown-body pre { background: #161b22 !important; }\n .markdown-body code { background: rgba(110, 118, 129, 0.4) !important; }\n .markdown-body table th, .markdown-body table td { border-color: #30363d !important; }\n .markdown-body img { background: #0d1117; }\n .markdown-body blockquote { border-left-color: #8b949e; }\n .markdown-body hr { border-color: #30363d; }\n ';\n document.head.appendChild(style);\n})();", "GitHub Dark Mode README Fix"); } } catch(__e) { console.warn('[Userscript:GitHub Dark Mode README Fix]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content

Allow enabling at most one blockchain client feature - #38

Merged
notmandatory merged 10 commits into
bitcoindevkit:masterfrom
notmandatory:single_blockchain_feature
Aug 13, 2021
Merged

Allow enabling at most one blockchain client feature#38
notmandatory merged 10 commits into
bitcoindevkit:masterfrom
notmandatory:single_blockchain_feature

Conversation

@notmandatory

@notmandatorynotmandatory commented Aug 5, 2021

Copy link
Copy Markdown
Member

Description

Allow at most one blockchain client feature be enabled at a time for builds. If no blockchain client feature is enabled then online wallet commands are disabled. This will simplify the options shown to the user and make adding new blockchain clients (such as #36) easier. Electrum is still the default, to make a build with a different blockchain client the --no-default-features build option will need to be used. No blockchain client is included in the default features, so if one is needed it must be specified with --features. I also added a default esplora server url so the user doesn't need to specify one if selecting that client, which is how the electrum and compact_filters clients work.

Notes to the reviewers

I changed the server option for both electrum and esplora to --server or -s since that now won't cause a conflict. I also simplified the CHANGELOG to focus on what a user would see as a change while using the bin.

I've also added a build.rs file to prevent more than one blockchain client feature from being enabled.

Checklists

All Submissions:

  • I've signed all my commits
  • I followed the contribution guidelines
  • I ran cargo fmt and cargo clippy before committing

New Features:

  • I've added tests for the new feature
  • I've added docs for the new feature
  • I've updated CHANGELOG.md

Bugfixes:

  • This pull request breaks the existing API
  • I've added tests to reproduce the issue which are now passing
  • I'm linking the issue being fixed by this PR

@notmandatory
notmandatoryforce-pushed the single_blockchain_feature branch 4 times, most recently from 65729b9 to 47e0962CompareAugust 5, 2021 06:15
@notmandatorynotmandatory changed the title Single blockchain featureOnly allow enabling at most one blockchain client featureAug 5, 2021
@notmandatorynotmandatory changed the title Only allow enabling at most one blockchain client featureAllow enabling at most one blockchain client featureAug 5, 2021
@notmandatory
notmandatoryforce-pushed the single_blockchain_feature branch 2 times, most recently from f9cd936 to c81a99eCompareAugust 5, 2021 06:42
@notmandatory
notmandatory marked this pull request as ready for review August 5, 2021 06:43

@rajarshimaitrarajarshimaitra left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks @notmandatory for the PR, we are close almost. I just have a few more comments.

Is there any specific use of Repl mode here?

bdk-cli/src/lib.rs

Lines 258 to 262 in 378b33a

#[structopt(long_about = "REPL command loop mode")]
Repl{
#[structopt(flatten)]
wallet_opts:WalletOpts,
},

It just seems to be duplicating WalletOpts and no commands. If not we can remove this, it seems redundant.

One problem here is using --no-default-features will turn off repl too, which is required dep for the binary, so it will not compile any binary. This has been the crux of the problem because cargo doesn't let us selectively disable features. So if we disable default, it disables everything in default.

I think the only way to solve this problem is by having a very minimal default with only the stuffs that we need to create the minimal possible binary. And then add stuff to it with features flag. This will also remove the use of --no-default-feature if we only want esplora but not electrum.

So I propose something like this:

[features]
default = ["repl"]
repl = ["bdk/key-value-db", "clap", "dirs-next", "env_logger", "regex", "rustyline"]
electrum = ["bdk/electrum"]
esplora = ["bdk/esplora"]
compiler = ["bdk/compiler"]
async-interface = ["bdk/async-interface"]
compact_filters = ["bdk/compact_filters"]
[[bin]]
name = "bdk-cli"
path = "src/bdk_cli.rs"
required-features = ["repl"]

This will create the following builds

cargo build : build only repl stuffs, no backend
cargo build --features [backend] : build repl + [backend] blockchain.

I don't think there's any adverse effect of not having a blockchain by default. the only method we have with blockchain is sync and broadcast, everything else can be done without a blockchain. So it's safe to remove it in default.

@rajarshimaitra

rajarshimaitra commented Aug 5, 2021

Copy link
Copy Markdown
Contributor

Also, I am not sure if we should silently ignore "no binary built" scenarios in CI.

run: cargo build --features ${{ matrix.features }} --no-default-features

with current changes for example cargo build --features esplora --no-default-features will not build any binary, but the CI doesn't complain.

you can check that locally with

$ cargo clean
$ cargo build --features esplora --no-default-features
$ ./target/debug/bdk-cli wallet --help
bash: ./target/debug/bdk-cli: No such file or directory

I am not sure how then it's passing the tests without a binary.

@notmandatory

notmandatory commented Aug 6, 2021

Copy link
Copy Markdown
MemberAuthor

I think tests were passing because they only needed a lib build to run. But I agree it would be nice to not have to use the --no-default-features flag. I did the following to try and address this:

  1. split the repl feature into cli for the required dependencies to build the cli bin, and repl to enable the cli repl commands, then made the cli feature required to build the cli bin, but the cli and repl features on by default.
  2. added cfg statements so someone could build the cli without the repl command if they want fewer dependencies and use the --no-default-features flag
  3. update the CI to test with the default (no blockchain client) features, or each blockchain client, or the 'compiler' feature

@rajarshimaitrarajarshimaitra left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Code review ACK. This simplifies the issue.

I had the following observation. It seems if we compile the library using cargo build --features cli --no-default-features, that produces a binary that is perfectly workable with non backend wallet. It has functionality like this

$ ./target/debug/bdk-cli wallet --help
bdk-cli-wallet 0.2.1-dev
Wallet mode
USAGE:
bdk-cli wallet [FLAGS] [OPTIONS] --descriptor <DESCRIPTOR> <SUBCOMMAND>
FLAGS:
-v, --verbose Adds verbosity, returns PSBT in JSON format alongside serialized
-h, --help Prints help information
-V, --version Prints version information
OPTIONS:
-c, --change_descriptor <CHANGE_DESCRIPTOR> Sets the descriptor to use for internal addresses
-d, --descriptor <DESCRIPTOR> Sets the descriptor to use for the external addresses
-w, --wallet <WALLET_NAME> Selects the wallet to use [default: main]
SUBCOMMANDS:
bump_fee Bumps the fees of an RBF transaction
combine_psbt Combines multiple PSBTs into one
create_tx Creates a new unsigned transaction
extract_psbt Extracts a raw transaction from a PSBT
finalize_psbt Finalizes a PSBT
get_balance Returns the current wallet balance
get_new_address Generates a new external address
help Prints this message or the help of the given subcommand(s)
list_transactions Lists all the incoming and outgoing transactions of the wallet
list_unspent Lists the available spendable UTXOs
policies Returns the available spending policies for the descriptor
public_descriptor Returns the public version of the wallet's descriptor(s)
sign Signs and tries to finalize a PSBT

So that begs the question I had before, what do we need the repl thing for?

Also from here https://github.com/notmandatory/bdk-cli/blob/69b1d80bcd4715a3b78af4aafacebe2fc5ca2b88/src/bdk_cli.rs#L318-L331
it seems all a repl does is to perse existing commands and use them with either wallet or key functions. Maybe I am missing something, but I am not seeing any use of having the same methods called twice in different ways.

If two features cli and repl that does the same thing, it seems confusing to me.

Comment threadsrc/bdk_cli.rs Outdated
feature = "esplora",
any(feature = "electrum", feature = "compact_filters")
))]
compile_error!("Only one blockchain client feature can be enabled at a time.");

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It seems for every combination of electrum, esplora and compact_filters, this error is being duplicated with the one defined few lines below.

Instead, if we write it like this

#[cfg(all(
any( feature = "electrum", feature = "esplora", feature = "compact_filters"),
any( feature = "electrum", feature = "esplora", feature = "compact_filters")
))]

this will activate for any combination of the above three. And we won't need to specify compiler_error! multiple times.

Also for future extension, if we just add a new backend to the list above, that will taker care of multiple backend activation errors.

@notmandatorynotmandatoryAug 6, 2021

Copy link
Copy Markdown
MemberAuthor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Unfortunately the cfg all any any approach doesn't work, when I added this code:

#[cfg(all(any( feature = "electrum", feature = "esplora", feature = "compact_filters"),any( feature = "electrum", feature = "esplora", feature = "compact_filters")))]compile_error!("Only one blockchain client feature can be enabled at a time.");

I get the error even with only one blockchain client feature enabled (ie. cargo build --features esplora).

Looks like other's have had this same problem and are proposing a Rust RFC to allow a set of features to provide another feature in a mutually exclusive way.

Until mutually exclusive features are possible I can fix this in a simplistic way in the build.rs file as below or just leave it as it.. What do you think?

fnmain(){let electrum = env::var_os("CARGO_FEATURE_ELECTRUM").map(|_| "electrum".to_string());let esplora = env::var_os("CARGO_FEATURE_ESPLORA").map(|_| "esplora".to_string());let compact_filters = env::var_os("CARGO_FEATURE_COMPACT_FILTERS").map(|_| "compact_filters".to_string());let blockchain_features :Vec<String> = vec!(electrum, esplora, compact_filters).iter().map(|f| f.to_owned()).flatten().collect();if blockchain_features.len() > 1{panic!("At most one blockchain client feature can be enabled but these features were enabled: {:?}", blockchain_features)}}

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ah ok.. I thought it would work because my analyzer didn't throw. Yes there should be a way to handle mutually exclusive features in cargo itself.

I like the build script approach. It's clear and concise. Till it's available in cargo we can use a guard like above.

@rajarshimaitra

Copy link
Copy Markdown
Contributor

The following structure and function call could use feature guard. They exist in binary compiled without a backend, but are never used.

https://github.com/notmandatory/bdk-cli/blob/69b1d80bcd4715a3b78af4aafacebe2fc5ca2b88/src/lib.rs#L892

https://github.com/notmandatory/bdk-cli/blob/69b1d80bcd4715a3b78af4aafacebe2fc5ca2b88/src/lib.rs#L638

@notmandatory
notmandatoryforce-pushed the single_blockchain_feature branch from d3c0af3 to 9bb1c60CompareAugust 7, 2021 00:27

@rajarshimaitrarajarshimaitra left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

tACK 9bb1c60

With some minor nits.

Comment threadCHANGELOG.md Outdated
Comment threadCargo.toml
name = "bdk-cli"
path = "src/bdk_cli.rs"
required-features = ["repl", "electrum"]
required-features = ["cli"]

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is this required-features value necessary? By putting cli in default we are ensuring that the build will always include cli. (we also removed any necessity of using --no-default-features).

Copy link
Copy Markdown
MemberAuthor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think we still need cli as required to force anyone building the bin without repl (using --no-default-features) to still include cli.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ya makes sense.

Comment threadREADME.md Outdated
Comment threadREADME.md

```shell
cargo run -- wallet --descriptor "wpkh(tpubEBr4i6yk5nf5DAaJpsi9N2pPYBeJ7fZ5Z9rmN4977iYLCGco1VyjB9tvvuvYtfZzjD5A8igzgw3HeWeeKFmanHYqksqZXYXGsw5zjnj7KM9/*)" sync
cargo run --features electrum -- wallet --descriptor "wpkh(tpubEBr4i6yk5nf5DAaJpsi9N2pPYBeJ7fZ5Z9rmN4977iYLCGco1VyjB9tvvuvYtfZzjD5A8igzgw3HeWeeKFmanHYqksqZXYXGsw5zjnj7KM9/*)" sync

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Few lines ago we mentioned how to install bdk-cli with cargo.

Instructing to use cargo run here will build the local files instead of using the installed binary. So if someone is in their cloned repo, using cargo run they will actually build and then run the master branch instead of the release binary he just installed (this might be an unexpected behavior for the user, unless he knows cargo stuffs).

Even worse if someone didn't clone the repo, cargo run will not run anything, even if they have bdk-cli binary installed (and we don't have that instruction anywhere).

I think in the "bdk-cli bin usage examples" section, we should just instruct to use bdk-cli binary instead of crago run, which will make the instruction simpler also.

This doesn't have to be fixed here. Just mentioned as it occurred to me.

Copy link
Copy Markdown
MemberAuthor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I agree we should probably update the README to focus on installing with different features, and then usage with an installed version instead of using cargo run since anyone making local changes should already know how to use cargo. But let's do that cleanup in a different PR.

Comment threadsrc/lib.rs
@rajarshimaitra

Copy link
Copy Markdown
Contributor

ACK 062542a

@notmandatory
notmandatoryforce-pushed the single_blockchain_feature branch from 062542a to 7c4f5e7CompareAugust 12, 2021 14:13

@rajarshimaitrarajarshimaitra left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Code review with testing ACK 4fd39b7

@notmandatory
notmandatory merged commit 4fd39b7 into bitcoindevkit:masterAug 13, 2021
@notmandatory

Copy link
Copy Markdown
MemberAuthor

Thanks for the suggestions and review on this @rajarshimaitra, all ready to rebase your #36 PR.

Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants

@notmandatory@rajarshimaitra
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Highlight search terms from Google/DuckDuckGo/Bing referrer\n(function() {\n var ref = document.referrer;\n var terms = [];\n \n if (ref.includes('google.com') || ref.includes('duckduckgo.com') || ref.includes('bing.com')) {\n var url = new URL(ref);\n var q = url.searchParams.get('q') || url.searchParams.get('p');\n if (q) {\n terms = q.split(/\\s+/).filter(function(t) { return t.length > 2; });\n }\n }\n \n if (terms.length === 0) return;\n \n var style = document.createElement('style');\n style.textContent = '.userscript-highlight { background: #fbbf24; color: #1a1a2e; padding: 1px 3px; border-radius: 2px; }';\n document.head.appendChild(style);\n \n function highlight(node) {\n if (node.nodeType === 3) { // text node\n var text = node.textContent;\n var found = false;\n terms.forEach(function(term) {\n var regex = new RegExp('(' + term.replace(/[.*+?^${}()|[\\]\\\\]/g, '\\\\') + ')', 'gi');\n if (regex.test(text)) {\n found = true;\n var frag = document.createDocumentFragment();\n var parts = text.split(regex);\n parts.forEach(function(part, i) {\n if (i % 2 === 0) {\n frag.appendChild(document.createTextNode(part));\n } else {\n var span = document.createElement('span');\n span.className = 'userscript-highlight';\n span.textContent = part;\n frag.appendChild(span);\n }\n });\n node.parentNode.replaceChild(frag, node);\n }\n });\n } else if (node.nodeType === 1 && node.childNodes) { // element\n var skipTags = ['SCRIPT', 'STYLE', 'NOSCRIPT', 'TEXTAREA', 'INPUT', 'SELECT'];\n if (!skipTags.includes(node.tagName)) {\n Array.from(node.childNodes).forEach(highlight);\n }\n }\n }\n \n highlight(document.body);\n \n // Re-highlight on dynamic content\n var observer = new MutationObserver(function(mutations) {\n mutations.forEach(function(m) {\n m.addedNodes.forEach(function(node) {\n if (node.nodeType === 1 || node.nodeType === 3) highlight(node);\n });\n });\n });\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "Highlight Search Terms"); } } catch(__e) { console.warn('[Userscript:Highlight Search Terms]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content

Allow enabling at most one blockchain client feature - #38

Merged
notmandatory merged 10 commits into
bitcoindevkit:masterfrom
notmandatory:single_blockchain_feature
Aug 13, 2021
Merged

Allow enabling at most one blockchain client feature#38
notmandatory merged 10 commits into
bitcoindevkit:masterfrom
notmandatory:single_blockchain_feature

Conversation

@notmandatory

@notmandatorynotmandatory commented Aug 5, 2021

Copy link
Copy Markdown
Member

Description

Allow at most one blockchain client feature be enabled at a time for builds. If no blockchain client feature is enabled then online wallet commands are disabled. This will simplify the options shown to the user and make adding new blockchain clients (such as #36) easier. Electrum is still the default, to make a build with a different blockchain client the --no-default-features build option will need to be used. No blockchain client is included in the default features, so if one is needed it must be specified with --features. I also added a default esplora server url so the user doesn't need to specify one if selecting that client, which is how the electrum and compact_filters clients work.

Notes to the reviewers

I changed the server option for both electrum and esplora to --server or -s since that now won't cause a conflict. I also simplified the CHANGELOG to focus on what a user would see as a change while using the bin.

I've also added a build.rs file to prevent more than one blockchain client feature from being enabled.

Checklists

All Submissions:

  • I've signed all my commits
  • I followed the contribution guidelines
  • I ran cargo fmt and cargo clippy before committing

New Features:

  • I've added tests for the new feature
  • I've added docs for the new feature
  • I've updated CHANGELOG.md

Bugfixes:

  • This pull request breaks the existing API
  • I've added tests to reproduce the issue which are now passing
  • I'm linking the issue being fixed by this PR

@notmandatory
notmandatoryforce-pushed the single_blockchain_feature branch 4 times, most recently from 65729b9 to 47e0962CompareAugust 5, 2021 06:15
@notmandatorynotmandatory changed the title Single blockchain featureOnly allow enabling at most one blockchain client featureAug 5, 2021
@notmandatorynotmandatory changed the title Only allow enabling at most one blockchain client featureAllow enabling at most one blockchain client featureAug 5, 2021
@notmandatory
notmandatoryforce-pushed the single_blockchain_feature branch 2 times, most recently from f9cd936 to c81a99eCompareAugust 5, 2021 06:42
@notmandatory
notmandatory marked this pull request as ready for review August 5, 2021 06:43

@rajarshimaitrarajarshimaitra left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks @notmandatory for the PR, we are close almost. I just have a few more comments.

Is there any specific use of Repl mode here?

bdk-cli/src/lib.rs

Lines 258 to 262 in 378b33a

#[structopt(long_about = "REPL command loop mode")]
Repl{
#[structopt(flatten)]
wallet_opts:WalletOpts,
},

It just seems to be duplicating WalletOpts and no commands. If not we can remove this, it seems redundant.

One problem here is using --no-default-features will turn off repl too, which is required dep for the binary, so it will not compile any binary. This has been the crux of the problem because cargo doesn't let us selectively disable features. So if we disable default, it disables everything in default.

I think the only way to solve this problem is by having a very minimal default with only the stuffs that we need to create the minimal possible binary. And then add stuff to it with features flag. This will also remove the use of --no-default-feature if we only want esplora but not electrum.

So I propose something like this:

[features]
default = ["repl"]
repl = ["bdk/key-value-db", "clap", "dirs-next", "env_logger", "regex", "rustyline"]
electrum = ["bdk/electrum"]
esplora = ["bdk/esplora"]
compiler = ["bdk/compiler"]
async-interface = ["bdk/async-interface"]
compact_filters = ["bdk/compact_filters"]
[[bin]]
name = "bdk-cli"
path = "src/bdk_cli.rs"
required-features = ["repl"]

This will create the following builds

cargo build : build only repl stuffs, no backend
cargo build --features [backend] : build repl + [backend] blockchain.

I don't think there's any adverse effect of not having a blockchain by default. the only method we have with blockchain is sync and broadcast, everything else can be done without a blockchain. So it's safe to remove it in default.

@rajarshimaitra

rajarshimaitra commented Aug 5, 2021

Copy link
Copy Markdown
Contributor

Also, I am not sure if we should silently ignore "no binary built" scenarios in CI.

run: cargo build --features ${{ matrix.features }} --no-default-features

with current changes for example cargo build --features esplora --no-default-features will not build any binary, but the CI doesn't complain.

you can check that locally with

$ cargo clean
$ cargo build --features esplora --no-default-features
$ ./target/debug/bdk-cli wallet --help
bash: ./target/debug/bdk-cli: No such file or directory

I am not sure how then it's passing the tests without a binary.

@notmandatory

notmandatory commented Aug 6, 2021

Copy link
Copy Markdown
MemberAuthor

I think tests were passing because they only needed a lib build to run. But I agree it would be nice to not have to use the --no-default-features flag. I did the following to try and address this:

  1. split the repl feature into cli for the required dependencies to build the cli bin, and repl to enable the cli repl commands, then made the cli feature required to build the cli bin, but the cli and repl features on by default.
  2. added cfg statements so someone could build the cli without the repl command if they want fewer dependencies and use the --no-default-features flag
  3. update the CI to test with the default (no blockchain client) features, or each blockchain client, or the 'compiler' feature

@rajarshimaitrarajarshimaitra left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Code review ACK. This simplifies the issue.

I had the following observation. It seems if we compile the library using cargo build --features cli --no-default-features, that produces a binary that is perfectly workable with non backend wallet. It has functionality like this

$ ./target/debug/bdk-cli wallet --help
bdk-cli-wallet 0.2.1-dev
Wallet mode
USAGE:
bdk-cli wallet [FLAGS] [OPTIONS] --descriptor <DESCRIPTOR> <SUBCOMMAND>
FLAGS:
-v, --verbose Adds verbosity, returns PSBT in JSON format alongside serialized
-h, --help Prints help information
-V, --version Prints version information
OPTIONS:
-c, --change_descriptor <CHANGE_DESCRIPTOR> Sets the descriptor to use for internal addresses
-d, --descriptor <DESCRIPTOR> Sets the descriptor to use for the external addresses
-w, --wallet <WALLET_NAME> Selects the wallet to use [default: main]
SUBCOMMANDS:
bump_fee Bumps the fees of an RBF transaction
combine_psbt Combines multiple PSBTs into one
create_tx Creates a new unsigned transaction
extract_psbt Extracts a raw transaction from a PSBT
finalize_psbt Finalizes a PSBT
get_balance Returns the current wallet balance
get_new_address Generates a new external address
help Prints this message or the help of the given subcommand(s)
list_transactions Lists all the incoming and outgoing transactions of the wallet
list_unspent Lists the available spendable UTXOs
policies Returns the available spending policies for the descriptor
public_descriptor Returns the public version of the wallet's descriptor(s)
sign Signs and tries to finalize a PSBT

So that begs the question I had before, what do we need the repl thing for?

Also from here https://github.com/notmandatory/bdk-cli/blob/69b1d80bcd4715a3b78af4aafacebe2fc5ca2b88/src/bdk_cli.rs#L318-L331
it seems all a repl does is to perse existing commands and use them with either wallet or key functions. Maybe I am missing something, but I am not seeing any use of having the same methods called twice in different ways.

If two features cli and repl that does the same thing, it seems confusing to me.

Comment threadsrc/bdk_cli.rs Outdated
feature = "esplora",
any(feature = "electrum", feature = "compact_filters")
))]
compile_error!("Only one blockchain client feature can be enabled at a time.");

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It seems for every combination of electrum, esplora and compact_filters, this error is being duplicated with the one defined few lines below.

Instead, if we write it like this

#[cfg(all(
any( feature = "electrum", feature = "esplora", feature = "compact_filters"),
any( feature = "electrum", feature = "esplora", feature = "compact_filters")
))]

this will activate for any combination of the above three. And we won't need to specify compiler_error! multiple times.

Also for future extension, if we just add a new backend to the list above, that will taker care of multiple backend activation errors.

@notmandatorynotmandatoryAug 6, 2021

Copy link
Copy Markdown
MemberAuthor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Unfortunately the cfg all any any approach doesn't work, when I added this code:

#[cfg(all(any( feature = "electrum", feature = "esplora", feature = "compact_filters"),any( feature = "electrum", feature = "esplora", feature = "compact_filters")))]compile_error!("Only one blockchain client feature can be enabled at a time.");

I get the error even with only one blockchain client feature enabled (ie. cargo build --features esplora).

Looks like other's have had this same problem and are proposing a Rust RFC to allow a set of features to provide another feature in a mutually exclusive way.

Until mutually exclusive features are possible I can fix this in a simplistic way in the build.rs file as below or just leave it as it.. What do you think?

fnmain(){let electrum = env::var_os("CARGO_FEATURE_ELECTRUM").map(|_| "electrum".to_string());let esplora = env::var_os("CARGO_FEATURE_ESPLORA").map(|_| "esplora".to_string());let compact_filters = env::var_os("CARGO_FEATURE_COMPACT_FILTERS").map(|_| "compact_filters".to_string());let blockchain_features :Vec<String> = vec!(electrum, esplora, compact_filters).iter().map(|f| f.to_owned()).flatten().collect();if blockchain_features.len() > 1{panic!("At most one blockchain client feature can be enabled but these features were enabled: {:?}", blockchain_features)}}

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ah ok.. I thought it would work because my analyzer didn't throw. Yes there should be a way to handle mutually exclusive features in cargo itself.

I like the build script approach. It's clear and concise. Till it's available in cargo we can use a guard like above.

@rajarshimaitra

Copy link
Copy Markdown
Contributor

The following structure and function call could use feature guard. They exist in binary compiled without a backend, but are never used.

https://github.com/notmandatory/bdk-cli/blob/69b1d80bcd4715a3b78af4aafacebe2fc5ca2b88/src/lib.rs#L892

https://github.com/notmandatory/bdk-cli/blob/69b1d80bcd4715a3b78af4aafacebe2fc5ca2b88/src/lib.rs#L638

@notmandatory
notmandatoryforce-pushed the single_blockchain_feature branch from d3c0af3 to 9bb1c60CompareAugust 7, 2021 00:27

@rajarshimaitrarajarshimaitra left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

tACK 9bb1c60

With some minor nits.

Comment threadCHANGELOG.md Outdated
Comment threadCargo.toml
name = "bdk-cli"
path = "src/bdk_cli.rs"
required-features = ["repl", "electrum"]
required-features = ["cli"]

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is this required-features value necessary? By putting cli in default we are ensuring that the build will always include cli. (we also removed any necessity of using --no-default-features).

Copy link
Copy Markdown
MemberAuthor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think we still need cli as required to force anyone building the bin without repl (using --no-default-features) to still include cli.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ya makes sense.

Comment threadREADME.md Outdated
Comment threadREADME.md

```shell
cargo run -- wallet --descriptor "wpkh(tpubEBr4i6yk5nf5DAaJpsi9N2pPYBeJ7fZ5Z9rmN4977iYLCGco1VyjB9tvvuvYtfZzjD5A8igzgw3HeWeeKFmanHYqksqZXYXGsw5zjnj7KM9/*)" sync
cargo run --features electrum -- wallet --descriptor "wpkh(tpubEBr4i6yk5nf5DAaJpsi9N2pPYBeJ7fZ5Z9rmN4977iYLCGco1VyjB9tvvuvYtfZzjD5A8igzgw3HeWeeKFmanHYqksqZXYXGsw5zjnj7KM9/*)" sync

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Few lines ago we mentioned how to install bdk-cli with cargo.

Instructing to use cargo run here will build the local files instead of using the installed binary. So if someone is in their cloned repo, using cargo run they will actually build and then run the master branch instead of the release binary he just installed (this might be an unexpected behavior for the user, unless he knows cargo stuffs).

Even worse if someone didn't clone the repo, cargo run will not run anything, even if they have bdk-cli binary installed (and we don't have that instruction anywhere).

I think in the "bdk-cli bin usage examples" section, we should just instruct to use bdk-cli binary instead of crago run, which will make the instruction simpler also.

This doesn't have to be fixed here. Just mentioned as it occurred to me.

Copy link
Copy Markdown
MemberAuthor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I agree we should probably update the README to focus on installing with different features, and then usage with an installed version instead of using cargo run since anyone making local changes should already know how to use cargo. But let's do that cleanup in a different PR.

Comment threadsrc/lib.rs
@rajarshimaitra

Copy link
Copy Markdown
Contributor

ACK 062542a

@notmandatory
notmandatoryforce-pushed the single_blockchain_feature branch from 062542a to 7c4f5e7CompareAugust 12, 2021 14:13

@rajarshimaitrarajarshimaitra left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Code review with testing ACK 4fd39b7

@notmandatory
notmandatory merged commit 4fd39b7 into bitcoindevkit:masterAug 13, 2021
@notmandatory

Copy link
Copy Markdown
MemberAuthor

Thanks for the suggestions and review on this @rajarshimaitra, all ready to rebase your #36 PR.

Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants

@notmandatory@rajarshimaitra
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Strip utm_, fbclid, gclid, etc. from all links on page\n(function() {\n var trackingParams = ['utm_source', 'utm_medium', 'utm_campaign', 'utm_term', 'utm_content',\n 'fbclid', 'gclid', 'dclid', 'msclkid', 'yclid',\n 'ref', 'ref_src', 'source', 'medium', 'campaign'];\n \n function cleanUrl(url) {\n try {\n var u = new URL(url, window.location.origin);\n var changed = false;\n trackingParams.forEach(function(p) {\n if (u.searchParams.has(p)) {\n u.searchParams.delete(p);\n changed = true;\n }\n });\n return changed ? u.toString() : url;\n } catch (e) {\n return url;\n }\n }\n \n function cleanLinks() {\n document.querySelectorAll('a[href]').forEach(function(a) {\n var clean = cleanUrl(a.href);\n if (clean !== a.href) a.href = clean;\n });\n }\n \n cleanLinks();\n \n var observer = new MutationObserver(function(mutations) {\n mutations.forEach(function(m) {\n m.addedNodes.forEach(function(node) {\n if (node.nodeType === 1) {\n if (node.tagName === 'A') cleanLinks();\n node.querySelectorAll('a[href]').forEach(function(a) {\n var clean = cleanUrl(a.href);\n if (clean !== a.href) a.href = clean;\n });\n }\n });\n });\n });\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "Remove Tracking Parameters from Links"); } } catch(__e) { console.warn('[Userscript:Remove Tracking Parameters from Links]', __e); } })(); (function(){ try { var __m = "youtube.com"; var __re = new RegExp('^' + "youtube\\.com" + '
Skip to content

Allow enabling at most one blockchain client feature - #38

Merged
notmandatory merged 10 commits into
bitcoindevkit:masterfrom
notmandatory:single_blockchain_feature
Aug 13, 2021
Merged

Allow enabling at most one blockchain client feature#38
notmandatory merged 10 commits into
bitcoindevkit:masterfrom
notmandatory:single_blockchain_feature

Conversation

@notmandatory

@notmandatorynotmandatory commented Aug 5, 2021

Copy link
Copy Markdown
Member

Description

Allow at most one blockchain client feature be enabled at a time for builds. If no blockchain client feature is enabled then online wallet commands are disabled. This will simplify the options shown to the user and make adding new blockchain clients (such as #36) easier. Electrum is still the default, to make a build with a different blockchain client the --no-default-features build option will need to be used. No blockchain client is included in the default features, so if one is needed it must be specified with --features. I also added a default esplora server url so the user doesn't need to specify one if selecting that client, which is how the electrum and compact_filters clients work.

Notes to the reviewers

I changed the server option for both electrum and esplora to --server or -s since that now won't cause a conflict. I also simplified the CHANGELOG to focus on what a user would see as a change while using the bin.

I've also added a build.rs file to prevent more than one blockchain client feature from being enabled.

Checklists

All Submissions:

  • I've signed all my commits
  • I followed the contribution guidelines
  • I ran cargo fmt and cargo clippy before committing

New Features:

  • I've added tests for the new feature
  • I've added docs for the new feature
  • I've updated CHANGELOG.md

Bugfixes:

  • This pull request breaks the existing API
  • I've added tests to reproduce the issue which are now passing
  • I'm linking the issue being fixed by this PR

@notmandatory
notmandatoryforce-pushed the single_blockchain_feature branch 4 times, most recently from 65729b9 to 47e0962CompareAugust 5, 2021 06:15
@notmandatorynotmandatory changed the title Single blockchain featureOnly allow enabling at most one blockchain client featureAug 5, 2021
@notmandatorynotmandatory changed the title Only allow enabling at most one blockchain client featureAllow enabling at most one blockchain client featureAug 5, 2021
@notmandatory
notmandatoryforce-pushed the single_blockchain_feature branch 2 times, most recently from f9cd936 to c81a99eCompareAugust 5, 2021 06:42
@notmandatory
notmandatory marked this pull request as ready for review August 5, 2021 06:43

@rajarshimaitrarajarshimaitra left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks @notmandatory for the PR, we are close almost. I just have a few more comments.

Is there any specific use of Repl mode here?

bdk-cli/src/lib.rs

Lines 258 to 262 in 378b33a

#[structopt(long_about = "REPL command loop mode")]
Repl{
#[structopt(flatten)]
wallet_opts:WalletOpts,
},

It just seems to be duplicating WalletOpts and no commands. If not we can remove this, it seems redundant.

One problem here is using --no-default-features will turn off repl too, which is required dep for the binary, so it will not compile any binary. This has been the crux of the problem because cargo doesn't let us selectively disable features. So if we disable default, it disables everything in default.

I think the only way to solve this problem is by having a very minimal default with only the stuffs that we need to create the minimal possible binary. And then add stuff to it with features flag. This will also remove the use of --no-default-feature if we only want esplora but not electrum.

So I propose something like this:

[features]
default = ["repl"]
repl = ["bdk/key-value-db", "clap", "dirs-next", "env_logger", "regex", "rustyline"]
electrum = ["bdk/electrum"]
esplora = ["bdk/esplora"]
compiler = ["bdk/compiler"]
async-interface = ["bdk/async-interface"]
compact_filters = ["bdk/compact_filters"]
[[bin]]
name = "bdk-cli"
path = "src/bdk_cli.rs"
required-features = ["repl"]

This will create the following builds

cargo build : build only repl stuffs, no backend
cargo build --features [backend] : build repl + [backend] blockchain.

I don't think there's any adverse effect of not having a blockchain by default. the only method we have with blockchain is sync and broadcast, everything else can be done without a blockchain. So it's safe to remove it in default.

@rajarshimaitra

rajarshimaitra commented Aug 5, 2021

Copy link
Copy Markdown
Contributor

Also, I am not sure if we should silently ignore "no binary built" scenarios in CI.

run: cargo build --features ${{ matrix.features }} --no-default-features

with current changes for example cargo build --features esplora --no-default-features will not build any binary, but the CI doesn't complain.

you can check that locally with

$ cargo clean
$ cargo build --features esplora --no-default-features
$ ./target/debug/bdk-cli wallet --help
bash: ./target/debug/bdk-cli: No such file or directory

I am not sure how then it's passing the tests without a binary.

@notmandatory

notmandatory commented Aug 6, 2021

Copy link
Copy Markdown
MemberAuthor

I think tests were passing because they only needed a lib build to run. But I agree it would be nice to not have to use the --no-default-features flag. I did the following to try and address this:

  1. split the repl feature into cli for the required dependencies to build the cli bin, and repl to enable the cli repl commands, then made the cli feature required to build the cli bin, but the cli and repl features on by default.
  2. added cfg statements so someone could build the cli without the repl command if they want fewer dependencies and use the --no-default-features flag
  3. update the CI to test with the default (no blockchain client) features, or each blockchain client, or the 'compiler' feature

@rajarshimaitrarajarshimaitra left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Code review ACK. This simplifies the issue.

I had the following observation. It seems if we compile the library using cargo build --features cli --no-default-features, that produces a binary that is perfectly workable with non backend wallet. It has functionality like this

$ ./target/debug/bdk-cli wallet --help
bdk-cli-wallet 0.2.1-dev
Wallet mode
USAGE:
bdk-cli wallet [FLAGS] [OPTIONS] --descriptor <DESCRIPTOR> <SUBCOMMAND>
FLAGS:
-v, --verbose Adds verbosity, returns PSBT in JSON format alongside serialized
-h, --help Prints help information
-V, --version Prints version information
OPTIONS:
-c, --change_descriptor <CHANGE_DESCRIPTOR> Sets the descriptor to use for internal addresses
-d, --descriptor <DESCRIPTOR> Sets the descriptor to use for the external addresses
-w, --wallet <WALLET_NAME> Selects the wallet to use [default: main]
SUBCOMMANDS:
bump_fee Bumps the fees of an RBF transaction
combine_psbt Combines multiple PSBTs into one
create_tx Creates a new unsigned transaction
extract_psbt Extracts a raw transaction from a PSBT
finalize_psbt Finalizes a PSBT
get_balance Returns the current wallet balance
get_new_address Generates a new external address
help Prints this message or the help of the given subcommand(s)
list_transactions Lists all the incoming and outgoing transactions of the wallet
list_unspent Lists the available spendable UTXOs
policies Returns the available spending policies for the descriptor
public_descriptor Returns the public version of the wallet's descriptor(s)
sign Signs and tries to finalize a PSBT

So that begs the question I had before, what do we need the repl thing for?

Also from here https://github.com/notmandatory/bdk-cli/blob/69b1d80bcd4715a3b78af4aafacebe2fc5ca2b88/src/bdk_cli.rs#L318-L331
it seems all a repl does is to perse existing commands and use them with either wallet or key functions. Maybe I am missing something, but I am not seeing any use of having the same methods called twice in different ways.

If two features cli and repl that does the same thing, it seems confusing to me.

Comment threadsrc/bdk_cli.rs Outdated
feature = "esplora",
any(feature = "electrum", feature = "compact_filters")
))]
compile_error!("Only one blockchain client feature can be enabled at a time.");

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It seems for every combination of electrum, esplora and compact_filters, this error is being duplicated with the one defined few lines below.

Instead, if we write it like this

#[cfg(all(
any( feature = "electrum", feature = "esplora", feature = "compact_filters"),
any( feature = "electrum", feature = "esplora", feature = "compact_filters")
))]

this will activate for any combination of the above three. And we won't need to specify compiler_error! multiple times.

Also for future extension, if we just add a new backend to the list above, that will taker care of multiple backend activation errors.

@notmandatorynotmandatoryAug 6, 2021

Copy link
Copy Markdown
MemberAuthor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Unfortunately the cfg all any any approach doesn't work, when I added this code:

#[cfg(all(any( feature = "electrum", feature = "esplora", feature = "compact_filters"),any( feature = "electrum", feature = "esplora", feature = "compact_filters")))]compile_error!("Only one blockchain client feature can be enabled at a time.");

I get the error even with only one blockchain client feature enabled (ie. cargo build --features esplora).

Looks like other's have had this same problem and are proposing a Rust RFC to allow a set of features to provide another feature in a mutually exclusive way.

Until mutually exclusive features are possible I can fix this in a simplistic way in the build.rs file as below or just leave it as it.. What do you think?

fnmain(){let electrum = env::var_os("CARGO_FEATURE_ELECTRUM").map(|_| "electrum".to_string());let esplora = env::var_os("CARGO_FEATURE_ESPLORA").map(|_| "esplora".to_string());let compact_filters = env::var_os("CARGO_FEATURE_COMPACT_FILTERS").map(|_| "compact_filters".to_string());let blockchain_features :Vec<String> = vec!(electrum, esplora, compact_filters).iter().map(|f| f.to_owned()).flatten().collect();if blockchain_features.len() > 1{panic!("At most one blockchain client feature can be enabled but these features were enabled: {:?}", blockchain_features)}}

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ah ok.. I thought it would work because my analyzer didn't throw. Yes there should be a way to handle mutually exclusive features in cargo itself.

I like the build script approach. It's clear and concise. Till it's available in cargo we can use a guard like above.

@rajarshimaitra

Copy link
Copy Markdown
Contributor

The following structure and function call could use feature guard. They exist in binary compiled without a backend, but are never used.

https://github.com/notmandatory/bdk-cli/blob/69b1d80bcd4715a3b78af4aafacebe2fc5ca2b88/src/lib.rs#L892

https://github.com/notmandatory/bdk-cli/blob/69b1d80bcd4715a3b78af4aafacebe2fc5ca2b88/src/lib.rs#L638

@notmandatory
notmandatoryforce-pushed the single_blockchain_feature branch from d3c0af3 to 9bb1c60CompareAugust 7, 2021 00:27

@rajarshimaitrarajarshimaitra left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

tACK 9bb1c60

With some minor nits.

Comment threadCHANGELOG.md Outdated
Comment threadCargo.toml
name = "bdk-cli"
path = "src/bdk_cli.rs"
required-features = ["repl", "electrum"]
required-features = ["cli"]

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is this required-features value necessary? By putting cli in default we are ensuring that the build will always include cli. (we also removed any necessity of using --no-default-features).

Copy link
Copy Markdown
MemberAuthor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think we still need cli as required to force anyone building the bin without repl (using --no-default-features) to still include cli.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ya makes sense.

Comment threadREADME.md Outdated
Comment threadREADME.md

```shell
cargo run -- wallet --descriptor "wpkh(tpubEBr4i6yk5nf5DAaJpsi9N2pPYBeJ7fZ5Z9rmN4977iYLCGco1VyjB9tvvuvYtfZzjD5A8igzgw3HeWeeKFmanHYqksqZXYXGsw5zjnj7KM9/*)" sync
cargo run --features electrum -- wallet --descriptor "wpkh(tpubEBr4i6yk5nf5DAaJpsi9N2pPYBeJ7fZ5Z9rmN4977iYLCGco1VyjB9tvvuvYtfZzjD5A8igzgw3HeWeeKFmanHYqksqZXYXGsw5zjnj7KM9/*)" sync

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Few lines ago we mentioned how to install bdk-cli with cargo.

Instructing to use cargo run here will build the local files instead of using the installed binary. So if someone is in their cloned repo, using cargo run they will actually build and then run the master branch instead of the release binary he just installed (this might be an unexpected behavior for the user, unless he knows cargo stuffs).

Even worse if someone didn't clone the repo, cargo run will not run anything, even if they have bdk-cli binary installed (and we don't have that instruction anywhere).

I think in the "bdk-cli bin usage examples" section, we should just instruct to use bdk-cli binary instead of crago run, which will make the instruction simpler also.

This doesn't have to be fixed here. Just mentioned as it occurred to me.

Copy link
Copy Markdown
MemberAuthor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I agree we should probably update the README to focus on installing with different features, and then usage with an installed version instead of using cargo run since anyone making local changes should already know how to use cargo. But let's do that cleanup in a different PR.

Comment threadsrc/lib.rs
@rajarshimaitra

Copy link
Copy Markdown
Contributor

ACK 062542a

@notmandatory
notmandatoryforce-pushed the single_blockchain_feature branch from 062542a to 7c4f5e7CompareAugust 12, 2021 14:13

@rajarshimaitrarajarshimaitra left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Code review with testing ACK 4fd39b7

@notmandatory
notmandatory merged commit 4fd39b7 into bitcoindevkit:masterAug 13, 2021
@notmandatory

Copy link
Copy Markdown
MemberAuthor

Thanks for the suggestions and review on this @rajarshimaitra, all ready to rebase your #36 PR.

Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants

@notmandatory@rajarshimaitra
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Auto-enable theater mode on YouTube\n(function() {\n function tryTheater() {\n var btn = document.querySelector('button[aria-label=\"Theater mode\"], ytd-player #player button[title=\"Theater mode\"]');\n if (btn && !btn.classList.contains('activated')) {\n btn.click();\n }\n }\n \n // Try immediately\n tryTheater();\n \n // Try after navigation (SPA)\n var lastUrl = location.href;\n setInterval(function() {\n if (location.href !== lastUrl) {\n lastUrl = location.href;\n setTimeout(tryTheater, 500);\n }\n }, 1000);\n \n // Also try on player load\n var observer = new MutationObserver(tryTheater);\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "YouTube Theater Mode Default"); } } catch(__e) { console.warn('[Userscript:YouTube Theater Mode Default]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content

Allow enabling at most one blockchain client feature - #38

Merged
notmandatory merged 10 commits into
bitcoindevkit:masterfrom
notmandatory:single_blockchain_feature
Aug 13, 2021
Merged

Allow enabling at most one blockchain client feature#38
notmandatory merged 10 commits into
bitcoindevkit:masterfrom
notmandatory:single_blockchain_feature

Conversation

@notmandatory

@notmandatorynotmandatory commented Aug 5, 2021

Copy link
Copy Markdown
Member

Description

Allow at most one blockchain client feature be enabled at a time for builds. If no blockchain client feature is enabled then online wallet commands are disabled. This will simplify the options shown to the user and make adding new blockchain clients (such as #36) easier. Electrum is still the default, to make a build with a different blockchain client the --no-default-features build option will need to be used. No blockchain client is included in the default features, so if one is needed it must be specified with --features. I also added a default esplora server url so the user doesn't need to specify one if selecting that client, which is how the electrum and compact_filters clients work.

Notes to the reviewers

I changed the server option for both electrum and esplora to --server or -s since that now won't cause a conflict. I also simplified the CHANGELOG to focus on what a user would see as a change while using the bin.

I've also added a build.rs file to prevent more than one blockchain client feature from being enabled.

Checklists

All Submissions:

  • I've signed all my commits
  • I followed the contribution guidelines
  • I ran cargo fmt and cargo clippy before committing

New Features:

  • I've added tests for the new feature
  • I've added docs for the new feature
  • I've updated CHANGELOG.md

Bugfixes:

  • This pull request breaks the existing API
  • I've added tests to reproduce the issue which are now passing
  • I'm linking the issue being fixed by this PR

@notmandatory
notmandatoryforce-pushed the single_blockchain_feature branch 4 times, most recently from 65729b9 to 47e0962CompareAugust 5, 2021 06:15
@notmandatorynotmandatory changed the title Single blockchain featureOnly allow enabling at most one blockchain client featureAug 5, 2021
@notmandatorynotmandatory changed the title Only allow enabling at most one blockchain client featureAllow enabling at most one blockchain client featureAug 5, 2021
@notmandatory
notmandatoryforce-pushed the single_blockchain_feature branch 2 times, most recently from f9cd936 to c81a99eCompareAugust 5, 2021 06:42
@notmandatory
notmandatory marked this pull request as ready for review August 5, 2021 06:43

@rajarshimaitrarajarshimaitra left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks @notmandatory for the PR, we are close almost. I just have a few more comments.

Is there any specific use of Repl mode here?

bdk-cli/src/lib.rs

Lines 258 to 262 in 378b33a

#[structopt(long_about = "REPL command loop mode")]
Repl{
#[structopt(flatten)]
wallet_opts:WalletOpts,
},

It just seems to be duplicating WalletOpts and no commands. If not we can remove this, it seems redundant.

One problem here is using --no-default-features will turn off repl too, which is required dep for the binary, so it will not compile any binary. This has been the crux of the problem because cargo doesn't let us selectively disable features. So if we disable default, it disables everything in default.

I think the only way to solve this problem is by having a very minimal default with only the stuffs that we need to create the minimal possible binary. And then add stuff to it with features flag. This will also remove the use of --no-default-feature if we only want esplora but not electrum.

So I propose something like this:

[features]
default = ["repl"]
repl = ["bdk/key-value-db", "clap", "dirs-next", "env_logger", "regex", "rustyline"]
electrum = ["bdk/electrum"]
esplora = ["bdk/esplora"]
compiler = ["bdk/compiler"]
async-interface = ["bdk/async-interface"]
compact_filters = ["bdk/compact_filters"]
[[bin]]
name = "bdk-cli"
path = "src/bdk_cli.rs"
required-features = ["repl"]

This will create the following builds

cargo build : build only repl stuffs, no backend
cargo build --features [backend] : build repl + [backend] blockchain.

I don't think there's any adverse effect of not having a blockchain by default. the only method we have with blockchain is sync and broadcast, everything else can be done without a blockchain. So it's safe to remove it in default.

@rajarshimaitra

rajarshimaitra commented Aug 5, 2021

Copy link
Copy Markdown
Contributor

Also, I am not sure if we should silently ignore "no binary built" scenarios in CI.

run: cargo build --features ${{ matrix.features }} --no-default-features

with current changes for example cargo build --features esplora --no-default-features will not build any binary, but the CI doesn't complain.

you can check that locally with

$ cargo clean
$ cargo build --features esplora --no-default-features
$ ./target/debug/bdk-cli wallet --help
bash: ./target/debug/bdk-cli: No such file or directory

I am not sure how then it's passing the tests without a binary.

@notmandatory

notmandatory commented Aug 6, 2021

Copy link
Copy Markdown
MemberAuthor

I think tests were passing because they only needed a lib build to run. But I agree it would be nice to not have to use the --no-default-features flag. I did the following to try and address this:

  1. split the repl feature into cli for the required dependencies to build the cli bin, and repl to enable the cli repl commands, then made the cli feature required to build the cli bin, but the cli and repl features on by default.
  2. added cfg statements so someone could build the cli without the repl command if they want fewer dependencies and use the --no-default-features flag
  3. update the CI to test with the default (no blockchain client) features, or each blockchain client, or the 'compiler' feature

@rajarshimaitrarajarshimaitra left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Code review ACK. This simplifies the issue.

I had the following observation. It seems if we compile the library using cargo build --features cli --no-default-features, that produces a binary that is perfectly workable with non backend wallet. It has functionality like this

$ ./target/debug/bdk-cli wallet --help
bdk-cli-wallet 0.2.1-dev
Wallet mode
USAGE:
bdk-cli wallet [FLAGS] [OPTIONS] --descriptor <DESCRIPTOR> <SUBCOMMAND>
FLAGS:
-v, --verbose Adds verbosity, returns PSBT in JSON format alongside serialized
-h, --help Prints help information
-V, --version Prints version information
OPTIONS:
-c, --change_descriptor <CHANGE_DESCRIPTOR> Sets the descriptor to use for internal addresses
-d, --descriptor <DESCRIPTOR> Sets the descriptor to use for the external addresses
-w, --wallet <WALLET_NAME> Selects the wallet to use [default: main]
SUBCOMMANDS:
bump_fee Bumps the fees of an RBF transaction
combine_psbt Combines multiple PSBTs into one
create_tx Creates a new unsigned transaction
extract_psbt Extracts a raw transaction from a PSBT
finalize_psbt Finalizes a PSBT
get_balance Returns the current wallet balance
get_new_address Generates a new external address
help Prints this message or the help of the given subcommand(s)
list_transactions Lists all the incoming and outgoing transactions of the wallet
list_unspent Lists the available spendable UTXOs
policies Returns the available spending policies for the descriptor
public_descriptor Returns the public version of the wallet's descriptor(s)
sign Signs and tries to finalize a PSBT

So that begs the question I had before, what do we need the repl thing for?

Also from here https://github.com/notmandatory/bdk-cli/blob/69b1d80bcd4715a3b78af4aafacebe2fc5ca2b88/src/bdk_cli.rs#L318-L331
it seems all a repl does is to perse existing commands and use them with either wallet or key functions. Maybe I am missing something, but I am not seeing any use of having the same methods called twice in different ways.

If two features cli and repl that does the same thing, it seems confusing to me.

Comment threadsrc/bdk_cli.rs Outdated
feature = "esplora",
any(feature = "electrum", feature = "compact_filters")
))]
compile_error!("Only one blockchain client feature can be enabled at a time.");

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It seems for every combination of electrum, esplora and compact_filters, this error is being duplicated with the one defined few lines below.

Instead, if we write it like this

#[cfg(all(
any( feature = "electrum", feature = "esplora", feature = "compact_filters"),
any( feature = "electrum", feature = "esplora", feature = "compact_filters")
))]

this will activate for any combination of the above three. And we won't need to specify compiler_error! multiple times.

Also for future extension, if we just add a new backend to the list above, that will taker care of multiple backend activation errors.

@notmandatorynotmandatoryAug 6, 2021

Copy link
Copy Markdown
MemberAuthor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Unfortunately the cfg all any any approach doesn't work, when I added this code:

#[cfg(all(any( feature = "electrum", feature = "esplora", feature = "compact_filters"),any( feature = "electrum", feature = "esplora", feature = "compact_filters")))]compile_error!("Only one blockchain client feature can be enabled at a time.");

I get the error even with only one blockchain client feature enabled (ie. cargo build --features esplora).

Looks like other's have had this same problem and are proposing a Rust RFC to allow a set of features to provide another feature in a mutually exclusive way.

Until mutually exclusive features are possible I can fix this in a simplistic way in the build.rs file as below or just leave it as it.. What do you think?

fnmain(){let electrum = env::var_os("CARGO_FEATURE_ELECTRUM").map(|_| "electrum".to_string());let esplora = env::var_os("CARGO_FEATURE_ESPLORA").map(|_| "esplora".to_string());let compact_filters = env::var_os("CARGO_FEATURE_COMPACT_FILTERS").map(|_| "compact_filters".to_string());let blockchain_features :Vec<String> = vec!(electrum, esplora, compact_filters).iter().map(|f| f.to_owned()).flatten().collect();if blockchain_features.len() > 1{panic!("At most one blockchain client feature can be enabled but these features were enabled: {:?}", blockchain_features)}}

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ah ok.. I thought it would work because my analyzer didn't throw. Yes there should be a way to handle mutually exclusive features in cargo itself.

I like the build script approach. It's clear and concise. Till it's available in cargo we can use a guard like above.

@rajarshimaitra

Copy link
Copy Markdown
Contributor

The following structure and function call could use feature guard. They exist in binary compiled without a backend, but are never used.

https://github.com/notmandatory/bdk-cli/blob/69b1d80bcd4715a3b78af4aafacebe2fc5ca2b88/src/lib.rs#L892

https://github.com/notmandatory/bdk-cli/blob/69b1d80bcd4715a3b78af4aafacebe2fc5ca2b88/src/lib.rs#L638

@notmandatory
notmandatoryforce-pushed the single_blockchain_feature branch from d3c0af3 to 9bb1c60CompareAugust 7, 2021 00:27

@rajarshimaitrarajarshimaitra left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

tACK 9bb1c60

With some minor nits.

Comment threadCHANGELOG.md Outdated
Comment threadCargo.toml
name = "bdk-cli"
path = "src/bdk_cli.rs"
required-features = ["repl", "electrum"]
required-features = ["cli"]

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is this required-features value necessary? By putting cli in default we are ensuring that the build will always include cli. (we also removed any necessity of using --no-default-features).

Copy link
Copy Markdown
MemberAuthor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think we still need cli as required to force anyone building the bin without repl (using --no-default-features) to still include cli.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ya makes sense.

Comment threadREADME.md Outdated
Comment threadREADME.md

```shell
cargo run -- wallet --descriptor "wpkh(tpubEBr4i6yk5nf5DAaJpsi9N2pPYBeJ7fZ5Z9rmN4977iYLCGco1VyjB9tvvuvYtfZzjD5A8igzgw3HeWeeKFmanHYqksqZXYXGsw5zjnj7KM9/*)" sync
cargo run --features electrum -- wallet --descriptor "wpkh(tpubEBr4i6yk5nf5DAaJpsi9N2pPYBeJ7fZ5Z9rmN4977iYLCGco1VyjB9tvvuvYtfZzjD5A8igzgw3HeWeeKFmanHYqksqZXYXGsw5zjnj7KM9/*)" sync

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Few lines ago we mentioned how to install bdk-cli with cargo.

Instructing to use cargo run here will build the local files instead of using the installed binary. So if someone is in their cloned repo, using cargo run they will actually build and then run the master branch instead of the release binary he just installed (this might be an unexpected behavior for the user, unless he knows cargo stuffs).

Even worse if someone didn't clone the repo, cargo run will not run anything, even if they have bdk-cli binary installed (and we don't have that instruction anywhere).

I think in the "bdk-cli bin usage examples" section, we should just instruct to use bdk-cli binary instead of crago run, which will make the instruction simpler also.

This doesn't have to be fixed here. Just mentioned as it occurred to me.

Copy link
Copy Markdown
MemberAuthor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I agree we should probably update the README to focus on installing with different features, and then usage with an installed version instead of using cargo run since anyone making local changes should already know how to use cargo. But let's do that cleanup in a different PR.

Comment threadsrc/lib.rs
@rajarshimaitra

Copy link
Copy Markdown
Contributor

ACK 062542a

@notmandatory
notmandatoryforce-pushed the single_blockchain_feature branch from 062542a to 7c4f5e7CompareAugust 12, 2021 14:13

@rajarshimaitrarajarshimaitra left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Code review with testing ACK 4fd39b7

@notmandatory
notmandatory merged commit 4fd39b7 into bitcoindevkit:masterAug 13, 2021
@notmandatory

Copy link
Copy Markdown
MemberAuthor

Thanks for the suggestions and review on this @rajarshimaitra, all ready to rebase your #36 PR.

Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants

@notmandatory@rajarshimaitra
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Remove or un-stick sticky/fixed headers that block content\n(function() {\n function unstick() {\n document.querySelectorAll('header, nav, [role=\"banner\"], .header, .navbar, .sticky, .fixed-top, [style*=\"position: fixed\"], [style*=\"position:sticky\"]').forEach(function(el) {\n if (el.style.position === 'fixed' || el.style.position === 'sticky' || \n getComputedStyle(el).position === 'fixed' || getComputedStyle(el).position === 'sticky') {\n el.style.position = 'static';\n el.style.top = 'auto';\n el.style.zIndex = 'auto';\n }\n });\n }\n \n unstick();\n \n var observer = new MutationObserver(unstick);\n observer.observe(document.body, { childList: true, subtree: true, attributes: true, attributeFilter: ['style', 'class'] });\n})();", "Kill Sticky Headers"); } } catch(__e) { console.warn('[Userscript:Kill Sticky Headers]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content

Allow enabling at most one blockchain client feature - #38

Merged
notmandatory merged 10 commits into
bitcoindevkit:masterfrom
notmandatory:single_blockchain_feature
Aug 13, 2021
Merged

Allow enabling at most one blockchain client feature#38
notmandatory merged 10 commits into
bitcoindevkit:masterfrom
notmandatory:single_blockchain_feature

Conversation

@notmandatory

@notmandatorynotmandatory commented Aug 5, 2021

Copy link
Copy Markdown
Member

Description

Allow at most one blockchain client feature be enabled at a time for builds. If no blockchain client feature is enabled then online wallet commands are disabled. This will simplify the options shown to the user and make adding new blockchain clients (such as #36) easier. Electrum is still the default, to make a build with a different blockchain client the --no-default-features build option will need to be used. No blockchain client is included in the default features, so if one is needed it must be specified with --features. I also added a default esplora server url so the user doesn't need to specify one if selecting that client, which is how the electrum and compact_filters clients work.

Notes to the reviewers

I changed the server option for both electrum and esplora to --server or -s since that now won't cause a conflict. I also simplified the CHANGELOG to focus on what a user would see as a change while using the bin.

I've also added a build.rs file to prevent more than one blockchain client feature from being enabled.

Checklists

All Submissions:

  • I've signed all my commits
  • I followed the contribution guidelines
  • I ran cargo fmt and cargo clippy before committing

New Features:

  • I've added tests for the new feature
  • I've added docs for the new feature
  • I've updated CHANGELOG.md

Bugfixes:

  • This pull request breaks the existing API
  • I've added tests to reproduce the issue which are now passing
  • I'm linking the issue being fixed by this PR

@notmandatory
notmandatoryforce-pushed the single_blockchain_feature branch 4 times, most recently from 65729b9 to 47e0962CompareAugust 5, 2021 06:15
@notmandatorynotmandatory changed the title Single blockchain featureOnly allow enabling at most one blockchain client featureAug 5, 2021
@notmandatorynotmandatory changed the title Only allow enabling at most one blockchain client featureAllow enabling at most one blockchain client featureAug 5, 2021
@notmandatory
notmandatoryforce-pushed the single_blockchain_feature branch 2 times, most recently from f9cd936 to c81a99eCompareAugust 5, 2021 06:42
@notmandatory
notmandatory marked this pull request as ready for review August 5, 2021 06:43

@rajarshimaitrarajarshimaitra left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks @notmandatory for the PR, we are close almost. I just have a few more comments.

Is there any specific use of Repl mode here?

bdk-cli/src/lib.rs

Lines 258 to 262 in 378b33a

#[structopt(long_about = "REPL command loop mode")]
Repl{
#[structopt(flatten)]
wallet_opts:WalletOpts,
},

It just seems to be duplicating WalletOpts and no commands. If not we can remove this, it seems redundant.

One problem here is using --no-default-features will turn off repl too, which is required dep for the binary, so it will not compile any binary. This has been the crux of the problem because cargo doesn't let us selectively disable features. So if we disable default, it disables everything in default.

I think the only way to solve this problem is by having a very minimal default with only the stuffs that we need to create the minimal possible binary. And then add stuff to it with features flag. This will also remove the use of --no-default-feature if we only want esplora but not electrum.

So I propose something like this:

[features]
default = ["repl"]
repl = ["bdk/key-value-db", "clap", "dirs-next", "env_logger", "regex", "rustyline"]
electrum = ["bdk/electrum"]
esplora = ["bdk/esplora"]
compiler = ["bdk/compiler"]
async-interface = ["bdk/async-interface"]
compact_filters = ["bdk/compact_filters"]
[[bin]]
name = "bdk-cli"
path = "src/bdk_cli.rs"
required-features = ["repl"]

This will create the following builds

cargo build : build only repl stuffs, no backend
cargo build --features [backend] : build repl + [backend] blockchain.

I don't think there's any adverse effect of not having a blockchain by default. the only method we have with blockchain is sync and broadcast, everything else can be done without a blockchain. So it's safe to remove it in default.

@rajarshimaitra

rajarshimaitra commented Aug 5, 2021

Copy link
Copy Markdown
Contributor

Also, I am not sure if we should silently ignore "no binary built" scenarios in CI.

run: cargo build --features ${{ matrix.features }} --no-default-features

with current changes for example cargo build --features esplora --no-default-features will not build any binary, but the CI doesn't complain.

you can check that locally with

$ cargo clean
$ cargo build --features esplora --no-default-features
$ ./target/debug/bdk-cli wallet --help
bash: ./target/debug/bdk-cli: No such file or directory

I am not sure how then it's passing the tests without a binary.

@notmandatory

notmandatory commented Aug 6, 2021

Copy link
Copy Markdown
MemberAuthor

I think tests were passing because they only needed a lib build to run. But I agree it would be nice to not have to use the --no-default-features flag. I did the following to try and address this:

  1. split the repl feature into cli for the required dependencies to build the cli bin, and repl to enable the cli repl commands, then made the cli feature required to build the cli bin, but the cli and repl features on by default.
  2. added cfg statements so someone could build the cli without the repl command if they want fewer dependencies and use the --no-default-features flag
  3. update the CI to test with the default (no blockchain client) features, or each blockchain client, or the 'compiler' feature

@rajarshimaitrarajarshimaitra left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Code review ACK. This simplifies the issue.

I had the following observation. It seems if we compile the library using cargo build --features cli --no-default-features, that produces a binary that is perfectly workable with non backend wallet. It has functionality like this

$ ./target/debug/bdk-cli wallet --help
bdk-cli-wallet 0.2.1-dev
Wallet mode
USAGE:
bdk-cli wallet [FLAGS] [OPTIONS] --descriptor <DESCRIPTOR> <SUBCOMMAND>
FLAGS:
-v, --verbose Adds verbosity, returns PSBT in JSON format alongside serialized
-h, --help Prints help information
-V, --version Prints version information
OPTIONS:
-c, --change_descriptor <CHANGE_DESCRIPTOR> Sets the descriptor to use for internal addresses
-d, --descriptor <DESCRIPTOR> Sets the descriptor to use for the external addresses
-w, --wallet <WALLET_NAME> Selects the wallet to use [default: main]
SUBCOMMANDS:
bump_fee Bumps the fees of an RBF transaction
combine_psbt Combines multiple PSBTs into one
create_tx Creates a new unsigned transaction
extract_psbt Extracts a raw transaction from a PSBT
finalize_psbt Finalizes a PSBT
get_balance Returns the current wallet balance
get_new_address Generates a new external address
help Prints this message or the help of the given subcommand(s)
list_transactions Lists all the incoming and outgoing transactions of the wallet
list_unspent Lists the available spendable UTXOs
policies Returns the available spending policies for the descriptor
public_descriptor Returns the public version of the wallet's descriptor(s)
sign Signs and tries to finalize a PSBT

So that begs the question I had before, what do we need the repl thing for?

Also from here https://github.com/notmandatory/bdk-cli/blob/69b1d80bcd4715a3b78af4aafacebe2fc5ca2b88/src/bdk_cli.rs#L318-L331
it seems all a repl does is to perse existing commands and use them with either wallet or key functions. Maybe I am missing something, but I am not seeing any use of having the same methods called twice in different ways.

If two features cli and repl that does the same thing, it seems confusing to me.

Comment threadsrc/bdk_cli.rs Outdated
feature = "esplora",
any(feature = "electrum", feature = "compact_filters")
))]
compile_error!("Only one blockchain client feature can be enabled at a time.");

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It seems for every combination of electrum, esplora and compact_filters, this error is being duplicated with the one defined few lines below.

Instead, if we write it like this

#[cfg(all(
any( feature = "electrum", feature = "esplora", feature = "compact_filters"),
any( feature = "electrum", feature = "esplora", feature = "compact_filters")
))]

this will activate for any combination of the above three. And we won't need to specify compiler_error! multiple times.

Also for future extension, if we just add a new backend to the list above, that will taker care of multiple backend activation errors.

@notmandatorynotmandatoryAug 6, 2021

Copy link
Copy Markdown
MemberAuthor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Unfortunately the cfg all any any approach doesn't work, when I added this code:

#[cfg(all(any( feature = "electrum", feature = "esplora", feature = "compact_filters"),any( feature = "electrum", feature = "esplora", feature = "compact_filters")))]compile_error!("Only one blockchain client feature can be enabled at a time.");

I get the error even with only one blockchain client feature enabled (ie. cargo build --features esplora).

Looks like other's have had this same problem and are proposing a Rust RFC to allow a set of features to provide another feature in a mutually exclusive way.

Until mutually exclusive features are possible I can fix this in a simplistic way in the build.rs file as below or just leave it as it.. What do you think?

fnmain(){let electrum = env::var_os("CARGO_FEATURE_ELECTRUM").map(|_| "electrum".to_string());let esplora = env::var_os("CARGO_FEATURE_ESPLORA").map(|_| "esplora".to_string());let compact_filters = env::var_os("CARGO_FEATURE_COMPACT_FILTERS").map(|_| "compact_filters".to_string());let blockchain_features :Vec<String> = vec!(electrum, esplora, compact_filters).iter().map(|f| f.to_owned()).flatten().collect();if blockchain_features.len() > 1{panic!("At most one blockchain client feature can be enabled but these features were enabled: {:?}", blockchain_features)}}

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ah ok.. I thought it would work because my analyzer didn't throw. Yes there should be a way to handle mutually exclusive features in cargo itself.

I like the build script approach. It's clear and concise. Till it's available in cargo we can use a guard like above.

@rajarshimaitra

Copy link
Copy Markdown
Contributor

The following structure and function call could use feature guard. They exist in binary compiled without a backend, but are never used.

https://github.com/notmandatory/bdk-cli/blob/69b1d80bcd4715a3b78af4aafacebe2fc5ca2b88/src/lib.rs#L892

https://github.com/notmandatory/bdk-cli/blob/69b1d80bcd4715a3b78af4aafacebe2fc5ca2b88/src/lib.rs#L638

@notmandatory
notmandatoryforce-pushed the single_blockchain_feature branch from d3c0af3 to 9bb1c60CompareAugust 7, 2021 00:27

@rajarshimaitrarajarshimaitra left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

tACK 9bb1c60

With some minor nits.

Comment threadCHANGELOG.md Outdated
Comment threadCargo.toml
name = "bdk-cli"
path = "src/bdk_cli.rs"
required-features = ["repl", "electrum"]
required-features = ["cli"]

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is this required-features value necessary? By putting cli in default we are ensuring that the build will always include cli. (we also removed any necessity of using --no-default-features).

Copy link
Copy Markdown
MemberAuthor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think we still need cli as required to force anyone building the bin without repl (using --no-default-features) to still include cli.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ya makes sense.

Comment threadREADME.md Outdated
Comment threadREADME.md

```shell
cargo run -- wallet --descriptor "wpkh(tpubEBr4i6yk5nf5DAaJpsi9N2pPYBeJ7fZ5Z9rmN4977iYLCGco1VyjB9tvvuvYtfZzjD5A8igzgw3HeWeeKFmanHYqksqZXYXGsw5zjnj7KM9/*)" sync
cargo run --features electrum -- wallet --descriptor "wpkh(tpubEBr4i6yk5nf5DAaJpsi9N2pPYBeJ7fZ5Z9rmN4977iYLCGco1VyjB9tvvuvYtfZzjD5A8igzgw3HeWeeKFmanHYqksqZXYXGsw5zjnj7KM9/*)" sync

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Few lines ago we mentioned how to install bdk-cli with cargo.

Instructing to use cargo run here will build the local files instead of using the installed binary. So if someone is in their cloned repo, using cargo run they will actually build and then run the master branch instead of the release binary he just installed (this might be an unexpected behavior for the user, unless he knows cargo stuffs).

Even worse if someone didn't clone the repo, cargo run will not run anything, even if they have bdk-cli binary installed (and we don't have that instruction anywhere).

I think in the "bdk-cli bin usage examples" section, we should just instruct to use bdk-cli binary instead of crago run, which will make the instruction simpler also.

This doesn't have to be fixed here. Just mentioned as it occurred to me.

Copy link
Copy Markdown
MemberAuthor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I agree we should probably update the README to focus on installing with different features, and then usage with an installed version instead of using cargo run since anyone making local changes should already know how to use cargo. But let's do that cleanup in a different PR.

Comment threadsrc/lib.rs
@rajarshimaitra

Copy link
Copy Markdown
Contributor

ACK 062542a

@notmandatory
notmandatoryforce-pushed the single_blockchain_feature branch from 062542a to 7c4f5e7CompareAugust 12, 2021 14:13

@rajarshimaitrarajarshimaitra left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Code review with testing ACK 4fd39b7

@notmandatory
notmandatory merged commit 4fd39b7 into bitcoindevkit:masterAug 13, 2021
@notmandatory

Copy link
Copy Markdown
MemberAuthor

Thanks for the suggestions and review on this @rajarshimaitra, all ready to rebase your #36 PR.

Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants

@notmandatory@rajarshimaitra
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Universal Dark Mode - works on any site\n(function() {\n var enabled = true;\n \n function applyDarkMode() {\n if (!enabled) return;\n \n // Create style element if it doesn't exist\n var style = document.getElementById('universal-dark-mode-style');\n if (!style) {\n style = document.createElement('style');\n style.id = 'universal-dark-mode-style';\n document.head.appendChild(style);\n }\n \n // Dark mode CSS - inverts colors but preserves images/video\n style.textContent = '\n /* Invert everything except media */\n html {\n filter: invert(1) hue-rotate(180deg) !important;\n background: #1a1a2e !important;\n }\n \n /* Restore images, videos, iframes, canvas */\n img, video, iframe, canvas, svg, picture, [style*=\"background-image\"] {\n filter: invert(1) hue-rotate(180deg) !important;\n }\n \n /* Preserve specific elements that should not be inverted */\n .no-dark-mode, .no-dark-mode *,\n [data-theme=\"light\"], [data-theme=\"light\"],\n .ace_editor, .ace_editor *,\n .CodeMirror, .CodeMirror *,\n .monaco-editor, .monaco-editor *,\n .markdown-body pre, .markdown-body pre *,\n .highlight, .highlight *,\n pre code, pre code * {\n filter: none !important;\n }\n \n /* Fix common UI elements */\n .modal, .popup, .dropdown-menu, .tooltip, .popover {\n filter: invert(1) hue-rotate(180deg) !important;\n background: #2d2d44 !important;\n border-color: #444 !important;\n }\n \n /* Scrollbars */\n ::-webkit-scrollbar { background: #1a1a2e !important; }\n ::-webkit-scrollbar-thumb { background: #444 !important; }\n ::-webkit-scrollbar-thumb:hover { background: #555 !important; }\n \n /* Selection */\n ::selection { background: #4ecdc4 !important; color: #1a1a2e !important; }\n ::-moz-selection { background: #4ecdc4 !important; color: #1a1a2e !important; }\n ';\n }\n \n function removeDarkMode() {\n var style = document.getElementById('universal-dark-mode-style');\n if (style) style.remove();\n }\n \n // Toggle with Alt+Shift+D\n document.addEventListener('keydown', function(e) {\n if (e.altKey && e.shiftKey && e.key === 'D') {\n e.preventDefault();\n enabled = !enabled;\n if (enabled) {\n applyDarkMode();\n console.log('[Universal Dark Mode] Enabled');\n } else {\n removeDarkMode();\n console.log('[Universal Dark Mode] Disabled');\n }\n }\n });\n \n // Apply on load\n applyDarkMode();\n \n // Re-apply on dynamic content\n var observer = new MutationObserver(function(mutations) {\n if (enabled && !document.getElementById('universal-dark-mode-style')) {\n applyDarkMode();\n }\n });\n observer.observe(document.head, { childList: true });\n \n console.log('[Universal Dark Mode] Loaded - Press Alt+Shift+D to toggle');\n})();", "Universal Dark Mode"); } } catch(__e) { console.warn('[Userscript:Universal Dark Mode]', __e); } })(); })();
Skip to content

Allow enabling at most one blockchain client feature - #38

Merged
notmandatory merged 10 commits into
bitcoindevkit:masterfrom
notmandatory:single_blockchain_feature
Aug 13, 2021
Merged

Allow enabling at most one blockchain client feature#38
notmandatory merged 10 commits into
bitcoindevkit:masterfrom
notmandatory:single_blockchain_feature

Conversation

@notmandatory

@notmandatorynotmandatory commented Aug 5, 2021

Copy link
Copy Markdown
Member

Description

Allow at most one blockchain client feature be enabled at a time for builds. If no blockchain client feature is enabled then online wallet commands are disabled. This will simplify the options shown to the user and make adding new blockchain clients (such as #36) easier. Electrum is still the default, to make a build with a different blockchain client the --no-default-features build option will need to be used. No blockchain client is included in the default features, so if one is needed it must be specified with --features. I also added a default esplora server url so the user doesn't need to specify one if selecting that client, which is how the electrum and compact_filters clients work.

Notes to the reviewers

I changed the server option for both electrum and esplora to --server or -s since that now won't cause a conflict. I also simplified the CHANGELOG to focus on what a user would see as a change while using the bin.

I've also added a build.rs file to prevent more than one blockchain client feature from being enabled.

Checklists

All Submissions:

  • I've signed all my commits
  • I followed the contribution guidelines
  • I ran cargo fmt and cargo clippy before committing

New Features:

  • I've added tests for the new feature
  • I've added docs for the new feature
  • I've updated CHANGELOG.md

Bugfixes:

  • This pull request breaks the existing API
  • I've added tests to reproduce the issue which are now passing
  • I'm linking the issue being fixed by this PR

@notmandatory
notmandatoryforce-pushed the single_blockchain_feature branch 4 times, most recently from 65729b9 to 47e0962CompareAugust 5, 2021 06:15
@notmandatorynotmandatory changed the title Single blockchain featureOnly allow enabling at most one blockchain client featureAug 5, 2021
@notmandatorynotmandatory changed the title Only allow enabling at most one blockchain client featureAllow enabling at most one blockchain client featureAug 5, 2021
@notmandatory
notmandatoryforce-pushed the single_blockchain_feature branch 2 times, most recently from f9cd936 to c81a99eCompareAugust 5, 2021 06:42
@notmandatory
notmandatory marked this pull request as ready for review August 5, 2021 06:43

@rajarshimaitrarajarshimaitra left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks @notmandatory for the PR, we are close almost. I just have a few more comments.

Is there any specific use of Repl mode here?

bdk-cli/src/lib.rs

Lines 258 to 262 in 378b33a

#[structopt(long_about = "REPL command loop mode")]
Repl{
#[structopt(flatten)]
wallet_opts:WalletOpts,
},

It just seems to be duplicating WalletOpts and no commands. If not we can remove this, it seems redundant.

One problem here is using --no-default-features will turn off repl too, which is required dep for the binary, so it will not compile any binary. This has been the crux of the problem because cargo doesn't let us selectively disable features. So if we disable default, it disables everything in default.

I think the only way to solve this problem is by having a very minimal default with only the stuffs that we need to create the minimal possible binary. And then add stuff to it with features flag. This will also remove the use of --no-default-feature if we only want esplora but not electrum.

So I propose something like this:

[features]
default = ["repl"]
repl = ["bdk/key-value-db", "clap", "dirs-next", "env_logger", "regex", "rustyline"]
electrum = ["bdk/electrum"]
esplora = ["bdk/esplora"]
compiler = ["bdk/compiler"]
async-interface = ["bdk/async-interface"]
compact_filters = ["bdk/compact_filters"]
[[bin]]
name = "bdk-cli"
path = "src/bdk_cli.rs"
required-features = ["repl"]

This will create the following builds

cargo build : build only repl stuffs, no backend
cargo build --features [backend] : build repl + [backend] blockchain.

I don't think there's any adverse effect of not having a blockchain by default. the only method we have with blockchain is sync and broadcast, everything else can be done without a blockchain. So it's safe to remove it in default.

@rajarshimaitra

rajarshimaitra commented Aug 5, 2021

Copy link
Copy Markdown
Contributor

Also, I am not sure if we should silently ignore "no binary built" scenarios in CI.

run: cargo build --features ${{ matrix.features }} --no-default-features

with current changes for example cargo build --features esplora --no-default-features will not build any binary, but the CI doesn't complain.

you can check that locally with

$ cargo clean
$ cargo build --features esplora --no-default-features
$ ./target/debug/bdk-cli wallet --help
bash: ./target/debug/bdk-cli: No such file or directory

I am not sure how then it's passing the tests without a binary.

@notmandatory

notmandatory commented Aug 6, 2021

Copy link
Copy Markdown
MemberAuthor

I think tests were passing because they only needed a lib build to run. But I agree it would be nice to not have to use the --no-default-features flag. I did the following to try and address this:

  1. split the repl feature into cli for the required dependencies to build the cli bin, and repl to enable the cli repl commands, then made the cli feature required to build the cli bin, but the cli and repl features on by default.
  2. added cfg statements so someone could build the cli without the repl command if they want fewer dependencies and use the --no-default-features flag
  3. update the CI to test with the default (no blockchain client) features, or each blockchain client, or the 'compiler' feature

@rajarshimaitrarajarshimaitra left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Code review ACK. This simplifies the issue.

I had the following observation. It seems if we compile the library using cargo build --features cli --no-default-features, that produces a binary that is perfectly workable with non backend wallet. It has functionality like this

$ ./target/debug/bdk-cli wallet --help
bdk-cli-wallet 0.2.1-dev
Wallet mode
USAGE:
bdk-cli wallet [FLAGS] [OPTIONS] --descriptor <DESCRIPTOR> <SUBCOMMAND>
FLAGS:
-v, --verbose Adds verbosity, returns PSBT in JSON format alongside serialized
-h, --help Prints help information
-V, --version Prints version information
OPTIONS:
-c, --change_descriptor <CHANGE_DESCRIPTOR> Sets the descriptor to use for internal addresses
-d, --descriptor <DESCRIPTOR> Sets the descriptor to use for the external addresses
-w, --wallet <WALLET_NAME> Selects the wallet to use [default: main]
SUBCOMMANDS:
bump_fee Bumps the fees of an RBF transaction
combine_psbt Combines multiple PSBTs into one
create_tx Creates a new unsigned transaction
extract_psbt Extracts a raw transaction from a PSBT
finalize_psbt Finalizes a PSBT
get_balance Returns the current wallet balance
get_new_address Generates a new external address
help Prints this message or the help of the given subcommand(s)
list_transactions Lists all the incoming and outgoing transactions of the wallet
list_unspent Lists the available spendable UTXOs
policies Returns the available spending policies for the descriptor
public_descriptor Returns the public version of the wallet's descriptor(s)
sign Signs and tries to finalize a PSBT

So that begs the question I had before, what do we need the repl thing for?

Also from here https://github.com/notmandatory/bdk-cli/blob/69b1d80bcd4715a3b78af4aafacebe2fc5ca2b88/src/bdk_cli.rs#L318-L331
it seems all a repl does is to perse existing commands and use them with either wallet or key functions. Maybe I am missing something, but I am not seeing any use of having the same methods called twice in different ways.

If two features cli and repl that does the same thing, it seems confusing to me.

Comment threadsrc/bdk_cli.rs Outdated
feature = "esplora",
any(feature = "electrum", feature = "compact_filters")
))]
compile_error!("Only one blockchain client feature can be enabled at a time.");

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It seems for every combination of electrum, esplora and compact_filters, this error is being duplicated with the one defined few lines below.

Instead, if we write it like this

#[cfg(all(
any( feature = "electrum", feature = "esplora", feature = "compact_filters"),
any( feature = "electrum", feature = "esplora", feature = "compact_filters")
))]

this will activate for any combination of the above three. And we won't need to specify compiler_error! multiple times.

Also for future extension, if we just add a new backend to the list above, that will taker care of multiple backend activation errors.

@notmandatorynotmandatoryAug 6, 2021

Copy link
Copy Markdown
MemberAuthor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Unfortunately the cfg all any any approach doesn't work, when I added this code:

#[cfg(all(any( feature = "electrum", feature = "esplora", feature = "compact_filters"),any( feature = "electrum", feature = "esplora", feature = "compact_filters")))]compile_error!("Only one blockchain client feature can be enabled at a time.");

I get the error even with only one blockchain client feature enabled (ie. cargo build --features esplora).

Looks like other's have had this same problem and are proposing a Rust RFC to allow a set of features to provide another feature in a mutually exclusive way.

Until mutually exclusive features are possible I can fix this in a simplistic way in the build.rs file as below or just leave it as it.. What do you think?

fnmain(){let electrum = env::var_os("CARGO_FEATURE_ELECTRUM").map(|_| "electrum".to_string());let esplora = env::var_os("CARGO_FEATURE_ESPLORA").map(|_| "esplora".to_string());let compact_filters = env::var_os("CARGO_FEATURE_COMPACT_FILTERS").map(|_| "compact_filters".to_string());let blockchain_features :Vec<String> = vec!(electrum, esplora, compact_filters).iter().map(|f| f.to_owned()).flatten().collect();if blockchain_features.len() > 1{panic!("At most one blockchain client feature can be enabled but these features were enabled: {:?}", blockchain_features)}}

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ah ok.. I thought it would work because my analyzer didn't throw. Yes there should be a way to handle mutually exclusive features in cargo itself.

I like the build script approach. It's clear and concise. Till it's available in cargo we can use a guard like above.

@rajarshimaitra

Copy link
Copy Markdown
Contributor

The following structure and function call could use feature guard. They exist in binary compiled without a backend, but are never used.

https://github.com/notmandatory/bdk-cli/blob/69b1d80bcd4715a3b78af4aafacebe2fc5ca2b88/src/lib.rs#L892

https://github.com/notmandatory/bdk-cli/blob/69b1d80bcd4715a3b78af4aafacebe2fc5ca2b88/src/lib.rs#L638

@notmandatory
notmandatoryforce-pushed the single_blockchain_feature branch from d3c0af3 to 9bb1c60CompareAugust 7, 2021 00:27

@rajarshimaitrarajarshimaitra left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

tACK 9bb1c60

With some minor nits.

Comment threadCHANGELOG.md Outdated
Comment threadCargo.toml
name = "bdk-cli"
path = "src/bdk_cli.rs"
required-features = ["repl", "electrum"]
required-features = ["cli"]

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is this required-features value necessary? By putting cli in default we are ensuring that the build will always include cli. (we also removed any necessity of using --no-default-features).

Copy link
Copy Markdown
MemberAuthor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think we still need cli as required to force anyone building the bin without repl (using --no-default-features) to still include cli.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ya makes sense.

Comment threadREADME.md Outdated
Comment threadREADME.md

```shell
cargo run -- wallet --descriptor "wpkh(tpubEBr4i6yk5nf5DAaJpsi9N2pPYBeJ7fZ5Z9rmN4977iYLCGco1VyjB9tvvuvYtfZzjD5A8igzgw3HeWeeKFmanHYqksqZXYXGsw5zjnj7KM9/*)" sync
cargo run --features electrum -- wallet --descriptor "wpkh(tpubEBr4i6yk5nf5DAaJpsi9N2pPYBeJ7fZ5Z9rmN4977iYLCGco1VyjB9tvvuvYtfZzjD5A8igzgw3HeWeeKFmanHYqksqZXYXGsw5zjnj7KM9/*)" sync

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Few lines ago we mentioned how to install bdk-cli with cargo.

Instructing to use cargo run here will build the local files instead of using the installed binary. So if someone is in their cloned repo, using cargo run they will actually build and then run the master branch instead of the release binary he just installed (this might be an unexpected behavior for the user, unless he knows cargo stuffs).

Even worse if someone didn't clone the repo, cargo run will not run anything, even if they have bdk-cli binary installed (and we don't have that instruction anywhere).

I think in the "bdk-cli bin usage examples" section, we should just instruct to use bdk-cli binary instead of crago run, which will make the instruction simpler also.

This doesn't have to be fixed here. Just mentioned as it occurred to me.

Copy link
Copy Markdown
MemberAuthor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I agree we should probably update the README to focus on installing with different features, and then usage with an installed version instead of using cargo run since anyone making local changes should already know how to use cargo. But let's do that cleanup in a different PR.

Comment threadsrc/lib.rs
@rajarshimaitra

Copy link
Copy Markdown
Contributor

ACK 062542a

@notmandatory
notmandatoryforce-pushed the single_blockchain_feature branch from 062542a to 7c4f5e7CompareAugust 12, 2021 14:13

@rajarshimaitrarajarshimaitra left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Code review with testing ACK 4fd39b7

@notmandatory
notmandatory merged commit 4fd39b7 into bitcoindevkit:masterAug 13, 2021
@notmandatory

Copy link
Copy Markdown
MemberAuthor

Thanks for the suggestions and review on this @rajarshimaitra, all ready to rebase your #36 PR.

Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants

@notmandatory@rajarshimaitra