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