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(&mut self, transaction: TransactionId, catalyst_id: CatalystId) {
51        self.transactions.insert(transaction, catalyst_id);
52    }
53
54    /// Returns a Catalyst ID of the given transaction ID if it exists in the context.
55    pub fn find_transaction(&self, transaction_id: &TransactionId) -> Option<&CatalystId> {
56        self.transactions.get(transaction_id)
57    }
58
59    /// Adds a stake address to the context.
60    pub fn insert_address(&mut self, address: StakeAddress, catalyst_id: CatalystId) {
61        self.addresses.insert(address, catalyst_id);
62    }
63
64    /// Adds multiple addresses to the context.
65    pub fn insert_addresses(
66        &mut self, addresses: impl IntoIterator<Item = StakeAddress>, catalyst_id: &CatalystId,
67    ) {
68        for address in addresses {
69            self.insert_address(address, catalyst_id.clone());
70        }
71    }
72
73    /// Returns a Catalyst ID corresponding the given stake address.
74    pub fn find_address(&self, address: &StakeAddress) -> Option<&CatalystId> {
75        self.addresses.get(address)
76    }
77
78    /// Adds a public key to the context.
79    pub fn insert_public_key(&mut self, key: VerifyingKey, catalyst_id: CatalystId) {
80        self.public_keys.insert(key, catalyst_id);
81    }
82
83    /// Adds multiple public keys to the context.
84    pub fn insert_public_keys(
85        &mut self, keys: impl IntoIterator<Item = VerifyingKey>, catalyst_id: &CatalystId,
86    ) {
87        for key in keys {
88            self.insert_public_key(key, catalyst_id.clone());
89        }
90    }
91
92    /// Returns a Catalyst ID corresponding the given public key.
93    pub fn find_public_key(&self, key: &VerifyingKey) -> Option<&CatalystId> {
94        self.public_keys.get(key)
95    }
96
97    /// Adds a registration to the context.
98    pub fn insert_registration(
99        &mut self, id: CatalystId, txn_id: TransactionId, slot: Slot, txn_index: TxnIndex,
100        prv_txn: Option<TransactionId>, removed_stake_addresses: HashSet<StakeAddress>,
101    ) {
102        use std::collections::hash_map::Entry;
103
104        let value = RbacQuery {
105            txn_id: txn_id.into(),
106            slot_no: slot.into(),
107            txn_index: txn_index.into(),
108            prv_txn_id: prv_txn.map(Into::into),
109            removed_stake_addresses: removed_stake_addresses
110                .into_iter()
111                .map(Into::into)
112                .collect(),
113        };
114
115        match self.registrations.entry(id) {
116            Entry::Occupied(e) => {
117                e.into_mut().push(value);
118            },
119            Entry::Vacant(e) => {
120                e.insert(vec![value]);
121            },
122        }
123    }
124
125    /// Returns a list of registrations.
126    pub fn find_registrations(&self, id: &CatalystId) -> Option<&[RbacQuery]> {
127        self.registrations.get(id).map(Vec::as_slice)
128    }
129}