1use async_trait::async_trait;
2use hopr_crypto_types::types::OffchainPublicKey;
3use hopr_db_api::{
4 errors::{DbError, Result},
5 resolver::HoprDbResolverOperations,
6};
7use hopr_primitive_types::{primitives::Address, traits::ToHex};
8use multiaddr::PeerId;
9
10use crate::{accounts::HoprDbAccountOperations, db::HoprDb};
11
12#[async_trait]
13impl HoprDbResolverOperations for HoprDb {
14 #[tracing::instrument(level = "trace", skip_all, fields(onchain_key = onchain_key.to_hex().as_str()), err)]
15 async fn resolve_packet_key(&self, onchain_key: &Address) -> Result<Option<OffchainPublicKey>> {
16 Ok(self
17 .translate_key(None, *onchain_key)
18 .await?
19 .map(|k| k.try_into())
20 .inspect(|v: &std::result::Result<OffchainPublicKey, _>| {
21 if let Ok(offchain_pk) = v {
22 tracing::trace!(
23 peer = %Into::<PeerId>::into(offchain_pk),
24 offchain_pk = offchain_pk.to_hex(),
25 "found offchain key",
26 );
27 }
28 })
29 .transpose()
30 .map_err(|_e| DbError::LogicalError("failed to transpose the translated key".into()))?)
31 }
32
33 #[tracing::instrument(level = "trace", skip_all, fields(offchain_key = %Into::<PeerId>::into(offchain_key)), ret, err)]
34 async fn resolve_chain_key(&self, offchain_key: &OffchainPublicKey) -> Result<Option<Address>> {
35 Ok(self
36 .translate_key(None, *offchain_key)
37 .await?
38 .map(|k| k.try_into())
39 .transpose()
40 .map_err(|_e| DbError::LogicalError("failed to transpose the translated key".into()))?)
41 }
42}
43
44#[cfg(test)]
45mod tests {
46 use hopr_crypto_types::prelude::{ChainKeypair, Keypair, OffchainKeypair};
47 use hopr_internal_types::account::{AccountEntry, AccountType};
48 use hopr_primitive_types::prelude::ToHex;
49 use sea_orm::{EntityTrait, Set};
50
51 use super::*;
52
53 #[tokio::test]
54 async fn test_get_offchain_key_should_return_nothing_if_a_mapping_to_chain_key_does_not_exist() -> anyhow::Result<()>
55 {
56 let db = HoprDb::new_in_memory(ChainKeypair::random()).await?;
57
58 let chain = ChainKeypair::random().public().to_address();
59
60 let actual_pk = db.resolve_packet_key(&chain).await?;
61 assert_eq!(actual_pk, None, "offchain key should not be present");
62 Ok(())
63 }
64
65 #[tokio::test]
66 async fn test_get_chain_key_should_return_nothing_if_a_mapping_to_offchain_key_does_not_exist() -> anyhow::Result<()>
67 {
68 let db = HoprDb::new_in_memory(ChainKeypair::random()).await?;
69
70 let packet = *OffchainKeypair::random().public();
71
72 let actual_ck = db.resolve_chain_key(&packet).await?;
73 assert_eq!(actual_ck, None, "chain key should not be present");
74 Ok(())
75 }
76
77 #[tokio::test]
78 async fn test_get_chain_key_should_succeed_if_a_mapping_to_offchain_key_exists() -> anyhow::Result<()> {
79 let db = HoprDb::new_in_memory(ChainKeypair::random()).await?;
80
81 let chain_1 = ChainKeypair::random().public().to_address();
84 let packet_1 = *OffchainKeypair::random().public();
85 let account_1 = hopr_db_entity::account::ActiveModel {
86 chain_key: Set(chain_1.to_hex()),
87 packet_key: Set(packet_1.to_hex()),
88 ..Default::default()
89 };
90
91 let chain_2 = ChainKeypair::random().public().to_address();
92 let packet_2 = *OffchainKeypair::random().public();
93 let account_2 = hopr_db_entity::account::ActiveModel {
94 chain_key: Set(chain_2.to_hex()),
95 packet_key: Set(packet_2.to_hex()),
96 ..Default::default()
97 };
98
99 hopr_db_entity::account::Entity::insert_many([account_1, account_2])
100 .exec(db.index_db.read_write())
101 .await?;
102
103 let actual_ck = db.resolve_chain_key(&packet_1).await?;
104 assert_eq!(actual_ck, Some(chain_1), "chain keys must match");
105 Ok(())
106 }
107
108 #[tokio::test]
109 async fn test_get_chain_key_should_succeed_if_a_mapping_to_offchain_key_exists_with_cache() -> anyhow::Result<()> {
110 let db = HoprDb::new_in_memory(ChainKeypair::random()).await?;
111
112 let chain_1 = ChainKeypair::random().public().to_address();
115 let packet_1 = *OffchainKeypair::random().public();
116 db.insert_account(
117 None,
118 AccountEntry {
119 public_key: packet_1,
120 chain_addr: chain_1,
121 entry_type: AccountType::NotAnnounced,
122 published_at: 1,
123 },
124 )
125 .await?;
126
127 let chain_2 = ChainKeypair::random().public().to_address();
128 let packet_2 = *OffchainKeypair::random().public();
129 db.insert_account(
130 None,
131 AccountEntry {
132 public_key: packet_2,
133 chain_addr: chain_2,
134 entry_type: AccountType::NotAnnounced,
135 published_at: 1,
136 },
137 )
138 .await?;
139
140 let actual_ck = db.resolve_chain_key(&packet_1).await?;
141 assert_eq!(actual_ck, Some(chain_1), "chain keys must match");
142 Ok(())
143 }
144
145 #[tokio::test]
146 async fn test_get_offchain_key_should_succeed_if_a_mapping_to_chain_key_exists() -> anyhow::Result<()> {
147 let db = HoprDb::new_in_memory(ChainKeypair::random()).await?;
148
149 let chain_1 = ChainKeypair::random().public().to_address();
152 let packet_1 = *OffchainKeypair::random().public();
153 let account_1 = hopr_db_entity::account::ActiveModel {
154 chain_key: Set(chain_1.to_hex()),
155 packet_key: Set(packet_1.to_hex()),
156 ..Default::default()
157 };
158
159 let chain_2 = ChainKeypair::random().public().to_address();
160 let packet_2 = *OffchainKeypair::random().public();
161 let account_2 = hopr_db_entity::account::ActiveModel {
162 chain_key: Set(chain_2.to_hex()),
163 packet_key: Set(packet_2.to_hex()),
164 ..Default::default()
165 };
166
167 hopr_db_entity::account::Entity::insert_many([account_1, account_2])
168 .exec(db.index_db.read_write())
169 .await?;
170
171 let actual_pk = db.resolve_packet_key(&chain_2).await?;
172
173 assert_eq!(actual_pk, Some(packet_2), "packet keys must match");
174 Ok(())
175 }
176
177 #[tokio::test]
178 async fn test_get_offchain_key_should_succeed_if_a_mapping_to_chain_key_exists_with_cache() -> anyhow::Result<()> {
179 let db = HoprDb::new_in_memory(ChainKeypair::random()).await?;
180
181 let chain_1 = ChainKeypair::random().public().to_address();
184 let packet_1 = *OffchainKeypair::random().public();
185 db.insert_account(
186 None,
187 AccountEntry {
188 public_key: packet_1,
189 chain_addr: chain_1,
190 entry_type: AccountType::NotAnnounced,
191 published_at: 1,
192 },
193 )
194 .await?;
195
196 let chain_2 = ChainKeypair::random().public().to_address();
197 let packet_2 = *OffchainKeypair::random().public();
198 db.insert_account(
199 None,
200 AccountEntry {
201 public_key: packet_2,
202 chain_addr: chain_2,
203 entry_type: AccountType::NotAnnounced,
204 published_at: 1,
205 },
206 )
207 .await?;
208
209 let actual_pk = db.resolve_packet_key(&chain_2).await?;
210
211 assert_eq!(actual_pk, Some(packet_2), "packet keys must match");
212 Ok(())
213 }
214}