diff --git a/sway-lib-std/src/experimental/storage.sw b/sway-lib-std/src/experimental/storage.sw index 0fad417b610..abe742fca3d 100644 --- a/sway-lib-std/src/experimental/storage.sw +++ b/sway-lib-std/src/experimental/storage.sw @@ -225,6 +225,35 @@ impl StorageMap { read::(key, 0) } + /// Retrieves the `StorageHandle` that describes the raw location in storage of the value + /// stored at `key`, regardless of whether a value is actually stored at that location or not. + /// + /// ### Arguments + /// + /// * `key` - The key to which the value is paired. + /// + /// ### Examples + /// + /// ```sway + /// storage { + /// map: StorageMap = StorageMap {} + /// } + /// + /// fn foo() { + /// let key = 5_u64; + /// let value = true; + /// storage.map.insert(key, value); + /// let retrieved_value = storage.map.get_handle(key).read().unwrap(); + /// assert(value == retrieved_value); + /// } + /// ``` + pub fn get_handle(self: StorageHandle, key: K) -> StorageHandle { + StorageHandle { + key: sha256((key, self.key)), + offset: 0 + } + } + /// Clears a value previously stored using a key /// /// Return a Boolean indicating whether there was a value previously stored at `key`. diff --git a/test/src/sdk-harness/test_projects/experimental_storage/mod.rs b/test/src/sdk-harness/test_projects/experimental_storage/mod.rs index f08d0b60cac..43940b2a10b 100644 --- a/test/src/sdk-harness/test_projects/experimental_storage/mod.rs +++ b/test/src/sdk-harness/test_projects/experimental_storage/mod.rs @@ -156,10 +156,3 @@ async fn maps_in_struct_access() { (None, None) ); } - -#[tokio::test] -async fn maps_in_map_access() { - let methods = test_experimental_storage_instance().await.methods(); - - methods.map_in_map_access().call().await.unwrap(); -} diff --git a/test/src/sdk-harness/test_projects/experimental_storage/src/main.sw b/test/src/sdk-harness/test_projects/experimental_storage/src/main.sw index 8b2930d96b5..5ea6d5c2012 100644 --- a/test/src/sdk-harness/test_projects/experimental_storage/src/main.sw +++ b/test/src/sdk-harness/test_projects/experimental_storage/src/main.sw @@ -80,7 +80,6 @@ storage { z: 0, w: 0, }, - map_in_map: StorageMap>> = StorageMap {}, } abi ExperimentalStorageTest { @@ -107,9 +106,6 @@ abi ExperimentalStorageTest { #[storage(read, write)] fn map_in_struct_write(key: (u64, u64), value: (u64, u64)); - - #[storage(read, write)] - fn map_in_map_access(); } impl ExperimentalStorageTest for Contract { @@ -220,23 +216,4 @@ impl ExperimentalStorageTest for Contract { storage.s2.map0.insert(key.0, value.0); storage.s2.map1.insert(key.1, value.1); } - - #[storage(read, write)] - fn map_in_map_access() { - storage.map_in_map.insert(0, StorageHandle { - key: std::hash::sha256((storage.map_in_map, 0)), - offset: 0, - }); - - storage.map_in_map.insert(1, StorageHandle { - key: std::hash::sha256((storage.map_in_map, 1)), - offset: 0, - }); - - storage.map_in_map.get(0).unwrap().insert(1, 42); - assert(storage.map_in_map.get(0).unwrap().get(1).unwrap() == 42); - - storage.map_in_map.get(1).unwrap().insert(1, 24); - assert(storage.map_in_map.get(1).unwrap().get(1).unwrap() == 24); - } } diff --git a/test/src/sdk-harness/test_projects/experimental_storage_nested_maps/Forc.lock b/test/src/sdk-harness/test_projects/experimental_storage_nested_maps/Forc.lock new file mode 100644 index 00000000000..3a1314f7d97 --- /dev/null +++ b/test/src/sdk-harness/test_projects/experimental_storage_nested_maps/Forc.lock @@ -0,0 +1,13 @@ +[[package]] +name = 'core' +source = 'path+from-root-2064A4F50B965AB3' + +[[package]] +name = 'experimental_storage_nested_maps' +source = 'member' +dependencies = ['std'] + +[[package]] +name = 'std' +source = 'path+from-root-2064A4F50B965AB3' +dependencies = ['core'] diff --git a/test/src/sdk-harness/test_projects/experimental_storage_nested_maps/Forc.toml b/test/src/sdk-harness/test_projects/experimental_storage_nested_maps/Forc.toml new file mode 100644 index 00000000000..37e0db43f42 --- /dev/null +++ b/test/src/sdk-harness/test_projects/experimental_storage_nested_maps/Forc.toml @@ -0,0 +1,8 @@ +[project] +authors = ["Fuel Labs "] +entry = "main.sw" +license = "Apache-2.0" +name = "experimental_storage_nested_maps" + +[dependencies] +std = { path = "../../../../../sway-lib-std" } diff --git a/test/src/sdk-harness/test_projects/experimental_storage_nested_maps/mod.rs b/test/src/sdk-harness/test_projects/experimental_storage_nested_maps/mod.rs new file mode 100644 index 00000000000..4a86209a1cd --- /dev/null +++ b/test/src/sdk-harness/test_projects/experimental_storage_nested_maps/mod.rs @@ -0,0 +1,51 @@ +use fuels::prelude::*; + +abigen!(Contract( + name = "TestExperimentalStorageNestedMapsContract", + abi = "test_projects/experimental_storage_nested_maps/out/debug/experimental_storage_nested_maps-abi.json", +)); + +async fn test_experimental_storage_nested_maps_instance( +) -> TestExperimentalStorageNestedMapsContract { + let wallet = launch_provider_and_get_wallet().await; + let id = Contract::deploy( + "test_projects/experimental_storage_nested_maps/out/debug/experimental_storage_nested_maps.bin", + &wallet, + TxParameters::default(), + StorageConfiguration::with_storage_path(Some( + "test_projects/experimental_storage_nested_maps/out/debug/experimental_storage_nested_maps-storage_slots.json" + .to_string(), + )), + ) + .await + .unwrap(); + + TestExperimentalStorageNestedMapsContract::new(id.clone(), wallet) +} + +#[tokio::test] +async fn nested_map_1_access() { + let methods = test_experimental_storage_nested_maps_instance() + .await + .methods(); + + methods.nested_map_1_access().call().await.unwrap(); +} + +#[tokio::test] +async fn nested_map_2_access() { + let methods = test_experimental_storage_nested_maps_instance() + .await + .methods(); + + methods.nested_map_2_access().call().await.unwrap(); +} + +#[tokio::test] +async fn nested_map_3_access() { + let methods = test_experimental_storage_nested_maps_instance() + .await + .methods(); + + methods.nested_map_3_access().call().await.unwrap(); +} diff --git a/test/src/sdk-harness/test_projects/experimental_storage_nested_maps/src/main.sw b/test/src/sdk-harness/test_projects/experimental_storage_nested_maps/src/main.sw new file mode 100644 index 00000000000..40c58776305 --- /dev/null +++ b/test/src/sdk-harness/test_projects/experimental_storage_nested_maps/src/main.sw @@ -0,0 +1,136 @@ +contract; + +use core::experimental::storage::*; +use std::experimental::storage::*; + +struct M { + u: b256, + v: u64, +} + +impl core::ops::Eq for M { + fn eq(self, other: Self) -> bool { + self.u == other.u && self.v == other.v + } +} + +pub enum E { + A: u64, + B: b256, +} + +impl core::ops::Eq for E { + fn eq(self, other: Self) -> bool { + match (self, other) { + (E::A(l), E::A(r)) => l == r, + (E::B(l), E::B(r)) => l == r, + _ => false, + } + } +} + +storage { + nested_map_1: StorageMap>> = StorageMap {}, + nested_map_2: StorageMap<(u64, u64), StorageMap>> = StorageMap {}, + nested_map_3: StorageMap>> = StorageMap {}, +} + +abi ExperimentalStorageTest { + #[storage(read, write)] + fn nested_map_1_access(); + + #[storage(read, write)] + fn nested_map_2_access(); + + #[storage(read, write)] + fn nested_map_3_access(); +} + +impl ExperimentalStorageTest for Contract { + #[storage(read, write)] + fn nested_map_1_access() { + storage.nested_map_1.get_handle(0).get_handle(0).insert(0, 1); + storage.nested_map_1.get_handle(0).get_handle(0).insert(1, 2); + storage.nested_map_1.get_handle(0).get_handle(1).insert(0, 3); + storage.nested_map_1.get_handle(0).get_handle(1).insert(1, 4); + storage.nested_map_1.get_handle(1).get_handle(0).insert(0, 5); + storage.nested_map_1.get_handle(1).get_handle(0).insert(1, 6); + storage.nested_map_1.get_handle(1).get_handle(1).insert(0, 7); + storage.nested_map_1.get_handle(1).get_handle(1).insert(1, 8); + + assert(storage.nested_map_1.get_handle(0).get_handle(0).get(0).unwrap() == 1); + assert(storage.nested_map_1.get_handle(0).get_handle(0).get(1).unwrap() == 2); + assert(storage.nested_map_1.get_handle(0).get_handle(1).get(0).unwrap() == 3); + assert(storage.nested_map_1.get_handle(0).get_handle(1).get(1).unwrap() == 4); + assert(storage.nested_map_1.get_handle(1).get_handle(0).get(0).unwrap() == 5); + assert(storage.nested_map_1.get_handle(1).get_handle(0).get(1).unwrap() == 6); + assert(storage.nested_map_1.get_handle(1).get_handle(1).get(0).unwrap() == 7); + assert(storage.nested_map_1.get_handle(1).get_handle(1).get(1).unwrap() == 8); + + assert(storage.nested_map_1.get_handle(2).get_handle(1).get(1).is_none()); + assert(storage.nested_map_1.get_handle(1).get_handle(2).get(1).is_none()); + assert(storage.nested_map_1.get_handle(1).get_handle(1).get(2).is_none()); + } + + #[storage(read, write)] + fn nested_map_2_access() { + let m1 = M { + u: 0x1111111111111111111111111111111111111111111111111111111111111111, + v: 1 + }; + let m2 = M { + u: 0x2222222222222222222222222222222222222222222222222222222222222222, + v: 2 + }; + + storage.nested_map_2.get_handle((0, 0)).get_handle("0000").insert(0, m1); + storage.nested_map_2.get_handle((0, 0)).get_handle("0001").insert(1, m2); + storage.nested_map_2.get_handle((0, 1)).get_handle("0000").insert(0, m1); + storage.nested_map_2.get_handle((0, 1)).get_handle("0001").insert(1, m2); + storage.nested_map_2.get_handle((1, 0)).get_handle("0000").insert(0, m1); + storage.nested_map_2.get_handle((1, 0)).get_handle("0001").insert(1, m2); + storage.nested_map_2.get_handle((1, 1)).get_handle("0000").insert(0, m1); + storage.nested_map_2.get_handle((1, 1)).get_handle("0001").insert(1, m2); + + assert(storage.nested_map_2.get_handle((0, 0)).get_handle("0000").get(0).unwrap() == m1); + assert(storage.nested_map_2.get_handle((0, 0)).get_handle("0001").get(1).unwrap() == m2); + assert(storage.nested_map_2.get_handle((0, 1)).get_handle("0000").get(0).unwrap() == m1); + assert(storage.nested_map_2.get_handle((0, 1)).get_handle("0001").get(1).unwrap() == m2); + assert(storage.nested_map_2.get_handle((1, 0)).get_handle("0000").get(0).unwrap() == m1); + assert(storage.nested_map_2.get_handle((1, 0)).get_handle("0001").get(1).unwrap() == m2); + assert(storage.nested_map_2.get_handle((1, 1)).get_handle("0000").get(0).unwrap() == m1); + assert(storage.nested_map_2.get_handle((1, 1)).get_handle("0001").get(1).unwrap() == m2); + } + + #[storage(read, write)] + fn nested_map_3_access() { + let m1 = M { + u: 0x1111111111111111111111111111111111111111111111111111111111111111, + v: 1 + }; + let m2 = M { + u: 0x2222222222222222222222222222222222222222222222222222222222222222, + v: 2 + }; + let e1 = E::A(42); + let e2 = E::B(0x3333333333333333333333333333333333333333333333333333333333333333); + + storage.nested_map_3.get_handle(0).get_handle(m1).insert(0, e1); + storage.nested_map_3.get_handle(0).get_handle(m2).insert(1, e2); + storage.nested_map_3.get_handle(0).get_handle(m1).insert(0, e1); + storage.nested_map_3.get_handle(0).get_handle(m2).insert(1, e2); + storage.nested_map_3.get_handle(1).get_handle(m1).insert(0, e1); + storage.nested_map_3.get_handle(1).get_handle(m2).insert(1, e2); + storage.nested_map_3.get_handle(1).get_handle(m1).insert(0, e1); + storage.nested_map_3.get_handle(1).get_handle(m2).insert(1, e2); + + assert(storage.nested_map_3.get_handle(0).get_handle(m1).get(0).unwrap() == e1); + assert(storage.nested_map_3.get_handle(0).get_handle(m2).get(1).unwrap() == e2); + assert(storage.nested_map_3.get_handle(0).get_handle(m1).get(0).unwrap() == e1); + assert(storage.nested_map_3.get_handle(0).get_handle(m2).get(1).unwrap() == e2); + assert(storage.nested_map_3.get_handle(1).get_handle(m1).get(0).unwrap() == e1); + assert(storage.nested_map_3.get_handle(1).get_handle(m2).get(1).unwrap() == e2); + assert(storage.nested_map_3.get_handle(1).get_handle(m1).get(0).unwrap() == e1); + assert(storage.nested_map_3.get_handle(1).get_handle(m2).get(1).unwrap() == e2); + } +} diff --git a/test/src/sdk-harness/test_projects/harness.rs b/test/src/sdk-harness/test_projects/harness.rs index dfc1e94f560..9e30b3ef18a 100644 --- a/test/src/sdk-harness/test_projects/harness.rs +++ b/test/src/sdk-harness/test_projects/harness.rs @@ -14,6 +14,7 @@ mod evm_ec_recover; mod experimental_storage; mod experimental_storage_init; mod experimental_storage_map; +mod experimental_storage_nested_maps; mod exponentiation; mod generics_in_abi; mod hashing;