Skip to main content

iota_types/
deny_rule_governance.rs

1// Copyright (c) 2026 IOTA Stiftung
2// SPDX-License-Identifier: Apache-2.0
3
4use iota_sdk_types::{Address, DenyRuleSet, ObjectId};
5
6/// Read access to a set of transaction deny rules.
7///
8/// Implemented by both a validator's local `TransactionDenyConfig` and the
9/// consensus-governed [`DenyRuleSet`], so the deny checks can run against
10/// either source without knowing which one is in effect.
11pub trait DenyRuleConfig: Send + Sync {
12    /// Whether `address` is denied as a transaction sender or gas sponsor.
13    fn is_address_denied(&self, address: &Address) -> bool;
14    /// Whether the object `id` is denied as an input or receiving object.
15    fn is_object_denied(&self, id: &ObjectId) -> bool;
16    /// Whether the package `id` is denied as a (transitive) dependency.
17    fn is_package_denied(&self, id: &ObjectId) -> bool;
18    /// Whether any address is denied; lets checks skip scanning signers when
19    /// there are none.
20    fn has_denied_addresses(&self) -> bool;
21    /// Whether any object is denied; lets checks skip scanning input and
22    /// receiving objects when there are none.
23    fn has_denied_objects(&self) -> bool;
24    /// Whether any package is denied; lets checks skip resolving package
25    /// dependencies (which loads packages from the store) when there are none.
26    fn has_denied_packages(&self) -> bool;
27    fn package_publish_disabled(&self) -> bool;
28    fn package_upgrade_disabled(&self) -> bool;
29    fn shared_object_disabled(&self) -> bool;
30    fn user_transaction_disabled(&self) -> bool;
31    fn receiving_objects_disabled(&self) -> bool;
32    fn move_authenticator_disabled(&self) -> bool;
33}
34
35impl DenyRuleConfig for DenyRuleSet {
36    fn is_address_denied(&self, address: &Address) -> bool {
37        self.denied_addresses.contains(address)
38    }
39
40    fn is_object_denied(&self, id: &ObjectId) -> bool {
41        self.denied_objects.contains(id)
42    }
43
44    fn is_package_denied(&self, id: &ObjectId) -> bool {
45        self.denied_packages.contains(id)
46    }
47
48    fn has_denied_addresses(&self) -> bool {
49        !self.denied_addresses.is_empty()
50    }
51
52    fn has_denied_objects(&self) -> bool {
53        !self.denied_objects.is_empty()
54    }
55
56    fn has_denied_packages(&self) -> bool {
57        !self.denied_packages.is_empty()
58    }
59
60    fn package_publish_disabled(&self) -> bool {
61        self.package_publish_disabled
62    }
63
64    fn package_upgrade_disabled(&self) -> bool {
65        self.package_upgrade_disabled
66    }
67
68    fn shared_object_disabled(&self) -> bool {
69        self.shared_object_disabled
70    }
71
72    fn user_transaction_disabled(&self) -> bool {
73        self.user_transaction_disabled
74    }
75
76    fn receiving_objects_disabled(&self) -> bool {
77        self.receiving_objects_disabled
78    }
79
80    fn move_authenticator_disabled(&self) -> bool {
81        self.move_authenticator_disabled
82    }
83}
84
85#[cfg(test)]
86mod tests {
87    use iota_sdk_types::{Address, DenyRuleSet, ObjectId};
88
89    use crate::deny_rule_governance::DenyRuleConfig;
90
91    fn sample_rule_set() -> DenyRuleSet {
92        DenyRuleSet {
93            denied_addresses: [Address::new([1u8; 32]), Address::new([2u8; 32])]
94                .into_iter()
95                .collect(),
96            denied_objects: [ObjectId::new([3u8; 32])].into_iter().collect(),
97            denied_packages: [ObjectId::new([4u8; 32])].into_iter().collect(),
98            package_publish_disabled: true,
99            package_upgrade_disabled: false,
100            shared_object_disabled: true,
101            user_transaction_disabled: false,
102            receiving_objects_disabled: true,
103            move_authenticator_disabled: false,
104        }
105    }
106
107    #[test]
108    fn deny_rule_config_reflects_set_contents() {
109        let rules = sample_rule_set();
110
111        assert!(rules.is_address_denied(&Address::new([1u8; 32])));
112        assert!(!rules.is_address_denied(&Address::new([9u8; 32])));
113        assert!(rules.is_object_denied(&ObjectId::new([3u8; 32])));
114        assert!(!rules.is_object_denied(&ObjectId::new([9u8; 32])));
115        assert!(rules.is_package_denied(&ObjectId::new([4u8; 32])));
116        assert!(!rules.is_package_denied(&ObjectId::new([9u8; 32])));
117
118        assert!(rules.has_denied_addresses());
119        assert!(rules.has_denied_objects());
120        assert!(rules.has_denied_packages());
121
122        assert!(rules.package_publish_disabled());
123        assert!(!rules.package_upgrade_disabled());
124        assert!(rules.shared_object_disabled());
125        assert!(!rules.user_transaction_disabled());
126        assert!(rules.receiving_objects_disabled());
127        assert!(!rules.move_authenticator_disabled());
128    }
129
130    /// An empty set denies nothing.
131    #[test]
132    fn empty_deny_rule_set_denies_nothing() {
133        let rules = DenyRuleSet::default();
134        assert!(!rules.is_address_denied(&Address::new([1u8; 32])));
135        assert!(!rules.is_object_denied(&ObjectId::new([1u8; 32])));
136        assert!(!rules.has_denied_addresses());
137        assert!(!rules.has_denied_objects());
138        assert!(!rules.has_denied_packages());
139        assert!(!rules.user_transaction_disabled());
140    }
141}