iota_types/
transaction_deny_rules.rs1use std::fmt;
5
6use iota_sdk_move_types::iota_framework::linked_table::{LinkedTable, Node};
7pub use iota_sdk_move_types::iota_framework::transaction_deny_rules::{
8 TransactionDenyRules, TransactionDenyRulesInnerV1,
9};
10use iota_sdk_types::{DenyRuleSet, Identifier, Version};
11use move_core_types::{account_address::AccountAddress, ident_str, identifier::IdentStr};
12use serde::{Serialize, de::DeserializeOwned};
13
14use crate::{
15 IOTA_FRAMEWORK_ADDRESS, IOTA_TRANSACTION_DENY_RULES_OBJECT_ID, MoveTypeTagTrait,
16 dynamic_field::get_dynamic_field_from_store,
17 error::{IotaError, IotaResult},
18 storage::ObjectStore,
19};
20
21pub const TRANSACTION_DENY_RULES_MODULE_NAME: &IdentStr = ident_str!("transaction_deny_rules");
22pub const TRANSACTION_DENY_RULES_MODULE: Identifier =
23 Identifier::from_static("transaction_deny_rules");
24pub const TRANSACTION_DENY_RULES_UPDATE_FUNCTION_NAME: Identifier =
25 Identifier::from_static("update");
26pub const TRANSACTION_DENY_RULES_CREATE_FUNCTION_NAME: Identifier =
27 Identifier::from_static("create");
28pub const RESOLVED_IOTA_TRANSACTION_DENY_RULES: (&AccountAddress, &IdentStr, &IdentStr) = (
29 &IOTA_FRAMEWORK_ADDRESS,
30 ident_str!("transaction_deny_rules"),
31 ident_str!("TransactionDenyRules"),
32);
33
34pub fn get_transaction_deny_rules_obj_initial_shared_version(
43 object_store: &dyn ObjectStore,
44) -> IotaResult<Option<Version>> {
45 Ok(object_store
46 .try_get_object(&IOTA_TRANSACTION_DENY_RULES_OBJECT_ID)?
47 .map(|obj| {
48 obj.owner
49 .into_opt_shared()
50 .expect("TransactionDenyRules object must be shared")
51 }))
52}
53
54pub const TRANSACTION_DENY_RULES_INNER_V1: u64 = 1;
55
56pub fn get_transaction_deny_rules(
64 object_store: &dyn ObjectStore,
65) -> IotaResult<Option<DenyRuleSet>> {
66 let Some(object) = object_store.try_get_object(&IOTA_TRANSACTION_DENY_RULES_OBJECT_ID)? else {
67 return Ok(None);
68 };
69 let iota_sdk_types::ObjectData::Struct(move_object) = &object.data else {
70 return Err(IotaError::ObjectDeserialization {
71 error: "TransactionDenyRules object must be a Move object".to_string(),
72 });
73 };
74 let rules: TransactionDenyRules = bcs::from_bytes(move_object.contents()).map_err(|err| {
75 IotaError::ObjectDeserialization {
76 error: format!("failed to decode TransactionDenyRules: {err}"),
77 }
78 })?;
79 if rules.inner.version != TRANSACTION_DENY_RULES_INNER_V1 {
80 return Err(IotaError::ObjectDeserialization {
81 error: format!(
82 "unsupported TransactionDenyRules inner version {}",
83 rules.inner.version
84 ),
85 });
86 }
87 let inner: TransactionDenyRulesInnerV1 =
88 get_dynamic_field_from_store(object_store, rules.inner.id.id.bytes, &rules.inner.version)?;
89
90 Ok(Some(DenyRuleSet {
91 denied_addresses: walk_linked_table(object_store, &inner.denied_addresses)?
92 .into_iter()
93 .collect(),
94 denied_objects: walk_linked_table(object_store, &inner.denied_objects)?
95 .into_iter()
96 .map(|id| id.bytes)
97 .collect(),
98 denied_packages: walk_linked_table(object_store, &inner.denied_packages)?
99 .into_iter()
100 .map(|id| id.bytes)
101 .collect(),
102 package_publish_disabled: inner.package_publish_disabled,
103 package_upgrade_disabled: inner.package_upgrade_disabled,
104 shared_object_disabled: inner.shared_object_disabled,
105 user_transaction_disabled: inner.user_transaction_disabled,
106 receiving_objects_disabled: inner.receiving_objects_disabled,
107 move_authenticator_disabled: inner.move_authenticator_disabled,
108 }))
109}
110
111fn walk_linked_table<K>(
114 object_store: &dyn ObjectStore,
115 table: &LinkedTable<K, bool>,
116) -> IotaResult<Vec<K>>
117where
118 K: MoveTypeTagTrait + Serialize + DeserializeOwned + Clone + fmt::Debug,
119{
120 let table_id = table.id.id.bytes;
121 let mut keys = Vec::with_capacity(table.size as usize);
122 let mut next = table.head.clone();
123 while let Some(key) = next {
124 if keys.len() as u64 == table.size {
127 return Err(IotaError::ObjectDeserialization {
128 error: format!(
129 "LinkedTable {} has more linked entries than its size {}",
130 table_id, table.size
131 ),
132 });
133 }
134 let node: Node<K, bool> = get_dynamic_field_from_store(object_store, table_id, &key)?;
135 keys.push(key);
136 next = node.next;
137 }
138 if keys.len() as u64 != table.size {
139 return Err(IotaError::ObjectDeserialization {
140 error: format!(
141 "LinkedTable {} links {} entries but its size is {}",
142 table_id,
143 keys.len(),
144 table.size
145 ),
146 });
147 }
148 Ok(keys)
149}