diff --git a/lianad/src/commands/mod.rs b/lianad/src/commands/mod.rs index ff0e223e..1c9dabde 100644 --- a/lianad/src/commands/mod.rs +++ b/lianad/src/commands/mod.rs @@ -36,7 +36,11 @@ use std::{ }; use miniscript::{ - bitcoin::{self, address, bip32, psbt::Psbt}, + bitcoin::{ + self, address, + bip32::{self, ChildNumber}, + psbt::Psbt, + }, psbt::PsbtExt, }; use serde::{Deserialize, Serialize}; @@ -353,6 +357,39 @@ impl DaemonControl { GetAddressResult::new(address, index) } + /// Update derivation indexes + pub fn update_deriv_indexes( + &self, + receive: Option, + change: Option, + ) -> Result<(), CommandError> { + let mut db_conn = self.db.connection(); + + if let Some(index) = receive { + let child = match ChildNumber::from_normal_idx(index) { + Ok(i) => i, + Err(_) => return Err(CommandError::InvalidDerivationIndex), + }; + let db_receive = db_conn.receive_index(); + if child > db_receive { + db_conn.set_receive_index(child, &self.secp); + } + } + + if let Some(index) = change { + let child = match ChildNumber::from_normal_idx(index) { + Ok(i) => i, + Err(_) => return Err(CommandError::InvalidDerivationIndex), + }; + let db_change = db_conn.change_index(); + if child > db_change { + db_conn.set_change_index(child, &self.secp); + } + } + + Ok(()) + } + /// list addresses pub fn list_addresses( &self, diff --git a/lianad/src/jsonrpc/api.rs b/lianad/src/jsonrpc/api.rs index fe087a93..29a0ce85 100644 --- a/lianad/src/jsonrpc/api.rs +++ b/lianad/src/jsonrpc/api.rs @@ -199,6 +199,49 @@ fn list_addresses( Ok(serde_json::json!(&res)) } +fn update_deriv_indexes( + control: &DaemonControl, + params: Params, +) -> Result { + let receive = params.get(0, "receive"); + let change = params.get(1, "change"); + + if receive.is_none() && change.is_none() { + return Err(Error::invalid_params( + "Missing 'receive' or 'change' parameter", + )); + } + + let receive = match receive { + Some(i) => { + let res = i.as_i64().ok_or(Error::invalid_params( + "Invalid value for 'receive' param".to_string(), + ))?; + let res = res + .try_into() + .map_err(|_| Error::invalid_params("Invalid value for 'receive' param"))?; + Some(res) + } + None => None, + }; + + let change = match change { + Some(i) => { + let res = i.as_i64().ok_or(Error::invalid_params( + "Invalid value for 'change' param".to_string(), + ))?; + let res = res + .try_into() + .map_err(|_| Error::invalid_params("Invalid value for 'change' param"))?; + Some(res) + } + None => None, + }; + + control.update_deriv_indexes(receive, change)?; + Ok(serde_json::json!({})) +} + fn list_confirmed(control: &DaemonControl, params: Params) -> Result { let start: u32 = params .get(0, "start") @@ -417,6 +460,12 @@ pub fn handle_request(control: &mut DaemonControl, req: Request) -> Result serde_json::json!(&control.get_info()), "getnewaddress" => serde_json::json!(&control.get_new_address()), + "updatederivationindexes" => { + let params = req.params.ok_or_else(|| { + Error::invalid_params("Missing 'receive' or 'change' parameters.") + })?; + update_deriv_indexes(control, params)? + } "listcoins" => { let params = req.params; list_coins(control, params)?