chainseeker_server/db/
address_index.rs1use bitcoin::{Block, Txid, Script};
2
3use super::super::*;
4
5#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord)]
6pub struct AddressIndexDBKey {
7 pub script_pubkey: Script,
8 pub txid: Txid,
9}
10
11impl Serialize for AddressIndexDBKey {
12 fn serialize(&self) -> Vec<u8> {
13 [consensus_encode(&self.script_pubkey), consensus_encode(&self.txid)].concat()
14 }
15}
16
17impl Deserialize for AddressIndexDBKey {
18 fn deserialize(buf: &[u8]) -> Self {
19 let script_pubkey = consensus_decode(&buf[0..buf.len()-32]);
20 let txid = consensus_decode(&buf[buf.len()-32..]);
21 AddressIndexDBKey {
22 script_pubkey,
23 txid,
24 }
25 }
26}
27
28pub type AddressIndexDBValue = Empty;
29
30#[derive(Debug)]
31pub struct AddressIndexDB {
32 db: RocksDB<AddressIndexDBKey, AddressIndexDBValue>,
33}
34
35impl AddressIndexDB {
37 pub fn get_path(coin: &str) -> String {
38 format!("{}/{}/address_index", data_dir(), coin)
39 }
40 pub fn new(coin: &str, temporary: bool) -> Self {
41 let path = Self::get_path(coin);
42 Self {
43 db: RocksDB::new(&path, temporary),
44 }
45 }
46 pub fn get(&self, script_pubkey: &Script) -> Vec<Txid> {
47 let script_pubkey = consensus_encode(script_pubkey);
48 self.db.prefix_iter(script_pubkey).map(|(key, _value)| key.txid).collect()
49 }
50 pub fn put(&self, script_pubkey: &Script, txid: &Txid) {
51 let key = AddressIndexDBKey {
52 script_pubkey: (*script_pubkey).clone(),
53 txid: *txid,
54 };
55 self.db.put(&key, &Default::default());
56 }
57 pub fn process_block(&self, block: &Block, previous_utxos: &[UtxoEntry]) {
58 let mut previous_utxo_index = 0;
59 for tx in block.txdata.iter() {
60 let txid = tx.txid();
61 for vin in tx.input.iter() {
63 if !vin.previous_output.is_null() {
64 self.put(&previous_utxos[previous_utxo_index].script_pubkey, &txid);
66 previous_utxo_index += 1;
67 }
68 }
69 for vout in tx.output.iter() {
71 self.put(&vout.script_pubkey, &txid);
72 }
73 }
74 }
75}
76
77#[cfg(test)]
78mod tests {
79 use super::*;
80 #[allow(dead_code)]
81 fn print_addr_index_db(addr_index_db: &AddressIndexDB) {
82 let mut entries = addr_index_db.db.iter().map(|(key, _value)| key).collect::<Vec<AddressIndexDBKey>>();
83 entries.sort();
84 for entry in entries.iter() {
85 println!(" AddressIndexDBKey {{ script_pubkey: consensus_decode(&hex::decode(\"{}\").unwrap()), txid: consensus_decode(&hex::decode(\"{}\").unwrap()), }},",
86 hex::encode(consensus_encode(&entry.script_pubkey)),
87 hex::encode(consensus_encode(&entry.txid)));
88 }
89 }
90 #[test]
91 fn addr_index_db() {
92 let addr_index_db = AddressIndexDB::new("test/address_index", true);
93 let mut utxo_db = UtxoDB::new("test/address_index", true);
94 for block in fixtures::regtest_blocks().iter() {
95 let prev_utxos = utxo_db.process_block(&block, false);
96 addr_index_db.process_block(&block, &prev_utxos);
97 }
98 print_addr_index_db(&addr_index_db);
99 let mut entries_test = addr_index_db.db.iter().map(|(key, _value)| key).collect::<Vec<AddressIndexDBKey>>();
100 entries_test.sort();
101 let mut entries = fixtures::addr_index_db();
102 entries.sort();
103 assert_eq!(entries_test, entries);
104 for entry in entries.iter() {
105 let mut found = false;
106 for txid in addr_index_db.get(&entry.script_pubkey).iter() {
107 if *txid == entry.txid {
108 found = true;
109 break;
110 }
111 }
112 assert!(found);
113 }
114 }
115}