Skip to content

Commit 0ac318e

Browse files
authored
Merge pull request #47 from iotaledger/feat/add-invariants-checking
Feat/add invariants checking
2 parents 354c6dd + 20cf939 commit 0ac318e

File tree

2 files changed

+102
-2
lines changed

2 files changed

+102
-2
lines changed

notarization-move/Move.lock

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -30,8 +30,8 @@ flavor = "iota"
3030

3131
[env.localnet]
3232
chain-id = "c7a0abbd"
33-
original-published-id = "0x3cb59fb212b83ee62dd6258025fcbe0332ca156ceb8d5d85fe9b9a6cf066c4ab"
34-
latest-published-id = "0x3cb59fb212b83ee62dd6258025fcbe0332ca156ceb8d5d85fe9b9a6cf066c4ab"
33+
original-published-id = "0x7fab7adeb06a0087b65cd6712e270d338d39f002f8abfb3d252f88c843b61070"
34+
latest-published-id = "0x7fab7adeb06a0087b65cd6712e270d338d39f002f8abfb3d252f88c843b61070"
3535
published-version = "1"
3636

3737
[env.devnet]

notarization-rs/src/core/notarization.rs

Lines changed: 100 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@ use super::event::{DynamicNotarizationCreated, Event, LockedNotarizationCreated}
2020
use super::metadata::ImmutableMetadata;
2121
use super::operations::{NotarizationImpl, NotarizationOperations};
2222
use super::state::State;
23+
use super::timelock::{LockMetadata, TimeLock};
2324
use crate::error::Error;
2425
use crate::package::notarization_package_id;
2526

@@ -50,6 +51,38 @@ impl<M: Clone> CreateNotarization<M> {
5051
}
5152
}
5253

54+
/// Indicates if the invariants for `NotarizationMethod::Dynamic` are satisfied:
55+
///
56+
/// - Dynamic notarization can only have transfer locking or no
57+
/// `immutable_metadata.locking`.
58+
/// If `immutable_metadata.locking` exists, all locks except `transfer_lock`
59+
/// must be `TimeLock::None`
60+
/// and the `transfer_lock` must not be `TimeLock::None`.
61+
fn are_dynamic_notarization_invariants_ok(locking: &Option<LockMetadata>) -> bool {
62+
match locking {
63+
Some(lock_metadata) => {
64+
lock_metadata.delete_lock == TimeLock::None
65+
&& lock_metadata.update_lock == TimeLock::None
66+
&& lock_metadata.transfer_lock != TimeLock::None
67+
}
68+
None => true,
69+
}
70+
}
71+
72+
/// Indicates if the invariants for `NotarizationMethod::Locked` are satisfied:
73+
///
74+
/// - `locking` must exist.
75+
/// - `update_lock` and `transfer_lock` must be `TimeLock::UntilDestroyed`.
76+
fn are_locked_notarization_invariants_ok(locking: &Option<LockMetadata>) -> bool {
77+
match locking {
78+
Some(lock_metadata) => {
79+
lock_metadata.transfer_lock == TimeLock::UntilDestroyed
80+
&& lock_metadata.update_lock == TimeLock::UntilDestroyed
81+
}
82+
None => false,
83+
}
84+
}
85+
5386
/// Makes a [`ProgrammableTransaction`] for the [`CreateNotarization`] instance.
5487
async fn make_ptb(&self, client: &impl CoreClientReadOnly) -> Result<ProgrammableTransaction, Error> {
5588
let NotarizationBuilder {
@@ -74,6 +107,20 @@ impl<M: Clone> CreateNotarization<M> {
74107
));
75108
}
76109

110+
// Construct the locking metadata for dynamic notarization
111+
let locking = transfer_lock.as_ref().map(|t_lock| LockMetadata {
112+
update_lock: TimeLock::None,
113+
delete_lock: TimeLock::None,
114+
transfer_lock: t_lock.clone(),
115+
});
116+
117+
// Check invariants
118+
if !Self::are_dynamic_notarization_invariants_ok(&locking) {
119+
return Err(Error::InvalidArgument(
120+
"Dynamic notarization invariants are not satisfied".to_string(),
121+
));
122+
}
123+
77124
NotarizationImpl::new_dynamic(
78125
package_id,
79126
state,
@@ -93,6 +140,20 @@ impl<M: Clone> CreateNotarization<M> {
93140
Error::InvalidArgument("Delete lock is required for locked notarizations".to_string())
94141
})?;
95142

143+
// Construct the locking metadata for locked notarization
144+
let locking = Some(LockMetadata {
145+
update_lock: TimeLock::UntilDestroyed,
146+
delete_lock: delete_lock.clone(),
147+
transfer_lock: TimeLock::UntilDestroyed,
148+
});
149+
150+
// Check invariants
151+
if !Self::are_locked_notarization_invariants_ok(&locking) {
152+
return Err(Error::InvalidArgument(
153+
"Locked notarization invariants are not satisfied".to_string(),
154+
));
155+
}
156+
96157
NotarizationImpl::new_locked(
97158
package_id,
98159
state,
@@ -186,3 +247,42 @@ pub(crate) async fn get_object_ref_by_id_with_bcs<T: DeserializeOwned>(
186247

187248
Ok(notarization)
188249
}
250+
251+
#[cfg(test)]
252+
mod tests {
253+
use super::*;
254+
255+
#[test]
256+
fn test_dynamic_notarization_invariants() {
257+
let are_dynamic_notarization_invariants_ok = CreateNotarization::<()>::are_dynamic_notarization_invariants_ok;
258+
259+
assert!(are_dynamic_notarization_invariants_ok(&None));
260+
assert!(are_dynamic_notarization_invariants_ok(&Some(LockMetadata {
261+
update_lock: TimeLock::None,
262+
delete_lock: TimeLock::None,
263+
transfer_lock: TimeLock::UntilDestroyed,
264+
})));
265+
assert!(!are_dynamic_notarization_invariants_ok(&Some(LockMetadata {
266+
update_lock: TimeLock::None,
267+
delete_lock: TimeLock::None,
268+
transfer_lock: TimeLock::None,
269+
})));
270+
}
271+
272+
#[test]
273+
fn test_locked_notarization_invariants() {
274+
let are_locked_notarization_invariants_ok = CreateNotarization::<()>::are_locked_notarization_invariants_ok;
275+
276+
assert!(!are_locked_notarization_invariants_ok(&None));
277+
assert!(are_locked_notarization_invariants_ok(&Some(LockMetadata {
278+
update_lock: TimeLock::UntilDestroyed,
279+
delete_lock: TimeLock::UntilDestroyed,
280+
transfer_lock: TimeLock::UntilDestroyed,
281+
})));
282+
assert!(!are_locked_notarization_invariants_ok(&Some(LockMetadata {
283+
update_lock: TimeLock::UntilDestroyed,
284+
delete_lock: TimeLock::UntilDestroyed,
285+
transfer_lock: TimeLock::None,
286+
})));
287+
}
288+
}

0 commit comments

Comments
 (0)