cat_gateway/rbac/
indexing_context.rs

1//! A RBAC context used during indexing.
2
3use std::collections::{HashMap, HashSet};
4
5use cardano_chain_follower::{Slot, StakeAddress, TxnIndex, hashes::TransactionId};
6use catalyst_types::catalyst_id::CatalystId;
7use ed25519_dalek::VerifyingKey;
8
9use crate::db::index::queries::rbac::get_rbac_registrations::Query as RbacQuery;
10
11/// A RBAC context used during indexing.
12///
13/// During indexing the information is written to the database only after processing the
14/// whole block. If there are multiple RBAC registrations in one block, then when
15/// validating subsequent transactions we wouldn't be able to find information about the
16/// previous ones in the database. This context is used to hold such information during
17/// block processing in order to mitigate that issue.
18pub struct RbacBlockIndexingContext {
19    /// A map containing pending data that will be written in the `catalyst_id_for_txn_id`
20    /// table.
21    transactions: HashMap<TransactionId, CatalystId>,
22    /// A map contains pending data that will be written in the
23    /// `catalyst_id_for_stake_address` table.
24    addresses: HashMap<StakeAddress, CatalystId>,
25    /// A map containing pending data that will be written in the
26    /// `catalyst_id_for_public_key` table.
27    public_keys: HashMap<VerifyingKey, CatalystId>,
28    /// A map containing pending data that will be written in the `rbac_registration`
29    /// table.
30    registrations: HashMap<CatalystId, Vec<RbacQuery>>,
31}
32
33impl RbacBlockIndexingContext {
34    /// Creates a new context issue.
35    pub fn new() -> Self {
36        let transactions = HashMap::new();
37        let addresses = HashMap::new();
38        let public_keys = HashMap::new();
39        let registrations = HashMap::new();
40
41        Self {
42            transactions,
43            addresses,
44            public_keys,
45            registrations,
46        }
47    }
48
49    /// Adds a transaction to the context.
50    pub fn insert_transaction(
51        &mut self,
52        transaction: TransactionId,
53        catalyst_id: CatalystId,
54    ) {
55        self.transactions.insert(transaction, catalyst_id);
56    }
57
58    /// Returns a Catalyst ID of the given transaction ID if it exists in the context.
59    pub fn find_transaction(
60        &self,
61        transaction_id: &TransactionId,
62    ) -> Option<&CatalystId> {
63        self.transactions.get(transaction_id)
64    }
65
66    /// Adds a stake address to the context.
67    pub fn insert_address(
68        &mut self,
69        address: StakeAddress,
70        catalyst_id: CatalystId,
71    ) {
72        self.addresses.insert(address, catalyst_id);
73    }
74
75    /// Adds multiple addresses to the context.
76    pub fn insert_addresses(
77        &mut self,
78        addresses: impl IntoIterator<Item = StakeAddress>,
79        catalyst_id: &CatalystId,
80    ) {
81        for address in addresses {
82            self.insert_address(address, catalyst_id.clone());
83        }
84    }
85
86    /// Returns a Catalyst ID corresponding the given stake address.
87    pub fn find_address(
88        &self,
89        address: &StakeAddress,
90    ) -> Option<&CatalystId> {
91        self.addresses.get(address)
92    }
93
94    /// Removes multiple addresses from the context.
95    pub fn remove_addresses(
96        &mut self,
97        addresses: &HashSet<StakeAddress>,
98    ) {
99        for address in addresses {
100            self.addresses.remove(address);
101        }
102    }
103
104    /// Adds a public key to the context.
105    pub fn insert_public_key(
106        &mut self,
107        key: VerifyingKey,
108        catalyst_id: CatalystId,
109    ) {
110        self.public_keys.insert(key, catalyst_id);
111    }
112
113    /// Adds multiple public keys to the context.
114    pub fn insert_public_keys(
115        &mut self,
116        keys: impl IntoIterator<Item = VerifyingKey>,
117        catalyst_id: &CatalystId,
118    ) {
119        for key in keys {
120            self.insert_public_key(key, catalyst_id.clone());
121        }
122    }
123
124    /// Returns a Catalyst ID corresponding the given public key.
125    pub fn find_public_key(
126        &self,
127        key: &VerifyingKey,
128    ) -> Option<&CatalystId> {
129        self.public_keys.get(key)
130    }
131
132    /// Adds a registration to the context.
133    pub fn insert_registration(
134        &mut self,
135        id: CatalystId,
136        txn_id: TransactionId,
137        slot: Slot,
138        txn_index: TxnIndex,
139        prv_txn: Option<TransactionId>,
140    ) {
141        use std::collections::hash_map::Entry;
142
143        let value = RbacQuery {
144            txn_id: txn_id.into(),
145            slot_no: slot.into(),
146            txn_index: txn_index.into(),
147            prv_txn_id: prv_txn.map(Into::into),
148        };
149
150        match self.registrations.entry(id) {
151            Entry::Occupied(e) => {
152                e.into_mut().push(value);
153            },
154            Entry::Vacant(e) => {
155                e.insert(vec![value]);
156            },
157        }
158    }
159
160    /// Returns a list of registrations.
161    pub fn find_registrations(
162        &self,
163        id: &CatalystId,
164    ) -> Option<&[RbacQuery]> {
165        self.registrations.get(id).map(Vec::as_slice)
166    }
167}