iota_config/
transaction_deny_config.rs

1// Copyright (c) Mysten Labs, Inc.
2// Modifications Copyright (c) 2024 IOTA Stiftung
3// SPDX-License-Identifier: Apache-2.0
4
5use std::collections::HashSet;
6
7use iota_types::base_types::{IotaAddress, ObjectID};
8use once_cell::sync::OnceCell;
9use serde::{Deserialize, Serialize};
10
11#[derive(Clone, Debug, Default, Deserialize, Serialize)]
12#[serde(rename_all = "kebab-case")]
13pub struct TransactionDenyConfig {
14    /// A list of object IDs that are not allowed to be accessed/used in
15    /// transactions. Note that since this is checked during transaction
16    /// signing, only root object ids are supported here (i.e. no
17    /// child-objects). Similarly this does not apply to wrapped objects as
18    /// they are not directly accessible.
19    #[serde(default, skip_serializing_if = "Vec::is_empty")]
20    object_deny_list: Vec<ObjectID>,
21
22    /// A list of package object IDs that are not allowed to be called into in
23    /// transactions, either directly or indirectly through transitive
24    /// dependencies. Note that this does not apply to type arguments.
25    /// Also since we only compare the deny list against the upgraded package ID
26    /// of each dependency in the used package, when a package ID is denied,
27    /// newer versions of that package are still allowed. If we want to deny
28    /// the entire upgrade family of a package, we need to explicitly
29    /// specify all the package IDs in the deny list. TODO: We could
30    /// consider making this more flexible, e.g. whether to check in type args,
31    /// whether to block entire upgrade family, whether to allow upgrade and
32    /// etc.
33    #[serde(default, skip_serializing_if = "Vec::is_empty")]
34    package_deny_list: Vec<ObjectID>,
35
36    /// A list of iota addresses that are not allowed to be used as the sender
37    /// or sponsor.
38    #[serde(default, skip_serializing_if = "Vec::is_empty")]
39    address_deny_list: Vec<IotaAddress>,
40
41    /// Whether publishing new packages is disabled.
42    #[serde(default)]
43    package_publish_disabled: bool,
44
45    /// Whether upgrading existing packages is disabled.
46    #[serde(default)]
47    package_upgrade_disabled: bool,
48
49    /// Whether usage of shared objects is disabled.
50    #[serde(default)]
51    shared_object_disabled: bool,
52
53    /// Whether user transactions are disabled (i.e. only system transactions
54    /// are allowed). This is essentially a kill switch for transactions
55    /// processing to a degree.
56    #[serde(default)]
57    user_transaction_disabled: bool,
58
59    /// In-memory maps for faster lookup of various lists.
60    #[serde(skip)]
61    object_deny_set: OnceCell<HashSet<ObjectID>>,
62
63    #[serde(skip)]
64    package_deny_set: OnceCell<HashSet<ObjectID>>,
65
66    #[serde(skip)]
67    address_deny_set: OnceCell<HashSet<IotaAddress>>,
68
69    /// Whether receiving objects transferred to other objects is allowed
70    #[serde(default)]
71    receiving_objects_disabled: bool,
72
73    /// Whether `MoveAuthenticator` is disabled
74    #[serde(default)]
75    move_authenticator_disabled: bool,
76    // TODO: We could consider add a deny list for types that we want to disable public transfer.
77    // TODO: We could also consider disable more types of commands, such as transfer, split and
78    // etc.
79}
80
81impl TransactionDenyConfig {
82    pub fn get_object_deny_set(&self) -> &HashSet<ObjectID> {
83        self.object_deny_set
84            .get_or_init(|| self.object_deny_list.iter().cloned().collect())
85    }
86
87    pub fn get_package_deny_set(&self) -> &HashSet<ObjectID> {
88        self.package_deny_set
89            .get_or_init(|| self.package_deny_list.iter().cloned().collect())
90    }
91
92    pub fn get_address_deny_set(&self) -> &HashSet<IotaAddress> {
93        self.address_deny_set
94            .get_or_init(|| self.address_deny_list.iter().cloned().collect())
95    }
96
97    pub fn package_publish_disabled(&self) -> bool {
98        self.package_publish_disabled
99    }
100
101    pub fn package_upgrade_disabled(&self) -> bool {
102        self.package_upgrade_disabled
103    }
104
105    pub fn shared_object_disabled(&self) -> bool {
106        self.shared_object_disabled
107    }
108
109    pub fn user_transaction_disabled(&self) -> bool {
110        self.user_transaction_disabled
111    }
112
113    pub fn receiving_objects_disabled(&self) -> bool {
114        self.receiving_objects_disabled
115    }
116
117    pub fn move_authenticator_disabled(&self) -> bool {
118        self.move_authenticator_disabled
119    }
120}
121
122#[derive(Default)]
123pub struct TransactionDenyConfigBuilder {
124    config: TransactionDenyConfig,
125}
126
127impl TransactionDenyConfigBuilder {
128    pub fn new() -> Self {
129        Self::default()
130    }
131
132    pub fn build(self) -> TransactionDenyConfig {
133        self.config
134    }
135
136    pub fn disable_user_transaction(mut self) -> Self {
137        self.config.user_transaction_disabled = true;
138        self
139    }
140
141    pub fn disable_shared_object_transaction(mut self) -> Self {
142        self.config.shared_object_disabled = true;
143        self
144    }
145
146    pub fn disable_package_publish(mut self) -> Self {
147        self.config.package_publish_disabled = true;
148        self
149    }
150
151    pub fn disable_package_upgrade(mut self) -> Self {
152        self.config.package_upgrade_disabled = true;
153        self
154    }
155
156    pub fn disable_receiving_objects(mut self) -> Self {
157        self.config.receiving_objects_disabled = true;
158        self
159    }
160
161    pub fn add_denied_object(mut self, id: ObjectID) -> Self {
162        self.config.object_deny_list.push(id);
163        self
164    }
165
166    pub fn add_denied_address(mut self, address: IotaAddress) -> Self {
167        self.config.address_deny_list.push(address);
168        self
169    }
170
171    pub fn add_denied_package(mut self, id: ObjectID) -> Self {
172        self.config.package_deny_list.push(id);
173        self
174    }
175
176    pub fn disable_move_authenticator(mut self) -> Self {
177        self.config.move_authenticator_disabled = true;
178        self
179    }
180}