diff --git a/src/internet_identity/src/anchor_management/registration.rs b/src/internet_identity/src/anchor_management/registration.rs index 76aacf5607..bd14a6b12e 100644 --- a/src/internet_identity/src/anchor_management/registration.rs +++ b/src/internet_identity/src/anchor_management/registration.rs @@ -244,20 +244,25 @@ pub fn register( verify_caller_is_device_or_temp_key(&temp_key, &device_principal); let allocation = state::storage_borrow_mut(|storage| storage.allocate_anchor()); - let Some((anchor_number, mut anchor)) = allocation else { + let Some(mut anchor) = allocation else { return RegisterResponse::CanisterFull; }; + let anchor_number = anchor.anchor_number(); - anchor - .add_device(device.clone()) - .unwrap_or_else(|err| trap(&format!("failed to register anchor {anchor_number}: {err}"))); + anchor.add_device(device.clone()).unwrap_or_else(|err| { + trap(&format!( + "failed to register anchor {}: {err}", + anchor_number + )) + }); activity_bookkeeping(&mut anchor, &device.pubkey); // write anchor to stable memory state::storage_borrow_mut(|storage| { - storage.write(anchor_number, anchor).unwrap_or_else(|err| { + storage.write(anchor).unwrap_or_else(|err| { trap(&format!( - "failed to write data of anchor {anchor_number}: {err}" + "failed to write data of anchor {}: {err}", + anchor_number )) }); }); diff --git a/src/internet_identity/src/authz_utils.rs b/src/internet_identity/src/authz_utils.rs index 9bcf1a7405..ab45262095 100644 --- a/src/internet_identity/src/authz_utils.rs +++ b/src/internet_identity/src/authz_utils.rs @@ -78,7 +78,7 @@ where let result = op(&mut anchor); // write back anchor - state::storage_borrow_mut(|storage| storage.write(anchor_number, anchor)) + state::storage_borrow_mut(|storage| storage.write(anchor)) .map_err(|err| E::from(IdentityUpdateError::StorageError(anchor_number, err)))?; match result { @@ -126,7 +126,7 @@ pub fn check_authz_and_record_activity( check_authorization(anchor_number).map_err(IdentityUpdateError::from)?; let maybe_domain = anchor.device(&device_key).unwrap().ii_domain(); anchor_management::activity_bookkeeping(&mut anchor, &device_key); - state::storage_borrow_mut(|storage| storage.write(anchor_number, anchor)) + state::storage_borrow_mut(|storage| storage.write(anchor)) .map_err(|err| IdentityUpdateError::StorageError(anchor_number, err))?; Ok(maybe_domain) } diff --git a/src/internet_identity/src/main.rs b/src/internet_identity/src/main.rs index 3db6899e17..f2e3006dff 100644 --- a/src/internet_identity/src/main.rs +++ b/src/internet_identity/src/main.rs @@ -203,27 +203,28 @@ fn remove(anchor_number: AnchorNumber, device_key: DeviceKey) { #[query] #[candid_method(query)] fn lookup(anchor_number: AnchorNumber) -> Vec { - state::storage_borrow(|storage| { - storage - .read(anchor_number) - .unwrap_or_default() - .into_devices() - .into_iter() - .map(DeviceData::from) - .map(|mut d| { - // Remove non-public fields. - d.alias = "".to_string(); - d.metadata = None; - d - }) - .collect() - }) + let Ok(anchor) = state::storage_borrow(|storage| storage.read(anchor_number)) else { + return vec![]; + }; + anchor + .into_devices() + .into_iter() + .map(DeviceData::from) + .map(|mut d| { + // Remove non-public fields. + d.alias = "".to_string(); + d.metadata = None; + d + }) + .collect() } #[query] #[candid_method(query)] fn get_anchor_credentials(anchor_number: AnchorNumber) -> AnchorCredentials { - let anchor = state::storage_borrow(|storage| storage.read(anchor_number).unwrap_or_default()); + let Ok(anchor) = state::storage_borrow(|storage| storage.read(anchor_number)) else { + return AnchorCredentials::default(); + }; anchor.into_devices().into_iter().fold( AnchorCredentials { @@ -506,8 +507,12 @@ mod v2_api { #[query] #[candid_method(query)] fn identity_authn_info(identity_number: IdentityNumber) -> Result { - let anchor = - state::storage_borrow(|storage| storage.read(identity_number).unwrap_or_default()); + let Ok(anchor) = state::storage_borrow(|storage| storage.read(identity_number)) else { + return Ok(IdentityAuthnInfo { + authn_methods: vec![], + recovery_authn_methods: vec![], + }); + }; let authn_info = anchor.into_devices().into_iter().fold( IdentityAuthnInfo { diff --git a/src/internet_identity/src/storage.rs b/src/internet_identity/src/storage.rs index f05acc0e57..01125332e2 100644 --- a/src/internet_identity/src/storage.rs +++ b/src/internet_identity/src/storage.rs @@ -270,18 +270,19 @@ impl Storage { /// /// Returns None if the range of Identity Anchor assigned to this /// storage is exhausted. - pub fn allocate_anchor(&mut self) -> Option<(AnchorNumber, Anchor)> { + pub fn allocate_anchor(&mut self) -> Option { let anchor_number = self.header.id_range_lo + self.header.num_anchors as u64; if anchor_number >= self.header.id_range_hi { return None; } self.header.num_anchors += 1; self.flush(); - Some((anchor_number, Anchor::new())) + Some(Anchor::new(anchor_number)) } /// Writes the data of the specified anchor to stable memory. - pub fn write(&mut self, anchor_number: AnchorNumber, data: Anchor) -> Result<(), StorageError> { + pub fn write(&mut self, data: Anchor) -> Result<(), StorageError> { + let anchor_number = data.anchor_number(); let storable_anchor = StorableAnchor::from(data); let buf = storable_anchor.to_bytes(); if buf.len() > self.header.entry_size as usize { @@ -310,7 +311,7 @@ impl Storage { reader.read_exact(&mut buf).expect("failed to read memory"); let storable_anchor = StorableAnchor::from_bytes(Cow::Owned(buf)); - Ok(Anchor::from(storable_anchor)) + Ok(Anchor::from((anchor_number, storable_anchor))) } /// Make sure all the required metadata is recorded to stable memory. diff --git a/src/internet_identity/src/storage/anchor.rs b/src/internet_identity/src/storage/anchor.rs index c6d7ccf468..416bbee27f 100644 --- a/src/internet_identity/src/storage/anchor.rs +++ b/src/internet_identity/src/storage/anchor.rs @@ -14,8 +14,9 @@ mod tests; /// The anchor has limited visibility for the constructor to make sure it is loaded from storage. /// The devices can only be modified by the exposed functions which keeps invariant checking local /// to this module. -#[derive(Clone, Debug, Default, Eq, PartialEq)] +#[derive(Clone, Debug, Eq, PartialEq)] pub struct Anchor { + anchor_number: AnchorNumber, devices: Vec, metadata: Option>, } @@ -107,9 +108,10 @@ impl From for StorableAnchor { } } -impl From for Anchor { - fn from(storable_anchor: StorableAnchor) -> Self { +impl From<(AnchorNumber, StorableAnchor)> for Anchor { + fn from((anchor_number, storable_anchor): (AnchorNumber, StorableAnchor)) -> Self { Anchor { + anchor_number, devices: storable_anchor.devices, metadata: storable_anchor.metadata, } @@ -119,13 +121,18 @@ impl From for Anchor { impl Anchor { /// Creation of new anchors is restricted in order to make sure that the device checks are /// not accidentally bypassed. - pub(super) fn new() -> Anchor { + pub(super) fn new(anchor_number: AnchorNumber) -> Anchor { Self { + anchor_number, devices: vec![], metadata: None, } } + pub fn anchor_number(&self) -> AnchorNumber { + self.anchor_number + } + pub fn add_device(&mut self, device: Device) -> Result<(), AnchorError> { if self.devices.iter().any(|e| e.pubkey == device.pubkey) { return Err(AnchorError::DuplicateDevice { diff --git a/src/internet_identity/src/storage/anchor/tests.rs b/src/internet_identity/src/storage/anchor/tests.rs index 6a1d9f4781..001dcdd7c8 100644 --- a/src/internet_identity/src/storage/anchor/tests.rs +++ b/src/internet_identity/src/storage/anchor/tests.rs @@ -1,16 +1,18 @@ use crate::storage::anchor::{Anchor, AnchorError, Device}; use candid::Principal; use internet_identity_interface::internet_identity::types::{ - DeviceData, DeviceProtection, KeyType, MetadataEntry, Purpose, Timestamp, + AnchorNumber, DeviceData, DeviceProtection, KeyType, MetadataEntry, Purpose, Timestamp, }; use serde_bytes::ByteBuf; use std::collections::HashMap; const TEST_CALLER_PUBKEY: [u8; 10] = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]; +const ANCHOR_NUMBER: AnchorNumber = 10_000; + #[test] fn should_add_device() { - let mut anchor = Anchor::new(); + let mut anchor = Anchor::new(ANCHOR_NUMBER); anchor.add_device(sample_device()).unwrap(); assert_eq!(anchor.devices, vec![sample_device()]) @@ -18,7 +20,7 @@ fn should_add_device() { #[test] fn should_remove_device() { - let mut anchor = Anchor::new(); + let mut anchor = Anchor::new(ANCHOR_NUMBER); anchor.add_device(sample_device()).unwrap(); assert_eq!(anchor.devices, vec![sample_device()]); @@ -29,7 +31,7 @@ fn should_remove_device() { #[test] fn should_modify_device() { - let mut anchor = Anchor::new(); + let mut anchor = Anchor::new(ANCHOR_NUMBER); let mut device = sample_device(); anchor.add_device(device.clone()).unwrap(); device.alias = "modified alias".to_string(); @@ -43,7 +45,7 @@ fn should_modify_device() { #[test] fn should_enforce_max_number_of_devices() { - let mut anchor = Anchor::new(); + let mut anchor = Anchor::new(ANCHOR_NUMBER); for i in 0..10 { anchor.add_device(device(i)).unwrap(); } @@ -56,7 +58,7 @@ fn should_enforce_max_number_of_devices() { #[test] fn should_enforce_pubkey_limit() { - let mut anchor = Anchor::new(); + let mut anchor = Anchor::new(ANCHOR_NUMBER); let mut device = sample_device(); device.pubkey = ByteBuf::from([0; 301]); @@ -71,7 +73,7 @@ fn should_enforce_pubkey_limit() { #[test] fn should_enforce_credential_id_limit() { - let mut anchor = Anchor::new(); + let mut anchor = Anchor::new(ANCHOR_NUMBER); let mut device = sample_device(); device.credential_id = Some(ByteBuf::from([0; 201])); @@ -86,7 +88,7 @@ fn should_enforce_credential_id_limit() { #[test] fn should_enforce_alias_limit() { - let mut anchor = Anchor::new(); + let mut anchor = Anchor::new(ANCHOR_NUMBER); let mut device = sample_device(); device.alias = "a".repeat(65); @@ -101,7 +103,7 @@ fn should_enforce_alias_limit() { #[test] fn should_enforce_unique_device_keys() { - let mut anchor = Anchor::new(); + let mut anchor = Anchor::new(ANCHOR_NUMBER); anchor.add_device(sample_device()).unwrap(); let result = anchor.add_device(sample_device()); @@ -112,7 +114,7 @@ fn should_enforce_unique_device_keys() { #[test] fn should_enforce_cumulative_device_limit() { - let mut anchor = Anchor::new(); + let mut anchor = Anchor::new(ANCHOR_NUMBER); for i in 0..4 { anchor.add_device(large_device(i)).unwrap(); @@ -140,7 +142,7 @@ fn should_enforce_cumulative_device_limit() { #[test] fn should_enforce_cumulative_size_limit_on_identity_metadata() { - let mut anchor = Anchor::new(); + let mut anchor = Anchor::new(ANCHOR_NUMBER); let metadata = HashMap::from_iter(vec![( "some key".to_string(), @@ -158,7 +160,7 @@ fn should_enforce_cumulative_size_limit_on_identity_metadata() { #[test] fn should_enforce_cumulative_size_limit_on_device_and_metadata() { - let mut anchor = Anchor::new(); + let mut anchor = Anchor::new(ANCHOR_NUMBER); for i in 0..4 { anchor.add_device(large_device(i)).unwrap(); @@ -179,7 +181,7 @@ fn should_enforce_cumulative_size_limit_on_device_and_metadata() { #[test] fn should_enforce_single_recovery_phrase() { - let mut anchor = Anchor::new(); + let mut anchor = Anchor::new(ANCHOR_NUMBER); anchor .add_device(recovery_phrase(0, DeviceProtection::Unprotected)) @@ -195,7 +197,7 @@ fn should_enforce_single_recovery_phrase() { #[test] fn should_allow_protection_only_on_recovery_phrases() { - let mut anchor = Anchor::new(); + let mut anchor = Anchor::new(ANCHOR_NUMBER); let result = anchor.add_device(Device { pubkey: Default::default(), @@ -220,6 +222,7 @@ fn should_allow_protection_only_on_recovery_phrases() { fn should_prevent_mutation_when_invariants_are_violated() { let mut device1 = recovery_phrase(1, DeviceProtection::Unprotected); let mut anchor = Anchor { + anchor_number: ANCHOR_NUMBER, devices: vec![ device1.clone(), recovery_phrase(2, DeviceProtection::Unprotected), @@ -236,6 +239,7 @@ fn should_prevent_mutation_when_invariants_are_violated() { #[test] fn should_prevent_addition_when_invariants_are_violated() { let mut anchor = Anchor { + anchor_number: ANCHOR_NUMBER, devices: vec![ recovery_phrase(1, DeviceProtection::Unprotected), recovery_phrase(2, DeviceProtection::Unprotected), @@ -252,6 +256,7 @@ fn should_prevent_addition_when_invariants_are_violated() { fn should_allow_removal_when_invariants_are_violated() { let device1 = recovery_phrase(1, DeviceProtection::Unprotected); let mut anchor = Anchor { + anchor_number: ANCHOR_NUMBER, devices: vec![ device1.clone(), recovery_phrase(2, DeviceProtection::Unprotected), @@ -267,7 +272,7 @@ fn should_allow_removal_when_invariants_are_violated() { #[test] fn should_enforce_caller_on_removal_of_protected_devices() { let device1 = recovery_phrase(1, DeviceProtection::Protected); - let mut anchor = Anchor::new(); + let mut anchor = Anchor::new(ANCHOR_NUMBER); anchor.add_device(device1.clone()).unwrap(); let result = anchor.remove_device(&device1.pubkey); @@ -282,7 +287,7 @@ fn should_enforce_caller_on_removal_of_protected_devices() { #[test] fn should_enforce_caller_on_modification_of_protected_devices() { let mut device1 = recovery_phrase(1, DeviceProtection::Protected); - let mut anchor = Anchor::new(); + let mut anchor = Anchor::new(ANCHOR_NUMBER); anchor.add_device(device1.clone()).unwrap(); device1.alias = "new alias".to_string(); @@ -301,7 +306,7 @@ fn should_allow_removal_of_protected_device_with_matching_caller() { let mut device1 = recovery_phrase(1, DeviceProtection::Protected); device1.pubkey = ByteBuf::from(TEST_CALLER_PUBKEY); - let mut anchor = Anchor::new(); + let mut anchor = Anchor::new(ANCHOR_NUMBER); anchor.add_device(device1.clone()).unwrap(); anchor.remove_device(&device1.pubkey).unwrap(); @@ -314,7 +319,7 @@ fn should_allow_modification_of_protected_device_with_matching_caller() { let mut device1 = recovery_phrase(1, DeviceProtection::Protected); device1.pubkey = ByteBuf::from(TEST_CALLER_PUBKEY); - let mut anchor = Anchor::new(); + let mut anchor = Anchor::new(ANCHOR_NUMBER); anchor.add_device(device1.clone()).unwrap(); device1.alias = "new alias".to_string(); @@ -328,7 +333,7 @@ fn should_allow_modification_of_protected_device_with_matching_caller() { #[test] fn should_not_remove_unknown_device() { - let mut anchor = Anchor::new(); + let mut anchor = Anchor::new(ANCHOR_NUMBER); anchor.add_device(sample_device()).unwrap(); let result = anchor.remove_device(&device(1).pubkey); @@ -339,7 +344,7 @@ fn should_not_remove_unknown_device() { #[test] fn should_not_modify_unknown_device() { - let mut anchor = Anchor::new(); + let mut anchor = Anchor::new(ANCHOR_NUMBER); anchor.add_device(sample_device()).unwrap(); let result = anchor.modify_device(&device(1).pubkey, device(1)); @@ -350,7 +355,7 @@ fn should_not_modify_unknown_device() { #[test] fn should_not_allow_modification_of_device_key() { - let mut anchor = Anchor::new(); + let mut anchor = Anchor::new(ANCHOR_NUMBER); anchor.add_device(sample_device()).unwrap(); let result = anchor.modify_device(&sample_device().pubkey, device(1)); @@ -364,7 +369,7 @@ fn should_not_allow_modification_of_device_key() { #[test] fn should_not_allow_to_add_recovery_phrase_with_credential_id() { - let mut anchor = Anchor::new(); + let mut anchor = Anchor::new(ANCHOR_NUMBER); let device = Device { key_type: KeyType::SeedPhrase, credential_id: Some(ByteBuf::from(vec![1, 2, 3])), @@ -381,7 +386,7 @@ fn should_not_allow_to_add_recovery_phrase_with_credential_id() { #[test] fn should_not_allow_to_modify_recovery_phrase_to_add_credential_id() { - let mut anchor = Anchor::new(); + let mut anchor = Anchor::new(ANCHOR_NUMBER); let mut device = Device { key_type: KeyType::SeedPhrase, credential_id: None, @@ -400,7 +405,7 @@ fn should_not_allow_to_modify_recovery_phrase_to_add_credential_id() { #[test] fn should_update_timestamp() { - let mut anchor = Anchor::new(); + let mut anchor = Anchor::new(ANCHOR_NUMBER); let device = sample_device(); const TIMESTAMP: Timestamp = 7896546556; anchor.add_device(device.clone()).unwrap(); @@ -460,7 +465,7 @@ fn should_not_allow_reserved_metadata_key() { "metadata", ]; - let mut anchor = Anchor::new(); + let mut anchor = Anchor::new(ANCHOR_NUMBER); for key in RESERVED_KEYS { let mut device = sample_device(); device.metadata = Some(HashMap::from([( diff --git a/src/internet_identity/src/storage/tests.rs b/src/internet_identity/src/storage/tests.rs index c833aeb1dc..61ce4f3a9a 100644 --- a/src/internet_identity/src/storage/tests.rs +++ b/src/internet_identity/src/storage/tests.rs @@ -60,13 +60,13 @@ fn should_recover_header_from_memory_v7() { fn add_test_anchor_data(storage: &mut Storage, number_of_anchors: usize) { for _ in 0..number_of_anchors { - let (anchor_number, mut anchor) = storage + let mut anchor = storage .allocate_anchor() .expect("Failure allocating an anchor."); anchor - .add_device(sample_unique_device(anchor_number as usize)) + .add_device(sample_unique_device(anchor.anchor_number() as usize)) .expect("Failure adding a device"); - storage.write(anchor_number, anchor.clone()).unwrap(); + storage.write(anchor.clone()).unwrap(); } } @@ -93,10 +93,11 @@ fn should_allocate_new_bucket_after_2048_anchors_v7() { fn should_read_previous_write() { let memory = VectorMemory::default(); let mut storage = Storage::new((12345, 678910), memory); - let (anchor_number, mut anchor) = storage.allocate_anchor().unwrap(); + let mut anchor = storage.allocate_anchor().unwrap(); + let anchor_number = anchor.anchor_number(); anchor.add_device(sample_device()).unwrap(); - storage.write(anchor_number, anchor.clone()).unwrap(); + storage.write(anchor.clone()).unwrap(); let read_anchor = storage.read(anchor_number).unwrap(); assert_eq!(anchor, read_anchor); @@ -106,20 +107,20 @@ fn should_read_previous_write() { fn should_serialize_first_record() { let memory = VectorMemory::default(); let mut storage = Storage::new((123, 456), memory.clone()); - let (anchor_number, mut anchor) = storage.allocate_anchor().unwrap(); - assert_eq!(anchor_number, 123u64); + let mut anchor = storage.allocate_anchor().unwrap(); + assert_eq!(anchor.anchor_number(), 123u64); anchor.add_device(sample_device()).unwrap(); let expected_length = candid::encode_one(StorableAnchor::from(anchor.clone())) .unwrap() .len(); - storage.write(anchor_number, anchor.clone()).unwrap(); + storage.write(anchor.clone()).unwrap(); let mut buf = vec![0u8; expected_length]; memory.read(RESERVED_HEADER_BYTES + LENGTH_OFFSET, &mut buf); let decoded_from_memory: StorableAnchor = candid::decode_one(&buf).unwrap(); - assert_eq!(Anchor::from(decoded_from_memory), anchor); + assert_eq!(Anchor::from((123u64, decoded_from_memory)), anchor); } #[test] @@ -130,15 +131,15 @@ fn should_serialize_subsequent_record_to_expected_memory_location() { for _ in 0..100 { storage.allocate_anchor().unwrap(); } - let (anchor_number, mut anchor) = storage.allocate_anchor().unwrap(); - assert_eq!(anchor_number, 223u64); + let mut anchor = storage.allocate_anchor().unwrap(); + assert_eq!(anchor.anchor_number(), 223u64); anchor.add_device(sample_device()).unwrap(); let expected_length = candid::encode_one(StorableAnchor::from(anchor.clone())) .unwrap() .len(); - storage.write(anchor_number, anchor.clone()).unwrap(); + storage.write(anchor.clone()).unwrap(); let mut buf = vec![0u8; expected_length]; memory.read( @@ -146,16 +147,18 @@ fn should_serialize_subsequent_record_to_expected_memory_location() { &mut buf, ); let decoded_from_memory: StorableAnchor = candid::decode_one(&buf).unwrap(); - assert_eq!(Anchor::from(decoded_from_memory), anchor); + assert_eq!(Anchor::from((223u64, decoded_from_memory)), anchor); } #[test] fn should_not_write_using_anchor_number_outside_allocated_range() { let memory = VectorMemory::default(); let mut storage = Storage::new((123, 456), memory); - let (_, anchor) = storage.allocate_anchor().unwrap(); + storage.allocate_anchor().unwrap(); + + let anchor = Anchor::new(222); - let result = storage.write(222, anchor); + let result = storage.write(anchor); assert!(matches!(result, Err(StorageError::BadAnchorNumber(_)))) } @@ -164,13 +167,13 @@ fn should_deserialize_first_record() { let memory = VectorMemory::default(); memory.grow(3); let mut storage = Storage::new((123, 456), memory.clone()); - let (anchor_number, mut anchor) = storage + let mut anchor = storage .allocate_anchor() .expect("Failed to allocate an anchor"); storage - .write(anchor_number, anchor.clone()) + .write(anchor.clone()) .expect("Failed to write anchor"); - assert_eq!(anchor_number, 123u64); + assert_eq!(anchor.anchor_number(), 123u64); anchor.add_device(sample_device()).unwrap(); let buf = candid::encode_one(StorableAnchor::from(anchor.clone())).unwrap(); @@ -188,15 +191,13 @@ fn should_deserialize_subsequent_record_at_expected_memory_location() { memory.grow(9); // grow memory to accommodate a write to record 100 let mut storage = Storage::new((123, 456), memory.clone()); for _ in 0..100 { - let (anchor_number, anchor) = storage + let anchor = storage .allocate_anchor() .expect("Failed to allocate an anchor"); - storage - .write(anchor_number, anchor) - .expect("Failed to write anchor"); + storage.write(anchor).expect("Failed to write anchor"); } - let (anchor_number, mut anchor) = storage.allocate_anchor().unwrap(); - assert_eq!(anchor_number, 223u64); + let mut anchor = storage.allocate_anchor().unwrap(); + assert_eq!(anchor.anchor_number(), 223u64); anchor.add_device(sample_device()).unwrap(); let buf = candid::encode_one(StorableAnchor::from(anchor.clone())).unwrap(); @@ -339,8 +340,8 @@ fn should_overwrite_persistent_state_with_next_anchor() { memory.read(EXPECTED_ADDRESS, &mut buf); assert_eq!(buf, PERSISTENT_STATE_MAGIC); - let (anchor_number, anchor) = storage.allocate_anchor().unwrap(); - storage.write(anchor_number, anchor).unwrap(); + let anchor = storage.allocate_anchor().unwrap(); + storage.write(anchor).unwrap(); let mut buf = vec![0u8; 4]; memory.read(EXPECTED_ADDRESS, &mut buf); @@ -362,10 +363,8 @@ fn should_read_previously_stored_persistent_state() { // Create storage, and add anchors (so that MemoryManager allocates a memory block for anchors). let mut storage = Storage::new((1, 100), memory.clone()); for _ in 0..NUM_ANCHORS { - let (anchor_number, anchor) = storage.allocate_anchor().expect("Failed allocating anchor"); - storage - .write(anchor_number, anchor) - .expect("Failed writing anchor"); + let anchor = storage.allocate_anchor().expect("Failed allocating anchor"); + storage.write(anchor).expect("Failed writing anchor"); } memory.write(EXPECTED_ADDRESS, b"IIPS".as_ref());