Test walletdisplayaddress#539
Conversation
|
|
||
| assert_eq!(first_tx.fingerprint, "deadbeef"); | ||
| } | ||
|
|
||
| #[test] | ||
| #[cfg(unix)] | ||
| #[cfg(not(feature = "v21_and_below"))] | ||
| fn signer__wallet_display_address() { | ||
| use std::os::unix::fs::PermissionsExt; | ||
|
|
||
| let xpub = "tpubD6NzVbkrYhZ4WaWSyoBvQwbpLkojyoTZPRsgXELWz3Popb3qkjcJyJUGLnL4qHHoQvao8ESaAstxYSnhyswJ76uZPStJRJCTKvosUCJZL5B"; | ||
|
|
||
| // Mock signer script that handles `enumerate`, `getdescriptors`, and | ||
| // `displayaddress` sub-commands — the three commands bitcoind invokes when | ||
| // creating an external-signer wallet and then displaying an address. | ||
| let script_path = integration_test::random_tmp_file(); | ||
| let script_body = format!( | ||
| r#"#!/bin/sh | ||
| CMD="" | ||
| ACCOUNT="" | ||
| DESC="" | ||
| while [ $# -gt 0 ]; do | ||
| case "$1" in | ||
| --fingerprint) shift ;; | ||
| --chain) shift ;; | ||
| --account) ACCOUNT="$2'"; shift ;; | ||
| --desc) DESC="$2"; shift ;; | ||
| enumerate|getdescriptors|displayaddress) CMD="$1" ;; | ||
| esac | ||
| shift | ||
| done | ||
|
|
||
| case "$CMD" in | ||
| enumerate) | ||
| echo '[{{"fingerprint":"00000001","type":"trezor","model":"trezor_t"}}]' | ||
| ;; | ||
| getdescriptors) | ||
| cat <<EOF | ||
| {{"receive":["wpkh([00000001/84h/1h/${{ACCOUNT}}]{xpub}/0/*)#h62dxaej"],"internal":["wpkh([00000001/84h/1h/${{ACCOUNT}}]{xpub}/1/*)#xw0vmgf2"]}} | ||
| EOF | ||
| ;; | ||
| displayaddress) | ||
| case "$DESC" in | ||
| "wpkh([00000001/84h/1h/0h/0/0]02c97dc3f4420402e01a113984311bf4a1b8de376cac0bdcfaf1b3ac81f13433c7)#3te6hhy7"|"wpkh([00000001/84'/1'/0'/0/0]02c97dc3f4420402e01a113984311bf4a1b8de376cac0bdcfaf1b3ac81f13433c7)#0yneg42r") | ||
| echo '{{"address":"bcrt1qm90ugl4d48jv8n6e5t9ln6t9zlpm5th68x4f8g"}}' | ||
| ;; | ||
| *) | ||
| echo '{{"error":"Unexpected descriptor","desc":"'"$DESC"'"}}' | ||
| exit 1 | ||
| ;; | ||
| esac | ||
| ;; | ||
| *) | ||
| echo '{{"error":"Unknown command"}}' | ||
| exit 1 | ||
| ;; | ||
| esac | ||
| "# | ||
| ); | ||
| std::fs::write(&script_path, script_body).expect("write signer script"); | ||
| std::fs::set_permissions(&script_path, std::fs::Permissions::from_mode(0o755)).expect("chmod"); | ||
|
|
||
| let signer_arg = format!("-signer={}", script_path.to_str().unwrap()); | ||
| let node = Node::with_wallet(Wallet::None, &[&signer_arg]); | ||
|
|
||
| let _: node::serde_json::Value = node | ||
| .client | ||
| .call( | ||
| "createwallet", | ||
| &[ | ||
| "hww".into(), // wallet_name | ||
| true.into(), // disable_private_keys | ||
| false.into(), // blank | ||
| "".into(), // passphrase | ||
| false.into(), // avoid_reuse | ||
| true.into(), // descriptors | ||
| node::serde_json::Value::Null, // load_on_startup | ||
| true.into(), // external_signer | ||
| ], | ||
| ) | ||
| .expect("createwallet with external signer"); | ||
|
|
||
| let address = "bcrt1qm90ugl4d48jv8n6e5t9ln6t9zlpm5th68x4f8g"; | ||
| let json: WalletDisplayAddress = | ||
| node.client.wallet_display_address(address).expect("walletdisplayaddress"); | ||
| assert_eq!(json.address, address); | ||
| } |
There was a problem hiding this comment.
NIT: the multi-line inline script in Rust is awkward to read. Please move the mock signer to a fixture file (e.g. integration_test/tests/fixtures/mock_signer.sh), and load/copy it from the test. Then I’ll re-test and ACK.
There was a problem hiding this comment.
I get your point, It's ~11 lines now, does just what it should do, testwalletdisplayaddress, it should be easier on the eyes now?
There was a problem hiding this comment.
Thanks for addressing, seem fair.
c53f47d to
d599574
Compare
| let _: node::serde_json::Value = node | ||
| .client | ||
| .call( | ||
| "createwallet", | ||
| &[ | ||
| "hww".into(), // wallet_name | ||
| true.into(), // disable_private_keys | ||
| false.into(), // blank | ||
| "".into(), // passphrase | ||
| false.into(), // avoid_reuse | ||
| true.into(), // descriptors | ||
| node::serde_json::Value::Null, // load_on_startup | ||
| true.into(), // external_signer | ||
| ], | ||
| ) | ||
| .expect("createwallet with external signer"); |
There was a problem hiding this comment.
I rekon it would be better if we created a function create_wallet_external_signer in a macro impl_client_v22__create_wallet like we do for create_descriptor_wallet.
| let json: WalletDisplayAddress = | ||
| node.client.wallet_display_address(address).expect("walletdisplayaddress"); |
There was a problem hiding this comment.
Can you call into_model and explicitly return the error type as well please.
let json: LoadTxOutSet =
node_b.client.load_tx_out_set(dump_path).expect("loadtxoutset should succeed");
let model: Result<mtype::LoadTxOutSet, LoadTxOutSetError> = json.into_model();
let model = model.unwrap();d599574 to
1f2d935
Compare
1f2d935 to
b326c78
Compare
jamillambert
left a comment
There was a problem hiding this comment.
The test looks good. Just a few minor comments.
| crate::impl_client_v17__add_multisig_address!(); | ||
| crate::impl_client_v17__backup_wallet!(); | ||
| crate::impl_client_v17__bump_fee!(); | ||
| crate::impl_client_v22__create_wallet!(); |
There was a problem hiding this comment.
Nit. order by version. i.e. v21 before v22.
There was a problem hiding this comment.
I appreciate the nit 👏
| impl Client { | ||
| /// Creates a wallet with external_signer=true. | ||
| /// | ||
| /// > createwallet "wallet_name" ( disable_private_keys blank "passphrase" avoid_reuse descriptors load_on_startup ) |
There was a problem hiding this comment.
| /// > createwallet "wallet_name" ( disable_private_keys blank "passphrase" avoid_reuse descriptors load_on_startup ) | |
| /// > createwallet "wallet_name" ( disable_private_keys blank "passphrase" avoid_reuse descriptors load_on_startup external_signer ) |
| fn signer__wallet_display_address() { | ||
| use std::os::unix::fs::PermissionsExt; | ||
|
|
||
| let address = "bcrt1qm90ugl4d48jv8n6e5t9ln6t9zlpm5th68x4f8g"; |
There was a problem hiding this comment.
| let address = "bcrt1qm90ugl4d48jv8n6e5t9ln6t9zlpm5th68x4f8g"; | |
| // Mock address and xpub from Bitcoin Core's `wallet_signer.py`. | |
| let address = "bcrt1qm90ugl4d48jv8n6e5t9ln6t9zlpm5th68x4f8g"; |
Or some other comment to where they came from.
|
|
||
| let json: WalletDisplayAddress = | ||
| node.client.wallet_display_address(address).expect("walletdisplayaddress"); | ||
| assert_eq!(json.address, address); |
There was a problem hiding this comment.
| assert_eq!(json.address, address); |
This is redundant, the modelled address is checked below.
There was a problem hiding this comment.
true, has been dropped 👍
b326c78 to
4c9c960
Compare
| crate::impl_client_v21__create_wallet!(); | ||
| crate::impl_client_v22__create_wallet!(); |
There was a problem hiding this comment.
This is surprising, I'd expect there to be just a single macro that implements createwallet.
|
hmm the Perhaps we should have a patch at the front of this PR that removes the @jamillambert do you have an opinion on this? We could also just merge this as is and fix as a follow up. |
|
|
Implement `create_wallet_external_signer` for creating wallets that can interact with external signers e.g. hardware wallet. Add an integration test `signer__wallet_display_address` to verify the functionality of the `walletdisplayaddress` RPC call when using an external signer. The test mocks a Hardware Wallet (HWW) interaction by: 1. Creating a temporary shell script that acts as an external signer. 2. Handling the 'enumerate', 'getdescriptors', and 'displayaddress' commands expected by Bitcoin Core. 3. Spawning a node with the `-signer` argument pointing to this mock. 4. Creating a descriptor-based wallet with `external_signer` enabled. 5. Asserting that calling `wallet_display_address` returns the expected address from the mock signer. Drop all `UNTESTED` for `walletdisplayaddress` RPC
4c9c960 to
df26039
Compare
Yeah, it's the only macro that has multiple version definitions at the same time. I wasn't sure if duplicating all the code in the v21 macro in v22 and so on is better or not. What is done here is functionally fine and can be cleaned up in a follow up. |
Works for me. |
signer__wallet_display_addresstestswalletdisplayaddressRPC call mocking an external signer.The test mocks a Hardware Wallet (HWW) interaction by:
-signerargument pointing to this mock.external_signerenabled.wallet_display_addressreturns the expected address from the mock signer.Heavily Inspired by wallet_signer.py