cat_gateway/db/index/block/cip36/
mod.rs1pub(crate) mod insert_cip36;
4pub(crate) mod insert_cip36_for_vote_key;
5pub(crate) mod insert_cip36_invalid;
6
7use std::sync::Arc;
8
9use cardano_blockchain_types::{Cip36, MultiEraBlock, Slot, StakeAddress, TxnIndex};
10use catalyst_types::hashes::Blake2b224Hash;
11use scylla::Session;
12
13use super::certs;
14use crate::{
15 db::index::{
16 queries::{FallibleQueryTasks, PreparedQuery, SizedBatch},
17 session::CassandraSession,
18 },
19 settings::cassandra_db,
20};
21
22pub(crate) struct Cip36InsertQuery {
24 registrations: Vec<insert_cip36::Params>,
26 invalid: Vec<insert_cip36_invalid::Params>,
28 for_vote_key: Vec<insert_cip36_for_vote_key::Params>,
30 stake_regs: Vec<certs::StakeRegistrationInsertQuery>,
32}
33
34impl Cip36InsertQuery {
35 pub(crate) fn new() -> Self {
37 Cip36InsertQuery {
38 registrations: Vec::new(),
39 invalid: Vec::new(),
40 for_vote_key: Vec::new(),
41 stake_regs: Vec::new(),
42 }
43 }
44
45 pub(crate) async fn prepare_batch(
47 session: &Arc<Session>, cfg: &cassandra_db::EnvVars,
48 ) -> anyhow::Result<(SizedBatch, SizedBatch, SizedBatch)> {
49 let insert_cip36_batch = insert_cip36::Params::prepare_batch(session, cfg).await;
50 let insert_cip36_invalid_batch =
51 insert_cip36_invalid::Params::prepare_batch(session, cfg).await;
52 let insert_cip36_for_vote_key_addr_batch =
53 insert_cip36_for_vote_key::Params::prepare_batch(session, cfg).await;
54 Ok((
59 insert_cip36_batch?,
60 insert_cip36_invalid_batch?,
61 insert_cip36_for_vote_key_addr_batch?,
62 ))
63 }
64
65 pub(crate) fn index(
67 &mut self, index: TxnIndex, slot_no: Slot, block: &MultiEraBlock,
68 ) -> anyhow::Result<()> {
69 match Cip36::new(block, index, true) {
71 Ok(Some(cip36)) if cip36.is_valid() => {
74 let voting_key = cip36.voting_pks().first().ok_or(anyhow::anyhow!(
76 "Valid CIP36 registration must have one voting key"
77 ))?;
78
79 let stake_pk = cip36.stake_pk().ok_or(anyhow::anyhow!(
80 "Valid CIP36 registration must have one stake public key"
81 ))?;
82 let stake_pk_hash = Blake2b224Hash::new(&stake_pk.to_bytes());
83 let stake_address = StakeAddress::new(block.network(), false, stake_pk_hash);
84
85 self.registrations.push(insert_cip36::Params::new(
86 voting_key, slot_no, index, &cip36,
87 ));
88 self.for_vote_key
89 .push(insert_cip36_for_vote_key::Params::new(
90 voting_key, slot_no, index, &cip36, true,
91 ));
92 self.stake_regs
93 .push(certs::StakeRegistrationInsertQuery::new(
94 stake_address,
95 slot_no,
96 index,
97 *stake_pk,
98 false,
99 false,
100 false,
101 true,
102 None,
103 ));
104 },
105 Ok(Some(cip36)) => {
107 if let Some(stake_pk) = cip36.stake_pk() {
109 if cip36.voting_pks().is_empty() {
110 self.invalid.push(insert_cip36_invalid::Params::new(
111 None, slot_no, index, &cip36,
112 ));
113 } else {
114 for voting_key in cip36.voting_pks() {
115 self.invalid.push(insert_cip36_invalid::Params::new(
116 Some(voting_key),
117 slot_no,
118 index,
119 &cip36,
120 ));
121 self.for_vote_key
122 .push(insert_cip36_for_vote_key::Params::new(
123 voting_key, slot_no, index, &cip36, false,
124 ));
125 }
126 }
127
128 let stake_pk_hash = Blake2b224Hash::new(&stake_pk.to_bytes());
129 let stake_address = StakeAddress::new(block.network(), false, stake_pk_hash);
130 self.stake_regs
131 .push(certs::StakeRegistrationInsertQuery::new(
132 stake_address,
133 slot_no,
134 index,
135 *stake_pk,
136 false,
137 false,
138 false,
139 true,
140 None,
141 ));
142 }
143 },
144 _ => {},
145 }
146 Ok(())
147 }
148
149 pub(crate) fn execute(self, session: &Arc<CassandraSession>) -> FallibleQueryTasks {
153 let mut query_handles: FallibleQueryTasks = Vec::new();
154
155 if !self.registrations.is_empty() {
156 let inner_session = session.clone();
157 query_handles.push(tokio::spawn(async move {
158 inner_session
159 .execute_batch(
160 PreparedQuery::Cip36RegistrationInsertQuery,
161 self.registrations,
162 )
163 .await
164 }));
165 }
166
167 if !self.invalid.is_empty() {
168 let inner_session = session.clone();
169 query_handles.push(tokio::spawn(async move {
170 inner_session
171 .execute_batch(
172 PreparedQuery::Cip36RegistrationInsertErrorQuery,
173 self.invalid,
174 )
175 .await
176 }));
177 }
178
179 if !self.for_vote_key.is_empty() {
180 let inner_session = session.clone();
181 query_handles.push(tokio::spawn(async move {
182 inner_session
183 .execute_batch(
184 PreparedQuery::Cip36RegistrationForVoteKeyInsertQuery,
185 self.for_vote_key,
186 )
187 .await
188 }));
189 }
190
191 if !self.stake_regs.is_empty() {
192 let inner_session = session.clone();
193 query_handles.push(tokio::spawn(async move {
194 inner_session
195 .execute_batch(PreparedQuery::StakeRegistrationInsertQuery, self.stake_regs)
196 .await
197 }));
198 }
199
200 query_handles
201 }
202}
203
204#[cfg(test)]
205mod tests {
206 use super::*;
207 use crate::db::index::tests::test_utils;
208
209 #[test]
210 fn index() {
211 let block = test_utils::block_2();
212 let mut query = Cip36InsertQuery::new();
213 query.index(0.into(), 0.into(), &block).unwrap();
214 assert_eq!(1, query.registrations.len());
215 assert!(query.invalid.is_empty());
216 assert_eq!(1, query.for_vote_key.len());
217 assert_eq!(1, query.stake_regs.len());
218 }
219}