1use std::collections::HashSet;
5
6use iota_protocol_config::ProtocolConfig;
7use iota_sdk_types::{
8 Address, MoveAuthenticator, MoveAuthenticatorV1, ObjectDigest, ObjectId, ObjectReference,
9 SharedObjectReference, TypeTag, Version, crypto::IntentMessage,
10};
11use serde::Serialize;
12
13use crate::{
14 error::{IotaError, IotaResult, UserInputError, UserInputResult},
15 signature::{AuthenticatorTrait, VerifyParams},
16 transaction::{CallArg, CallArgExt, InputObjectKind},
17};
18
19mod move_authenticator_ext {
20 pub trait Sealed {}
21 impl Sealed for super::MoveAuthenticator {}
22 impl Sealed for super::MoveAuthenticatorV1 {}
23}
24
25pub trait MoveAuthenticatorExt: Sized + move_authenticator_ext::Sealed {
26 fn address(&self) -> Address;
29
30 fn call_args(&self) -> &[CallArg];
33
34 fn type_args(&self) -> &[TypeTag];
36
37 fn object_to_authenticate(&self) -> &CallArg;
39
40 fn object_to_authenticate_components(
41 &self,
42 ) -> UserInputResult<(ObjectId, Option<Version>, Option<ObjectDigest>)>;
43
44 fn input_objects(&self) -> Vec<InputObjectKind>;
45
46 fn receiving_objects(&self) -> Vec<ObjectReference>;
47
48 fn shared_objects(&self) -> Vec<SharedObjectReference>;
49
50 fn validity_check(&self, config: &ProtocolConfig) -> UserInputResult;
51}
52
53impl MoveAuthenticatorExt for MoveAuthenticator {
54 fn address(&self) -> Address {
55 match self {
56 Self::V1(v1) => v1.address(),
57 _ => unimplemented!(
58 "a new MoveAuthenticator enum variant was added and needs to be handled"
59 ),
60 }
61 }
62
63 fn call_args(&self) -> &[CallArg] {
64 match self {
65 Self::V1(v1) => v1.call_args(),
66 _ => unimplemented!(
67 "a new MoveAuthenticator enum variant was added and needs to be handled"
68 ),
69 }
70 }
71
72 fn type_args(&self) -> &[TypeTag] {
73 match self {
74 Self::V1(v1) => v1.type_args(),
75 _ => unimplemented!(
76 "a new MoveAuthenticator enum variant was added and needs to be handled"
77 ),
78 }
79 }
80
81 fn object_to_authenticate(&self) -> &CallArg {
82 match self {
83 Self::V1(v1) => v1.object_to_authenticate(),
84 _ => unimplemented!(
85 "a new MoveAuthenticator enum variant was added and needs to be handled"
86 ),
87 }
88 }
89
90 fn object_to_authenticate_components(
91 &self,
92 ) -> UserInputResult<(ObjectId, Option<Version>, Option<ObjectDigest>)> {
93 match self {
94 Self::V1(v1) => v1.object_to_authenticate_components(),
95 _ => unimplemented!(
96 "a new MoveAuthenticator enum variant was added and needs to be handled"
97 ),
98 }
99 }
100
101 fn input_objects(&self) -> Vec<InputObjectKind> {
102 match self {
103 Self::V1(v1) => v1.input_objects(),
104 _ => unimplemented!(
105 "a new MoveAuthenticator enum variant was added and needs to be handled"
106 ),
107 }
108 }
109
110 fn receiving_objects(&self) -> Vec<ObjectReference> {
111 match self {
112 Self::V1(v1) => v1.receiving_objects(),
113 _ => unimplemented!(
114 "a new MoveAuthenticator enum variant was added and needs to be handled"
115 ),
116 }
117 }
118
119 fn shared_objects(&self) -> Vec<SharedObjectReference> {
120 match self {
121 Self::V1(v1) => v1.shared_objects(),
122 _ => unimplemented!(
123 "a new MoveAuthenticator enum variant was added and needs to be handled"
124 ),
125 }
126 }
127
128 fn validity_check(&self, config: &ProtocolConfig) -> UserInputResult {
129 match self {
130 Self::V1(v1) => v1.validity_check(config),
131 _ => unimplemented!(
132 "a new MoveAuthenticator enum variant was added and needs to be handled"
133 ),
134 }
135 }
136}
137
138impl MoveAuthenticatorExt for MoveAuthenticatorV1 {
139 fn address(&self) -> Address {
142 self.address()
143 }
144
145 fn call_args(&self) -> &[CallArg] {
146 self.call_args()
147 }
148
149 fn type_args(&self) -> &[TypeTag] {
150 self.type_args()
151 }
152
153 fn object_to_authenticate(&self) -> &CallArg {
154 self.object_to_authenticate()
155 }
156
157 fn object_to_authenticate_components(
158 &self,
159 ) -> UserInputResult<(ObjectId, Option<Version>, Option<ObjectDigest>)> {
160 Ok(match self.object_to_authenticate() {
161 CallArg::Pure(_) => {
162 return Err(UserInputError::Unsupported(
163 "MoveAuthenticatorV1 cannot authenticate pure inputs".to_string(),
164 ));
165 }
166 CallArg::ImmutableOrOwned(object_ref) => (
167 object_ref.object_id,
168 Some(object_ref.version),
169 Some(object_ref.digest),
170 ),
171 CallArg::Shared(SharedObjectReference {
172 object_id, mutable, ..
173 }) => {
174 if *mutable {
175 return Err(UserInputError::Unsupported(
176 "MoveAuthenticatorV1 cannot authenticate mutable shared objects"
177 .to_string(),
178 ));
179 }
180
181 (*object_id, None, None)
182 }
183 CallArg::Receiving(_) => {
184 return Err(UserInputError::Unsupported(
185 "MoveAuthenticator cannot authenticate receiving objects".to_string(),
186 ));
187 }
188 _ => unimplemented!("a new CallArg enum variant was added and needs to be handled"),
189 })
190 }
191
192 fn input_objects(&self) -> Vec<InputObjectKind> {
195 self.call_args()
196 .iter()
197 .filter_map(|arg| arg.input_object_kind())
198 .chain(self.object_to_authenticate().input_object_kind())
199 .collect::<Vec<_>>()
200 }
201
202 fn receiving_objects(&self) -> Vec<ObjectReference> {
203 self.call_args()
204 .iter()
205 .filter_map(|arg| arg.as_opt_receiving().copied())
206 .collect()
207 }
208
209 fn shared_objects(&self) -> Vec<SharedObjectReference> {
212 self.call_args()
213 .iter()
214 .filter_map(|arg| arg.as_opt_shared())
215 .chain(self.object_to_authenticate().as_opt_shared())
216 .cloned()
217 .collect()
218 }
219
220 fn validity_check(&self, config: &ProtocolConfig) -> UserInputResult {
222 self.object_to_authenticate_components()?;
224
225 let max_args = (config.max_function_parameters() - 3) as usize;
234 fp_ensure!(
235 self.call_args().len() < max_args,
236 UserInputError::SizeLimitExceeded {
237 limit: "maximum arguments in MoveAuthenticatorV1".to_string(),
238 value: max_args.to_string()
239 }
240 );
241
242 fp_ensure!(
243 self.receiving_objects().is_empty(),
244 UserInputError::Unsupported(
245 "MoveAuthenticatorV1 cannot have receiving objects as input".to_string(),
246 )
247 );
248
249 let input_objects = self.input_objects();
255 if config.disallow_randomness_in_move_authenticator() {
256 fp_ensure!(
257 input_objects
258 .iter()
259 .all(|o| o.object_id() != ObjectId::RANDOMNESS_STATE),
260 UserInputError::RandomnessStateIsInMoveAuthenticatorInput {
261 object_id: ObjectId::RANDOMNESS_STATE,
262 }
263 );
264 }
265
266 if config.enable_pcool_flow() {
271 for kind in &input_objects {
272 match *kind {
273 InputObjectKind::MovePackage(package_id) => {
274 return Err(UserInputError::PackageIsInMoveAuthenticatorInput {
275 package_id,
276 });
277 }
278 InputObjectKind::SharedMoveObject {
279 id: ObjectId::AUTHENTICATOR_STATE,
280 ..
281 } => {
282 return Err(UserInputError::InaccessibleSystemObject {
283 object_id: ObjectId::AUTHENTICATOR_STATE,
284 });
285 }
286 InputObjectKind::SharedMoveObject {
287 id, mutable: true, ..
288 } => {
289 return Err(UserInputError::MutableSharedIsInMoveAuthenticatorInput {
290 object_id: id,
291 });
292 }
293 InputObjectKind::SharedMoveObject { .. }
294 | InputObjectKind::ImmOrOwnedMoveObject(_) => {}
295 }
296 }
297 }
298
299 let mut used = HashSet::new();
300 fp_ensure!(
301 input_objects.iter().all(|o| used.insert(o.object_id())),
302 UserInputError::DuplicateObjectRefInput
303 );
304
305 self.object_to_authenticate().validity_check(config)?;
309
310 self.call_args()
311 .iter()
312 .try_for_each(|obj| obj.validity_check(config))?;
313
314 let mut type_arguments_count = 0;
319 self.type_args().iter().try_for_each(|type_arg| {
320 crate::transaction::type_tag_validity_check(type_arg, config, &mut type_arguments_count)
321 })?;
322
323 Ok(())
324 }
325}
326
327impl AuthenticatorTrait for MoveAuthenticator {
328 fn verify_claims<T>(
331 &self,
332 value: &IntentMessage<T>,
333 author: Address,
334 aux_verify_data: &VerifyParams,
335 ) -> IotaResult
336 where
337 T: Serialize,
338 {
339 match self {
340 Self::V1(v1) => v1.verify_claims(value, author, aux_verify_data),
341 _ => unimplemented!(
342 "a new MoveAuthenticator enum variant was added and needs to be handled"
343 ),
344 }
345 }
346}
347
348impl AuthenticatorTrait for MoveAuthenticatorV1 {
349 fn verify_claims<T>(
352 &self,
353 _value: &IntentMessage<T>,
354 author: Address,
355 _aux_verify_data: &VerifyParams,
356 ) -> IotaResult
357 where
358 T: Serialize,
359 {
360 if author != self.address() {
361 return Err(IotaError::InvalidSignature {
362 error: "Invalid author".to_string(),
363 });
364 };
365
366 Ok(())
367 }
368}