1use std::any::Any;
18use std::collections::BTreeMap;
19use std::ops::Bound::{Excluded, Included};
20
21use bitcoin::consensus::encode::{deserialize, serialize};
22use bitcoin::hash_types::Txid;
23use bitcoin::{OutPoint, Script, Transaction};
24
25use crate::database::{BatchDatabase, BatchOperations, ConfigurableDatabase, Database, SyncTime};
26use crate::error::Error;
27use crate::types::*;
28
29pub(crate) enum MapKey<'a> {
39 Path((Option<KeychainKind>, Option<u32>)),
40 Script(Option<&'a Script>),
41 Utxo(Option<&'a OutPoint>),
42 RawTx(Option<&'a Txid>),
43 Transaction(Option<&'a Txid>),
44 LastIndex(KeychainKind),
45 SyncTime,
46 DescriptorChecksum(KeychainKind),
47}
48
49impl MapKey<'_> {
50 fn as_prefix(&self) -> Vec<u8> {
51 match self {
52 MapKey::Path((st, _)) => {
53 let mut v = b"p".to_vec();
54 if let Some(st) = st {
55 v.push(st.as_byte());
56 }
57 v
58 }
59 MapKey::Script(_) => b"s".to_vec(),
60 MapKey::Utxo(_) => b"u".to_vec(),
61 MapKey::RawTx(_) => b"r".to_vec(),
62 MapKey::Transaction(_) => b"t".to_vec(),
63 MapKey::LastIndex(st) => [b"c", st.as_ref()].concat(),
64 MapKey::SyncTime => b"l".to_vec(),
65 MapKey::DescriptorChecksum(st) => [b"d", st.as_ref()].concat(),
66 }
67 }
68
69 fn serialize_content(&self) -> Vec<u8> {
70 match self {
71 MapKey::Path((_, Some(child))) => child.to_be_bytes().to_vec(),
72 MapKey::Script(Some(s)) => serialize(*s),
73 MapKey::Utxo(Some(s)) => serialize(*s),
74 MapKey::RawTx(Some(s)) => serialize(*s),
75 MapKey::Transaction(Some(s)) => serialize(*s),
76 _ => vec![],
77 }
78 }
79
80 pub fn as_map_key(&self) -> Vec<u8> {
81 let mut v = self.as_prefix();
82 v.extend_from_slice(&self.serialize_content());
83
84 v
85 }
86}
87
88fn after(key: &[u8]) -> Vec<u8> {
89 let mut key = key.to_owned();
90 let mut idx = key.len();
91 while idx > 0 {
92 if key[idx - 1] == 0xFF {
93 idx -= 1;
94 continue;
95 } else {
96 key[idx - 1] += 1;
97 break;
98 }
99 }
100
101 key
102}
103
104#[derive(Debug, Default)]
116pub struct MemoryDatabase {
117 map: BTreeMap<Vec<u8>, Box<dyn Any + Send + Sync>>,
118 deleted_keys: Vec<Vec<u8>>,
119}
120
121impl MemoryDatabase {
122 pub fn new() -> Self {
124 MemoryDatabase {
125 map: BTreeMap::new(),
126 deleted_keys: Vec::new(),
127 }
128 }
129}
130
131impl BatchOperations for MemoryDatabase {
132 fn set_script_pubkey(
133 &mut self,
134 script: &Script,
135 keychain: KeychainKind,
136 path: u32,
137 ) -> Result<(), Error> {
138 let key = MapKey::Path((Some(keychain), Some(path))).as_map_key();
139 self.map.insert(key, Box::new(script.clone()));
140
141 let key = MapKey::Script(Some(script)).as_map_key();
142 let value = json!({
143 "t": keychain,
144 "p": path,
145 });
146 self.map.insert(key, Box::new(value));
147
148 Ok(())
149 }
150
151 fn set_utxo(&mut self, utxo: &LocalUtxo) -> Result<(), Error> {
152 let key = MapKey::Utxo(Some(&utxo.outpoint)).as_map_key();
153 self.map.insert(
154 key,
155 Box::new((utxo.txout.clone(), utxo.keychain, utxo.is_spent)),
156 );
157
158 Ok(())
159 }
160 fn set_raw_tx(&mut self, transaction: &Transaction) -> Result<(), Error> {
161 let key = MapKey::RawTx(Some(&transaction.txid())).as_map_key();
162 self.map.insert(key, Box::new(transaction.clone()));
163
164 Ok(())
165 }
166 fn set_tx(&mut self, transaction: &TransactionDetails) -> Result<(), Error> {
167 let key = MapKey::Transaction(Some(&transaction.txid)).as_map_key();
168
169 if let Some(ref tx) = transaction.transaction {
171 self.set_raw_tx(tx)?;
172 }
173
174 let mut transaction = transaction.clone();
176 transaction.transaction = None;
177
178 self.map.insert(key, Box::new(transaction));
179
180 Ok(())
181 }
182 fn set_last_index(&mut self, keychain: KeychainKind, value: u32) -> Result<(), Error> {
183 let key = MapKey::LastIndex(keychain).as_map_key();
184 self.map.insert(key, Box::new(value));
185
186 Ok(())
187 }
188 fn set_sync_time(&mut self, data: SyncTime) -> Result<(), Error> {
189 let key = MapKey::SyncTime.as_map_key();
190 self.map.insert(key, Box::new(data));
191
192 Ok(())
193 }
194
195 fn del_script_pubkey_from_path(
196 &mut self,
197 keychain: KeychainKind,
198 path: u32,
199 ) -> Result<Option<Script>, Error> {
200 let key = MapKey::Path((Some(keychain), Some(path))).as_map_key();
201 let res = self.map.remove(&key);
202 self.deleted_keys.push(key);
203
204 Ok(res.map(|x| x.downcast_ref().cloned().unwrap()))
205 }
206 fn del_path_from_script_pubkey(
207 &mut self,
208 script: &Script,
209 ) -> Result<Option<(KeychainKind, u32)>, Error> {
210 let key = MapKey::Script(Some(script)).as_map_key();
211 let res = self.map.remove(&key);
212 self.deleted_keys.push(key);
213
214 match res {
215 None => Ok(None),
216 Some(b) => {
217 let mut val: serde_json::Value = b.downcast_ref().cloned().unwrap();
218 let st = serde_json::from_value(val["t"].take())?;
219 let path = serde_json::from_value(val["p"].take())?;
220
221 Ok(Some((st, path)))
222 }
223 }
224 }
225 fn del_utxo(&mut self, outpoint: &OutPoint) -> Result<Option<LocalUtxo>, Error> {
226 let key = MapKey::Utxo(Some(outpoint)).as_map_key();
227 let res = self.map.remove(&key);
228 self.deleted_keys.push(key);
229
230 match res {
231 None => Ok(None),
232 Some(b) => {
233 let (txout, keychain, is_spent) = b.downcast_ref().cloned().unwrap();
234 Ok(Some(LocalUtxo {
235 outpoint: *outpoint,
236 txout,
237 keychain,
238 is_spent,
239 }))
240 }
241 }
242 }
243 fn del_raw_tx(&mut self, txid: &Txid) -> Result<Option<Transaction>, Error> {
244 let key = MapKey::RawTx(Some(txid)).as_map_key();
245 let res = self.map.remove(&key);
246 self.deleted_keys.push(key);
247
248 Ok(res.map(|x| x.downcast_ref().cloned().unwrap()))
249 }
250 fn del_tx(
251 &mut self,
252 txid: &Txid,
253 include_raw: bool,
254 ) -> Result<Option<TransactionDetails>, Error> {
255 let raw_tx = if include_raw {
256 self.del_raw_tx(txid)?
257 } else {
258 None
259 };
260
261 let key = MapKey::Transaction(Some(txid)).as_map_key();
262 let res = self.map.remove(&key);
263 self.deleted_keys.push(key);
264
265 match res {
266 None => Ok(None),
267 Some(b) => {
268 let mut val: TransactionDetails = b.downcast_ref().cloned().unwrap();
269 val.transaction = raw_tx;
270
271 Ok(Some(val))
272 }
273 }
274 }
275 fn del_last_index(&mut self, keychain: KeychainKind) -> Result<Option<u32>, Error> {
276 let key = MapKey::LastIndex(keychain).as_map_key();
277 let res = self.map.remove(&key);
278 self.deleted_keys.push(key);
279
280 match res {
281 None => Ok(None),
282 Some(b) => Ok(Some(*b.downcast_ref().unwrap())),
283 }
284 }
285 fn del_sync_time(&mut self) -> Result<Option<SyncTime>, Error> {
286 let key = MapKey::SyncTime.as_map_key();
287 let res = self.map.remove(&key);
288 self.deleted_keys.push(key);
289
290 Ok(res.map(|b| b.downcast_ref().cloned().unwrap()))
291 }
292}
293
294impl Database for MemoryDatabase {
295 fn check_descriptor_checksum<B: AsRef<[u8]>>(
296 &mut self,
297 keychain: KeychainKind,
298 bytes: B,
299 ) -> Result<(), Error> {
300 let key = MapKey::DescriptorChecksum(keychain).as_map_key();
301
302 let prev = self
303 .map
304 .get(&key)
305 .map(|x| x.downcast_ref::<Vec<u8>>().unwrap());
306 if let Some(val) = prev {
307 if val == &bytes.as_ref().to_vec() {
308 Ok(())
309 } else {
310 Err(Error::ChecksumMismatch)
311 }
312 } else {
313 self.map.insert(key, Box::new(bytes.as_ref().to_vec()));
314 Ok(())
315 }
316 }
317
318 fn iter_script_pubkeys(&self, keychain: Option<KeychainKind>) -> Result<Vec<Script>, Error> {
319 let key = MapKey::Path((keychain, None)).as_map_key();
320 self.map
321 .range::<Vec<u8>, _>((Included(&key), Excluded(&after(&key))))
322 .map(|(_, v)| Ok(v.downcast_ref().cloned().unwrap()))
323 .collect()
324 }
325
326 fn iter_utxos(&self) -> Result<Vec<LocalUtxo>, Error> {
327 let key = MapKey::Utxo(None).as_map_key();
328 self.map
329 .range::<Vec<u8>, _>((Included(&key), Excluded(&after(&key))))
330 .map(|(k, v)| {
331 let outpoint = deserialize(&k[1..]).unwrap();
332 let (txout, keychain, is_spent) = v.downcast_ref().cloned().unwrap();
333 Ok(LocalUtxo {
334 outpoint,
335 txout,
336 keychain,
337 is_spent,
338 })
339 })
340 .collect()
341 }
342
343 fn iter_raw_txs(&self) -> Result<Vec<Transaction>, Error> {
344 let key = MapKey::RawTx(None).as_map_key();
345 self.map
346 .range::<Vec<u8>, _>((Included(&key), Excluded(&after(&key))))
347 .map(|(_, v)| Ok(v.downcast_ref().cloned().unwrap()))
348 .collect()
349 }
350
351 fn iter_txs(&self, include_raw: bool) -> Result<Vec<TransactionDetails>, Error> {
352 let key = MapKey::Transaction(None).as_map_key();
353 self.map
354 .range::<Vec<u8>, _>((Included(&key), Excluded(&after(&key))))
355 .map(|(k, v)| {
356 let mut txdetails: TransactionDetails = v.downcast_ref().cloned().unwrap();
357 if include_raw {
358 let txid = deserialize(&k[1..])?;
359 txdetails.transaction = self.get_raw_tx(&txid)?;
360 }
361
362 Ok(txdetails)
363 })
364 .collect()
365 }
366
367 fn get_script_pubkey_from_path(
368 &self,
369 keychain: KeychainKind,
370 path: u32,
371 ) -> Result<Option<Script>, Error> {
372 let key = MapKey::Path((Some(keychain), Some(path))).as_map_key();
373 Ok(self
374 .map
375 .get(&key)
376 .map(|b| b.downcast_ref().cloned().unwrap()))
377 }
378
379 fn get_path_from_script_pubkey(
380 &self,
381 script: &Script,
382 ) -> Result<Option<(KeychainKind, u32)>, Error> {
383 let key = MapKey::Script(Some(script)).as_map_key();
384 Ok(self.map.get(&key).map(|b| {
385 let mut val: serde_json::Value = b.downcast_ref().cloned().unwrap();
386 let st = serde_json::from_value(val["t"].take()).unwrap();
387 let path = serde_json::from_value(val["p"].take()).unwrap();
388
389 (st, path)
390 }))
391 }
392
393 fn get_utxo(&self, outpoint: &OutPoint) -> Result<Option<LocalUtxo>, Error> {
394 let key = MapKey::Utxo(Some(outpoint)).as_map_key();
395 Ok(self.map.get(&key).map(|b| {
396 let (txout, keychain, is_spent) = b.downcast_ref().cloned().unwrap();
397 LocalUtxo {
398 outpoint: *outpoint,
399 txout,
400 keychain,
401 is_spent,
402 }
403 }))
404 }
405
406 fn get_raw_tx(&self, txid: &Txid) -> Result<Option<Transaction>, Error> {
407 let key = MapKey::RawTx(Some(txid)).as_map_key();
408 Ok(self
409 .map
410 .get(&key)
411 .map(|b| b.downcast_ref().cloned().unwrap()))
412 }
413
414 fn get_tx(&self, txid: &Txid, include_raw: bool) -> Result<Option<TransactionDetails>, Error> {
415 let key = MapKey::Transaction(Some(txid)).as_map_key();
416 Ok(self.map.get(&key).map(|b| {
417 let mut txdetails: TransactionDetails = b.downcast_ref().cloned().unwrap();
418 if include_raw {
419 txdetails.transaction = self.get_raw_tx(txid).unwrap();
420 }
421
422 txdetails
423 }))
424 }
425
426 fn get_last_index(&self, keychain: KeychainKind) -> Result<Option<u32>, Error> {
427 let key = MapKey::LastIndex(keychain).as_map_key();
428 Ok(self.map.get(&key).map(|b| *b.downcast_ref().unwrap()))
429 }
430
431 fn get_sync_time(&self) -> Result<Option<SyncTime>, Error> {
432 let key = MapKey::SyncTime.as_map_key();
433 Ok(self
434 .map
435 .get(&key)
436 .map(|b| b.downcast_ref().cloned().unwrap()))
437 }
438
439 fn increment_last_index(&mut self, keychain: KeychainKind) -> Result<u32, Error> {
441 let key = MapKey::LastIndex(keychain).as_map_key();
442 let value = self
443 .map
444 .entry(key)
445 .and_modify(|x| *x.downcast_mut::<u32>().unwrap() += 1)
446 .or_insert_with(|| Box::<u32>::new(0))
447 .downcast_mut()
448 .unwrap();
449
450 Ok(*value)
451 }
452}
453
454impl BatchDatabase for MemoryDatabase {
455 type Batch = Self;
456
457 fn begin_batch(&self) -> Self::Batch {
458 MemoryDatabase::new()
459 }
460
461 fn commit_batch(&mut self, mut batch: Self::Batch) -> Result<(), Error> {
462 for key in batch.deleted_keys.iter() {
463 self.map.remove(key);
464 }
465 self.map.append(&mut batch.map);
466 Ok(())
467 }
468}
469
470impl ConfigurableDatabase for MemoryDatabase {
471 type Config = ();
472
473 fn from_config(_config: &Self::Config) -> Result<Self, Error> {
474 Ok(MemoryDatabase::default())
475 }
476}
477
478#[macro_export]
479#[doc(hidden)]
480macro_rules! populate_test_db {
484 ($db:expr, $tx_meta:expr, $current_height:expr$(,)?) => {{
485 $crate::populate_test_db!($db, $tx_meta, $current_height, (@coinbase false))
486 }};
487 ($db:expr, $tx_meta:expr, $current_height:expr, (@coinbase $is_coinbase:expr)$(,)?) => {{
488 use std::str::FromStr;
489 use $crate::database::SyncTime;
490 use $crate::database::{BatchOperations, Database};
491 let mut db = $db;
492 let tx_meta = $tx_meta;
493 let current_height: Option<u32> = $current_height;
494 let mut input = vec![$crate::bitcoin::TxIn::default()];
495 if !$is_coinbase {
496 input[0].previous_output.vout = 0;
497 }
498 let tx = $crate::bitcoin::Transaction {
499 version: 1,
500 lock_time: bitcoin::PackedLockTime(0),
501 input,
502 output: tx_meta
503 .output
504 .iter()
505 .map(|out_meta| $crate::bitcoin::TxOut {
506 value: out_meta.value,
507 script_pubkey: $crate::bitcoin::Address::from_str(&out_meta.to_address)
508 .unwrap()
509 .script_pubkey(),
510 })
511 .collect(),
512 };
513
514 let txid = tx.txid();
515 let confirmation_time = tx_meta
518 .min_confirmations
519 .and_then(|v| if v == 0 { None } else { Some(v) })
520 .map(|conf| $crate::BlockTime {
521 height: current_height.expect("Current height is needed for testing transaction with min-confirmation values").checked_sub(conf as u32).unwrap() + 1,
522 timestamp: 0,
523 });
524
525 if let Some(height) = db.get_sync_time().unwrap()
530 .map(|sync_time| sync_time.block_time.height)
531 .max(current_height) {
532 let sync_time = SyncTime {
533 block_time: BlockTime {
534 height,
535 timestamp: 0
536 }
537 };
538 db.set_sync_time(sync_time).unwrap();
539 }
540
541 let tx_details = $crate::TransactionDetails {
542 transaction: Some(tx.clone()),
543 txid,
544 fee: Some(0),
545 received: 0,
546 sent: 0,
547 confirmation_time,
548 };
549
550 db.set_tx(&tx_details).unwrap();
551 for (vout, out) in tx.output.iter().enumerate() {
552 db.set_utxo(&$crate::LocalUtxo {
553 txout: out.clone(),
554 outpoint: $crate::bitcoin::OutPoint {
555 txid,
556 vout: vout as u32,
557 },
558 keychain: $crate::KeychainKind::External,
559 is_spent: false,
560 })
561 .unwrap();
562 }
563
564 txid
565 }};
566}
567
568#[macro_export]
569#[doc(hidden)]
570macro_rules! doctest_wallet {
572 () => {{
573 use $crate::bitcoin::Network;
574 use $crate::database::MemoryDatabase;
575 use $crate::testutils;
576 let descriptor = "wpkh(cVpPVruEDdmutPzisEsYvtST1usBR3ntr8pXSyt6D2YYqXRyPcFW)";
577 let descriptors = testutils!(@descriptors (descriptor) (descriptor));
578
579 let mut db = MemoryDatabase::new();
580 let txid = populate_test_db!(
581 &mut db,
582 testutils! {
583 @tx ( (@external descriptors, 0) => 500_000 ) (@confirmations 1)
584 },
585 Some(100),
586 );
587
588 $crate::Wallet::new(
589 &descriptors.0,
590 descriptors.1.as_ref(),
591 Network::Regtest,
592 db
593 )
594 .unwrap()
595 }}
596}
597
598#[cfg(test)]
599mod test {
600 use super::MemoryDatabase;
601
602 fn get_tree() -> MemoryDatabase {
603 MemoryDatabase::new()
604 }
605
606 #[test]
607 fn test_script_pubkey() {
608 crate::database::test::test_script_pubkey(get_tree());
609 }
610
611 #[test]
612 fn test_batch_script_pubkey() {
613 crate::database::test::test_batch_script_pubkey(get_tree());
614 }
615
616 #[test]
617 fn test_iter_script_pubkey() {
618 crate::database::test::test_iter_script_pubkey(get_tree());
619 }
620
621 #[test]
622 fn test_del_script_pubkey() {
623 crate::database::test::test_del_script_pubkey(get_tree());
624 }
625
626 #[test]
627 fn test_utxo() {
628 crate::database::test::test_utxo(get_tree());
629 }
630
631 #[test]
632 fn test_raw_tx() {
633 crate::database::test::test_raw_tx(get_tree());
634 }
635
636 #[test]
637 fn test_tx() {
638 crate::database::test::test_tx(get_tree());
639 }
640
641 #[test]
642 fn test_last_index() {
643 crate::database::test::test_last_index(get_tree());
644 }
645
646 #[test]
647 fn test_sync_time() {
648 crate::database::test::test_sync_time(get_tree());
649 }
650
651 #[test]
652 fn test_iter_raw_txs() {
653 crate::database::test::test_iter_raw_txs(get_tree());
654 }
655
656 #[test]
657 fn test_del_path_from_script_pubkey() {
658 crate::database::test::test_del_path_from_script_pubkey(get_tree());
659 }
660
661 #[test]
662 fn test_iter_script_pubkeys() {
663 crate::database::test::test_iter_script_pubkeys(get_tree());
664 }
665
666 #[test]
667 fn test_del_utxo() {
668 crate::database::test::test_del_utxo(get_tree());
669 }
670
671 #[test]
672 fn test_del_raw_tx() {
673 crate::database::test::test_del_raw_tx(get_tree());
674 }
675
676 #[test]
677 fn test_del_tx() {
678 crate::database::test::test_del_tx(get_tree());
679 }
680
681 #[test]
682 fn test_del_last_index() {
683 crate::database::test::test_del_last_index(get_tree());
684 }
685
686 #[test]
687 fn test_check_descriptor_checksum() {
688 crate::database::test::test_check_descriptor_checksum(get_tree());
689 }
690}