diff --git a/.github/workflows/rust.yml b/.github/workflows/rust.yml index 5c41512e..9bff8eb2 100644 --- a/.github/workflows/rust.yml +++ b/.github/workflows/rust.yml @@ -27,7 +27,8 @@ jobs: profile: minimal toolchain: ${{ matrix.rust }} override: true - - run: cargo update -p serde --precise 1.0.152 + - run: cargo update -p serde_json --precise 1.0.100 + - run: cargo update -p serde --precise 1.0.189 - name: Running test script env: ${{ matrix.env }} run: ./contrib/test.sh diff --git a/client/src/client.rs b/client/src/client.rs index edb71e30..378624c1 100644 --- a/client/src/client.rs +++ b/client/src/client.rs @@ -284,18 +284,54 @@ pub trait RpcApi: Sized { blank: Option, passphrase: Option<&str>, avoid_reuse: Option, + descriptors: Option, ) -> Result { - let mut args = [ - wallet.into(), - opt_into_json(disable_private_keys)?, - opt_into_json(blank)?, - opt_into_json(passphrase)?, - opt_into_json(avoid_reuse)?, - ]; - self.call( - "createwallet", - handle_defaults(&mut args, &[false.into(), false.into(), into_json("")?, false.into()]), - ) + // the descriptors argument was added in version 21 + if self.version()? < 210000 { + // note: we allow Some(false) since it's the default behavior + if let Some(true) = descriptors { + return Err(Error::UnsupportedArgument("createwallet", "descriptors")); + } + // no descriptors argument yet + let mut args = [ + wallet.into(), + opt_into_json(disable_private_keys)?, + opt_into_json(blank)?, + opt_into_json(passphrase)?, + opt_into_json(avoid_reuse)?, + ]; + self.call( + "createwallet", + handle_defaults( + &mut args, + &[false.into(), false.into(), into_json("")?, false.into()], + ), + ) + } else { + let mut args = [ + wallet.into(), + opt_into_json(disable_private_keys)?, + opt_into_json(blank)?, + opt_into_json(passphrase)?, + opt_into_json(avoid_reuse)?, + opt_into_json(descriptors)?, + ]; + // from 23 on, the default value of the descriptors argument is true + let default_descriptors = self.version()? >= 230000; + self.call( + "createwallet", + handle_defaults( + &mut args, + &[ + false.into(), + false.into(), + into_json("")?, + false.into(), + default_descriptors.into(), + ], + ), + ) + } } fn list_wallets(&self) -> Result> { diff --git a/client/src/error.rs b/client/src/error.rs index 9ac04fea..16a08901 100644 --- a/client/src/error.rs +++ b/client/src/error.rs @@ -31,6 +31,8 @@ pub enum Error { UnexpectedStructure, /// The daemon returned an error string. ReturnedError(String), + /// The {0} RPC does not support the {1} argument on the connected bitcoin version. + UnsupportedArgument(&'static str, &'static str), } impl From for Error { @@ -88,6 +90,9 @@ impl fmt::Display for Error { Error::InvalidCookieFile => write!(f, "invalid cookie file"), Error::UnexpectedStructure => write!(f, "the JSON result had an unexpected structure"), Error::ReturnedError(ref s) => write!(f, "the daemon returned an error string: {}", s), + Error::UnsupportedArgument(rpc, arg) => { + write!(f, "the daemon version does not support the {} argument for {}", arg, rpc) + } } } } diff --git a/integration_test/src/main.rs b/integration_test/src/main.rs index d9f4dca7..7bd591eb 100644 --- a/integration_test/src/main.rs +++ b/integration_test/src/main.rs @@ -140,7 +140,7 @@ fn main() { unsafe { VERSION = cl.version().unwrap() }; println!("Version: {}", version()); - cl.create_wallet("testwallet", None, None, None, None).unwrap(); + cl.create_wallet("testwallet", None, None, None, None, None).unwrap(); test_get_mining_info(&cl); test_get_blockchain_info(&cl); @@ -1074,6 +1074,7 @@ fn test_create_wallet(cl: &Client) { blank: Option, passphrase: Option<&'a str>, avoid_reuse: Option, + descriptor: Option, } let mut wallet_params = vec![ @@ -1083,6 +1084,7 @@ fn test_create_wallet(cl: &Client) { blank: None, passphrase: None, avoid_reuse: None, + descriptor: None, }, WalletParams { name: wallet_names[1], @@ -1090,6 +1092,7 @@ fn test_create_wallet(cl: &Client) { blank: None, passphrase: None, avoid_reuse: None, + descriptor: None, }, WalletParams { name: wallet_names[2], @@ -1097,6 +1100,7 @@ fn test_create_wallet(cl: &Client) { blank: Some(true), passphrase: None, avoid_reuse: None, + descriptor: None, }, ]; @@ -1107,6 +1111,7 @@ fn test_create_wallet(cl: &Client) { blank: None, passphrase: Some("pass"), avoid_reuse: None, + descriptor: None, }); wallet_params.push(WalletParams { name: wallet_names[4], @@ -1114,6 +1119,7 @@ fn test_create_wallet(cl: &Client) { blank: None, passphrase: None, avoid_reuse: Some(true), + descriptor: Some(false), }); } @@ -1125,6 +1131,7 @@ fn test_create_wallet(cl: &Client) { wallet_param.blank, wallet_param.passphrase, wallet_param.avoid_reuse, + wallet_param.descriptor, ) .unwrap(); @@ -1278,7 +1285,7 @@ fn test_getblocktemplate(cl: &Client) { } fn test_unloadwallet(cl: &Client) { - cl.create_wallet("testunloadwallet", None, None, None, None).unwrap(); + cl.create_wallet("testunloadwallet", None, None, None, None, None).unwrap(); let res = new_wallet_client("testunloadwallet") .unload_wallet(None) @@ -1296,7 +1303,7 @@ fn test_loadwallet(_: &Client) { let wallet_client = new_wallet_client(wallet_name); assert!(wallet_client.load_wallet(wallet_name).is_err()); - wallet_client.create_wallet(wallet_name, None, None, None, None).unwrap(); + wallet_client.create_wallet(wallet_name, None, None, None, None, None).unwrap(); assert!(wallet_client.load_wallet(wallet_name).is_err()); wallet_client.unload_wallet(None).unwrap(); @@ -1311,7 +1318,7 @@ fn test_backupwallet(_: &Client) { assert!(wallet_client.backup_wallet(None).is_err()); assert!(wallet_client.backup_wallet(Some(&backup_path)).is_err()); - wallet_client.create_wallet("testbackupwallet", None, None, None, None).unwrap(); + wallet_client.create_wallet("testbackupwallet", None, None, None, None, None).unwrap(); assert!(wallet_client.backup_wallet(None).is_err()); assert!(wallet_client.backup_wallet(Some(&backup_path)).is_ok()); }