1use async_trait::async_trait;
2use hopr_db_entity::{network_eligibility, network_registry};
3use hopr_primitive_types::prelude::{Address, ToHex};
4use sea_orm::{ColumnTrait, DbErr, EntityTrait, QueryFilter, Set};
5use sea_query::OnConflict;
6
7use crate::{
8 HoprDbGeneralModelOperations, OptTx,
9 db::HoprDb,
10 errors::{DbSqlError, Result},
11};
12
13#[async_trait]
15pub trait HoprDbRegistryOperations {
16 async fn set_access_in_network_registry<'a>(&'a self, tx: OptTx<'a>, address: Address, allowed: bool)
18 -> Result<()>;
19
20 async fn is_allowed_in_network_registry<'a, T>(&'a self, tx: OptTx<'a>, address_like: &T) -> Result<bool>
22 where
23 Address: TryFrom<T>,
24 T: Clone + Sync;
25
26 async fn set_safe_eligibility<'a>(&'a self, tx: OptTx<'a>, address: Address, eligible: bool) -> Result<()>;
28
29 async fn is_safe_eligible<'a>(&'a self, tx: OptTx<'a>, address: Address) -> Result<bool>;
31}
32
33#[async_trait]
34impl HoprDbRegistryOperations for HoprDb {
35 async fn set_access_in_network_registry<'a>(
36 &'a self,
37 tx: OptTx<'a>,
38 address: Address,
39 allowed: bool,
40 ) -> Result<()> {
41 self.nest_transaction(tx)
42 .await?
43 .perform(|tx| {
44 Box::pin(async move {
45 if allowed {
46 let entry = network_registry::ActiveModel {
47 chain_address: Set(address.to_hex()),
48 ..Default::default()
49 };
50
51 match network_registry::Entity::insert(entry)
52 .on_conflict(
53 OnConflict::column(network_registry::Column::ChainAddress)
54 .do_nothing()
55 .to_owned(),
56 )
57 .exec(tx.as_ref())
58 .await
59 {
60 Ok(_) | Err(DbErr::RecordNotInserted) => Ok::<_, DbSqlError>(()),
61 Err(e) => Err(e.into()),
62 }
63 } else {
64 network_registry::Entity::delete_many()
65 .filter(network_registry::Column::ChainAddress.eq(address.to_hex()))
66 .exec(tx.as_ref())
67 .await?;
68 Ok::<_, DbSqlError>(())
69 }
70 })
71 })
72 .await
73 }
74
75 async fn is_allowed_in_network_registry<'a, T>(&'a self, tx: OptTx<'a>, address_like: &T) -> Result<bool>
76 where
77 Address: TryFrom<T>,
78 T: Clone + Sync,
79 {
80 let address = Address::try_from((*address_like).clone()).map_err(|_| DbSqlError::DecodingError)?;
81
82 self.nest_transaction(tx)
83 .await?
84 .perform(|tx| {
85 Box::pin(async move {
86 Ok::<_, DbSqlError>(
87 network_registry::Entity::find()
88 .filter(network_registry::Column::ChainAddress.eq(address.to_hex()))
89 .one(tx.as_ref())
90 .await?
91 .is_some(),
92 )
93 })
94 })
95 .await
96 }
97
98 async fn set_safe_eligibility<'a>(&'a self, tx: OptTx<'a>, address: Address, eligible: bool) -> Result<()> {
99 self.nest_transaction(tx)
100 .await?
101 .perform(|tx| {
102 Box::pin(async move {
103 if eligible {
104 let new_entry = network_eligibility::ActiveModel {
105 safe_address: Set(address.to_hex()),
106 ..Default::default()
107 };
108
109 match network_eligibility::Entity::insert(new_entry)
110 .on_conflict(
111 OnConflict::column(network_eligibility::Column::SafeAddress)
112 .do_nothing()
113 .to_owned(),
114 )
115 .exec(tx.as_ref())
116 .await
117 {
118 Ok(_) | Err(DbErr::RecordNotInserted) => Ok::<_, DbSqlError>(()),
119 Err(e) => Err(e.into()),
120 }
121 } else {
122 network_eligibility::Entity::delete_many()
123 .filter(network_eligibility::Column::SafeAddress.eq(address.to_hex()))
124 .exec(tx.as_ref())
125 .await?;
126 Ok::<_, DbSqlError>(())
127 }
128 })
129 })
130 .await
131 }
132
133 async fn is_safe_eligible<'a>(&'a self, tx: OptTx<'a>, address: Address) -> Result<bool> {
134 self.nest_transaction(tx)
135 .await?
136 .perform(|tx| {
137 Box::pin(async move {
138 Ok::<_, DbSqlError>(
139 network_eligibility::Entity::find()
140 .filter(network_eligibility::Column::SafeAddress.eq(address.to_hex()))
141 .one(tx.as_ref())
142 .await?
143 .is_some(),
144 )
145 })
146 })
147 .await
148 }
149}
150
151#[cfg(test)]
152mod tests {
153 use hopr_crypto_types::{keypairs::ChainKeypair, prelude::Keypair};
154 use hopr_primitive_types::prelude::Address;
155 use lazy_static::lazy_static;
156
157 use crate::{db::HoprDb, registry::HoprDbRegistryOperations};
158
159 lazy_static! {
160 static ref ADDR_1: Address = "4331eaa9542b6b034c43090d9ec1c2198758dbc3"
161 .parse()
162 .expect("lazy static address should be valid");
163 static ref ADDR_2: Address = "47d1677e018e79dcdd8a9c554466cb1556fa5007"
164 .parse()
165 .expect("lazy static address should be valid");
166 }
167
168 #[tokio::test]
169 async fn test_network_registry_db() -> anyhow::Result<()> {
170 let db = HoprDb::new_in_memory(ChainKeypair::random()).await?;
171
172 assert!(!db.is_allowed_in_network_registry(None, &ADDR_1.as_ref()).await?);
173 assert!(!db.is_allowed_in_network_registry(None, &ADDR_2.as_ref()).await?);
174
175 db.set_access_in_network_registry(None, *ADDR_1, true).await?;
176
177 assert!(db.is_allowed_in_network_registry(None, &ADDR_1.as_ref()).await?);
178 assert!(!db.is_allowed_in_network_registry(None, &ADDR_2.as_ref()).await?);
179
180 db.set_access_in_network_registry(None, *ADDR_1, true).await?;
181
182 assert!(db.is_allowed_in_network_registry(None, &ADDR_1.as_ref()).await?);
183 assert!(!db.is_allowed_in_network_registry(None, &ADDR_2.as_ref()).await?);
184
185 db.set_access_in_network_registry(None, *ADDR_1, false).await?;
186
187 assert!(!db.is_allowed_in_network_registry(None, &ADDR_1.as_ref()).await?);
188 assert!(!db.is_allowed_in_network_registry(None, &ADDR_2.as_ref()).await?);
189
190 db.set_access_in_network_registry(None, *ADDR_1, false).await?;
191
192 assert!(!db.is_allowed_in_network_registry(None, &ADDR_1.as_ref()).await?);
193 assert!(!db.is_allowed_in_network_registry(None, &ADDR_2.as_ref()).await?);
194 Ok(())
195 }
196
197 #[tokio::test]
198 async fn test_network_eligiblity_db() -> anyhow::Result<()> {
199 let db = HoprDb::new_in_memory(ChainKeypair::random()).await?;
200
201 assert!(!db.is_safe_eligible(None, *ADDR_1).await?);
202 assert!(!db.is_safe_eligible(None, *ADDR_2).await?);
203
204 db.set_safe_eligibility(None, *ADDR_1, true).await?;
205
206 assert!(db.is_safe_eligible(None, *ADDR_1).await?);
207 assert!(!db.is_safe_eligible(None, *ADDR_2).await?);
208
209 db.set_safe_eligibility(None, *ADDR_1, true).await?;
210
211 assert!(db.is_safe_eligible(None, *ADDR_1).await?);
212 assert!(!db.is_safe_eligible(None, *ADDR_2).await?);
213
214 db.set_safe_eligibility(None, *ADDR_1, false).await?;
215
216 assert!(!db.is_safe_eligible(None, *ADDR_1).await?);
217 assert!(!db.is_safe_eligible(None, *ADDR_2).await?);
218
219 db.set_safe_eligibility(None, *ADDR_1, false).await?;
220
221 assert!(!db.is_safe_eligible(None, *ADDR_1).await?);
222 assert!(!db.is_safe_eligible(None, *ADDR_2).await?);
223 Ok(())
224 }
225}