Skip to main content

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