identity_iota_core/rebased/migration/
registry.rs1use std::collections::HashMap;
5use std::str::FromStr as _;
6use std::sync::LazyLock;
7
8use iota_interaction::move_types::language_storage::StructTag;
9use iota_interaction::rpc_types::EventFilter;
10use iota_interaction::rpc_types::IotaData;
11use iota_interaction::types::base_types::ObjectID;
12use iota_interaction::types::id::ID;
13use iota_interaction::IotaClientTrait;
14use phf::phf_map;
15use phf::Map;
16use product_common::core_client::CoreClientReadOnly;
17use tokio::sync::RwLock;
18
19use crate::rebased::client::IdentityClientReadOnly;
20use crate::rebased::iota::package::identity_package_id;
21
22use super::get_identity;
23use super::OnChainIdentity;
24
25static MIGRATION_REGISTRY_ON_IOTA_NETWORK: Map<&str, &str> = phf_map! {
26 "e678123a" => "0x940ae1c2c48dade9ec01cc1eebab33ab6fecadda422ea18b105c47839fc64425", "2304aa97" => "0xaacb529c289aec9de2a474faaa4ef68b04632bb6a5d08372ca5b60e3df659f59", "6364aad5" => "0xa884c72da9971da8ec32efade0a9b05faa114770ba85f10925d0edbc3fa3edc3", };
30
31static MIGRATION_REGISTRY_ON_CUSTOM_NETWORK: LazyLock<RwLock<HashMap<String, ObjectID>>> =
32 LazyLock::new(|| RwLock::new(HashMap::default()));
33
34pub(crate) async fn migration_registry_id<C>(client: &C) -> Result<ObjectID, Error>
35where
36 C: CoreClientReadOnly,
37{
38 let network_id = client.network_name().as_ref();
39
40 if let Some(registry) = MIGRATION_REGISTRY_ON_CUSTOM_NETWORK.read().await.get(network_id) {
42 return Ok(*registry);
43 }
44
45 if let Some(registry) = MIGRATION_REGISTRY_ON_IOTA_NETWORK.get(network_id) {
47 return Ok(registry.parse().unwrap());
48 }
49
50 let package_id = identity_package_id(client)
51 .await
52 .map_err(|_| Error::Client(anyhow::anyhow!("unknown network {network_id}")))?;
53 let registry_id = find_migration_registry(client, package_id).await?;
54
55 MIGRATION_REGISTRY_ON_CUSTOM_NETWORK
57 .write()
58 .await
59 .insert(network_id.to_string(), registry_id);
60
61 Ok(package_id)
62}
63
64pub(crate) fn set_migration_registry_id(chain_id: &str, id: ObjectID) {
65 MIGRATION_REGISTRY_ON_CUSTOM_NETWORK
66 .blocking_write()
67 .insert(chain_id.to_owned(), id);
68}
69
70#[derive(thiserror::Error, Debug)]
72pub enum Error {
73 #[error(transparent)]
75 Client(#[from] anyhow::Error),
76 #[error("could not locate MigrationRegistry object: {0}")]
78 NotFound(String),
79 #[error("malformed MigrationRegistry's entry: {0}")]
81 Malformed(String),
82}
83
84pub async fn lookup(id_client: &IdentityClientReadOnly, alias_id: ObjectID) -> Result<Option<OnChainIdentity>, Error> {
87 let registry_id = migration_registry_id(id_client).await?;
88 let dynamic_field_name = serde_json::from_value(serde_json::json!({
89 "type": "0x2::object::ID",
90 "value": alias_id.to_string()
91 }))
92 .expect("valid move value");
93
94 let identity_id = id_client
95 .read_api()
96 .get_dynamic_field_object(registry_id, dynamic_field_name)
97 .await
98 .map_err(|e| Error::Client(e.into()))?
99 .data
100 .map(|data| {
101 data
102 .content
103 .and_then(|content| content.try_into_move())
104 .and_then(|move_object| move_object.fields.to_json_value().get_mut("value").map(std::mem::take))
105 .and_then(|value| serde_json::from_value::<ID>(value).map(|id| id.bytes).ok())
106 .ok_or(Error::Malformed(
107 "invalid MigrationRegistry's Entry encoding".to_string(),
108 ))
109 })
110 .transpose()?;
111
112 if let Some(id) = identity_id {
113 get_identity(id_client, id).await.map_err(|e| Error::Client(e.into()))
114 } else {
115 Ok(None)
116 }
117}
118
119async fn find_migration_registry<C>(iota_client: &C, package_id: ObjectID) -> Result<ObjectID, Error>
120where
121 C: CoreClientReadOnly,
122{
123 #[derive(serde::Deserialize)]
124 struct MigrationRegistryCreatedEvent {
125 id: ObjectID,
126 }
127
128 let event_filter = EventFilter::MoveEventType(
129 StructTag::from_str(&format!("{package_id}::migration_registry::MigrationRegistryCreated")).expect("valid utf8"),
130 );
131 let mut returned_events = iota_client
132 .client_adapter()
133 .event_api()
134 .query_events(event_filter, None, Some(1), false)
135 .await
136 .map_err(|e| Error::Client(e.into()))?
137 .data;
138 let event = if !returned_events.is_empty() {
139 returned_events.swap_remove(0)
140 } else {
141 return Err(Error::NotFound(format!(
142 "No MigrationRegistryCreated event on network {}",
143 iota_client.network_name()
144 )));
145 };
146
147 serde_json::from_value::<MigrationRegistryCreatedEvent>(event.parsed_json)
148 .map(|e| e.id)
149 .map_err(|e| Error::Malformed(e.to_string()))
150}