cuprate_blockchain/ops/
key_image.rs

1//! Key image functions.
2
3//---------------------------------------------------------------------------------------------------- Import
4use cuprate_database::{DatabaseRo, DatabaseRw, DbResult};
5
6use crate::{
7    ops::macros::{doc_add_block_inner_invariant, doc_error},
8    tables::KeyImages,
9    types::KeyImage,
10};
11
12//---------------------------------------------------------------------------------------------------- Key image functions
13/// Add a [`KeyImage`] to the "spent" set in the database.
14#[doc = doc_add_block_inner_invariant!()]
15#[doc = doc_error!()]
16#[inline]
17pub fn add_key_image(
18    key_image: &KeyImage,
19    table_key_images: &mut impl DatabaseRw<KeyImages>,
20) -> DbResult<()> {
21    table_key_images.put(key_image, &())
22}
23
24/// Remove a [`KeyImage`] from the "spent" set in the database.
25#[doc = doc_add_block_inner_invariant!()]
26#[doc = doc_error!()]
27#[inline]
28pub fn remove_key_image(
29    key_image: &KeyImage,
30    table_key_images: &mut impl DatabaseRw<KeyImages>,
31) -> DbResult<()> {
32    table_key_images.delete(key_image)
33}
34
35/// Check if a [`KeyImage`] exists - i.e. if it is "spent".
36#[doc = doc_error!()]
37#[inline]
38pub fn key_image_exists(
39    key_image: &KeyImage,
40    table_key_images: &impl DatabaseRo<KeyImages>,
41) -> DbResult<bool> {
42    table_key_images.contains(key_image)
43}
44
45//---------------------------------------------------------------------------------------------------- Tests
46#[cfg(test)]
47mod test {
48    use hex_literal::hex;
49
50    use cuprate_database::{Env, EnvInner, TxRw};
51
52    use super::*;
53
54    use crate::{
55        tables::{OpenTables, Tables, TablesMut},
56        tests::{assert_all_tables_are_empty, tmp_concrete_env, AssertTableLen},
57    };
58
59    /// Tests all above key-image functions.
60    ///
61    /// Note that this doesn't test the correctness of values added, as the
62    /// functions have a pre-condition that the caller handles this.
63    ///
64    /// It simply tests if the proper tables are mutated, and if the data
65    /// stored and retrieved is the same.
66    #[test]
67    fn all_key_image_functions() {
68        let (env, _tmp) = tmp_concrete_env();
69        let env_inner = env.env_inner();
70        assert_all_tables_are_empty(&env);
71
72        let key_images = [
73            hex!("be1c87fc8f958f68fbe346a18dfb314204dca7573f61aae14840b8037da5c286"),
74            hex!("c5e4a592c11f34a12e13516ab2883b7c580d47b286b8fe8b15d57d2a18ade275"),
75            hex!("93288b646f858edfb0997ae08d7c76f4599b04c127f108e8e69a0696ae7ba334"),
76            hex!("726e9e3d8f826d24811183f94ff53aeba766c9efe6274eb80806f69b06bfa3fc"),
77        ];
78
79        // Add.
80        {
81            let tx_rw = env_inner.tx_rw().unwrap();
82            let mut tables = env_inner.open_tables_mut(&tx_rw).unwrap();
83
84            for key_image in &key_images {
85                println!("add_key_image(): {}", hex::encode(key_image));
86                add_key_image(key_image, tables.key_images_mut()).unwrap();
87            }
88
89            drop(tables);
90            TxRw::commit(tx_rw).unwrap();
91        }
92
93        // Assert all reads are OK.
94        {
95            let tx_ro = env_inner.tx_ro().unwrap();
96            let tables = env_inner.open_tables(&tx_ro).unwrap();
97
98            // Assert only the proper tables were added to.
99            AssertTableLen {
100                key_images: tables.key_images().len().unwrap(),
101                ..Default::default()
102            }
103            .assert(&tables);
104
105            for key_image in &key_images {
106                println!("key_image_exists(): {}", hex::encode(key_image));
107                key_image_exists(key_image, tables.key_images()).unwrap();
108            }
109        }
110
111        // Remove.
112        {
113            let tx_rw = env_inner.tx_rw().unwrap();
114            let mut tables = env_inner.open_tables_mut(&tx_rw).unwrap();
115
116            for key_image in key_images {
117                println!("remove_key_image(): {}", hex::encode(key_image));
118                remove_key_image(&key_image, tables.key_images_mut()).unwrap();
119                assert!(!key_image_exists(&key_image, tables.key_images()).unwrap());
120            }
121
122            drop(tables);
123            TxRw::commit(tx_rw).unwrap();
124        }
125
126        assert_all_tables_are_empty(&env);
127    }
128}