cat_gateway/rbac/
indexing_context.rs

1//! A RBAC context used during indexing.
2
3use std::collections::{HashMap, HashSet};
4
5use cardano_chain_follower::{hashes::TransactionId, Slot, StakeAddress, TxnIndex};
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    /// Adds a public key to the context.
95    pub fn insert_public_key(
96        &mut self,
97        key: VerifyingKey,
98        catalyst_id: CatalystId,
99    ) {
100        self.public_keys.insert(key, catalyst_id);
101    }
102
103    /// Adds multiple public keys to the context.
104    pub fn insert_public_keys(
105        &mut self,
106        keys: impl IntoIterator<Item = VerifyingKey>,
107        catalyst_id: &CatalystId,
108    ) {
109        for key in keys {
110            self.insert_public_key(key, catalyst_id.clone());
111        }
112    }
113
114    /// Returns a Catalyst ID corresponding the given public key.
115    pub fn find_public_key(
116        &self,
117        key: &VerifyingKey,
118    ) -> Option<&CatalystId> {
119        self.public_keys.get(key)
120    }
121
122    /// Adds a registration to the context.
123    pub fn insert_registration(
124        &mut self,
125        id: CatalystId,
126        txn_id: TransactionId,
127        slot: Slot,
128        txn_index: TxnIndex,
129        prv_txn: Option<TransactionId>,
130        removed_stake_addresses: HashSet<StakeAddress>,
131    ) {
132        use std::collections::hash_map::Entry;
133
134        let value = RbacQuery {
135            txn_id: txn_id.into(),
136            slot_no: slot.into(),
137            txn_index: txn_index.into(),
138            prv_txn_id: prv_txn.map(Into::into),
139            removed_stake_addresses: removed_stake_addresses
140                .into_iter()
141                .map(Into::into)
142                .collect(),
143        };
144
145        match self.registrations.entry(id) {
146            Entry::Occupied(e) => {
147                e.into_mut().push(value);
148            },
149            Entry::Vacant(e) => {
150                e.insert(vec![value]);
151            },
152        }
153    }
154
155    /// Returns a list of registrations.
156    pub fn find_registrations(
157        &self,
158        id: &CatalystId,
159    ) -> Option<&[RbacQuery]> {
160        self.registrations.get(id).map(Vec::as_slice)
161    }
162}