1use std::collections::HashMap;
12use std::fs::File;
13use std::iter::FromIterator;
14use std::path::PathBuf;
15use std::{fmt, result};
16
17use crate::{bitcoint4, deserialize_hex};
18use bitcoin_private::hex::exts::DisplayHex;
19use jsonrpc;
20use serde;
21use serde_json;
22
23use crate::bitcoint4::address::{NetworkChecked, NetworkUnchecked};
24use crate::bitcoint4::hashes::hex::FromHex;
25use crate::bitcoint4::secp256k1::ecdsa::Signature;
26use crate::bitcoint4::{
27 Address, Amount, Block, OutPoint, PrivateKey, PublicKey, Script, Transaction,
28};
29use log::Level::{Debug, Trace, Warn};
30
31use crate::error::*;
32use crate::json;
33use crate::queryable;
34
35pub type Result<T> = result::Result<T, Error>;
38
39#[derive(Clone, Debug, Serialize, Deserialize)]
42pub struct JsonOutPoint {
43 pub txid: bitcoint4::Txid,
44 pub vout: u32,
45}
46
47impl From<OutPoint> for JsonOutPoint {
48 fn from(o: OutPoint) -> JsonOutPoint {
49 JsonOutPoint {
50 txid: o.txid,
51 vout: o.vout,
52 }
53 }
54}
55
56impl Into<OutPoint> for JsonOutPoint {
57 fn into(self) -> OutPoint {
58 OutPoint {
59 txid: self.txid,
60 vout: self.vout,
61 }
62 }
63}
64
65fn into_json<T>(val: T) -> Result<serde_json::Value>
67where
68 T: serde::ser::Serialize,
69{
70 Ok(serde_json::to_value(val)?)
71}
72
73fn opt_into_json<T>(opt: Option<T>) -> Result<serde_json::Value>
75where
76 T: serde::ser::Serialize,
77{
78 match opt {
79 Some(val) => Ok(into_json(val)?),
80 None => Ok(serde_json::Value::Null),
81 }
82}
83
84fn null() -> serde_json::Value {
86 serde_json::Value::Null
87}
88
89fn empty_arr() -> serde_json::Value {
91 serde_json::Value::Array(vec![])
92}
93
94fn empty_obj() -> serde_json::Value {
96 serde_json::Value::Object(Default::default())
97}
98
99fn handle_defaults<'a, 'b>(
115 args: &'a mut [serde_json::Value],
116 defaults: &'b [serde_json::Value],
117) -> &'a [serde_json::Value] {
118 assert!(args.len() >= defaults.len());
119
120 let mut first_non_null_optional_idx = None;
123 for i in 0..defaults.len() {
124 let args_i = args.len() - 1 - i;
125 let defaults_i = defaults.len() - 1 - i;
126 if args[args_i] == serde_json::Value::Null {
127 if first_non_null_optional_idx.is_some() {
128 if defaults[defaults_i] == serde_json::Value::Null {
129 panic!("Missing `default` for argument idx {}", args_i);
130 }
131 args[args_i] = defaults[defaults_i].clone();
132 }
133 } else if first_non_null_optional_idx.is_none() {
134 first_non_null_optional_idx = Some(args_i);
135 }
136 }
137
138 let required_num = args.len() - defaults.len();
139
140 if let Some(i) = first_non_null_optional_idx {
141 &args[..i + 1]
142 } else {
143 &args[..required_num]
144 }
145}
146
147fn opt_result<T: for<'a> serde::de::Deserialize<'a>>(
149 result: serde_json::Value,
150) -> Result<Option<T>> {
151 if result == serde_json::Value::Null {
152 Ok(None)
153 } else {
154 Ok(serde_json::from_value(result)?)
155 }
156}
157
158pub trait RawTx: Sized + Clone {
160 fn raw_hex(self) -> String;
161}
162
163impl<'a> RawTx for &'a Transaction {
164 fn raw_hex(self) -> String {
165 bitcoint4::consensus::encode::serialize_hex(self)
166 }
167}
168
169impl<'a> RawTx for &'a [u8] {
170 fn raw_hex(self) -> String {
171 self.to_lower_hex_string()
172 }
173}
174
175impl<'a> RawTx for &'a Vec<u8> {
176 fn raw_hex(self) -> String {
177 self.to_lower_hex_string()
178 }
179}
180
181impl<'a> RawTx for &'a str {
182 fn raw_hex(self) -> String {
183 self.to_owned()
184 }
185}
186
187impl RawTx for String {
188 fn raw_hex(self) -> String {
189 self
190 }
191}
192
193#[derive(Clone, Debug, Hash, Eq, PartialEq, Ord, PartialOrd)]
195pub enum Auth {
196 None,
197 UserPass(String, String),
198 CookieFile(PathBuf),
199}
200
201impl Auth {
202 pub fn get_user_pass(self) -> Result<(Option<String>, Option<String>)> {
204 use std::io::Read;
205 match self {
206 Auth::None => Ok((None, None)),
207 Auth::UserPass(u, p) => Ok((Some(u), Some(p))),
208 Auth::CookieFile(path) => {
209 let mut file = File::open(path)?;
210 let mut contents = String::new();
211 file.read_to_string(&mut contents)?;
212 let mut split = contents.splitn(2, ":");
213 Ok((
214 Some(split.next().ok_or(Error::InvalidCookieFile)?.into()),
215 Some(split.next().ok_or(Error::InvalidCookieFile)?.into()),
216 ))
217 }
218 }
219 }
220}
221
222pub trait RpcApi: Sized {
223 fn call<T: for<'a> serde::de::Deserialize<'a>>(
225 &self,
226 cmd: &str,
227 args: &[serde_json::Value],
228 ) -> Result<T>;
229
230 fn get_by_id<T: queryable::Queryable<Self>>(
232 &self,
233 id: &<T as queryable::Queryable<Self>>::Id,
234 ) -> Result<T> {
235 T::query(&self, &id)
236 }
237
238 fn get_network_info(&self) -> Result<json::GetNetworkInfoResult> {
239 self.call("getnetworkinfo", &[])
240 }
241
242 fn get_index_info(&self) -> Result<json::GetIndexInfoResult> {
243 self.call("getindexinfo", &[])
244 }
245
246 fn version(&self) -> Result<usize> {
247 #[derive(Deserialize)]
248 struct Response {
249 pub version: usize,
250 }
251 let res: Response = self.call("getnetworkinfo", &[])?;
252 Ok(res.version)
253 }
254
255 fn add_multisig_address(
256 &self,
257 nrequired: usize,
258 keys: &[json::PubKeyOrAddress],
259 label: Option<&str>,
260 address_type: Option<json::AddressType>,
261 ) -> Result<json::AddMultiSigAddressResult> {
262 let mut args = [
263 into_json(nrequired)?,
264 into_json(keys)?,
265 opt_into_json(label)?,
266 opt_into_json(address_type)?,
267 ];
268 self.call("addmultisigaddress", handle_defaults(&mut args, &[into_json("")?, null()]))
269 }
270
271 fn load_wallet(&self, wallet: &str) -> Result<json::LoadWalletResult> {
272 self.call("loadwallet", &[wallet.into()])
273 }
274
275 fn unload_wallet(&self, wallet: Option<&str>) -> Result<Option<json::UnloadWalletResult>> {
276 let mut args = [opt_into_json(wallet)?];
277 self.call("unloadwallet", handle_defaults(&mut args, &[null()]))
278 }
279
280 fn create_wallet(
281 &self,
282 wallet: &str,
283 disable_private_keys: Option<bool>,
284 blank: Option<bool>,
285 passphrase: Option<&str>,
286 avoid_reuse: Option<bool>,
287 ) -> Result<json::LoadWalletResult> {
288 let mut args = [
289 wallet.into(),
290 opt_into_json(disable_private_keys)?,
291 opt_into_json(blank)?,
292 opt_into_json(passphrase)?,
293 opt_into_json(avoid_reuse)?,
294 ];
295 self.call(
296 "createwallet",
297 handle_defaults(&mut args, &[false.into(), false.into(), into_json("")?, false.into()]),
298 )
299 }
300
301 fn list_wallets(&self) -> Result<Vec<String>> {
302 self.call("listwallets", &[])
303 }
304
305 fn list_wallet_dir(&self) -> Result<Vec<String>> {
306 let result: json::ListWalletDirResult = self.call("listwalletdir", &[])?;
307 let names = result.wallets.into_iter().map(|x| x.name).collect();
308 Ok(names)
309 }
310
311 fn get_wallet_info(&self) -> Result<json::GetWalletInfoResult> {
312 self.call("getwalletinfo", &[])
313 }
314
315 fn backup_wallet(&self, destination: Option<&str>) -> Result<()> {
316 let mut args = [opt_into_json(destination)?];
317 self.call("backupwallet", handle_defaults(&mut args, &[null()]))
318 }
319
320 fn dump_private_key(&self, address: &Address) -> Result<PrivateKey> {
321 self.call("dumpprivkey", &[address.to_string().into()])
322 }
323
324 fn encrypt_wallet(&self, passphrase: &str) -> Result<()> {
325 self.call("encryptwallet", &[into_json(passphrase)?])
326 }
327
328 fn get_difficulty(&self) -> Result<f64> {
329 self.call("getdifficulty", &[])
330 }
331
332 fn get_connection_count(&self) -> Result<usize> {
333 self.call("getconnectioncount", &[])
334 }
335
336 fn get_block(&self, hash: &bitcoint4::BlockHash) -> Result<Block> {
337 let hex: String = self.call("getblock", &[into_json(hash)?, 0.into()])?;
338 deserialize_hex(&hex)
339 }
340
341 fn get_block_hex(&self, hash: &bitcoint4::BlockHash) -> Result<String> {
342 self.call("getblock", &[into_json(hash)?, 0.into()])
343 }
344
345 fn get_block_info(&self, hash: &bitcoint4::BlockHash) -> Result<json::GetBlockResult> {
346 self.call("getblock", &[into_json(hash)?, 1.into()])
347 }
348 fn get_block_header(&self, hash: &bitcoint4::BlockHash) -> Result<bitcoint4::block::Header> {
351 let hex: String = self.call("getblockheader", &[into_json(hash)?, false.into()])?;
352 deserialize_hex(&hex)
353 }
354
355 fn get_block_header_info(
356 &self,
357 hash: &bitcoint4::BlockHash,
358 ) -> Result<json::GetBlockHeaderResult> {
359 self.call("getblockheader", &[into_json(hash)?, true.into()])
360 }
361
362 fn get_mining_info(&self) -> Result<json::GetMiningInfoResult> {
363 self.call("getmininginfo", &[])
364 }
365
366 fn get_block_template(
367 &self,
368 mode: json::GetBlockTemplateModes,
369 rules: &[json::GetBlockTemplateRules],
370 capabilities: &[json::GetBlockTemplateCapabilities],
371 ) -> Result<json::GetBlockTemplateResult> {
372 #[derive(Serialize)]
373 struct Argument<'a> {
374 mode: json::GetBlockTemplateModes,
375 rules: &'a [json::GetBlockTemplateRules],
376 capabilities: &'a [json::GetBlockTemplateCapabilities],
377 }
378
379 self.call(
380 "getblocktemplate",
381 &[into_json(Argument {
382 mode: mode,
383 rules: rules,
384 capabilities: capabilities,
385 })?],
386 )
387 }
388
389 fn get_blockchain_info(&self) -> Result<json::GetBlockchainInfoResult> {
392 let mut raw: serde_json::Value = self.call("getblockchaininfo", &[])?;
393 Ok(if self.version()? < 190000 {
397 use crate::Error::UnexpectedStructure as err;
398
399 let (bip9_softforks, old_softforks) = {
402 let map = raw.as_object_mut().ok_or(err)?;
403 let bip9_softforks = map.remove("bip9_softforks").ok_or(err)?;
404 let old_softforks = map.remove("softforks").ok_or(err)?;
405 map.insert("softforks".into(), serde_json::Map::new().into());
407 (bip9_softforks, old_softforks)
408 };
409 let mut ret: json::GetBlockchainInfoResult = serde_json::from_value(raw)?;
410
411 for sf in old_softforks.as_array().ok_or(err)?.iter() {
413 let json = sf.as_object().ok_or(err)?;
414 let id = json.get("id").ok_or(err)?.as_str().ok_or(err)?;
415 let reject = json.get("reject").ok_or(err)?.as_object().ok_or(err)?;
416 let active = reject.get("status").ok_or(err)?.as_bool().ok_or(err)?;
417 ret.softforks.insert(
418 id.into(),
419 json::Softfork {
420 type_: json::SoftforkType::Buried,
421 bip9: None,
422 height: None,
423 active: active,
424 },
425 );
426 }
427 for (id, sf) in bip9_softforks.as_object().ok_or(err)?.iter() {
428 #[derive(Deserialize)]
429 struct OldBip9SoftFork {
430 pub status: json::Bip9SoftforkStatus,
431 pub bit: Option<u8>,
432 #[serde(rename = "startTime")]
433 pub start_time: i64,
434 pub timeout: u64,
435 pub since: u32,
436 pub statistics: Option<json::Bip9SoftforkStatistics>,
437 }
438 let sf: OldBip9SoftFork = serde_json::from_value(sf.clone())?;
439 ret.softforks.insert(
440 id.clone(),
441 json::Softfork {
442 type_: json::SoftforkType::Bip9,
443 bip9: Some(json::Bip9SoftforkInfo {
444 status: sf.status,
445 bit: sf.bit,
446 start_time: sf.start_time,
447 timeout: sf.timeout,
448 since: sf.since,
449 statistics: sf.statistics,
450 }),
451 height: None,
452 active: sf.status == json::Bip9SoftforkStatus::Active,
453 },
454 );
455 }
456 ret
457 } else {
458 serde_json::from_value(raw)?
459 })
460 }
461
462 fn get_block_count(&self) -> Result<u64> {
464 self.call("getblockcount", &[])
465 }
466
467 fn get_best_block_hash(&self) -> Result<bitcoint4::BlockHash> {
469 self.call("getbestblockhash", &[])
470 }
471
472 fn get_block_hash(&self, height: u64) -> Result<bitcoint4::BlockHash> {
474 self.call("getblockhash", &[height.into()])
475 }
476
477 fn get_block_stats(&self, height: u64) -> Result<json::GetBlockStatsResult> {
478 self.call("getblockstats", &[height.into()])
479 }
480
481 fn get_block_stats_fields(
482 &self,
483 height: u64,
484 fields: &[json::BlockStatsFields],
485 ) -> Result<json::GetBlockStatsResultPartial> {
486 self.call("getblockstats", &[height.into(), fields.into()])
487 }
488
489 fn get_raw_transaction(
490 &self,
491 txid: &bitcoint4::Txid,
492 block_hash: Option<&bitcoint4::BlockHash>,
493 ) -> Result<Transaction> {
494 let mut args = [into_json(txid)?, into_json(false)?, opt_into_json(block_hash)?];
495 let hex: String = self.call("getrawtransaction", handle_defaults(&mut args, &[null()]))?;
496 deserialize_hex(&hex)
497 }
498
499 fn get_raw_transaction_hex(
500 &self,
501 txid: &bitcoint4::Txid,
502 block_hash: Option<&bitcoint4::BlockHash>,
503 ) -> Result<String> {
504 let mut args = [into_json(txid)?, into_json(false)?, opt_into_json(block_hash)?];
505 self.call("getrawtransaction", handle_defaults(&mut args, &[null()]))
506 }
507
508 fn get_raw_transaction_info(
509 &self,
510 txid: &bitcoint4::Txid,
511 block_hash: Option<&bitcoint4::BlockHash>,
512 ) -> Result<json::GetRawTransactionResult> {
513 let mut args = [into_json(txid)?, into_json(true)?, opt_into_json(block_hash)?];
514 self.call("getrawtransaction", handle_defaults(&mut args, &[null()]))
515 }
516
517 fn get_block_filter(
518 &self,
519 block_hash: &bitcoint4::BlockHash,
520 ) -> Result<json::GetBlockFilterResult> {
521 self.call("getblockfilter", &[into_json(block_hash)?])
522 }
523
524 fn get_balance(
525 &self,
526 minconf: Option<usize>,
527 include_watchonly: Option<bool>,
528 ) -> Result<Amount> {
529 let mut args = ["*".into(), opt_into_json(minconf)?, opt_into_json(include_watchonly)?];
530 Ok(Amount::from_btc(
531 self.call("getbalance", handle_defaults(&mut args, &[0.into(), null()]))?,
532 )?)
533 }
534
535 fn get_balances(&self) -> Result<json::GetBalancesResult> {
536 Ok(self.call("getbalances", &[])?)
537 }
538
539 fn get_received_by_address(&self, address: &Address, minconf: Option<u32>) -> Result<Amount> {
540 let mut args = [address.to_string().into(), opt_into_json(minconf)?];
541 Ok(Amount::from_btc(
542 self.call("getreceivedbyaddress", handle_defaults(&mut args, &[null()]))?,
543 )?)
544 }
545
546 fn get_transaction(
547 &self,
548 txid: &bitcoint4::Txid,
549 include_watchonly: Option<bool>,
550 ) -> Result<json::GetTransactionResult> {
551 let mut args = [into_json(txid)?, opt_into_json(include_watchonly)?];
552 self.call("gettransaction", handle_defaults(&mut args, &[null()]))
553 }
554
555 fn list_transactions(
556 &self,
557 label: Option<&str>,
558 count: Option<usize>,
559 skip: Option<usize>,
560 include_watchonly: Option<bool>,
561 ) -> Result<Vec<json::ListTransactionResult>> {
562 let mut args = [
563 label.unwrap_or("*").into(),
564 opt_into_json(count)?,
565 opt_into_json(skip)?,
566 opt_into_json(include_watchonly)?,
567 ];
568 self.call("listtransactions", handle_defaults(&mut args, &[10.into(), 0.into(), null()]))
569 }
570
571 fn list_since_block(
572 &self,
573 blockhash: Option<&bitcoint4::BlockHash>,
574 target_confirmations: Option<usize>,
575 include_watchonly: Option<bool>,
576 include_removed: Option<bool>,
577 ) -> Result<json::ListSinceBlockResult> {
578 let mut args = [
579 opt_into_json(blockhash)?,
580 opt_into_json(target_confirmations)?,
581 opt_into_json(include_watchonly)?,
582 opt_into_json(include_removed)?,
583 ];
584 self.call("listsinceblock", handle_defaults(&mut args, &[null()]))
585 }
586
587 fn get_tx_out(
588 &self,
589 txid: &bitcoint4::Txid,
590 vout: u32,
591 include_mempool: Option<bool>,
592 ) -> Result<Option<json::GetTxOutResult>> {
593 let mut args = [into_json(txid)?, into_json(vout)?, opt_into_json(include_mempool)?];
594 opt_result(self.call("gettxout", handle_defaults(&mut args, &[null()]))?)
595 }
596
597 fn get_tx_out_proof(
598 &self,
599 txids: &[bitcoint4::Txid],
600 block_hash: Option<&bitcoint4::BlockHash>,
601 ) -> Result<Vec<u8>> {
602 let mut args = [into_json(txids)?, opt_into_json(block_hash)?];
603 let hex: String = self.call("gettxoutproof", handle_defaults(&mut args, &[null()]))?;
604 Ok(FromHex::from_hex(&hex)?)
605 }
606
607 fn import_public_key(
608 &self,
609 pubkey: &PublicKey,
610 label: Option<&str>,
611 rescan: Option<bool>,
612 ) -> Result<()> {
613 let mut args = [pubkey.to_string().into(), opt_into_json(label)?, opt_into_json(rescan)?];
614 self.call("importpubkey", handle_defaults(&mut args, &[into_json("")?, null()]))
615 }
616
617 fn import_private_key(
618 &self,
619 privkey: &PrivateKey,
620 label: Option<&str>,
621 rescan: Option<bool>,
622 ) -> Result<()> {
623 let mut args = [privkey.to_string().into(), opt_into_json(label)?, opt_into_json(rescan)?];
624 self.call("importprivkey", handle_defaults(&mut args, &[into_json("")?, null()]))
625 }
626
627 fn import_address(
628 &self,
629 address: &Address,
630 label: Option<&str>,
631 rescan: Option<bool>,
632 ) -> Result<()> {
633 let mut args = [address.to_string().into(), opt_into_json(label)?, opt_into_json(rescan)?];
634 self.call("importaddress", handle_defaults(&mut args, &[into_json("")?, null()]))
635 }
636
637 fn import_address_script(
638 &self,
639 script: &Script,
640 label: Option<&str>,
641 rescan: Option<bool>,
642 p2sh: Option<bool>,
643 ) -> Result<()> {
644 let mut args = [
645 script.to_hex_string().into(),
646 opt_into_json(label)?,
647 opt_into_json(rescan)?,
648 opt_into_json(p2sh)?,
649 ];
650 self.call(
651 "importaddress",
652 handle_defaults(&mut args, &[into_json("")?, true.into(), null()]),
653 )
654 }
655
656 fn import_multi(
657 &self,
658 requests: &[json::ImportMultiRequest],
659 options: Option<&json::ImportMultiOptions>,
660 ) -> Result<Vec<json::ImportMultiResult>> {
661 let mut json_requests = Vec::with_capacity(requests.len());
662 for req in requests {
663 json_requests.push(serde_json::to_value(req)?);
664 }
665 let mut args = [json_requests.into(), opt_into_json(options)?];
666 self.call("importmulti", handle_defaults(&mut args, &[null()]))
667 }
668
669 fn import_descriptors(
670 &self,
671 req: json::ImportDescriptors,
672 ) -> Result<Vec<json::ImportMultiResult>> {
673 let json_request = vec![serde_json::to_value(req)?];
674 self.call("importdescriptors", handle_defaults(&mut [json_request.into()], &[null()]))
675 }
676
677 fn set_label(&self, address: &Address, label: &str) -> Result<()> {
678 self.call("setlabel", &[address.to_string().into(), label.into()])
679 }
680
681 fn key_pool_refill(&self, new_size: Option<usize>) -> Result<()> {
682 let mut args = [opt_into_json(new_size)?];
683 self.call("keypoolrefill", handle_defaults(&mut args, &[null()]))
684 }
685
686 fn list_unspent(
687 &self,
688 minconf: Option<usize>,
689 maxconf: Option<usize>,
690 addresses: Option<&[&Address<NetworkChecked>]>,
691 include_unsafe: Option<bool>,
692 query_options: Option<json::ListUnspentQueryOptions>,
693 ) -> Result<Vec<json::ListUnspentResultEntry>> {
694 let mut args = [
695 opt_into_json(minconf)?,
696 opt_into_json(maxconf)?,
697 opt_into_json(addresses)?,
698 opt_into_json(include_unsafe)?,
699 opt_into_json(query_options)?,
700 ];
701 let defaults = [into_json(0)?, into_json(9999999)?, empty_arr(), into_json(true)?, null()];
702 self.call("listunspent", handle_defaults(&mut args, &defaults))
703 }
704
705 fn lock_unspent(&self, outputs: &[OutPoint]) -> Result<bool> {
707 let outputs: Vec<_> = outputs
708 .into_iter()
709 .map(|o| serde_json::to_value(JsonOutPoint::from(*o)).unwrap())
710 .collect();
711 self.call("lockunspent", &[false.into(), outputs.into()])
712 }
713
714 fn unlock_unspent(&self, outputs: &[OutPoint]) -> Result<bool> {
715 let outputs: Vec<_> = outputs
716 .into_iter()
717 .map(|o| serde_json::to_value(JsonOutPoint::from(*o)).unwrap())
718 .collect();
719 self.call("lockunspent", &[true.into(), outputs.into()])
720 }
721
722 fn unlock_unspent_all(&self) -> Result<bool> {
724 self.call("lockunspent", &[true.into()])
725 }
726
727 fn list_received_by_address(
728 &self,
729 address_filter: Option<&Address>,
730 minconf: Option<u32>,
731 include_empty: Option<bool>,
732 include_watchonly: Option<bool>,
733 ) -> Result<Vec<json::ListReceivedByAddressResult>> {
734 let mut args = [
735 opt_into_json(minconf)?,
736 opt_into_json(include_empty)?,
737 opt_into_json(include_watchonly)?,
738 opt_into_json(address_filter)?,
739 ];
740 let defaults = [1.into(), false.into(), false.into(), null()];
741 self.call("listreceivedbyaddress", handle_defaults(&mut args, &defaults))
742 }
743
744 fn create_psbt(
745 &self,
746 inputs: &[json::CreateRawTransactionInput],
747 outputs: &HashMap<String, Amount>,
748 locktime: Option<i64>,
749 replaceable: Option<bool>,
750 ) -> Result<String> {
751 let outs_converted = serde_json::Map::from_iter(
752 outputs.iter().map(|(k, v)| (k.clone(), serde_json::Value::from(v.to_btc()))),
753 );
754 self.call(
755 "createpsbt",
756 &[
757 into_json(inputs)?,
758 into_json(outs_converted)?,
759 into_json(locktime)?,
760 into_json(replaceable)?,
761 ],
762 )
763 }
764
765 fn create_raw_transaction_hex(
766 &self,
767 utxos: &[json::CreateRawTransactionInput],
768 outs: &HashMap<String, Amount>,
769 locktime: Option<i64>,
770 replaceable: Option<bool>,
771 ) -> Result<String> {
772 let outs_converted = serde_json::Map::from_iter(
773 outs.iter().map(|(k, v)| (k.clone(), serde_json::Value::from(v.to_btc()))),
774 );
775 let mut args = [
776 into_json(utxos)?,
777 into_json(outs_converted)?,
778 opt_into_json(locktime)?,
779 opt_into_json(replaceable)?,
780 ];
781 let defaults = [into_json(0i64)?, null()];
782 self.call("createrawtransaction", handle_defaults(&mut args, &defaults))
783 }
784
785 fn create_raw_transaction(
786 &self,
787 utxos: &[json::CreateRawTransactionInput],
788 outs: &HashMap<String, Amount>,
789 locktime: Option<i64>,
790 replaceable: Option<bool>,
791 ) -> Result<Transaction> {
792 let hex: String = self.create_raw_transaction_hex(utxos, outs, locktime, replaceable)?;
793 deserialize_hex(&hex)
794 }
795
796 fn decode_raw_transaction<R: RawTx>(
797 &self,
798 tx: R,
799 is_witness: Option<bool>,
800 ) -> Result<json::DecodeRawTransactionResult> {
801 let mut args = [tx.raw_hex().into(), opt_into_json(is_witness)?];
802 let defaults = [null()];
803 self.call("decoderawtransaction", handle_defaults(&mut args, &defaults))
804 }
805
806 fn fund_raw_transaction<R: RawTx>(
807 &self,
808 tx: R,
809 options: Option<&json::FundRawTransactionOptions>,
810 is_witness: Option<bool>,
811 ) -> Result<json::FundRawTransactionResult> {
812 let mut args = [tx.raw_hex().into(), opt_into_json(options)?, opt_into_json(is_witness)?];
813 let defaults = [empty_obj(), null()];
814 self.call("fundrawtransaction", handle_defaults(&mut args, &defaults))
815 }
816
817 #[deprecated]
818 fn sign_raw_transaction<R: RawTx>(
819 &self,
820 tx: R,
821 utxos: Option<&[json::SignRawTransactionInput]>,
822 private_keys: Option<&[PrivateKey]>,
823 sighash_type: Option<json::SigHashType>,
824 ) -> Result<json::SignRawTransactionResult> {
825 let mut args = [
826 tx.raw_hex().into(),
827 opt_into_json(utxos)?,
828 opt_into_json(private_keys)?,
829 opt_into_json(sighash_type)?,
830 ];
831 let defaults = [empty_arr(), empty_arr(), null()];
832 self.call("signrawtransaction", handle_defaults(&mut args, &defaults))
833 }
834
835 fn sign_raw_transaction_with_wallet<R: RawTx>(
836 &self,
837 tx: R,
838 utxos: Option<&[json::SignRawTransactionInput]>,
839 sighash_type: Option<json::SigHashType>,
840 ) -> Result<json::SignRawTransactionResult> {
841 let mut args = [tx.raw_hex().into(), opt_into_json(utxos)?, opt_into_json(sighash_type)?];
842 let defaults = [empty_arr(), null()];
843 self.call("signrawtransactionwithwallet", handle_defaults(&mut args, &defaults))
844 }
845
846 fn sign_raw_transaction_with_key<R: RawTx>(
847 &self,
848 tx: R,
849 privkeys: &[PrivateKey],
850 prevtxs: Option<&[json::SignRawTransactionInput]>,
851 sighash_type: Option<json::SigHashType>,
852 ) -> Result<json::SignRawTransactionResult> {
853 let mut args = [
854 tx.raw_hex().into(),
855 into_json(privkeys)?,
856 opt_into_json(prevtxs)?,
857 opt_into_json(sighash_type)?,
858 ];
859 let defaults = [empty_arr(), null()];
860 self.call("signrawtransactionwithkey", handle_defaults(&mut args, &defaults))
861 }
862
863 fn test_mempool_accept<R: RawTx>(
864 &self,
865 rawtxs: &[R],
866 ) -> Result<Vec<json::TestMempoolAcceptResult>> {
867 let hexes: Vec<serde_json::Value> =
868 rawtxs.to_vec().into_iter().map(|r| r.raw_hex().into()).collect();
869 self.call("testmempoolaccept", &[hexes.into()])
870 }
871
872 fn stop(&self) -> Result<String> {
873 self.call("stop", &[])
874 }
875
876 fn verify_message(
877 &self,
878 address: &Address,
879 signature: &Signature,
880 message: &str,
881 ) -> Result<bool> {
882 let args = [address.to_string().into(), signature.to_string().into(), into_json(message)?];
883 self.call("verifymessage", &args)
884 }
885
886 fn get_new_address(
888 &self,
889 label: Option<&str>,
890 address_type: Option<json::AddressType>,
891 ) -> Result<Address<NetworkUnchecked>> {
892 self.call("getnewaddress", &[opt_into_json(label)?, opt_into_json(address_type)?])
893 }
894
895 fn get_raw_change_address(
897 &self,
898 address_type: Option<json::AddressType>,
899 ) -> Result<Address<NetworkUnchecked>> {
900 self.call("getrawchangeaddress", &[opt_into_json(address_type)?])
901 }
902
903 fn get_address_info(&self, address: &Address) -> Result<json::GetAddressInfoResult> {
904 self.call("getaddressinfo", &[address.to_string().into()])
905 }
906
907 fn generate_to_address(
911 &self,
912 block_num: u64,
913 address: &Address<NetworkChecked>,
914 ) -> Result<Vec<bitcoint4::BlockHash>> {
915 self.call("generatetoaddress", &[block_num.into(), address.to_string().into()])
916 }
917
918 fn generate(&self, block_num: u64, maxtries: Option<u64>) -> Result<Vec<bitcoint4::BlockHash>> {
921 self.call("generate", &[block_num.into(), opt_into_json(maxtries)?])
922 }
923
924 fn invalidate_block(&self, block_hash: &bitcoint4::BlockHash) -> Result<()> {
926 self.call("invalidateblock", &[into_json(block_hash)?])
927 }
928
929 fn reconsider_block(&self, block_hash: &bitcoint4::BlockHash) -> Result<()> {
931 self.call("reconsiderblock", &[into_json(block_hash)?])
932 }
933
934 fn get_mempool_info(&self) -> Result<json::GetMempoolInfoResult> {
936 self.call("getmempoolinfo", &[])
937 }
938
939 fn get_raw_mempool(&self) -> Result<Vec<bitcoint4::Txid>> {
941 self.call("getrawmempool", &[])
942 }
943
944 fn get_raw_mempool_verbose(
946 &self,
947 ) -> Result<HashMap<bitcoint4::Txid, json::GetMempoolEntryResult>> {
948 self.call("getrawmempool", &[into_json(true)?])
949 }
950
951 fn get_mempool_entry(&self, txid: &bitcoint4::Txid) -> Result<json::GetMempoolEntryResult> {
953 self.call("getmempoolentry", &[into_json(txid)?])
954 }
955
956 fn get_chain_tips(&self) -> Result<json::GetChainTipsResult> {
959 self.call("getchaintips", &[])
960 }
961
962 fn send_to_address(
963 &self,
964 address: &Address<NetworkChecked>,
965 amount: Amount,
966 comment: Option<&str>,
967 comment_to: Option<&str>,
968 subtract_fee: Option<bool>,
969 replaceable: Option<bool>,
970 confirmation_target: Option<u32>,
971 estimate_mode: Option<json::EstimateMode>,
972 ) -> Result<bitcoint4::Txid> {
973 let mut args = [
974 address.to_string().into(),
975 into_json(amount.to_btc())?,
976 opt_into_json(comment)?,
977 opt_into_json(comment_to)?,
978 opt_into_json(subtract_fee)?,
979 opt_into_json(replaceable)?,
980 opt_into_json(confirmation_target)?,
981 opt_into_json(estimate_mode)?,
982 ];
983 self.call(
984 "sendtoaddress",
985 handle_defaults(
986 &mut args,
987 &["".into(), "".into(), false.into(), false.into(), 6.into(), null()],
988 ),
989 )
990 }
991
992 fn add_node(&self, addr: &str) -> Result<()> {
995 self.call("addnode", &[into_json(&addr)?, into_json("add")?])
996 }
997
998 fn remove_node(&self, addr: &str) -> Result<()> {
1000 self.call("addnode", &[into_json(&addr)?, into_json("remove")?])
1001 }
1002
1003 fn onetry_node(&self, addr: &str) -> Result<()> {
1005 self.call("addnode", &[into_json(&addr)?, into_json("onetry")?])
1006 }
1007
1008 fn disconnect_node(&self, addr: &str) -> Result<()> {
1010 self.call("disconnectnode", &[into_json(&addr)?])
1011 }
1012
1013 fn disconnect_node_by_id(&self, node_id: u32) -> Result<()> {
1014 self.call("disconnectnode", &[into_json("")?, into_json(node_id)?])
1015 }
1016
1017 fn get_added_node_info(&self, node: Option<&str>) -> Result<Vec<json::GetAddedNodeInfoResult>> {
1019 if let Some(addr) = node {
1020 self.call("getaddednodeinfo", &[into_json(&addr)?])
1021 } else {
1022 self.call("getaddednodeinfo", &[])
1023 }
1024 }
1025
1026 fn get_node_addresses(
1028 &self,
1029 count: Option<usize>,
1030 ) -> Result<Vec<json::GetNodeAddressesResult>> {
1031 let cnt = count.unwrap_or(1);
1032 self.call("getnodeaddresses", &[into_json(&cnt)?])
1033 }
1034
1035 fn list_banned(&self) -> Result<Vec<json::ListBannedResult>> {
1037 self.call("listbanned", &[])
1038 }
1039
1040 fn clear_banned(&self) -> Result<()> {
1042 self.call("clearbanned", &[])
1043 }
1044
1045 fn add_ban(&self, subnet: &str, bantime: u64, absolute: bool) -> Result<()> {
1047 self.call(
1048 "setban",
1049 &[into_json(&subnet)?, into_json("add")?, into_json(&bantime)?, into_json(&absolute)?],
1050 )
1051 }
1052
1053 fn remove_ban(&self, subnet: &str) -> Result<()> {
1055 self.call("setban", &[into_json(&subnet)?, into_json("remove")?])
1056 }
1057
1058 fn set_network_active(&self, state: bool) -> Result<bool> {
1060 self.call("setnetworkactive", &[into_json(&state)?])
1061 }
1062
1063 fn get_peer_info(&self) -> Result<Vec<json::GetPeerInfoResult>> {
1068 self.call("getpeerinfo", &[])
1069 }
1070
1071 fn ping(&self) -> Result<()> {
1080 self.call("ping", &[])
1081 }
1082
1083 fn send_raw_transaction<R: RawTx>(&self, tx: R) -> Result<bitcoint4::Txid> {
1084 self.call("sendrawtransaction", &[tx.raw_hex().into()])
1085 }
1086
1087 fn estimate_smart_fee(
1088 &self,
1089 conf_target: u16,
1090 estimate_mode: Option<json::EstimateMode>,
1091 ) -> Result<json::EstimateSmartFeeResult> {
1092 let mut args = [into_json(conf_target)?, opt_into_json(estimate_mode)?];
1093 self.call("estimatesmartfee", handle_defaults(&mut args, &[null()]))
1094 }
1095
1096 fn wait_for_new_block(&self, timeout: u64) -> Result<json::BlockRef> {
1104 self.call("waitfornewblock", &[into_json(timeout)?])
1105 }
1106
1107 fn wait_for_block(
1116 &self,
1117 blockhash: &bitcoint4::BlockHash,
1118 timeout: u64,
1119 ) -> Result<json::BlockRef> {
1120 let args = [into_json(blockhash)?, into_json(timeout)?];
1121 self.call("waitforblock", &args)
1122 }
1123
1124 fn wallet_create_funded_psbt(
1125 &self,
1126 inputs: &[json::CreateRawTransactionInput],
1127 outputs: &HashMap<String, Amount>,
1128 locktime: Option<i64>,
1129 options: Option<json::WalletCreateFundedPsbtOptions>,
1130 bip32derivs: Option<bool>,
1131 ) -> Result<json::WalletCreateFundedPsbtResult> {
1132 let outputs_converted = serde_json::Map::from_iter(
1133 outputs.iter().map(|(k, v)| (k.clone(), serde_json::Value::from(v.to_btc()))),
1134 );
1135 let mut args = [
1136 into_json(inputs)?,
1137 into_json(outputs_converted)?,
1138 opt_into_json(locktime)?,
1139 opt_into_json(options)?,
1140 opt_into_json(bip32derivs)?,
1141 ];
1142 self.call(
1143 "walletcreatefundedpsbt",
1144 handle_defaults(&mut args, &[0.into(), serde_json::Map::new().into(), false.into()]),
1145 )
1146 }
1147
1148 fn wallet_process_psbt(
1149 &self,
1150 psbt: &str,
1151 sign: Option<bool>,
1152 sighash_type: Option<json::SigHashType>,
1153 bip32derivs: Option<bool>,
1154 ) -> Result<json::WalletProcessPsbtResult> {
1155 let mut args = [
1156 into_json(psbt)?,
1157 opt_into_json(sign)?,
1158 opt_into_json(sighash_type)?,
1159 opt_into_json(bip32derivs)?,
1160 ];
1161 let defaults = [
1162 true.into(),
1163 into_json(json::SigHashType::from(bitcoint4::sighash::EcdsaSighashType::All))?,
1164 true.into(),
1165 ];
1166 self.call("walletprocesspsbt", handle_defaults(&mut args, &defaults))
1167 }
1168
1169 fn get_descriptor_info(&self, desc: &str) -> Result<json::GetDescriptorInfoResult> {
1170 self.call("getdescriptorinfo", &[desc.to_string().into()])
1171 }
1172
1173 fn join_psbt(&self, psbts: &[String]) -> Result<String> {
1174 self.call("joinpsbts", &[into_json(psbts)?])
1175 }
1176
1177 fn combine_psbt(&self, psbts: &[String]) -> Result<String> {
1178 self.call("combinepsbt", &[into_json(psbts)?])
1179 }
1180
1181 fn combine_raw_transaction(&self, hex_strings: &[String]) -> Result<String> {
1182 self.call("combinerawtransaction", &[into_json(hex_strings)?])
1183 }
1184
1185 fn finalize_psbt(&self, psbt: &str, extract: Option<bool>) -> Result<json::FinalizePsbtResult> {
1186 let mut args = [into_json(psbt)?, opt_into_json(extract)?];
1187 self.call("finalizepsbt", handle_defaults(&mut args, &[true.into()]))
1188 }
1189
1190 fn derive_addresses(
1191 &self,
1192 descriptor: &str,
1193 range: Option<[u32; 2]>,
1194 ) -> Result<Vec<Address<NetworkUnchecked>>> {
1195 let mut args = [into_json(descriptor)?, opt_into_json(range)?];
1196 self.call("deriveaddresses", handle_defaults(&mut args, &[null()]))
1197 }
1198
1199 fn rescan_blockchain(
1200 &self,
1201 start_from: Option<usize>,
1202 stop_height: Option<usize>,
1203 ) -> Result<(usize, Option<usize>)> {
1204 let mut args = [opt_into_json(start_from)?, opt_into_json(stop_height)?];
1205
1206 #[derive(Deserialize)]
1207 struct Response {
1208 pub start_height: usize,
1209 pub stop_height: Option<usize>,
1210 }
1211 let res: Response =
1212 self.call("rescanblockchain", handle_defaults(&mut args, &[0.into(), null()]))?;
1213 Ok((res.start_height, res.stop_height))
1214 }
1215
1216 fn get_tx_out_set_info(
1219 &self,
1220 hash_type: Option<json::TxOutSetHashType>,
1221 hash_or_height: Option<json::HashOrHeight>,
1222 use_index: Option<bool>,
1223 ) -> Result<json::GetTxOutSetInfoResult> {
1224 let mut args =
1225 [opt_into_json(hash_type)?, opt_into_json(hash_or_height)?, opt_into_json(use_index)?];
1226 self.call("gettxoutsetinfo", handle_defaults(&mut args, &[null(), null(), null()]))
1227 }
1228
1229 fn get_net_totals(&self) -> Result<json::GetNetTotalsResult> {
1232 self.call("getnettotals", &[])
1233 }
1234
1235 fn get_network_hash_ps(&self, nblocks: Option<u64>, height: Option<u64>) -> Result<f64> {
1237 let mut args = [opt_into_json(nblocks)?, opt_into_json(height)?];
1238 self.call("getnetworkhashps", handle_defaults(&mut args, &[null(), null()]))
1239 }
1240
1241 fn uptime(&self) -> Result<u64> {
1243 self.call("uptime", &[])
1244 }
1245
1246 fn submit_block(&self, block: &bitcoint4::Block) -> Result<()> {
1248 let block_hex: String = bitcoint4::consensus::encode::serialize_hex(block);
1249 self.submit_block_hex(&block_hex)
1250 }
1251
1252 fn submit_block_bytes(&self, block_bytes: &[u8]) -> Result<()> {
1254 let block_hex: String = block_bytes.to_lower_hex_string();
1255 self.submit_block_hex(&block_hex)
1256 }
1257
1258 fn submit_block_hex(&self, block_hex: &str) -> Result<()> {
1260 match self.call("submitblock", &[into_json(&block_hex)?]) {
1261 Ok(serde_json::Value::Null) => Ok(()),
1262 Ok(res) => Err(Error::ReturnedError(res.to_string())),
1263 Err(err) => Err(err.into()),
1264 }
1265 }
1266
1267 fn scan_tx_out_set_blocking(
1268 &self,
1269 descriptors: &[json::ScanTxOutRequest],
1270 ) -> Result<json::ScanTxOutResult> {
1271 self.call("scantxoutset", &["start".into(), into_json(descriptors)?])
1272 }
1273}
1274
1275pub struct Client {
1277 client: jsonrpc::client::Client,
1278}
1279
1280impl fmt::Debug for Client {
1281 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
1282 write!(f, "bitcoincore_rpc::Client({:?})", self.client)
1283 }
1284}
1285
1286impl Client {
1287 pub fn new(url: &str, auth: Auth) -> Result<Self> {
1291 let (user, pass) = auth.get_user_pass()?;
1292 jsonrpc::client::Client::simple_http(url, user, pass)
1293 .map(|client| Client {
1294 client,
1295 })
1296 .map_err(|e| super::error::Error::JsonRpc(e.into()))
1297 }
1298
1299 pub fn from_jsonrpc(client: jsonrpc::client::Client) -> Client {
1301 Client {
1302 client,
1303 }
1304 }
1305
1306 pub fn get_jsonrpc_client(&self) -> &jsonrpc::client::Client {
1308 &self.client
1309 }
1310}
1311
1312impl RpcApi for Client {
1313 fn call<T: for<'a> serde::de::Deserialize<'a>>(
1315 &self,
1316 cmd: &str,
1317 args: &[serde_json::Value],
1318 ) -> Result<T> {
1319 let raw_args: Vec<_> = args
1320 .iter()
1321 .map(|a| {
1322 let json_string = serde_json::to_string(a)?;
1323 serde_json::value::RawValue::from_string(json_string) })
1325 .map(|a| a.map_err(|e| Error::Json(e)))
1326 .collect::<Result<Vec<_>>>()?;
1327 let req = self.client.build_request(&cmd, &raw_args);
1328 if log_enabled!(Debug) {
1329 debug!(target: "bitcoincore_rpc", "JSON-RPC request: {} {}", cmd, serde_json::Value::from(args));
1330 }
1331
1332 let resp = self.client.send_request(req).map_err(Error::from);
1333 log_response(cmd, &resp);
1334 Ok(resp?.result()?)
1335 }
1336}
1337
1338fn log_response(cmd: &str, resp: &Result<jsonrpc::Response>) {
1339 if log_enabled!(Warn) || log_enabled!(Debug) || log_enabled!(Trace) {
1340 match resp {
1341 Err(ref e) => {
1342 if log_enabled!(Debug) {
1343 debug!(target: "bitcoincore_rpc", "JSON-RPC failed parsing reply of {}: {:?}", cmd, e);
1344 }
1345 }
1346 Ok(ref resp) => {
1347 if let Some(ref e) = resp.error {
1348 if log_enabled!(Debug) {
1349 debug!(target: "bitcoincore_rpc", "JSON-RPC error for {}: {:?}", cmd, e);
1350 }
1351 } else if log_enabled!(Trace) {
1352 let def = serde_json::value::RawValue::from_string(
1354 serde_json::Value::Null.to_string(),
1355 )
1356 .unwrap();
1357 let result = resp.result.as_ref().unwrap_or(&def);
1358 trace!(target: "bitcoincore_rpc", "JSON-RPC response for {}: {}", cmd, result);
1359 }
1360 }
1361 }
1362 }
1363}
1364
1365#[cfg(test)]
1366mod tests {
1367 use super::*;
1368 use crate::bitcoint4;
1369 use serde_json;
1370
1371 #[test]
1372 fn test_raw_tx() {
1373 use crate::bitcoint4::consensus::encode;
1374 let client = Client::new("http://localhost/".into(), Auth::None).unwrap();
1375 let tx: bitcoint4::Transaction = encode::deserialize(&Vec::<u8>::from_hex("0200000001586bd02815cf5faabfec986a4e50d25dbee089bd2758621e61c5fab06c334af0000000006b483045022100e85425f6d7c589972ee061413bcf08dc8c8e589ce37b217535a42af924f0e4d602205c9ba9cb14ef15513c9d946fa1c4b797883e748e8c32171bdf6166583946e35c012103dae30a4d7870cd87b45dd53e6012f71318fdd059c1c2623b8cc73f8af287bb2dfeffffff021dc4260c010000001976a914f602e88b2b5901d8aab15ebe4a97cf92ec6e03b388ac00e1f505000000001976a914687ffeffe8cf4e4c038da46a9b1d37db385a472d88acfd211500").unwrap()).unwrap();
1376
1377 assert!(client.send_raw_transaction(&tx).is_err());
1378 assert!(client.send_raw_transaction(&encode::serialize(&tx)).is_err());
1379 assert!(client.send_raw_transaction("deadbeef").is_err());
1380 assert!(client.send_raw_transaction("deadbeef".to_owned()).is_err());
1381 }
1382
1383 fn test_handle_defaults_inner() -> Result<()> {
1384 {
1385 let mut args = [into_json(0)?, null(), null()];
1386 let defaults = [into_json(1)?, into_json(2)?];
1387 let res = [into_json(0)?];
1388 assert_eq!(handle_defaults(&mut args, &defaults), &res);
1389 }
1390 {
1391 let mut args = [into_json(0)?, into_json(1)?, null()];
1392 let defaults = [into_json(2)?];
1393 let res = [into_json(0)?, into_json(1)?];
1394 assert_eq!(handle_defaults(&mut args, &defaults), &res);
1395 }
1396 {
1397 let mut args = [into_json(0)?, null(), into_json(5)?];
1398 let defaults = [into_json(2)?, into_json(3)?];
1399 let res = [into_json(0)?, into_json(2)?, into_json(5)?];
1400 assert_eq!(handle_defaults(&mut args, &defaults), &res);
1401 }
1402 {
1403 let mut args = [into_json(0)?, null(), into_json(5)?, null()];
1404 let defaults = [into_json(2)?, into_json(3)?, into_json(4)?];
1405 let res = [into_json(0)?, into_json(2)?, into_json(5)?];
1406 assert_eq!(handle_defaults(&mut args, &defaults), &res);
1407 }
1408 {
1409 let mut args = [null(), null()];
1410 let defaults = [into_json(2)?, into_json(3)?];
1411 let res: [serde_json::Value; 0] = [];
1412 assert_eq!(handle_defaults(&mut args, &defaults), &res);
1413 }
1414 {
1415 let mut args = [null(), into_json(1)?];
1416 let defaults = [];
1417 let res = [null(), into_json(1)?];
1418 assert_eq!(handle_defaults(&mut args, &defaults), &res);
1419 }
1420 {
1421 let mut args = [];
1422 let defaults = [];
1423 let res: [serde_json::Value; 0] = [];
1424 assert_eq!(handle_defaults(&mut args, &defaults), &res);
1425 }
1426 {
1427 let mut args = [into_json(0)?];
1428 let defaults = [into_json(2)?];
1429 let res = [into_json(0)?];
1430 assert_eq!(handle_defaults(&mut args, &defaults), &res);
1431 }
1432 Ok(())
1433 }
1434
1435 #[test]
1436 fn test_handle_defaults() {
1437 test_handle_defaults_inner().unwrap();
1438 }
1439}