diff --git a/docs/book/src/blockchain-development/purity.md b/docs/book/src/blockchain-development/purity.md index 26612c76823..cd9bd563d7f 100644 --- a/docs/book/src/blockchain-development/purity.md +++ b/docs/book/src/blockchain-development/purity.md @@ -16,6 +16,8 @@ fn increment_amount(increment: u64) -> u64 { } ``` +> **Note**: the `#[storage(write)]` attribute also permits a function to read from storage. This is due to the fact that partially writing a storage slot requires first reading the slot. + Impure functions which call other impure functions must have at least the same storage privileges or a superset of those for the function called. For example, to call a function with write access a caller must also have write access, or both read and write access. To call a function with read and write access the caller must also have both privileges. The `storage` attribute may also be applied to [methods and associated functions](../basics/methods_and_associated_functions.md), [trait](../advanced/traits.md) and [ABI](../sway-program-types/smart_contracts.md#the-abi-declaration) declarations. diff --git a/docs/book/src/blockchain-development/storage.md b/docs/book/src/blockchain-development/storage.md index c320cf1f49d..9f4e160004c 100644 --- a/docs/book/src/blockchain-development/storage.md +++ b/docs/book/src/blockchain-development/storage.md @@ -32,7 +32,7 @@ Generic storage maps are available in the standard library as `StorageMap` ## Manual Storage Management -It is possible to leverage FuelVM storage operations directly using the `std::storage::store` and `std::storage::get` functions provided in the standard library. With this approach you will have to manually assign the internal key used for storage. An example is as follows: +It is possible to leverage FuelVM storage operations directly using the `std::storage::storage_api::write` and `std::storage::storage_api::read` functions provided in the standard library. With this approach you will have to manually assign the internal key used for storage. An example is as follows: ```sway {{#include ../../../../examples/storage_example/src/main.sw}} diff --git a/docs/book/src/common-collections/storage_map.md b/docs/book/src/common-collections/storage_map.md index 985076f4e15..19dad004f11 100644 --- a/docs/book/src/common-collections/storage_map.md +++ b/docs/book/src/common-collections/storage_map.md @@ -47,28 +47,24 @@ We can get a value out of the storage map by providing its `key` to the `get` me Here, `value1` will have the value that's associated with the first address, and the result will be `42`. The `get` method returns an `Option`; if there’s no value for that key in the storage map, `get` will return `Option::None`. This program handles the `Option` by calling `unwrap_or` to set `value1` to zero if `map` doesn't have an entry for the key. -## Storage maps with multiple keys +## Storage Maps with Multiple Keys -You might find yourself needing a `StorageMap` where the type `V1` is itself another `StorageMap`. This is not allowed in Sway. The right approach is to use a single `StorageMap` where `K` is a tuple `(K1, K2)`. For example: +Maps with multiple keys can be implemented using tuples as keys. For example: ```sway {{#include ../../../../examples/storage_map/src/main.sw:storage_map_tuple_key}} ``` -## Limitations +## Nested Storage Naps -It is not currently allowed to have a `StorageMap` as a component of a complex type such as a struct or an enum. For example, the code below is not legal: +It is possible to nest storage maps as follows: ```sway -Struct Wrapper { - map1: StorageMap, - map2: StorageMap, -} +{{#include ../../../../examples/storage_map/src/main.sw:storage_map_nested}} +``` -storage { - w: Wrapper -} -... +The nested map can then be accessed as follows: -storage.w.map1.insert(..); +```sway +{{#include ../../../../examples/storage_map/src/main.sw:storage_map_nested_access}} ``` diff --git a/docs/book/src/common-collections/storage_vec.md b/docs/book/src/common-collections/storage_vec.md index ad911a59509..54124808afd 100644 --- a/docs/book/src/common-collections/storage_vec.md +++ b/docs/book/src/common-collections/storage_vec.md @@ -47,7 +47,7 @@ To read a value stored in a vector at a particular index, you can use the `get` {{#include ../../../../examples/storage_vec/src/main.sw:storage_vec_get}} ``` -Note three details here. First, we use the index value of `2` to get the third element because vectors are indexed by number, starting at zero. Second, we get the third element by using the `get` method with the index passed as an argument, which gives us an `Option`. Third, the ABI function calling `get` only requires the annotation `#[storage(read)]` as one might expect because `get` does not write to storage. +Note three details here. First, we use the index value of `2` to get the third element because vectors are indexed by number, starting at zero. Second, we get the third element by using the `get` method with the index passed as an argument, which gives us an `Option>`. Third, the ABI function calling `get` only requires the annotation `#[storage(read)]` as one might expect because `get` does not write to storage. When the `get` method is passed an index that is outside the vector, it returns `None` without panicking. This is particularly useful if accessing an element beyond the range of the vector may happen occasionally under normal circumstances. Your code will then have logic to handle having either `Some(element)` or `None`. For example, the index could be coming as a contract method argument. If the argument passed is too large, the method `get` will return a `None` value, and the contract method may then decide to revert when that happens or return a meaningful error that tells the user how many items are in the current vector and give them another chance to pass a valid value. @@ -59,7 +59,7 @@ To access each element in a vector in turn, we would iterate through all of the {{#include ../../../../examples/storage_vec/src/main.sw:storage_vec_iterate}} ``` -Again, this is quite similar to iterating over the elements of a `Vec` where we use the method `len` to return the length of the vector. We also call the method `unwrap` to extract the `Option` returned by `get`. We know that `unwrap` will not fail (i.e. will not cause a revert) because each index `i` passed to `get` is known to be smaller than the length of the vector. +Again, this is quite similar to iterating over the elements of a `Vec` where we use the method `len` to return the length of the vector. We also call the method `unwrap` to extract the `Option` returned by `get` followed by a call to `read()` to actually read the stored value. We know that `unwrap` will not fail (i.e. will not cause a revert) because each index `i` passed to `get` is known to be smaller than the length of the vector. ## Using an Enum to store Multiple Types @@ -82,3 +82,17 @@ We can now push different enum variants to the storage vector as follows: ``` Now that we’ve discussed some of the most common ways to use storage vectors, be sure to review the API documentation for all the many useful methods defined on `StorageVec` by the standard library. For now, these can be found in the [source code for `StorageVec`](https://github.com/FuelLabs/sway/blob/master/sway-lib-std/src/storage.sw). For example, in addition to `push`, a `pop` method removes and returns the last element, a `remove` method removes and returns the element at some chosen index within the vector, an `insert` method inserts an element at some chosen index within the vector, etc. + +## Nested Storage Vecs + +It is possible to nest storage vectors as follows: + +```sway +{{#include ../../../../examples/storage_vec/src/main.sw:storage_vec_nested}} +``` + +The nested vector can then be accessed as follows: + +```sway +{{#include ../../../../examples/storage_vec/src/main.sw:access_nested_vec}} +``` diff --git a/docs/book/src/introduction/standard_library.md b/docs/book/src/introduction/standard_library.md index 03831ed9954..0d49f25c85d 100644 --- a/docs/book/src/introduction/standard_library.md +++ b/docs/book/src/introduction/standard_library.md @@ -13,7 +13,7 @@ The standard library is made implicitly available to all Forc projects created u Importing items from the standard library can be done using the `use` keyword, just as importing items from any Sway project. For example: ```sway -use std::storage::StorageVec; +use std::storage::storage_vec::*; ``` This imports the `StorageVec` type into the current namespace. @@ -30,7 +30,8 @@ The current version of the prelude lives in [`std::prelude`](https://github.com/ - [`std::contract_id::ContractId`](https://github.com/FuelLabs/sway/blob/master/sway-lib-std/src/contract_id.sw), a wrapper around the `b256` type representing the ID of a contract. - [`std::identity::Identity`](https://github.com/FuelLabs/sway/blob/master/sway-lib-std/src/identity.sw), an enum with two possible variants: `Address: Address` and `ContractId: ContractId`. - [`std::vec::Vec`](https://github.com/FuelLabs/sway/blob/master/sway-lib-std/src/vec.sw), a growable, heap-allocated vector. -- [`std::storage::StorageMap`](https://github.com/FuelLabs/sway/blob/master/sway-lib-std/src/storage.sw), a key-value mapping in contract storage. +- [`std::storage::storage_key::*`](https://github.com/FuelLabs/sway/blob/master/sway-lib-std/src/storage/storage_key.sw), contains the API for accessing a `core::storage::StorageKey` which describes a location in storage. +- [`std::storage::storage_map::*`](https://github.com/FuelLabs/sway/blob/master/sway-lib-std/src/storage/storage_map.sw), a key-value mapping in contract storage. - [`std::option::Option`](https://github.com/FuelLabs/sway/blob/master/sway-lib-std/src/option.sw), an enum which expresses the presence or absence of a value. - [`std::result::Result`](https://github.com/FuelLabs/sway/blob/master/sway-lib-std/src/result.sw), an enum for functions that may succeed or fail. - [`std::assert::assert`](https://github.com/FuelLabs/sway/blob/master/sway-lib-std/src/assert.sw), a function that reverts the VM if the condition provided to it is `false`. diff --git a/docs/book/src/reference/known_issues_and_workarounds.md b/docs/book/src/reference/known_issues_and_workarounds.md index 46d6afef58c..50ae1052b67 100644 --- a/docs/book/src/reference/known_issues_and_workarounds.md +++ b/docs/book/src/reference/known_issues_and_workarounds.md @@ -8,8 +8,6 @@ * [#1182](https://github.com/FuelLabs/sway/issues/1182) Arrays in a `storage` block are not yet supported. See the [Manual Storage Management](../blockchain-development/storage.md#manual-storage-management) section for details on how to use `store` and `get` from the standard library to manage storage slots directly. Note, however, that `StorageMap` _does_ support arbitrary types for `K` and `V` without any limitations. -* [#1796](https://github.com/FuelLabs/sway/issues/2465): It is not yet allowed to use `StorageMap` as a component of a complex type such as a struct or an enum. - ## General * No compiler optimization passes have been implemented yet, therefore bytecode will be more expensive and larger than it would be in production. Note that eventually the optimizer will support zero-cost abstractions, avoiding the need for developers to go down to inline assembly to produce optimal code. diff --git a/examples/Forc.lock b/examples/Forc.lock index 550a3da3400..e399de8ac3c 100644 --- a/examples/Forc.lock +++ b/examples/Forc.lock @@ -122,6 +122,7 @@ dependencies = ['std'] [[package]] name = 'storage_variables' source = 'member' +dependencies = ['std'] [[package]] name = 'storage_vec' diff --git a/examples/cei_analysis/src/main.sw b/examples/cei_analysis/src/main.sw index 4da5241b340..f74194699a1 100644 --- a/examples/cei_analysis/src/main.sw +++ b/examples/cei_analysis/src/main.sw @@ -19,7 +19,7 @@ impl MyContract for Contract { #[storage(read, write)] fn withdraw(external_contract_id: ContractId) { let sender = msg_sender().unwrap(); - let bal = storage.balances.get(sender).unwrap_or(0); + let bal = storage.balances.get(sender).try_read().unwrap_or(0); assert(bal > 0); diff --git a/examples/counter/src/main.sw b/examples/counter/src/main.sw index a80b7c112f1..d35b6fbeb77 100644 --- a/examples/counter/src/main.sw +++ b/examples/counter/src/main.sw @@ -15,14 +15,14 @@ storage { impl TestContract for Contract { #[storage(write)] fn initialize_counter(value: u64) -> u64 { - storage.counter = value; + storage.counter.write(value); value } #[storage(read, write)] fn increment_counter(amount: u64) -> u64 { - let incremented = storage.counter + amount; - storage.counter = incremented; + let incremented = storage.counter.read() + amount; + storage.counter.write(incremented); incremented } } diff --git a/examples/identity/src/main.sw b/examples/identity/src/main.sw index 7b485a3ccc9..67732a67e3c 100644 --- a/examples/identity/src/main.sw +++ b/examples/identity/src/main.sw @@ -55,7 +55,7 @@ impl IdentityExample for Contract { fn access_control_with_identity() { // ANCHOR: access_control_with_identity let sender = msg_sender().unwrap(); - require(sender == storage.owner, MyError::UnauthorizedUser(sender)); + require(sender == storage.owner.read(), MyError::UnauthorizedUser(sender)); // ANCHOR_END: access_control_with_identity } } diff --git a/examples/ownership/src/main.sw b/examples/ownership/src/main.sw index 695e146d24a..688757eb748 100644 --- a/examples/ownership/src/main.sw +++ b/examples/ownership/src/main.sw @@ -17,17 +17,17 @@ impl OwnershipExample for Contract { // ANCHOR: revoke_owner_example #[storage(write)] fn revoke_ownership() { - storage.owner = Option::None; + storage.owner.write(Option::None); } // ANCHOR_END: revoke_owner_example // ANCHOR: set_owner_example #[storage(write)] fn set_owner(identity: Identity) { - storage.owner = Option::Some(identity); + storage.owner.write(Option::Some(identity)); } // ANCHOR_END: set_owner_example #[storage(read)] fn owner() -> Option { - storage.owner + storage.owner.read() } } diff --git a/examples/storage_example/src/main.sw b/examples/storage_example/src/main.sw index 5b6f95aa800..9a0a3d6c035 100644 --- a/examples/storage_example/src/main.sw +++ b/examples/storage_example/src/main.sw @@ -1,6 +1,6 @@ contract; -use std::storage::{get, store}; +use std::storage::storage_api::{read, write}; abi StorageExample { #[storage(write)] @@ -15,12 +15,12 @@ const STORAGE_KEY: b256 = 0x0000000000000000000000000000000000000000000000000000 impl StorageExample for Contract { #[storage(write)] fn store_something(amount: u64) { - store(STORAGE_KEY, amount); + write(STORAGE_KEY, 0, amount); } #[storage(read)] fn get_something() -> u64 { - let value: Option = get::(STORAGE_KEY); + let value: Option = read::(STORAGE_KEY, 0); value.unwrap_or(0) } } diff --git a/examples/storage_map/src/main.sw b/examples/storage_map/src/main.sw index 147b54b1abe..1634dbbe25f 100644 --- a/examples/storage_map/src/main.sw +++ b/examples/storage_map/src/main.sw @@ -7,6 +7,9 @@ storage { // ANCHOR: storage_map_tuple_key map_two_keys: StorageMap<(b256, bool), b256> = StorageMap {}, // ANCHOR_END: storage_map_tuple_key + // ANCHOR: storage_map_nested + nested_map: StorageMap> = StorageMap {}, + // ANCHOR_END: storage_map_nested } abi StorageMapExample { @@ -15,6 +18,9 @@ abi StorageMapExample { #[storage(read, write)] fn get_from_storage_map(); + + #[storage(read, write)] + fn access_nested_map(); } impl StorageMapExample for Contract { @@ -37,7 +43,20 @@ impl StorageMapExample for Contract { storage.map.insert(addr1, 42); storage.map.insert(addr2, 77); - let value1 = storage.map.get(addr1).unwrap_or(0); + let value1 = storage.map.get(addr1).try_read().unwrap_or(0); } // ANCHOR_END: storage_map_get + + // ANCHOR: storage_map_nested_access + #[storage(read, write)] + fn access_nested_map() { + storage.nested_map.get(0).insert(1, 42); + storage.nested_map.get(2).insert(3, 24); + + assert(storage.nested_map.get(0).get(1).read() == 42); + assert(storage.nested_map.get(0).get(0).try_read().is_none()); // Nothing inserted here + assert(storage.nested_map.get(2).get(3).read() == 24); + assert(storage.nested_map.get(2).get(2).try_read().is_none()); // Nothing inserted here + } + // ANCHOR_END: storage_map_nested_access } diff --git a/examples/storage_variables/Forc.toml b/examples/storage_variables/Forc.toml index 31cdf60b574..779d8af8dd3 100644 --- a/examples/storage_variables/Forc.toml +++ b/examples/storage_variables/Forc.toml @@ -1,8 +1,8 @@ [project] authors = ["Fuel Labs "] entry = "main.sw" -implicit-std = false license = "Apache-2.0" name = "storage_variables" [dependencies] +std = { path = "../../sway-lib-std" } diff --git a/examples/storage_variables/src/main.sw b/examples/storage_variables/src/main.sw index 0fc1ff970ea..9859640de90 100644 --- a/examples/storage_variables/src/main.sw +++ b/examples/storage_variables/src/main.sw @@ -32,20 +32,20 @@ impl StorageExample for Contract { // ANCHOR: storage_write #[storage(write)] fn store_something() { - storage.var1.x = 42; - storage.var1.y = 77; - storage.var2.w = 0x1111111111111111111111111111111111111111111111111111111111111111; - storage.var2.z = true; + storage.var1.x.write(42); + storage.var1.y.write(77); + storage.var2.w.write(0x1111111111111111111111111111111111111111111111111111111111111111); + storage.var2.z.write(true); } // ANCHOR_END: storage_write // ANCHOR: storage_read #[storage(read)] fn get_something() -> (u64, u64, b256, bool) { ( - storage.var1.x, - storage.var1.y, - storage.var2.w, - storage.var2.z, + storage.var1.x.read(), + storage.var1.y.read(), + storage.var2.w.read(), + storage.var2.z.read(), ) } // ANCHOR_END: storage_read diff --git a/examples/storage_vec/src/main.sw b/examples/storage_vec/src/main.sw index d6f40e12aa7..e8bcbdb8323 100644 --- a/examples/storage_vec/src/main.sw +++ b/examples/storage_vec/src/main.sw @@ -1,7 +1,7 @@ contract; // ANCHOR: storage_vec_import -use std::storage::StorageVec; +use std::storage::storage_vec::*; // ANCHOR_END: storage_vec_import // ANCHOR: storage_vec_multiple_types_enum enum TableCell { @@ -17,6 +17,9 @@ storage { // ANCHOR: storage_vec_multiple_types_decl row: StorageVec = StorageVec {}, // ANCHOR_END: storage_vec_multiple_types_decl + // ANCHOR: storage_vec_nested + nested_vec: StorageVec> = StorageVec {}, + // ANCHOR_END: storage_vec_nested } abi StorageVecContract { @@ -31,6 +34,9 @@ abi StorageVecContract { #[storage(read, write)] fn push_to_multiple_types_storage_vec(); + + #[storage(read, write)] + fn access_nested_vec(); } impl StorageVecContract for Contract { @@ -48,7 +54,7 @@ impl StorageVecContract for Contract { fn read_from_storage_vec() { let third = storage.v.get(2); match third { - Option::Some(third) => log(third), + Option::Some(third) => log(third.read()), Option::None => revert(42), } } @@ -58,7 +64,7 @@ impl StorageVecContract for Contract { fn iterate_over_a_storage_vec() { let mut i = 0; while i < storage.v.len() { - log(storage.v.get(i).unwrap()); + log(storage.v.get(i).unwrap().read()); i += 1; } } @@ -71,4 +77,33 @@ impl StorageVecContract for Contract { storage.row.push(TableCell::Boolean(true)); } // ANCHOR_END: storage_vec_multiple_types_fn + + // ANCHOR: access_nested_vec + #[storage(read, write)] + fn access_nested_vec() { + storage.nested_vec.push(StorageVec {}); + storage.nested_vec.push(StorageVec {}); + + let mut inner_vec0 = storage.nested_vec.get(0).unwrap(); + let mut inner_vec1 = storage.nested_vec.get(1).unwrap(); + + inner_vec0.push(0); + inner_vec0.push(1); + + inner_vec1.push(2); + inner_vec1.push(3); + inner_vec1.push(4); + + assert(inner_vec0.len() == 2); + assert(inner_vec0.get(0).unwrap().read() == 0); + assert(inner_vec0.get(1).unwrap().read() == 1); + assert(inner_vec0.get(2).is_none()); + + assert(inner_vec1.len() == 3); + assert(inner_vec1.get(0).unwrap().read() == 2); + assert(inner_vec1.get(1).unwrap().read() == 3); + assert(inner_vec1.get(2).unwrap().read() == 4); + assert(inner_vec1.get(3).is_none()); + } + // ANCHOR_END: access_nested_vec } diff --git a/examples/subcurrency/src/main.sw b/examples/subcurrency/src/main.sw index 59c1b471a0f..ddc7f4c4d56 100644 --- a/examples/subcurrency/src/main.sw +++ b/examples/subcurrency/src/main.sw @@ -64,7 +64,7 @@ impl Token for Contract { }; // Increase the balance of receiver - storage.balances.insert(receiver, storage.balances.get(receiver).unwrap_or(0) + amount); + storage.balances.insert(receiver, storage.balances.get(receiver).try_read().unwrap_or(0) + amount); } #[storage(read, write)] @@ -76,12 +76,12 @@ impl Token for Contract { }; // Reduce the balance of sender - let sender_amount = storage.balances.get(sender).unwrap_or(0); + let sender_amount = storage.balances.get(sender).try_read().unwrap_or(0); assert(sender_amount > amount); storage.balances.insert(sender, sender_amount - amount); // Increase the balance of receiver - storage.balances.insert(receiver, storage.balances.get(receiver).unwrap_or(0) + amount); + storage.balances.insert(receiver, storage.balances.get(receiver).try_read().unwrap_or(0) + amount); log(Sent { from: sender, diff --git a/examples/wallet_smart_contract/src/main.sw b/examples/wallet_smart_contract/src/main.sw index dd86c4ac385..3796c924baf 100644 --- a/examples/wallet_smart_contract/src/main.sw +++ b/examples/wallet_smart_contract/src/main.sw @@ -26,7 +26,7 @@ impl Wallet for Contract { // If we received `BASE_ASSET_ID` then keep track of the balance. // Otherwise, we're receiving other native assets and don't care // about our balance of tokens. - storage.balance += msg_amount(); + storage.balance.write(storage.balance.read() + msg_amount()); } } @@ -38,10 +38,10 @@ impl Wallet for Contract { _ => revert(0), }; - let current_balance = storage.balance; + let current_balance = storage.balance.read(); assert(current_balance >= amount_to_send); - storage.balance = current_balance - amount_to_send; + storage.balance.write(current_balance - amount_to_send); // Note: `transfer_to_address()` is not a call and thus not an // interaction. Regardless, this code conforms to diff --git a/forc-pkg/src/manifest.rs b/forc-pkg/src/manifest.rs index 3fe4f8ec440..6ebc728d15f 100644 --- a/forc-pkg/src/manifest.rs +++ b/forc-pkg/src/manifest.rs @@ -214,7 +214,6 @@ pub struct BuildProfile { pub include_tests: bool, pub json_abi_with_callpaths: bool, pub error_on_warnings: bool, - pub experimental_storage: bool, } impl Dependency { @@ -658,7 +657,6 @@ impl BuildProfile { include_tests: false, json_abi_with_callpaths: false, error_on_warnings: false, - experimental_storage: false, } } @@ -675,7 +673,6 @@ impl BuildProfile { include_tests: false, json_abi_with_callpaths: false, error_on_warnings: false, - experimental_storage: false, } } } diff --git a/forc-pkg/src/pkg.rs b/forc-pkg/src/pkg.rs index 6bd278c1de6..1f79918a868 100644 --- a/forc-pkg/src/pkg.rs +++ b/forc-pkg/src/pkg.rs @@ -302,8 +302,6 @@ pub struct BuildOpts { pub tests: bool, /// The set of options to filter by member project kind. pub member_filter: MemberFilter, - /// Enable the experimental storage implementation and UI. - pub experimental_storage: bool, } /// The set of options to filter type of projects to build in a workspace. @@ -1546,8 +1544,7 @@ pub fn sway_build_config( .print_finalized_asm(build_profile.print_finalized_asm) .print_intermediate_asm(build_profile.print_intermediate_asm) .print_ir(build_profile.print_ir) - .include_tests(build_profile.include_tests) - .experimental_storage(build_profile.experimental_storage); + .include_tests(build_profile.include_tests); Ok(build_config) } @@ -1989,7 +1986,6 @@ fn build_profile_from_opts( time_phases, tests, error_on_warnings, - experimental_storage, .. } = build_options; let mut selected_build_profile = BuildProfile::DEBUG; @@ -2040,7 +2036,6 @@ fn build_profile_from_opts( profile.include_tests |= tests; profile.json_abi_with_callpaths |= pkg.json_abi_with_callpaths; profile.error_on_warnings |= error_on_warnings; - profile.experimental_storage |= experimental_storage; Ok((selected_build_profile.to_string(), profile)) } diff --git a/forc-plugins/forc-client/src/op/deploy.rs b/forc-plugins/forc-client/src/op/deploy.rs index 7488c2fac3c..0037820044d 100644 --- a/forc-plugins/forc-client/src/op/deploy.rs +++ b/forc-plugins/forc-client/src/op/deploy.rs @@ -255,7 +255,6 @@ fn build_opts_from_cmd(cmd: &cmd::Deploy) -> pkg::BuildOpts { build_target: BuildTarget::default(), tests: false, member_filter: pkg::MemberFilter::only_contracts(), - experimental_storage: cmd.build_profile.experimental_storage, } } diff --git a/forc-plugins/forc-client/src/op/run.rs b/forc-plugins/forc-client/src/op/run.rs index 311d06a57a5..fd7e828d372 100644 --- a/forc-plugins/forc-client/src/op/run.rs +++ b/forc-plugins/forc-client/src/op/run.rs @@ -176,6 +176,5 @@ fn build_opts_from_cmd(cmd: &cmd::Run) -> pkg::BuildOpts { debug_outfile: cmd.build_output.debug_file.clone(), tests: false, member_filter: pkg::MemberFilter::only_scripts(), - experimental_storage: cmd.build_profile.experimental_storage, } } diff --git a/forc-test/src/lib.rs b/forc-test/src/lib.rs index b9413340e23..a67b312b1eb 100644 --- a/forc-test/src/lib.rs +++ b/forc-test/src/lib.rs @@ -151,8 +151,6 @@ pub struct Opts { pub error_on_warnings: bool, /// Output the time elapsed over each part of the compilation process. pub time_phases: bool, - /// Enable the experimental storage implementation and UI. - pub experimental_storage: bool, } /// The set of options provided for controlling logs printed for each test. @@ -482,7 +480,6 @@ impl Opts { time_phases: self.time_phases, tests: true, member_filter: Default::default(), - experimental_storage: self.experimental_storage, } } } diff --git a/forc/src/cli/commands/test.rs b/forc/src/cli/commands/test.rs index 78e43e47574..2b7eea02542 100644 --- a/forc/src/cli/commands/test.rs +++ b/forc/src/cli/commands/test.rs @@ -199,6 +199,5 @@ fn opts_from_cmd(cmd: Command) -> forc_test::Opts { binary_outfile: cmd.build.output.bin_file, debug_outfile: cmd.build.output.debug_file, build_target: cmd.build.build_target, - experimental_storage: cmd.build.profile.experimental_storage, } } diff --git a/forc/src/cli/shared.rs b/forc/src/cli/shared.rs index f9215ddf3c4..ab8acd2b064 100644 --- a/forc/src/cli/shared.rs +++ b/forc/src/cli/shared.rs @@ -49,9 +49,6 @@ pub struct BuildProfile { /// Treat warnings as errors. #[clap(long)] pub error_on_warnings: bool, - /// Enable the experimental storage implementation and UI. - #[clap(long)] - pub experimental_storage: bool, } /// Options related to printing stages of compiler output. diff --git a/forc/src/ops/forc_build.rs b/forc/src/ops/forc_build.rs index e2d54f5aec2..bde935b2b7f 100644 --- a/forc/src/ops/forc_build.rs +++ b/forc/src/ops/forc_build.rs @@ -39,6 +39,5 @@ fn opts_from_cmd(cmd: BuildCommand) -> pkg::BuildOpts { build_target: cmd.build.build_target, tests: cmd.tests, member_filter: Default::default(), - experimental_storage: cmd.build.profile.experimental_storage, } } diff --git a/forc/src/ops/forc_contract_id.rs b/forc/src/ops/forc_contract_id.rs index 9308304f635..3a7ffed0049 100644 --- a/forc/src/ops/forc_contract_id.rs +++ b/forc/src/ops/forc_contract_id.rs @@ -75,6 +75,5 @@ fn build_opts_from_cmd(cmd: &ContractIdCommand) -> pkg::BuildOpts { build_target: BuildTarget::default(), tests: false, member_filter: pkg::MemberFilter::only_contracts(), - experimental_storage: cmd.build_profile.experimental_storage, } } diff --git a/forc/src/ops/forc_predicate_root.rs b/forc/src/ops/forc_predicate_root.rs index 68f3725093d..166ade58970 100644 --- a/forc/src/ops/forc_predicate_root.rs +++ b/forc/src/ops/forc_predicate_root.rs @@ -43,6 +43,5 @@ fn build_opts_from_cmd(cmd: PredicateRootCommand) -> pkg::BuildOpts { build_target: BuildTarget::default(), tests: false, member_filter: pkg::MemberFilter::only_predicates(), - experimental_storage: cmd.build_profile.experimental_storage, } } diff --git a/sway-ast/src/intrinsics.rs b/sway-ast/src/intrinsics.rs index ace542ccb81..f3620c34483 100644 --- a/sway-ast/src/intrinsics.rs +++ b/sway-ast/src/intrinsics.rs @@ -2,7 +2,6 @@ use std::fmt; #[derive(Eq, PartialEq, Debug, Clone, Hash)] pub enum Intrinsic { - GetStorageKey, IsReferenceType, SizeOfType, SizeOfVal, @@ -33,7 +32,6 @@ pub enum Intrinsic { impl fmt::Display for Intrinsic { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { let s = match self { - Intrinsic::GetStorageKey => "get_storage_key", Intrinsic::IsReferenceType => "is_reference_type", Intrinsic::SizeOfType => "size_of", Intrinsic::SizeOfVal => "size_of_val", @@ -68,7 +66,6 @@ impl Intrinsic { pub fn try_from_str(raw: &str) -> Option { use Intrinsic::*; Some(match raw { - "__get_storage_key" => GetStorageKey, "__is_reference_type" => IsReferenceType, "__size_of" => SizeOfType, "__size_of_val" => SizeOfVal, diff --git a/sway-core/src/asm_generation/fuel/fuel_asm_builder.rs b/sway-core/src/asm_generation/fuel/fuel_asm_builder.rs index e4b6bc85f02..95d57d496e4 100644 --- a/sway-core/src/asm_generation/fuel/fuel_asm_builder.rs +++ b/sway-core/src/asm_generation/fuel/fuel_asm_builder.rs @@ -13,7 +13,6 @@ use crate::{ asm_lang::{virtual_register::*, Label, Op, VirtualImmediate12, VirtualImmediate18, VirtualOp}, decl_engine::DeclRefFunction, error::*, - fuel_prelude::fuel_crypto::Hasher, metadata::MetadataManager, }; @@ -183,9 +182,6 @@ impl<'ir> FuelAsmBuilder<'ir> { .. } => self.compile_contract_call(instr_val, params, coins, asset_id, gas), Instruction::FuelVm(fuel_vm_instr) => match fuel_vm_instr { - FuelVmInstruction::GetStorageKey(_ty) => { - self.compile_get_storage_key(instr_val) - } FuelVmInstruction::Gtf { index, tx_field_id } => { self.compile_gtf(instr_val, index, *tx_field_id) } @@ -630,47 +626,6 @@ impl<'ir> FuelAsmBuilder<'ir> { Ok(()) } - fn compile_get_storage_key(&mut self, instr_val: &Value) -> Result<(), CompileError> { - let state_idx = self.md_mgr.val_to_storage_key(self.context, *instr_val); - let instr_span = self.md_mgr.val_to_span(self.context, *instr_val); - - let storage_slot_to_hash = match state_idx { - Some(state_idx) => { - format!( - "{}{}", - sway_utils::constants::STORAGE_DOMAIN_SEPARATOR, - state_idx - ) - } - None => { - return Err(CompileError::Internal( - "State index for __get_storage_key is not available as a metadata", - instr_span.unwrap_or_else(Span::dummy), - )); - } - }; - - let hashed_storage_slot = Hasher::hash(storage_slot_to_hash); - - let data_id = self.data_section.insert_data_value(Entry::new_byte_array( - (*hashed_storage_slot).to_vec(), - None, - None, - )); - - // Allocate a register for it, and a load instruction. - let reg = self.reg_seqr.next(); - - self.cur_bytecode.push(Op { - opcode: either::Either::Left(VirtualOp::LWDataId(reg.clone(), data_id)), - comment: "literal instantiation".into(), - owning_span: instr_span, - }); - self.reg_map.insert(*instr_val, reg); - - Ok(()) - } - fn compile_get_elem_ptr( &mut self, instr_val: &Value, diff --git a/sway-core/src/build_config.rs b/sway-core/src/build_config.rs index b941d1c72d5..a387ad839a4 100644 --- a/sway-core/src/build_config.rs +++ b/sway-core/src/build_config.rs @@ -46,7 +46,6 @@ pub struct BuildConfig { pub(crate) print_finalized_asm: bool, pub(crate) print_ir: bool, pub(crate) include_tests: bool, - pub(crate) experimental_storage: bool, } impl BuildConfig { @@ -89,7 +88,6 @@ impl BuildConfig { print_finalized_asm: false, print_ir: false, include_tests: false, - experimental_storage: false, } } @@ -128,13 +126,6 @@ impl BuildConfig { } } - pub fn experimental_storage(self, a: bool) -> Self { - Self { - experimental_storage: a, - ..self - } - } - /// Whether or not to include test functions in parsing, type-checking and codegen. /// /// This should be set to `true` by invocations like `forc test` or `forc check --tests`. diff --git a/sway-core/src/concurrent_slab.rs b/sway-core/src/concurrent_slab.rs index 57c3a956e72..5586239c02d 100644 --- a/sway-core/src/concurrent_slab.rs +++ b/sway-core/src/concurrent_slab.rs @@ -70,11 +70,6 @@ where let inner = self.inner.read().unwrap(); inner[index].clone() } - - pub fn exists bool>(&self, f: F) -> bool { - let inner = self.inner.read().unwrap(); - inner.iter().any(f) - } } impl ConcurrentSlab { diff --git a/sway-core/src/control_flow_analysis/dead_code_analysis.rs b/sway-core/src/control_flow_analysis/dead_code_analysis.rs index 0a5f10836b2..c86710c8264 100644 --- a/sway-core/src/control_flow_analysis/dead_code_analysis.rs +++ b/sway-core/src/control_flow_analysis/dead_code_analysis.rs @@ -1757,17 +1757,6 @@ fn connect_expression<'eng: 'cfg, 'cfg>( options, ) } - StorageReassignment(typed_storage_reassignment) => connect_expression( - engines, - &typed_storage_reassignment.rhs.expression, - graph, - leaves, - exit_node, - "variable reassignment", - tree_type, - typed_storage_reassignment.rhs.clone().span, - options, - ), Return(exp) => { let this_index = graph.add_node("return entry".into()); for leaf in leaves { diff --git a/sway-core/src/ir_generation.rs b/sway-core/src/ir_generation.rs index 0ef23f5e4a0..f6166a8dd56 100644 --- a/sway-core/src/ir_generation.rs +++ b/sway-core/src/ir_generation.rs @@ -19,7 +19,6 @@ pub fn compile_program( program: &ty::TyProgram, include_tests: bool, engines: Engines<'_>, - experimental_storage: bool, ) -> Result { let declaration_engine = engines.de(); @@ -60,7 +59,6 @@ pub fn compile_program( &logged_types, &messages_types, &test_fns, - experimental_storage, ), ty::TyProgramKind::Predicate { main_function } => compile::compile_predicate( engines, @@ -71,7 +69,6 @@ pub fn compile_program( &logged_types, &messages_types, &test_fns, - experimental_storage, ), ty::TyProgramKind::Contract { abi_entries } => compile::compile_contract( &mut ctx, @@ -82,7 +79,6 @@ pub fn compile_program( &messages_types, &test_fns, engines, - experimental_storage, ), ty::TyProgramKind::Library { .. } => compile::compile_library( engines, @@ -92,7 +88,6 @@ pub fn compile_program( &logged_types, &messages_types, &test_fns, - experimental_storage, ), }?; diff --git a/sway-core/src/ir_generation/compile.rs b/sway-core/src/ir_generation/compile.rs index a7bc25cd46d..84e53d49e43 100644 --- a/sway-core/src/ir_generation/compile.rs +++ b/sway-core/src/ir_generation/compile.rs @@ -30,7 +30,6 @@ pub(super) fn compile_script( logged_types_map: &HashMap, messages_types_map: &HashMap, test_fns: &[(ty::TyFunctionDecl, DeclRefFunction)], - experimental_storage: bool, ) -> Result { let module = Module::new(context, Kind::Script); let mut md_mgr = MetadataManager::default(); @@ -53,7 +52,6 @@ pub(super) fn compile_script( logged_types_map, messages_types_map, None, - experimental_storage, )?; compile_tests( engines, @@ -63,7 +61,6 @@ pub(super) fn compile_script( logged_types_map, messages_types_map, test_fns, - experimental_storage, )?; Ok(module) @@ -79,7 +76,6 @@ pub(super) fn compile_predicate( logged_types: &HashMap, messages_types: &HashMap, test_fns: &[(ty::TyFunctionDecl, DeclRefFunction)], - experimental_storage: bool, ) -> Result { let module = Module::new(context, Kind::Predicate); let mut md_mgr = MetadataManager::default(); @@ -102,7 +98,6 @@ pub(super) fn compile_predicate( &HashMap::new(), &HashMap::new(), None, - experimental_storage, )?; compile_tests( engines, @@ -112,7 +107,6 @@ pub(super) fn compile_predicate( logged_types, messages_types, test_fns, - experimental_storage, )?; Ok(module) @@ -128,7 +122,6 @@ pub(super) fn compile_contract( messages_types_map: &HashMap, test_fns: &[(ty::TyFunctionDecl, DeclRefFunction)], engines: Engines<'_>, - experimental_storage: bool, ) -> Result { let module = Module::new(context, Kind::Contract); let mut md_mgr = MetadataManager::default(); @@ -151,7 +144,6 @@ pub(super) fn compile_contract( logged_types_map, messages_types_map, engines, - experimental_storage, )?; } compile_tests( @@ -162,7 +154,6 @@ pub(super) fn compile_contract( logged_types_map, messages_types_map, test_fns, - experimental_storage, )?; Ok(module) @@ -177,7 +168,6 @@ pub(super) fn compile_library( logged_types_map: &HashMap, messages_types_map: &HashMap, test_fns: &[(ty::TyFunctionDecl, DeclRefFunction)], - experimental_storage: bool, ) -> Result { let module = Module::new(context, Kind::Library); let mut md_mgr = MetadataManager::default(); @@ -199,7 +189,6 @@ pub(super) fn compile_library( logged_types_map, messages_types_map, test_fns, - experimental_storage, )?; Ok(module) @@ -326,7 +315,6 @@ pub(super) fn compile_function( messages_types_map: &HashMap, is_entry: bool, test_decl_ref: Option, - experimental_storage: bool, ) -> Result, CompileError> { // Currently monomorphization of generics is inlined into main() and the functions with generic // args are still present in the AST declarations, but they can be ignored. @@ -344,7 +332,6 @@ pub(super) fn compile_function( logged_types_map, messages_types_map, test_decl_ref, - experimental_storage, ) .map(Some) } @@ -360,7 +347,6 @@ pub(super) fn compile_entry_function( logged_types_map: &HashMap, messages_types_map: &HashMap, test_decl_ref: Option, - experimental_storage: bool, ) -> Result { let is_entry = true; compile_function( @@ -373,7 +359,6 @@ pub(super) fn compile_entry_function( messages_types_map, is_entry, test_decl_ref, - experimental_storage, ) .map(|f| f.expect("entry point should never contain generics")) } @@ -387,7 +372,6 @@ pub(super) fn compile_tests( logged_types_map: &HashMap, messages_types_map: &HashMap, test_fns: &[(ty::TyFunctionDecl, DeclRefFunction)], - experimental_storage: bool, ) -> Result, CompileError> { test_fns .iter() @@ -401,7 +385,6 @@ pub(super) fn compile_tests( logged_types_map, messages_types_map, Some(decl_ref.clone()), - experimental_storage, ) }) .collect() @@ -419,7 +402,6 @@ fn compile_fn( logged_types_map: &HashMap, messages_types_map: &HashMap, test_decl_ref: Option, - experimental_storage: bool, ) -> Result { let type_engine = engines.te(); let decl_engine = engines.de(); @@ -504,7 +486,6 @@ fn compile_fn( func, logged_types_map, messages_types_map, - experimental_storage, ); let mut ret_val = compiler.compile_code_block(context, md_mgr, body)?; @@ -552,7 +533,6 @@ fn compile_abi_method( logged_types_map: &HashMap, messages_types_map: &HashMap, engines: Engines<'_>, - experimental_storage: bool, ) -> Result { let type_engine = engines.te(); let decl_engine = engines.de(); @@ -592,6 +572,5 @@ fn compile_abi_method( logged_types_map, messages_types_map, None, - experimental_storage, ) } diff --git a/sway-core/src/ir_generation/const_eval.rs b/sway-core/src/ir_generation/const_eval.rs index d55a5ce1ab0..d83413e9bb3 100644 --- a/sway-core/src/ir_generation/const_eval.rs +++ b/sway-core/src/ir_generation/const_eval.rs @@ -497,7 +497,6 @@ fn const_eval_typed_expr( ty::TyExpressionVariant::ArrayIndex { .. } | ty::TyExpressionVariant::CodeBlock(_) | ty::TyExpressionVariant::Reassignment(_) - | ty::TyExpressionVariant::StorageReassignment(_) | ty::TyExpressionVariant::FunctionParameter | ty::TyExpressionVariant::IfExp { .. } | ty::TyExpressionVariant::AsmExpression { .. } @@ -622,8 +621,7 @@ fn const_eval_intrinsic( sway_ast::Intrinsic::AddrOf => Ok(None), sway_ast::Intrinsic::PtrAdd => Ok(None), sway_ast::Intrinsic::PtrSub => Ok(None), - sway_ast::Intrinsic::GetStorageKey - | sway_ast::Intrinsic::IsReferenceType + sway_ast::Intrinsic::IsReferenceType | sway_ast::Intrinsic::Gtf | sway_ast::Intrinsic::StateClear | sway_ast::Intrinsic::StateLoadWord diff --git a/sway-core/src/ir_generation/function.rs b/sway-core/src/ir_generation/function.rs index 7a835695945..d2aa8de9ec2 100644 --- a/sway-core/src/ir_generation/function.rs +++ b/sway-core/src/ir_generation/function.rs @@ -72,7 +72,6 @@ pub(crate) struct FnCompiler<'eng> { logged_types_map: HashMap, // This is a map from the type IDs of a message data type and the ID of the corresponding smo messages_types_map: HashMap, - experimental_storage: bool, } impl<'eng> FnCompiler<'eng> { @@ -84,7 +83,6 @@ impl<'eng> FnCompiler<'eng> { function: Function, logged_types_map: &HashMap, messages_types_map: &HashMap, - experimental_storage: bool, ) -> Self { let (type_engine, decl_engine) = engines.unwrap(); let lexical_map = LexicalMap::from_iter( @@ -105,7 +103,6 @@ impl<'eng> FnCompiler<'eng> { current_fn_param: None, logged_types_map: logged_types_map.clone(), messages_types_map: messages_types_map.clone(), - experimental_storage, } } @@ -275,7 +272,6 @@ impl<'eng> FnCompiler<'eng> { contract_call_params, arguments, fn_ref, - self_state_idx, selector, type_binding: _, } => { @@ -292,14 +288,7 @@ impl<'eng> FnCompiler<'eng> { ) } else { let function_decl = self.decl_engine.get_function(fn_ref); - self.compile_fn_call( - context, - md_mgr, - arguments, - &function_decl, - *self_state_idx, - span_md_idx, - ) + self.compile_fn_call(context, md_mgr, arguments, &function_decl, span_md_idx) } } ty::TyExpressionVariant::LazyOperator { op, lhs, rhs } => { @@ -456,15 +445,6 @@ impl<'eng> FnCompiler<'eng> { ty::TyExpressionVariant::Reassignment(reassignment) => { self.compile_reassignment(context, md_mgr, reassignment, span_md_idx) } - ty::TyExpressionVariant::StorageReassignment(storage_reassignment) => self - .compile_storage_reassignment( - context, - md_mgr, - &storage_reassignment.fields, - &storage_reassignment.ix, - &storage_reassignment.rhs, - span_md_idx, - ), ty::TyExpressionVariant::Return(exp) => { self.compile_return_statement(context, md_mgr, exp) } @@ -558,14 +538,6 @@ impl<'eng> FnCompiler<'eng> { let val = !self.type_engine.get_unaliased(targ.type_id).is_copy_type(); Ok(Constant::get_bool(context, val)) } - Intrinsic::GetStorageKey => { - let span_md_idx = md_mgr.span_to_md(context, &span); - Ok(self - .current_block - .ins(context) - .get_storage_key() - .add_metadatum(context, span_md_idx)) - } Intrinsic::Eq | Intrinsic::Gt | Intrinsic::Lt => { let lhs = &arguments[0]; let rhs = &arguments[1]; @@ -1332,7 +1304,6 @@ impl<'eng> FnCompiler<'eng> { md_mgr: &mut MetadataManager, ast_args: &[(Ident, ty::TyExpression)], callee: &ty::TyFunctionDecl, - self_state_idx: Option, span_md_idx: Option, ) -> Result { // The compiler inlines everything very lazily. Function calls include the body of the @@ -1385,7 +1356,6 @@ impl<'eng> FnCompiler<'eng> { &self.messages_types_map, is_entry, None, - self.experimental_storage, )? .unwrap(); self.recreated_fns.insert(fn_key, new_func); @@ -1409,16 +1379,11 @@ impl<'eng> FnCompiler<'eng> { args.push(arg); } - let state_idx_md_idx = self_state_idx.and_then(|self_state_idx| { - md_mgr.storage_key_to_md(context, self_state_idx.to_usize() as u64) - }); - Ok(self .current_block .ins(context) .call(new_callee, &args) - .add_metadatum(context, span_md_idx) - .add_metadatum(context, state_idx_md_idx)) + .add_metadatum(context, span_md_idx)) } fn compile_if( @@ -1989,45 +1954,6 @@ impl<'eng> FnCompiler<'eng> { Ok(Constant::get_unit(context).add_metadatum(context, span_md_idx)) } - fn compile_storage_reassignment( - &mut self, - context: &mut Context, - md_mgr: &mut MetadataManager, - fields: &[ty::TyStorageReassignDescriptor], - ix: &StateIndex, - rhs: &ty::TyExpression, - span_md_idx: Option, - ) -> Result { - // Compile the RHS into a value - let rhs = self.compile_expression_to_value(context, md_mgr, rhs)?; - if rhs.is_diverging(context) { - return Ok(rhs); - } - - // Get the type of the access which can be a subfield - let access_type = convert_resolved_typeid_no_span( - self.type_engine, - self.decl_engine, - context, - &fields.last().expect("guaranteed by grammar").type_id, - )?; - - // Get the list of indices used to access the storage field. This will be empty - // if the storage field type is not a struct. - let base_type = fields[0].type_id; - let field_idcs = get_indices_for_struct_access( - self.type_engine, - self.decl_engine, - base_type, - &fields[1..], - )?; - - // Do the actual work. This is a recursive function because we want to drill down - // to store each primitive type in the storage field in its own storage slot. - self.compile_storage_write(context, ix, &field_idcs, &access_type, rhs, span_md_idx)?; - Ok(Constant::get_unit(context).add_metadatum(context, span_md_idx)) - } - fn compile_array_expr( &mut self, context: &mut Context, @@ -2447,14 +2373,6 @@ impl<'eng> FnCompiler<'eng> { ix: &StateIndex, span_md_idx: Option, ) -> Result { - // Get the type of the access which can be a subfield - let access_type = convert_resolved_typeid_no_span( - self.type_engine, - self.decl_engine, - context, - &fields.last().expect("guaranteed by grammar").type_id, - )?; - // Get the list of indices used to access the storage field. This will be empty // if the storage field type is not a struct. // FIXME: shouldn't have to extract the first field like this. @@ -2476,14 +2394,7 @@ impl<'eng> FnCompiler<'eng> { // Do the actual work. This is a recursive function because we want to drill down // to load each primitive type in the storage field in its own storage slot. - self.compile_storage_read( - context, - ix, - &field_idcs, - &base_type, - &access_type, - span_md_idx, - ) + self.compile_storage_read(context, ix, &field_idcs, &base_type, span_md_idx) } #[allow(clippy::too_many_arguments)] @@ -2598,639 +2509,74 @@ impl<'eng> FnCompiler<'eng> { ix: &StateIndex, indices: &[u64], base_type: &Type, - ty: &Type, span_md_idx: Option, ) -> Result { - if ty.is_struct(context) && !self.experimental_storage { - let temp_name = self.lexical_map.insert_anon(); - let struct_var = self - .function - .new_local_var(context, temp_name, *ty, None, false) - .map_err(|ir_error| { - CompileError::InternalOwned(ir_error.to_string(), Span::dummy()) - })?; - let struct_val = self - .current_block - .ins(context) - .get_local(struct_var) - .add_metadatum(context, span_md_idx); - - let fields = ty.get_field_types(context); - for (field_idx, field_type) in fields.into_iter().enumerate() { - let field_idx = field_idx as u64; - - // Recurse. The base case is for primitive types that fit in a single storage slot. - let mut new_indices = indices.to_owned(); - new_indices.push(field_idx); - - let val_to_insert = self.compile_storage_read( - context, - ix, - &new_indices, - base_type, - &field_type, - span_md_idx, - )?; - - // Insert the loaded value to the aggregate at the given index - let gep_val = self - .current_block - .ins(context) - .get_elem_ptr_with_idx(struct_val, field_type, field_idx) - .add_metadatum(context, span_md_idx); - self.current_block - .ins(context) - .store(gep_val, val_to_insert) - .add_metadatum(context, span_md_idx); - } - - Ok(self - .current_block - .ins(context) - .load(struct_val) - .add_metadatum(context, span_md_idx)) - } else { - // New name for the key - let mut key_name = format!("{}{}", "key_for_", ix.to_usize()); - - // Get the actual storage key as a `Bytes32` as well as the offset, in words, - // within the slot. The offset depends on what field of the top level storage - // variable is being accessed. - let (storage_key, offset_within_slot) = if !self.experimental_storage { - for ix in indices { - key_name = format!("{key_name}_{ix}"); - } - (get_storage_key(ix, indices), 0) - } else { - let offset_in_words = self.get_offset(context, base_type, indices)?; - let offset_in_slots = offset_in_words / 4; - let offset_remaining = offset_in_words % 4; - - // The storage key we need is the storage key of the top level storage variable - // plus the offset, in number of slots, computed above. The offset within this - // particular slot is the remaining offset, in words. - ( - add_to_b256(get_storage_key::(ix, &[]), offset_in_slots), - offset_remaining, - ) - }; - - let alias_key_name = self.lexical_map.insert(key_name.as_str().to_owned()); - - // Local pointer for the key - let key_var = self - .function - .new_local_var( - context, - alias_key_name, - Type::get_b256(context), - None, - false, - ) - .map_err(|ir_error| { - CompileError::InternalOwned(ir_error.to_string(), Span::dummy()) - })?; - - // Const value for the key from the hash - let const_key = convert_literal_to_value(context, &Literal::B256(storage_key.into())) - .add_metadatum(context, span_md_idx); - - let key_ptr = self - .current_block - .ins(context) - .get_local(key_var) - .add_metadatum(context, span_md_idx); - - if self.experimental_storage { - // The type of a storage access is `StorageKey` which is a struct containing - // a `b256` and ` u64`. - let b256_ty = Type::get_b256(context); - let uint64_ty = Type::get_uint64(context); - let storage_key_aggregate = Type::new_struct(context, vec![b256_ty, uint64_ty]); - - // Local variable holding the `StorageKey` struct - let storage_key_local_name = self.lexical_map.insert_anon(); - let storage_key_ptr = self - .function - .new_local_var( - context, - storage_key_local_name, - storage_key_aggregate, - None, - false, - ) - .map_err(|ir_error| { - CompileError::InternalOwned(ir_error.to_string(), Span::dummy()) - })?; - let storage_key = self - .current_block - .ins(context) - .get_local(storage_key_ptr) - .add_metadatum(context, span_md_idx); - - // Store the key as the first field in the `StorageKey` struct - let gep_0_val = - self.current_block - .ins(context) - .get_elem_ptr_with_idx(storage_key, b256_ty, 0); - self.current_block - .ins(context) - .store(gep_0_val, const_key) - .add_metadatum(context, span_md_idx); - - // Store the offset as the second field in the `StorageKey` struct - let offset_within_slot_val = Constant::get_uint(context, 64, offset_within_slot); - let gep_1_val = self.current_block.ins(context).get_elem_ptr_with_idx( - storage_key, - uint64_ty, - 1, - ); - self.current_block - .ins(context) - .store(gep_1_val, offset_within_slot_val) - .add_metadatum(context, span_md_idx); - - Ok(storage_key) - } else { - // Store the const hash value to the key pointer value - self.current_block - .ins(context) - .store(key_ptr, const_key) - .add_metadatum(context, span_md_idx); - - match ty.get_content(context) { - TypeContent::Array(..) => Err(CompileError::Internal( - "Arrays in storage have not been implemented yet.", - Span::dummy(), - )), - TypeContent::Slice => Err(CompileError::Internal( - "Slices in storage are not valid.", - Span::dummy(), - )), - TypeContent::Pointer(_) => Err(CompileError::Internal( - "Pointers in storage are not valid.", - Span::dummy(), - )), - TypeContent::B256 => { - self.compile_b256_storage_read(context, ix, indices, &key_ptr, span_md_idx) - } - TypeContent::Bool | TypeContent::Uint(_) => { - self.compile_uint_or_bool_storage_read(context, &key_ptr, ty, span_md_idx) - } - TypeContent::String(_) | TypeContent::Union(_) => self - .compile_union_or_string_storage_read( - context, - ix, - indices, - &key_ptr, - ty, - span_md_idx, - ), - TypeContent::Struct(_) => unreachable!("structs are already handled!"), - TypeContent::Unit => { - Ok(Constant::get_unit(context).add_metadatum(context, span_md_idx)) - } - } - } - } - } - - #[allow(clippy::too_many_arguments)] - fn compile_storage_write( - &mut self, - context: &mut Context, - ix: &StateIndex, - indices: &[u64], - ty: &Type, - rhs: Value, - span_md_idx: Option, - ) -> Result<(), CompileError> { - match ty { - ty if ty.is_struct(context) => { - // Create a temporary local struct, store the RHS to it, and read each field from - // there. - let temp_name = self.lexical_map.insert_anon(); - let tmp_struct_var = self - .function - .new_local_var(context, temp_name, *ty, None, false) - .map_err(|ir_error| { - CompileError::InternalOwned(ir_error.to_string(), Span::dummy()) - })?; - let tmp_struct_val = self - .current_block - .ins(context) - .get_local(tmp_struct_var) - .add_metadatum(context, span_md_idx); - self.current_block.ins(context).store(tmp_struct_val, rhs); - - let fields = ty.get_field_types(context); - for (field_idx, field_type) in fields.into_iter().enumerate() { - let field_idx = field_idx as u64; - - // Recurse. The base case is for primitive types that fit in a single storage slot. - let mut new_indices = indices.to_owned(); - new_indices.push(field_idx); - - // Extract the value from the aggregate at the given index - let gep_val = self - .current_block - .ins(context) - .get_elem_ptr_with_idx(tmp_struct_val, field_type, field_idx) - .add_metadatum(context, span_md_idx); - let rhs = self - .current_block - .ins(context) - .load(gep_val) - .add_metadatum(context, span_md_idx); - - self.compile_storage_write( - context, - ix, - &new_indices, - &field_type, - rhs, - span_md_idx, - )?; - } - Ok(()) - } - _ => { - let storage_key = get_storage_key(ix, indices); - - // New name for the key - let mut key_name = format!("{}{}", "key_for_", ix.to_usize()); - for ix in indices { - key_name = format!("{key_name}_{ix}"); - } - let alias_key_name = self.lexical_map.insert(key_name.as_str().to_owned()); - - // Local pointer for the key - let key_var = self - .function - .new_local_var( - context, - alias_key_name, - Type::get_b256(context), - None, - false, - ) - .map_err(|ir_error| { - CompileError::InternalOwned(ir_error.to_string(), Span::dummy()) - })?; - - // Const value for the key from the hash - let const_key = - convert_literal_to_value(context, &Literal::B256(storage_key.into())) - .add_metadatum(context, span_md_idx); - - // Convert the key pointer to a value using get_ptr - let key_val = self - .current_block - .ins(context) - .get_local(key_var) - .add_metadatum(context, span_md_idx); - - // Store the const hash value to the key pointer value - self.current_block - .ins(context) - .store(key_val, const_key) - .add_metadatum(context, span_md_idx); - - match ty.get_content(context) { - TypeContent::Array(..) => Err(CompileError::Internal( - "Arrays in storage have not been implemented yet.", - Span::dummy(), - )), - TypeContent::Slice => Err(CompileError::Internal( - "Slices in storage are not valid.", - Span::dummy(), - )), - TypeContent::Pointer(_) => Err(CompileError::Internal( - "Pointers in storage are not valid.", - Span::dummy(), - )), - TypeContent::B256 => self.compile_b256_storage_write( - context, - ix, - indices, - &key_val, - rhs, - span_md_idx, - ), - TypeContent::Bool | TypeContent::Uint(_) => { - self.compile_uint_or_bool_storage_write(context, &key_val, rhs, span_md_idx) - } - TypeContent::String(_) | TypeContent::Union(_) => self - .compile_union_or_string_storage_write( - context, - ix, - indices, - &key_val, - ty, - rhs, - span_md_idx, - ), - TypeContent::Struct(_) => unreachable!("structs are already handled!"), - TypeContent::Unit => Ok(()), - } - } - } - } - - fn compile_uint_or_bool_storage_read( - &mut self, - context: &mut Context, - key_ptr_val: &Value, - ty: &Type, - span_md_idx: Option, - ) -> Result { - // `state_load_word` always returns a `u64`. Cast the result back - // to the right type before returning - let load_val = self - .current_block - .ins(context) - .state_load_word(*key_ptr_val) - .add_metadatum(context, span_md_idx); - let val = self - .current_block - .ins(context) - .bitcast(load_val, *ty) - .add_metadatum(context, span_md_idx); - Ok(val) - } - - fn compile_uint_or_bool_storage_write( - &mut self, - context: &mut Context, - key_ptr_val: &Value, - rhs: Value, - span_md_idx: Option, - ) -> Result<(), CompileError> { - let u64_ty = Type::get_uint64(context); - // `state_store_word` requires a `u64`. Cast the value to store to - // `u64` first before actually storing. - let rhs_u64 = self - .current_block - .ins(context) - .bitcast(rhs, u64_ty) - .add_metadatum(context, span_md_idx); - self.current_block - .ins(context) - .state_store_word(rhs_u64, *key_ptr_val) - .add_metadatum(context, span_md_idx); - Ok(()) - } - - fn compile_b256_storage_read( - &mut self, - context: &mut Context, - ix: &StateIndex, - indices: &[u64], - key_ptr_val: &Value, - span_md_idx: Option, - ) -> Result { - // B256 requires 4 words. Use state_load_quad_word/state_store_quad_word - // First, create a name for the value to load from or store to - let mut value_name = format!("{}{}", "val_for_", ix.to_usize()); - for ix in indices { - value_name = format!("{value_name}_{ix}"); - } - let alias_value_name = self.lexical_map.insert(value_name.as_str().to_owned()); - - // Local pointer to hold the B256 - let local_var = self - .function - .new_local_var( - context, - alias_value_name, - Type::get_b256(context), - None, - false, + // Get the actual storage key as a `Bytes32` as well as the offset, in words, + // within the slot. The offset depends on what field of the top level storage + // variable is being accessed. + let (storage_key, offset_within_slot) = { + let offset_in_words = self.get_offset(context, base_type, indices)?; + let offset_in_slots = offset_in_words / 4; + let offset_remaining = offset_in_words % 4; + + // The storage key we need is the storage key of the top level storage variable + // plus the offset, in number of slots, computed above. The offset within this + // particular slot is the remaining offset, in words. + ( + add_to_b256(get_storage_key::(ix, &[]), offset_in_slots), + offset_remaining, ) - .map_err(|ir_error| CompileError::InternalOwned(ir_error.to_string(), Span::dummy()))?; - - // Convert the local pointer created to a value using get_ptr - let local_ptr = self - .current_block - .ins(context) - .get_local(local_var) - .add_metadatum(context, span_md_idx); + }; - let one_value = convert_literal_to_value(context, &Literal::U64(1)); - self.current_block - .ins(context) - .state_load_quad_word(local_ptr, *key_ptr_val, one_value) - .add_metadatum(context, span_md_idx); - let local_val = self - .current_block - .ins(context) - .load(local_ptr) + // Const value for the key from the hash + let const_key = convert_literal_to_value(context, &Literal::B256(storage_key.into())) .add_metadatum(context, span_md_idx); - Ok(local_val) - } - - fn compile_b256_storage_write( - &mut self, - context: &mut Context, - ix: &StateIndex, - indices: &[u64], - key_ptr_val: &Value, - rhs: Value, - span_md_idx: Option, - ) -> Result<(), CompileError> { - // B256 requires 4 words. Use state_load_quad_word/state_store_quad_word - // First, create a name for the value to load from or store to - let mut value_name = format!("{}{}", "val_for_", ix.to_usize()); - for ix in indices { - value_name = format!("{value_name}_{ix}"); - } - let alias_value_name = self.lexical_map.insert(value_name.as_str().to_owned()); + // The type of a storage access is `StorageKey` which is a struct containing + // a `b256` and ` u64`. + let b256_ty = Type::get_b256(context); + let uint64_ty = Type::get_uint64(context); + let storage_key_aggregate = Type::new_struct(context, vec![b256_ty, uint64_ty]); - // Local pointer to hold the B256 - let local_var = self + // Local variable holding the `StorageKey` struct + let storage_key_local_name = self.lexical_map.insert_anon(); + let storage_key_ptr = self .function .new_local_var( context, - alias_value_name, - Type::get_b256(context), + storage_key_local_name, + storage_key_aggregate, None, false, ) .map_err(|ir_error| CompileError::InternalOwned(ir_error.to_string(), Span::dummy()))?; - - // Convert the local pointer created to a value using get_ptr - let local_val = self + let storage_key = self .current_block .ins(context) - .get_local(local_var) + .get_local(storage_key_ptr) .add_metadatum(context, span_md_idx); - // Store the value to the local pointer created for rhs - self.current_block - .ins(context) - .store(local_val, rhs) - .add_metadatum(context, span_md_idx); - - // Finally, just call state_load_quad_word/state_store_quad_word - let one_value = convert_literal_to_value(context, &Literal::U64(1)); + // Store the key as the first field in the `StorageKey` struct + let gep_0_val = + self.current_block + .ins(context) + .get_elem_ptr_with_idx(storage_key, b256_ty, 0); self.current_block .ins(context) - .state_store_quad_word(local_val, *key_ptr_val, one_value) - .add_metadatum(context, span_md_idx); - Ok(()) - } - - #[allow(clippy::too_many_arguments)] - fn compile_union_or_string_storage_read( - &mut self, - context: &mut Context, - ix: &StateIndex, - indices: &[u64], - key_val: &Value, - ty: &Type, - span_md_idx: Option, - ) -> Result { - // First, create a name for the value to load from or store to - let value_name = format!( - "val_for_{}{}", - ix.to_usize(), - indices - .iter() - .map(|idx| format!("_{idx}")) - .collect::>() - .join("") - ); - let local_value_name = self.lexical_map.insert(value_name); - - // Create an array of `b256` that will hold the value to store into storage - // or the value loaded from storage. The array has to fit the whole type. - let number_of_elements = (ir_type_size_in_bytes(context, ty) + 31) / 32; - let b256_array_type = Type::new_array(context, Type::get_b256(context), number_of_elements); - - // Local pointer to hold the array of b256s - let local_var = self - .function - .new_local_var(context, local_value_name, b256_array_type, None, false) - .map_err(|ir_error| CompileError::InternalOwned(ir_error.to_string(), Span::dummy()))?; - - // Convert the local pointer created to a value of the original type using cast_ptr. - let local_val = self - .current_block - .ins(context) - .get_local(local_var) + .store(gep_0_val, const_key) .add_metadatum(context, span_md_idx); - let ptr_ty = Type::new_ptr(context, *ty); - let final_val = self - .current_block - .ins(context) - .cast_ptr(local_val, ptr_ty) - .add_metadatum(context, span_md_idx); - let b256_ptr_ty = Type::new_ptr(context, Type::get_b256(context)); - - if number_of_elements > 0 { - // Get the b256 from the array at index iter - let value_val_b256 = self - .current_block - .ins(context) - .get_local(local_var) - .add_metadatum(context, span_md_idx); - let indexed_value_val_b256 = self - .current_block - .ins(context) - .cast_ptr(value_val_b256, b256_ptr_ty) - .add_metadatum(context, span_md_idx); - let count_value = convert_literal_to_value(context, &Literal::U64(number_of_elements)); + // Store the offset as the second field in the `StorageKey` struct + let offset_within_slot_val = Constant::get_uint(context, 64, offset_within_slot); + let gep_1_val = self.current_block .ins(context) - .state_load_quad_word(indexed_value_val_b256, *key_val, count_value) - .add_metadatum(context, span_md_idx); - } - - Ok(self - .current_block - .ins(context) - .load(final_val) - .add_metadatum(context, span_md_idx)) - } - - #[allow(clippy::too_many_arguments)] - fn compile_union_or_string_storage_write( - &mut self, - context: &mut Context, - ix: &StateIndex, - indices: &[u64], - key_val: &Value, - ty: &Type, - rhs: Value, - span_md_idx: Option, - ) -> Result<(), CompileError> { - // First, create a name for the value to load from or store to - let value_name = format!( - "val_for_{}{}", - ix.to_usize(), - indices - .iter() - .map(|idx| format!("_{idx}")) - .collect::>() - .join("") - ); - let local_value_name = self.lexical_map.insert(value_name); - - // Create an array of `b256` that will hold the value to store into storage - // or the value loaded from storage. The array has to fit the whole type. - let number_of_elements = (ir_type_size_in_bytes(context, ty) + 31) / 32; - let b256_array_type = Type::new_array(context, Type::get_b256(context), number_of_elements); - - // Local pointer to hold the array of b256s - let local_var = self - .function - .new_local_var(context, local_value_name, b256_array_type, None, false) - .map_err(|ir_error| CompileError::InternalOwned(ir_error.to_string(), Span::dummy()))?; - - // Convert the local pointer created to a value of the original type using - // get_ptr. - let local_val = self - .current_block - .ins(context) - .get_local(local_var) - .add_metadatum(context, span_md_idx); - let ptr_ty = Type::new_ptr(context, *ty); - let final_val = self - .current_block - .ins(context) - .cast_ptr(local_val, ptr_ty) - .add_metadatum(context, span_md_idx); - - // Store the value to the local pointer created for rhs + .get_elem_ptr_with_idx(storage_key, uint64_ty, 1); self.current_block .ins(context) - .store(final_val, rhs) + .store(gep_1_val, offset_within_slot_val) .add_metadatum(context, span_md_idx); - let b256_ptr_ty = Type::new_ptr(context, Type::get_b256(context)); - if number_of_elements > 0 { - // Get the b256 from the array at index iter - let value_ptr_val_b256 = self - .current_block - .ins(context) - .get_local(local_var) - .add_metadatum(context, span_md_idx); - let indexed_value_ptr_val_b256 = self - .current_block - .ins(context) - .cast_ptr(value_ptr_val_b256, b256_ptr_ty) - .add_metadatum(context, span_md_idx); - - // Finally, just call state_load_quad_word/state_store_quad_word - let count_value = convert_literal_to_value(context, &Literal::U64(number_of_elements)); - self.current_block - .ins(context) - .state_store_quad_word(indexed_value_ptr_val_b256, *key_val, count_value) - .add_metadatum(context, span_md_idx); - } - - Ok(()) + Ok(storage_key) } } diff --git a/sway-core/src/ir_generation/purity.rs b/sway-core/src/ir_generation/purity.rs index 5be5e9a221f..7fa0a261c5b 100644 --- a/sway-core/src/ir_generation/purity.rs +++ b/sway-core/src/ir_generation/purity.rs @@ -117,19 +117,18 @@ pub(crate) fn check_function_purity( // Or the attribute must match the behaviour. (Some(StorageOperation::Reads), _, true) => error(span, "write", Reads, Writes), - (Some(StorageOperation::Writes), true, _) => error(span, "read", Writes, Reads), // Or we have unneeded attributes. (Some(StorageOperation::ReadsWrites), false, true) => warn(span, Reads), (Some(StorageOperation::ReadsWrites), true, false) => warn(span, Writes), (Some(StorageOperation::ReadsWrites), false, false) => warn(span, ReadsWrites), (Some(StorageOperation::Reads), false, false) => warn(span, Reads), - (Some(StorageOperation::Writes), false, false) => warn(span, Writes), + (Some(StorageOperation::Writes), _, false) => warn(span, Writes), // Attributes and effects are in total agreement (None, false, false) | (Some(StorageOperation::Reads), true, false) - | (Some(StorageOperation::Writes), false, true) + | (Some(StorageOperation::Writes), _, true) // storage(write) allows reading as well | (Some(StorageOperation::ReadsWrites), true, true) => (), }; diff --git a/sway-core/src/ir_generation/storage.rs b/sway-core/src/ir_generation/storage.rs index 209692463cf..3ba5b41217d 100644 --- a/sway-core/src/ir_generation/storage.rs +++ b/sway-core/src/ir_generation/storage.rs @@ -62,7 +62,6 @@ pub fn serialize_to_storage_slots( ix: &StateIndex, ty: &Type, indices: &[usize], - experimental_storage: bool, ) -> Vec { match &constant.value { ConstantValue::Undef => vec![], @@ -108,31 +107,7 @@ pub fn serialize_to_storage_slots( ConstantValue::Array(_a) if ty.is_array(context) => { unimplemented!("Arrays in storage have not been implemented yet.") } - ConstantValue::Struct(vec) if ty.is_struct(context) && !experimental_storage => { - let field_tys = ty.get_field_types(context); - vec.iter() - .zip(field_tys.iter()) - .enumerate() - .flat_map(|(i, (f, ty))| { - serialize_to_storage_slots( - f, - context, - ix, - ty, - &indices - .iter() - .cloned() - .chain(vec![i].iter().cloned()) - .collect::>(), - experimental_storage, - ) - }) - .collect() - } - _ if ty.is_string(context) - || (experimental_storage && ty.is_struct(context)) - || ty.is_union(context) => - { + _ if ty.is_string(context) || ty.is_struct(context) || ty.is_union(context) => { // Serialize the constant data in words and add zero words until the number of words // is a multiple of 4. This is useful because each storage slot is 4 words. let mut packed = serialize_to_words(constant, context, ty); diff --git a/sway-core/src/ir_generation/types.rs b/sway-core/src/ir_generation/types.rs index 5e124182fc2..85ecf1efa4b 100644 --- a/sway-core/src/ir_generation/types.rs +++ b/sway-core/src/ir_generation/types.rs @@ -142,9 +142,7 @@ impl TypedNamedField for ty::ProjectionKind { } use ty::TyStorageAccessDescriptor; -use ty::TyStorageReassignDescriptor; impl_typed_named_field_for!(TyStorageAccessDescriptor); -impl_typed_named_field_for!(TyStorageReassignDescriptor); pub(super) fn get_indices_for_struct_access( type_engine: &TypeEngine, diff --git a/sway-core/src/language/parsed/expression/mod.rs b/sway-core/src/language/parsed/expression/mod.rs index 120aed6e880..956ca6937b9 100644 --- a/sway-core/src/language/parsed/expression/mod.rs +++ b/sway-core/src/language/parsed/expression/mod.rs @@ -221,13 +221,9 @@ pub enum ExpressionKind { Return(Box), } -/// Represents the left hand side of a reassignment, which could either be a regular variable -/// expression, denoted by [ReassignmentTarget::VariableExpression], or, a storage field, denoted -/// by [ReassignmentTarget::StorageField]. #[derive(Debug, Clone)] pub enum ReassignmentTarget { VariableExpression(Box), - StorageField(Span, Vec), } #[derive(Debug, Clone)] diff --git a/sway-core/src/language/purity.rs b/sway-core/src/language/purity.rs index 79ed3cc0ef2..4b498b2fcdd 100644 --- a/sway-core/src/language/purity.rs +++ b/sway-core/src/language/purity.rs @@ -15,7 +15,7 @@ impl Purity { match self { Purity::Pure => other == Purity::Pure, Purity::Reads => other == Purity::Pure || other == Purity::Reads, - Purity::Writes => other == Purity::Pure || other == Purity::Writes, + Purity::Writes => true, // storage(write) allows reading as well Purity::ReadsWrites => true, } } diff --git a/sway-core/src/language/ty/expression/expression.rs b/sway-core/src/language/ty/expression/expression.rs index f0d764f9049..7e5cc1a922c 100644 --- a/sway-core/src/language/ty/expression/expression.rs +++ b/sway-core/src/language/ty/expression/expression.rs @@ -420,22 +420,6 @@ impl CollectTypesMetadata for TyExpression { errors )); } - StorageReassignment(storage_reassignment) => { - for field in storage_reassignment.fields.iter() { - res.append(&mut check!( - field.type_id.collect_types_metadata(ctx), - return err(warnings, errors), - warnings, - errors - )); - } - res.append(&mut check!( - storage_reassignment.rhs.collect_types_metadata(ctx), - return err(warnings, errors), - warnings, - errors - )); - } } ok(res, warnings, errors) } @@ -526,9 +510,6 @@ impl DeterministicallyAborts for TyExpression { Reassignment(reassignment) => reassignment .rhs .deterministically_aborts(decl_engine, check_call_body), - StorageReassignment(storage_reassignment) => storage_reassignment - .rhs - .deterministically_aborts(decl_engine, check_call_body), // TODO: Is this correct? // I'm not sure what this function is supposed to do exactly. It's called // "deterministically_aborts" which I thought meant it checks for an abort/panic, but diff --git a/sway-core/src/language/ty/expression/expression_variant.rs b/sway-core/src/language/ty/expression/expression_variant.rs index 3a5afb6ea9c..724ddec2ee4 100644 --- a/sway-core/src/language/ty/expression/expression_variant.rs +++ b/sway-core/src/language/ty/expression/expression_variant.rs @@ -4,7 +4,7 @@ use std::{ hash::{Hash, Hasher}, }; -use sway_types::{state::StateIndex, Ident, Named, Span}; +use sway_types::{Ident, Named, Span}; use crate::{ decl_engine::*, @@ -21,9 +21,6 @@ pub enum TyExpressionVariant { contract_call_params: HashMap, arguments: Vec<(Ident, TyExpression)>, fn_ref: DeclRefFunction, - /// If this is `Some(val)` then `val` is the metadata. If this is `None`, then - /// there is no selector. - self_state_idx: Option, selector: Option, /// optional binding information for the LSP type_binding: Option>, @@ -132,7 +129,6 @@ pub enum TyExpressionVariant { Break, Continue, Reassignment(Box), - StorageReassignment(Box), Return(Box), } @@ -410,7 +406,6 @@ impl HashWithEngines for TyExpressionVariant { // these fields are not hashed because they aren't relevant/a // reliable source of obj v. obj distinction contract_call_params: _, - self_state_idx: _, selector: _, type_binding: _, } => { @@ -581,9 +576,6 @@ impl HashWithEngines for TyExpressionVariant { Self::Reassignment(exp) => { exp.hash(state, engines); } - Self::StorageReassignment(exp) => { - exp.hash(state, engines); - } Self::Return(exp) => { exp.hash(state, engines); } @@ -726,7 +718,6 @@ impl SubstTypes for TyExpressionVariant { Break => (), Continue => (), Reassignment(reassignment) => reassignment.subst(type_mapping, engines), - StorageReassignment(..) => (), Return(stmt) => stmt.subst(type_mapping, engines), } } @@ -861,7 +852,6 @@ impl ReplaceSelfType for TyExpressionVariant { Break => (), Continue => (), Reassignment(reassignment) => reassignment.replace_self_type(engines, self_type), - StorageReassignment(..) => (), Return(stmt) => stmt.replace_self_type(engines, self_type), } } @@ -969,7 +959,6 @@ impl ReplaceDecls for TyExpressionVariant { Break => (), Continue => (), Reassignment(reassignment) => reassignment.replace_decls(decl_mapping, engines), - StorageReassignment(..) => (), Return(stmt) => stmt.replace_decls(decl_mapping, engines), } } @@ -1070,7 +1059,6 @@ impl UpdateConstantExpression for TyExpressionVariant { Reassignment(reassignment) => { reassignment.update_constant_expression(engines, implementing_type) } - StorageReassignment(..) => (), Return(stmt) => stmt.update_constant_expression(engines, implementing_type), } } @@ -1225,16 +1213,6 @@ impl DebugWithEngines for TyExpressionVariant { } format!("reassignment to {place}") } - TyExpressionVariant::StorageReassignment(storage_reassignment) => { - let place: String = { - storage_reassignment - .fields - .iter() - .map(|field| field.name.as_str()) - .collect() - }; - format!("storage reassignment to {place}") - } TyExpressionVariant::Return(exp) => { format!("return {:?}", engines.help_out(&**exp)) } @@ -1290,9 +1268,6 @@ impl TyExpressionVariant { TyExpressionVariant::Reassignment(reassignment) => { reassignment.rhs.gather_return_statements() } - TyExpressionVariant::StorageReassignment(storage_reassignment) => { - storage_reassignment.rhs.gather_return_statements() - } TyExpressionVariant::LazyOperator { lhs, rhs, .. } => [lhs, rhs] .into_iter() .flat_map(|expr| expr.gather_return_statements()) diff --git a/sway-core/src/language/ty/expression/reassignment.rs b/sway-core/src/language/ty/expression/reassignment.rs index 420bdffc9fb..da675760271 100644 --- a/sway-core/src/language/ty/expression/reassignment.rs +++ b/sway-core/src/language/ty/expression/reassignment.rs @@ -3,7 +3,7 @@ use std::{ hash::{Hash, Hasher}, }; -use sway_types::{state::StateIndex, Ident, Span, Spanned}; +use sway_types::{Ident, Span, Spanned}; use crate::{decl_engine::*, engine_threading::*, language::ty::*, type_system::*}; @@ -164,91 +164,3 @@ impl ProjectionKind { } } } - -/// Describes each field being drilled down into in storage and its type. -#[derive(Clone, Debug)] -pub struct TyStorageReassignment { - pub fields: Vec, - pub(crate) ix: StateIndex, - pub rhs: TyExpression, - pub storage_keyword_span: Span, -} - -impl EqWithEngines for TyStorageReassignment {} -impl PartialEqWithEngines for TyStorageReassignment { - fn eq(&self, other: &Self, engines: Engines<'_>) -> bool { - self.fields.eq(&other.fields, engines) - && self.ix == other.ix - && self.rhs.eq(&other.rhs, engines) - } -} - -impl HashWithEngines for TyStorageReassignment { - fn hash(&self, state: &mut H, engines: Engines<'_>) { - let TyStorageReassignment { - fields, - ix, - rhs, - // these fields are not hashed because they aren't relevant/a - // reliable source of obj v. obj distinction - storage_keyword_span: _, - } = self; - fields.hash(state, engines); - ix.hash(state); - rhs.hash(state, engines); - } -} - -impl Spanned for TyStorageReassignment { - fn span(&self) -> Span { - self.fields - .iter() - .fold(self.fields[0].span.clone(), |acc, field| { - Span::join(acc, field.span.clone()) - }) - } -} - -impl TyStorageReassignment { - pub fn names(&self) -> Vec { - self.fields - .iter() - .map(|f| f.name.clone()) - .collect::>() - } -} - -/// Describes a single subfield access in the sequence when reassigning to a subfield within -/// storage. -#[derive(Clone, Debug)] -pub struct TyStorageReassignDescriptor { - pub name: Ident, - pub type_id: TypeId, - pub(crate) span: Span, -} - -impl EqWithEngines for TyStorageReassignDescriptor {} -impl PartialEqWithEngines for TyStorageReassignDescriptor { - fn eq(&self, other: &Self, engines: Engines<'_>) -> bool { - let type_engine = engines.te(); - self.name == other.name - && type_engine - .get(self.type_id) - .eq(&type_engine.get(other.type_id), engines) - } -} - -impl HashWithEngines for TyStorageReassignDescriptor { - fn hash(&self, state: &mut H, engines: Engines<'_>) { - let TyStorageReassignDescriptor { - name, - type_id, - // these fields are not hashed because they aren't relevant/a - // reliable source of obj v. obj distinction - span: _, - } = self; - let type_engine = engines.te(); - name.hash(state); - type_engine.get(*type_id).hash(state, engines); - } -} diff --git a/sway-core/src/language/ty/program.rs b/sway-core/src/language/ty/program.rs index e71a8f0747e..c4bddcf57eb 100644 --- a/sway-core/src/language/ty/program.rs +++ b/sway-core/src/language/ty/program.rs @@ -3,7 +3,6 @@ use crate::{ error::*, fuel_prelude::fuel_tx::StorageSlot, language::{parsed, ty::*, Purity}, - semantic_analysis::storage_only_types, type_system::*, types::*, Engines, @@ -30,7 +29,6 @@ impl TyProgram { root: &TyModule, kind: parsed::TreeType, package_name: &str, - experimental_storage: bool, ) -> CompileResult<(TyProgramKind, Vec, Vec)> { // Extract program-kind-specific properties from the root nodes. let mut errors = vec![]; @@ -48,7 +46,6 @@ impl TyProgram { &submodule.module, parsed::TreeType::Library, package_name, - experimental_storage, ), continue, warnings, @@ -140,20 +137,6 @@ impl TyProgram { }; } - if !experimental_storage { - for ast_n in &root.all_nodes { - check!( - storage_only_types::validate_decls_for_storage_only_types_in_ast( - engines, - &ast_n.content - ), - continue, - warnings, - errors - ); - } - } - // Some checks that are specific to non-contracts if kind != parsed::TreeType::Contract { // impure functions are disallowed in non-contracts diff --git a/sway-core/src/lib.rs b/sway-core/src/lib.rs index 78e8d2663d4..17b407dd1df 100644 --- a/sway-core/src/lib.rs +++ b/sway-core/src/lib.rs @@ -334,22 +334,12 @@ pub fn parsed_to_ast( build_config: Option<&BuildConfig>, package_name: &str, ) -> CompileResult { - let experimental_storage = match build_config { - Some(build_config) => build_config.experimental_storage, - None => true, - }; // Type check the program. let CompileResult { value: typed_program_opt, mut warnings, mut errors, - } = ty::TyProgram::type_check( - engines, - parse_program, - initial_namespace, - package_name, - experimental_storage, - ); + } = ty::TyProgram::type_check(engines, parse_program, initial_namespace, package_name); let mut typed_program = match typed_program_opt { Some(typed_program) => typed_program, None => return err(warnings, errors), @@ -420,7 +410,6 @@ pub fn parsed_to_ast( &mut ctx, &mut md_mgr, module, - experimental_storage, ); warnings.extend(typed_wiss_res.warnings); errors.extend(typed_wiss_res.errors); @@ -561,12 +550,8 @@ pub(crate) fn compile_ast_to_ir_to_asm( // IR phase. let tree_type = program.kind.tree_type(); - let mut ir = match ir_generation::compile_program( - program, - build_config.include_tests, - engines, - build_config.experimental_storage, - ) { + let mut ir = match ir_generation::compile_program(program, build_config.include_tests, engines) + { Ok(ir) => ir, Err(e) => return err(warnings, vec![e]), }; diff --git a/sway-core/src/metadata.rs b/sway-core/src/metadata.rs index c99d2cf10ee..076299f2bec 100644 --- a/sway-core/src/metadata.rs +++ b/sway-core/src/metadata.rs @@ -21,7 +21,6 @@ pub(crate) struct MetadataManager { md_span_cache: HashMap, md_file_loc_cache: HashMap, Arc)>, md_storage_op_cache: HashMap, - md_storage_key_cache: HashMap, md_inline_cache: HashMap, md_test_decl_index_cache: HashMap>, md_config_const_name_cache: HashMap>, @@ -29,7 +28,6 @@ pub(crate) struct MetadataManager { span_md_cache: HashMap, file_loc_md_cache: HashMap<*const PathBuf, MetadataIndex>, storage_op_md_cache: HashMap, - storage_key_md_cache: HashMap, inline_md_cache: HashMap, test_decl_index_md_cache: HashMap, MetadataIndex>, config_const_name_md_cache: HashMap, MetadataIndex>, @@ -122,28 +120,6 @@ impl MetadataManager { }) } - pub(crate) fn md_to_storage_key( - &mut self, - context: &Context, - md_idx: Option, - ) -> Option { - Self::for_each_md_idx(context, md_idx, |md_idx| { - self.md_storage_key_cache.get(&md_idx).copied().or_else(|| { - // Create a new storage key and save it in the cache. - md_idx - .get_content(context) - .unwrap_struct("state_index", 1) - .and_then(|fields| { - let key = fields[0].unwrap_integer()?; - - self.md_storage_key_cache.insert(md_idx, key); - - Some(key) - }) - }) - }) - } - /// Gets Inline information from metadata index. /// TODO: We temporarily allow this because we need this /// in the sway-ir inliner, but cannot access it. So the code @@ -230,10 +206,6 @@ impl MetadataManager { self.md_to_span(context, value.get_metadata(context)) } - pub(crate) fn val_to_storage_key(&mut self, context: &Context, value: Value) -> Option { - self.md_to_storage_key(context, value.get_metadata(context)) - } - pub(crate) fn span_to_md( &mut self, context: &mut Context, @@ -280,28 +252,6 @@ impl MetadataManager { }) } - pub(crate) fn storage_key_to_md( - &mut self, - context: &mut Context, - storage_key: u64, - ) -> Option { - self.storage_key_md_cache - .get(&storage_key) - .copied() - .or_else(|| { - // Create new metadatum. - let md_idx = MetadataIndex::new_struct( - context, - "state_index", - vec![Metadatum::Integer(storage_key)], - ); - - self.storage_key_md_cache.insert(storage_key, md_idx); - - Some(md_idx) - }) - } - pub(crate) fn purity_to_md( &mut self, context: &mut Context, diff --git a/sway-core/src/monomorphize/gather/expression.rs b/sway-core/src/monomorphize/gather/expression.rs index 5391c891103..3076149e764 100644 --- a/sway-core/src/monomorphize/gather/expression.rs +++ b/sway-core/src/monomorphize/gather/expression.rs @@ -85,7 +85,6 @@ pub(crate) fn gather_from_exp_inner( ty::TyExpressionVariant::UnsafeDowncast { .. } => todo!(), ty::TyExpressionVariant::WhileLoop { .. } => todo!(), ty::TyExpressionVariant::Reassignment(_) => todo!(), - ty::TyExpressionVariant::StorageReassignment(_) => todo!(), ty::TyExpressionVariant::Return(exp) => { gather_from_exp(ctx.by_ref(), handler, exp)?; } diff --git a/sway-core/src/monomorphize/instruct/expression.rs b/sway-core/src/monomorphize/instruct/expression.rs index 3f53bfd7e4e..efbd198cffd 100644 --- a/sway-core/src/monomorphize/instruct/expression.rs +++ b/sway-core/src/monomorphize/instruct/expression.rs @@ -85,7 +85,6 @@ pub(crate) fn instruct_exp_inner( ty::TyExpressionVariant::UnsafeDowncast { .. } => todo!(), ty::TyExpressionVariant::WhileLoop { .. } => todo!(), ty::TyExpressionVariant::Reassignment(_) => todo!(), - ty::TyExpressionVariant::StorageReassignment(_) => todo!(), ty::TyExpressionVariant::Return(exp) => { instruct_exp(ctx.by_ref(), handler, exp)?; } diff --git a/sway-core/src/semantic_analysis.rs b/sway-core/src/semantic_analysis.rs index 965a2961cde..e27574e7393 100644 --- a/sway-core/src/semantic_analysis.rs +++ b/sway-core/src/semantic_analysis.rs @@ -6,7 +6,6 @@ mod module; pub mod namespace; mod node_dependencies; mod program; -pub(crate) mod storage_only_types; mod type_check_context; pub use ast_node::*; pub use namespace::Namespace; diff --git a/sway-core/src/semantic_analysis/ast_node/declaration/impl_trait.rs b/sway-core/src/semantic_analysis/ast_node/declaration/impl_trait.rs index 5f3e366579d..928d5d0dd3e 100644 --- a/sway-core/src/semantic_analysis/ast_node/declaration/impl_trait.rs +++ b/sway-core/src/semantic_analysis/ast_node/declaration/impl_trait.rs @@ -228,227 +228,6 @@ impl ty::TyImplTrait { ok(impl_trait, warnings, errors) } - // If any method contains a call to get_storage_index, then - // impl_typ can only be a storage type. - // This is noted down in the type engine. - fn gather_storage_only_types( - engines: Engines<'_>, - impl_typ: TypeId, - items: &[TyImplItem], - access_span: &Span, - ) -> Result<(), CompileError> { - fn ast_node_contains_get_storage_index( - decl_engine: &DeclEngine, - x: &ty::TyAstNodeContent, - access_span: &Span, - ) -> Result { - match x { - ty::TyAstNodeContent::Expression(expr) - | ty::TyAstNodeContent::ImplicitReturnExpression(expr) => { - expr_contains_get_storage_index(decl_engine, expr, access_span) - } - ty::TyAstNodeContent::Declaration(decl) => { - decl_contains_get_storage_index(decl_engine, decl, access_span) - } - ty::TyAstNodeContent::SideEffect(_) => Ok(false), - } - } - - fn expr_contains_get_storage_index( - decl_engine: &DeclEngine, - expr: &ty::TyExpression, - access_span: &Span, - ) -> Result { - let res = match &expr.expression { - ty::TyExpressionVariant::Literal(_) - | ty::TyExpressionVariant::ConstantExpression { .. } - | ty::TyExpressionVariant::VariableExpression { .. } - | ty::TyExpressionVariant::FunctionParameter - | ty::TyExpressionVariant::AsmExpression { .. } - | ty::TyExpressionVariant::Break - | ty::TyExpressionVariant::Continue - | ty::TyExpressionVariant::StorageAccess(_) - | ty::TyExpressionVariant::AbiName(_) => false, - ty::TyExpressionVariant::FunctionApplication { arguments, .. } => { - for f in arguments.iter() { - let b = expr_contains_get_storage_index(decl_engine, &f.1, access_span)?; - if b { - return Ok(true); - } - } - false - } - ty::TyExpressionVariant::LazyOperator { - lhs: expr1, - rhs: expr2, - .. - } - | ty::TyExpressionVariant::ArrayIndex { - prefix: expr1, - index: expr2, - } => { - expr_contains_get_storage_index(decl_engine, expr1, access_span)? - || expr_contains_get_storage_index(decl_engine, expr2, access_span)? - } - ty::TyExpressionVariant::Tuple { fields: exprvec } - | ty::TyExpressionVariant::Array { - elem_type: _, - contents: exprvec, - } => { - for f in exprvec.iter() { - let b = expr_contains_get_storage_index(decl_engine, f, access_span)?; - if b { - return Ok(true); - } - } - false - } - - ty::TyExpressionVariant::StructExpression { fields, .. } => { - for f in fields.iter() { - let b = - expr_contains_get_storage_index(decl_engine, &f.value, access_span)?; - if b { - return Ok(true); - } - } - false - } - ty::TyExpressionVariant::CodeBlock(cb) => { - codeblock_contains_get_storage_index(decl_engine, cb, access_span)? - } - ty::TyExpressionVariant::MatchExp { desugared, .. } => { - expr_contains_get_storage_index(decl_engine, desugared, access_span)? - } - ty::TyExpressionVariant::IfExp { - condition, - then, - r#else, - } => { - expr_contains_get_storage_index(decl_engine, condition, access_span)? - || expr_contains_get_storage_index(decl_engine, then, access_span)? - || r#else.as_ref().map_or(Ok(false), |r#else| { - expr_contains_get_storage_index(decl_engine, r#else, access_span) - })? - } - ty::TyExpressionVariant::StructFieldAccess { prefix: exp, .. } - | ty::TyExpressionVariant::TupleElemAccess { prefix: exp, .. } - | ty::TyExpressionVariant::AbiCast { address: exp, .. } - | ty::TyExpressionVariant::EnumTag { exp } - | ty::TyExpressionVariant::UnsafeDowncast { exp, .. } => { - expr_contains_get_storage_index(decl_engine, exp, access_span)? - } - ty::TyExpressionVariant::EnumInstantiation { contents, .. } => { - contents.as_ref().map_or(Ok(false), |f| { - expr_contains_get_storage_index(decl_engine, f, access_span) - })? - } - - ty::TyExpressionVariant::IntrinsicFunction(ty::TyIntrinsicFunctionKind { - kind, - .. - }) => matches!(kind, sway_ast::intrinsics::Intrinsic::GetStorageKey), - ty::TyExpressionVariant::WhileLoop { condition, body } => { - expr_contains_get_storage_index(decl_engine, condition, access_span)? - || codeblock_contains_get_storage_index(decl_engine, body, access_span)? - } - ty::TyExpressionVariant::Reassignment(reassignment) => { - expr_contains_get_storage_index(decl_engine, &reassignment.rhs, access_span)? - } - ty::TyExpressionVariant::StorageReassignment(storage_reassignment) => { - expr_contains_get_storage_index( - decl_engine, - &storage_reassignment.rhs, - access_span, - )? - } - ty::TyExpressionVariant::Return(exp) => { - expr_contains_get_storage_index(decl_engine, exp, access_span)? - } - }; - Ok(res) - } - - fn decl_contains_get_storage_index( - decl_engine: &DeclEngine, - decl: &ty::TyDecl, - access_span: &Span, - ) -> Result { - match decl { - ty::TyDecl::VariableDecl(decl) => { - expr_contains_get_storage_index(decl_engine, &decl.body, access_span) - } - ty::TyDecl::ConstantDecl(ty::ConstantDecl { decl_id, .. }) => { - let ty::TyConstantDecl { value: expr, .. } = decl_engine.get_constant(decl_id); - match expr { - Some(expr) => { - expr_contains_get_storage_index(decl_engine, &expr, access_span) - } - None => Ok(false), - } - } - // We're already inside a type's impl. So we can't have these - // nested functions etc. We just ignore them. - ty::TyDecl::FunctionDecl { .. } - | ty::TyDecl::TraitDecl { .. } - | ty::TyDecl::StructDecl { .. } - | ty::TyDecl::EnumDecl { .. } - | ty::TyDecl::EnumVariantDecl { .. } - | ty::TyDecl::ImplTrait { .. } - | ty::TyDecl::AbiDecl { .. } - | ty::TyDecl::GenericTypeForFunctionScope { .. } - | ty::TyDecl::ErrorRecovery(_) - | ty::TyDecl::TypeAliasDecl { .. } - | ty::TyDecl::StorageDecl { .. } => Ok(false), - } - } - - fn codeblock_contains_get_storage_index( - decl_engine: &DeclEngine, - cb: &ty::TyCodeBlock, - access_span: &Span, - ) -> Result { - for content in cb.contents.iter() { - let b = ast_node_contains_get_storage_index( - decl_engine, - &content.content, - access_span, - )?; - if b { - return Ok(true); - } - } - Ok(false) - } - - let type_engine = engines.te(); - let decl_engine = engines.de(); - - for item in items.iter() { - let contains_get_storage_index = match item { - ty::TyTraitItem::Fn(fn_decl) => { - let method = decl_engine.get_function(fn_decl); - codeblock_contains_get_storage_index(decl_engine, &method.body, access_span)? - } - ty::TyTraitItem::Constant(const_decl) => { - let const_decl = decl_engine.get_constant(const_decl); - match const_decl.value { - Some(expr) => { - expr_contains_get_storage_index(decl_engine, &expr, access_span) - } - None => Ok(false), - }? - } - }; - if contains_get_storage_index { - type_engine.set_type_as_storage_only(impl_typ); - return Ok(()); - } - } - - Ok(()) - } - pub(crate) fn type_check_impl_self( ctx: TypeCheckContext, impl_self: ImplSelf, @@ -570,18 +349,6 @@ impl ty::TyImplTrait { return err(warnings, errors); } - check!( - CompileResult::from(Self::gather_storage_only_types( - engines, - implementing_for.type_id, - &new_items, - &implementing_for.span, - )), - return err(warnings, errors), - warnings, - errors - ); - let impl_trait = ty::TyImplTrait { impl_type_parameters: new_impl_type_parameters, trait_name, diff --git a/sway-core/src/semantic_analysis/ast_node/declaration/storage.rs b/sway-core/src/semantic_analysis/ast_node/declaration/storage.rs index 13053e79e74..3244b60aeed 100644 --- a/sway-core/src/semantic_analysis/ast_node/declaration/storage.rs +++ b/sway-core/src/semantic_analysis/ast_node/declaration/storage.rs @@ -19,7 +19,6 @@ impl ty::TyStorageDecl { context: &mut Context, md_mgr: &mut MetadataManager, module: Module, - experimental_storage: bool, ) -> CompileResult> { let mut errors = vec![]; let storage_slots = self @@ -33,7 +32,6 @@ impl ty::TyStorageDecl { md_mgr, module, &StateIndex::new(i), - experimental_storage, ) }) .filter_map(|s| s.map_err(|e| errors.push(e)).ok()) @@ -55,7 +53,6 @@ impl ty::TyStorageField { md_mgr: &mut MetadataManager, module: Module, ix: &StateIndex, - experimental_storage: bool, ) -> Result, CompileError> { compile_constant_expression_to_constant( engines, @@ -66,15 +63,6 @@ impl ty::TyStorageField { None, &self.initializer, ) - .map(|constant| { - serialize_to_storage_slots( - &constant, - context, - ix, - &constant.ty, - &[], - experimental_storage, - ) - }) + .map(|constant| serialize_to_storage_slots(&constant, context, ix, &constant.ty, &[])) } } diff --git a/sway-core/src/semantic_analysis/ast_node/expression/intrinsic_function.rs b/sway-core/src/semantic_analysis/ast_node/expression/intrinsic_function.rs index b372317c633..89ed2360d83 100644 --- a/sway-core/src/semantic_analysis/ast_node/expression/intrinsic_function.rs +++ b/sway-core/src/semantic_analysis/ast_node/expression/intrinsic_function.rs @@ -35,9 +35,6 @@ impl ty::TyIntrinsicFunctionKind { Intrinsic::IsReferenceType => { type_check_is_reference_type(ctx, kind, arguments, type_arguments, span) } - Intrinsic::GetStorageKey => { - type_check_get_storage_key(ctx, kind, arguments, type_arguments, span) - } Intrinsic::Eq | Intrinsic::Gt | Intrinsic::Lt => { type_check_cmp(ctx, kind, arguments, span) } @@ -245,35 +242,6 @@ fn type_check_is_reference_type( ) } -/// Signature: `__get_storage_key() -> b256` -/// Description: Returns the storage key used by a given `struct` in storage when called from a -/// method on that `struct`. -/// Constraints: None. -fn type_check_get_storage_key( - ctx: TypeCheckContext, - kind: sway_ast::Intrinsic, - _arguments: Vec, - _type_arguments: Vec, - span: Span, -) -> CompileResult<(ty::TyIntrinsicFunctionKind, TypeId)> { - let type_engine = ctx.type_engine; - let decl_engine = ctx.decl_engine; - - ok( - ( - ty::TyIntrinsicFunctionKind { - kind, - arguments: vec![], - type_arguments: vec![], - span, - }, - type_engine.insert(decl_engine, TypeInfo::B256), - ), - vec![], - vec![], - ) -} - /// Signature: `__eq(lhs: T, rhs: T) -> bool` /// Description: Returns whether `lhs` and `rhs` are equal. /// Constraints: `T` is `bool`, `u8`, `u16`, `u32`, `u64`, or `raw_ptr`. diff --git a/sway-core/src/semantic_analysis/ast_node/expression/typed_expression.rs b/sway-core/src/semantic_analysis/ast_node/expression/typed_expression.rs index 086381161d9..eea74d3fa30 100644 --- a/sway-core/src/semantic_analysis/ast_node/expression/typed_expression.rs +++ b/sway-core/src/semantic_analysis/ast_node/expression/typed_expression.rs @@ -102,7 +102,6 @@ impl ty::TyExpression { contract_call_params: HashMap::new(), arguments: args_and_names, fn_ref: decl_ref, - self_state_idx: None, selector: None, type_binding: None, }, @@ -904,67 +903,65 @@ impl ty::TyExpression { errors ); - if ctx.experimental_storage_enabled() { - // The type of a storage access is `core::experimental::storage::StorageKey`. This is - // the path to it. - let storage_key_mod_path = vec![ - Ident::new_with_override("core".into(), span.clone()), - Ident::new_with_override("experimental".into(), span.clone()), - Ident::new_with_override("storage".into(), span.clone()), - ]; - let storage_key_ident = Ident::new_with_override("StorageKey".into(), span.clone()); - - // Search for the struct declaration with the call path above. - let storage_key_decl_opt = check!( - ctx.namespace - .root() - .resolve_symbol(&storage_key_mod_path, &storage_key_ident), - return err(warnings, errors), - warnings, - errors - ); - let storage_key_struct_decl_ref = check!( - storage_key_decl_opt.to_struct_ref(engines), - return err(warnings, errors), - warnings, - errors - ); - let mut storage_key_struct_decl = decl_engine.get_struct(&storage_key_struct_decl_ref); + // The type of a storage access is `core::storage::StorageKey`. This is + // the path to it. + let storage_key_mod_path = vec![ + Ident::new_with_override("core".into(), span.clone()), + Ident::new_with_override("storage".into(), span.clone()), + ]; + let storage_key_ident = Ident::new_with_override("StorageKey".into(), span.clone()); - // Set the type arguments to `StorageKey` to the `access_type`, which is represents the - // type of the data that the `StorageKey` "points" to. - let mut type_arguments = vec![TypeArgument { - initial_type_id: access_type, - type_id: access_type, - span: span.clone(), - call_path_tree: None, - }]; + // Search for the struct declaration with the call path above. + let storage_key_decl_opt = check!( + ctx.namespace + .root() + .resolve_symbol(&storage_key_mod_path, &storage_key_ident), + return err(warnings, errors), + warnings, + errors + ); + let storage_key_struct_decl_ref = check!( + storage_key_decl_opt.to_struct_ref(engines), + return err(warnings, errors), + warnings, + errors + ); + let mut storage_key_struct_decl = decl_engine.get_struct(&storage_key_struct_decl_ref); + + // Set the type arguments to `StorageKey` to the `access_type`, which is represents the + // type of the data that the `StorageKey` "points" to. + let mut type_arguments = vec![TypeArgument { + initial_type_id: access_type, + type_id: access_type, + span: span.clone(), + call_path_tree: None, + }]; + + // Monomorphize the generic `StorageKey` type given the type argument specified above + let mut ctx = ctx; + check!( + ctx.monomorphize( + &mut storage_key_struct_decl, + &mut type_arguments, + EnforceTypeArguments::Yes, + span + ), + return err(warnings, errors), + warnings, + errors + ); - // Monomorphize the generic `StorageKey` type given the type argument specified above - let mut ctx = ctx; - check!( - ctx.monomorphize( - &mut storage_key_struct_decl, - &mut type_arguments, - EnforceTypeArguments::Yes, - span - ), - return err(warnings, errors), - warnings, - errors - ); + // Update `access_type` to be the type of the monomorphized struct after inserting it + // into the type engine + let storage_key_struct_decl_ref = ctx.engines().de().insert(storage_key_struct_decl); + access_type = + type_engine.insert(decl_engine, TypeInfo::Struct(storage_key_struct_decl_ref)); - // Update `access_type` to be the type of the monomorphized struct after inserting it - // into the type engine - let storage_key_struct_decl_ref = ctx.engines().de().insert(storage_key_struct_decl); - access_type = - type_engine.insert(decl_engine, TypeInfo::Struct(storage_key_struct_decl_ref)); + // take any trait items that apply to `StorageKey` and copy them to the + // monomorphized type + ctx.namespace + .insert_trait_implementation_for_type(engines, access_type); - // take any trait items that apply to `StorageKey` and copy them to the - // monomorphized type - ctx.namespace - .insert_trait_implementation_for_type(engines, access_type); - } ok( ty::TyExpression { expression: ty::TyExpressionVariant::StorageAccess(storage_access), @@ -1878,28 +1875,6 @@ impl ty::TyExpression { errors, ) } - ReassignmentTarget::StorageField(storage_keyword_span, fields) => { - let ctx = ctx - .with_type_annotation(type_engine.insert(decl_engine, TypeInfo::Unknown)) - .with_help_text(""); - let reassignment = check!( - reassign_storage_subfield(ctx, fields, rhs, span.clone(), storage_keyword_span), - return err(warnings, errors), - warnings, - errors, - ); - ok( - ty::TyExpression { - expression: ty::TyExpressionVariant::StorageReassignment(Box::new( - reassignment, - )), - return_type: type_engine.insert(decl_engine, TypeInfo::Tuple(Vec::new())), - span, - }, - warnings, - errors, - ) - } } } diff --git a/sway-core/src/semantic_analysis/ast_node/expression/typed_expression/function_application.rs b/sway-core/src/semantic_analysis/ast_node/expression/typed_expression/function_application.rs index 07caee22f19..2b3d8733076 100644 --- a/sway-core/src/semantic_analysis/ast_node/expression/typed_expression/function_application.rs +++ b/sway-core/src/semantic_analysis/ast_node/expression/typed_expression/function_application.rs @@ -98,7 +98,6 @@ pub(crate) fn instantiate_function_application( contract_call_params: HashMap::new(), arguments: typed_arguments_with_names, fn_ref: new_decl_ref, - self_state_idx: None, selector: None, type_binding: Some(call_path_binding.strip_inner()), }, diff --git a/sway-core/src/semantic_analysis/ast_node/expression/typed_expression/method_application.rs b/sway-core/src/semantic_analysis/ast_node/expression/typed_expression/method_application.rs index 74974970841..8b684b3dcc8 100644 --- a/sway-core/src/semantic_analysis/ast_node/expression/typed_expression/method_application.rs +++ b/sway-core/src/semantic_analysis/ast_node/expression/typed_expression/method_application.rs @@ -10,7 +10,7 @@ use std::collections::{HashMap, VecDeque}; use sway_error::error::CompileError; use sway_types::{constants, integer_bits::IntegerBits}; use sway_types::{constants::CONTRACT_CALL_COINS_PARAMETER_NAME, Spanned}; -use sway_types::{state::StateIndex, Ident, Span}; +use sway_types::{Ident, Span}; #[allow(clippy::too_many_arguments)] pub(crate) fn type_check_method_application( @@ -157,40 +157,6 @@ pub(crate) fn type_check_method_application( } } - // If this method was called with self being a `StorageAccess` (e.g. storage.map.insert(..)), - // then record the index of that storage variable and pass it on. - let mut self_state_idx = None; - if ctx.namespace.has_storage_declared() { - let storage_fields = check!( - ctx.namespace.get_storage_field_descriptors(decl_engine), - return err(warnings, errors), - warnings, - errors - ); - - self_state_idx = match arguments.first().map(|expr| &expr.kind) { - Some(ExpressionKind::StorageAccess(StorageAccessExpression { field_names })) => { - let first_field = field_names[0].clone(); - let self_state_idx = match storage_fields - .iter() - .enumerate() - .find(|(_, ty::TyStorageField { name, .. })| name == &first_field) - { - Some((ix, _)) => StateIndex::new(ix), - None => { - errors.push(CompileError::StorageFieldDoesNotExist { - name: first_field.clone(), - span: first_field.span(), - }); - return err(warnings, errors); - } - }; - Some(self_state_idx) - } - _ => None, - } - }; - // If this function is being called with method call syntax, a.b(c), // then make sure the first parameter is self, else issue an error. let mut is_method_call_syntax_used = false; @@ -352,7 +318,6 @@ pub(crate) fn type_check_method_application( contract_call_params: contract_call_params_map, arguments: typed_arguments_with_names, fn_ref: decl_ref, - self_state_idx, selector, type_binding: Some(method_name_binding.strip_inner()), }, diff --git a/sway-core/src/semantic_analysis/ast_node/mod.rs b/sway-core/src/semantic_analysis/ast_node/mod.rs index 7d4757af0fb..8e7627db7c3 100644 --- a/sway-core/src/semantic_analysis/ast_node/mod.rs +++ b/sway-core/src/semantic_analysis/ast_node/mod.rs @@ -15,8 +15,8 @@ use crate::{ Ident, }; -use sway_error::{error::CompileError, warning::Warning}; -use sway_types::{span::Span, state::StateIndex, Spanned}; +use sway_error::warning::Warning; +use sway_types::{span::Span, Spanned}; impl ty::TyAstNode { pub(crate) fn type_check(ctx: TypeCheckContext, node: AstNode) -> CompileResult { @@ -157,118 +157,3 @@ impl ty::TyAstNode { ok(node, warnings, errors) } } - -pub(crate) fn reassign_storage_subfield( - ctx: TypeCheckContext, - fields: Vec, - rhs: Expression, - span: Span, - storage_keyword_span: Span, -) -> CompileResult { - let mut errors = vec![]; - let mut warnings = vec![]; - - let type_engine = ctx.type_engine; - let decl_engine = ctx.decl_engine; - let engines = ctx.engines(); - - if !ctx.namespace.has_storage_declared() { - errors.push(CompileError::NoDeclaredStorage { span }); - - return err(warnings, errors); - } - - let storage_fields = check!( - ctx.namespace.get_storage_field_descriptors(decl_engine), - return err(warnings, errors), - warnings, - errors - ); - let mut type_checked_buf = vec![]; - let mut fields: Vec<_> = fields.into_iter().rev().collect(); - - let first_field = fields.pop().expect("guaranteed by grammar"); - let (ix, initial_field_type) = match storage_fields - .iter() - .enumerate() - .find(|(_, ty::TyStorageField { name, .. })| name == &first_field) - { - Some((ix, ty::TyStorageField { type_argument, .. })) => { - (StateIndex::new(ix), type_argument.type_id) - } - None => { - errors.push(CompileError::StorageFieldDoesNotExist { - name: first_field.clone(), - span: first_field.span(), - }); - return err(warnings, errors); - } - }; - - type_checked_buf.push(ty::TyStorageReassignDescriptor { - name: first_field.clone(), - type_id: initial_field_type, - span: first_field.span(), - }); - - let update_available_struct_fields = |id: TypeId| match type_engine.get(id) { - TypeInfo::Struct(decl_ref) => decl_engine.get_struct(&decl_ref).fields, - _ => vec![], - }; - let mut curr_type = initial_field_type; - - // if the previously iterated type was a struct, put its fields here so we know that, - // in the case of a subfield, we can type check the that the subfield exists and its type. - let mut available_struct_fields = update_available_struct_fields(initial_field_type); - - // get the initial field's type - // make sure the next field exists in that type - for field in fields.into_iter().rev() { - match available_struct_fields - .iter() - .find(|x| x.name.as_str() == field.as_str()) - { - Some(struct_field) => { - curr_type = struct_field.type_argument.type_id; - type_checked_buf.push(ty::TyStorageReassignDescriptor { - name: field.clone(), - type_id: struct_field.type_argument.type_id, - span: field.span().clone(), - }); - available_struct_fields = - update_available_struct_fields(struct_field.type_argument.type_id); - } - None => { - let available_fields = available_struct_fields - .iter() - .map(|x| x.name.as_str()) - .collect::>(); - errors.push(CompileError::FieldNotFound { - field_name: field.clone(), - available_fields: available_fields.join(", "), - struct_name: type_checked_buf.last().unwrap().name.clone(), - span: field.span(), - }); - return err(warnings, errors); - } - } - } - let ctx = ctx.with_type_annotation(curr_type).with_help_text(""); - let rhs = check!( - ty::TyExpression::type_check(ctx, rhs), - ty::TyExpression::error(span, engines), - warnings, - errors - ); - - ok( - ty::TyStorageReassignment { - storage_keyword_span, - fields: type_checked_buf, - ix, - rhs, - }, - warnings, - errors, - ) -} diff --git a/sway-core/src/semantic_analysis/cei_pattern_analysis.rs b/sway-core/src/semantic_analysis/cei_pattern_analysis.rs index d0182725fdd..6fa319eec49 100644 --- a/sway-core/src/semantic_analysis/cei_pattern_analysis.rs +++ b/sway-core/src/semantic_analysis/cei_pattern_analysis.rs @@ -218,20 +218,6 @@ fn analyze_expression( | Continue | AbiName(_) => effects_of_expression(engines, expr), Reassignment(reassgn) => analyze_expression(engines, &reassgn.rhs, block_name, warnings), - StorageReassignment(reassgn) => { - let storage_effs = HashSet::from([Effect::StorageWrite]); - let rhs_effs = analyze_expression(engines, &reassgn.rhs, block_name, warnings); - if rhs_effs.contains(&Effect::Interaction) { - warn_after_interaction( - &storage_effs, - &reassgn.rhs.span, - &expr.span, - block_name, - warnings, - ) - }; - set_union(storage_effs, rhs_effs) - } CodeBlock(codeblock) => analyze_code_block(engines, codeblock, block_name, warnings), LazyOperator { lhs: left, @@ -533,11 +519,6 @@ fn effects_of_expression(engines: Engines<'_>, expr: &ty::TyExpression) -> HashS } _ => HashSet::from([Effect::StorageRead]), }, - StorageReassignment(storage_reassign) => { - let mut effs = HashSet::from([Effect::StorageWrite]); - effs.extend(effects_of_expression(engines, &storage_reassign.rhs)); - effs - } LazyOperator { lhs, rhs, .. } | ArrayIndex { prefix: lhs, @@ -623,9 +604,7 @@ fn effects_of_intrinsic(intr: &sway_ast::Intrinsic) -> HashSet { StateLoadWord | StateLoadQuad => HashSet::from([Effect::StorageRead]), Smo => HashSet::from([Effect::OutputMessage]), Revert | IsReferenceType | SizeOfType | SizeOfVal | Eq | Gt | Lt | Gtf | AddrOf | Log - | Add | Sub | Mul | Div | And | Or | Xor | PtrAdd | PtrSub | GetStorageKey => { - HashSet::new() - } + | Add | Sub | Mul | Div | And | Or | Xor | PtrAdd | PtrSub => HashSet::new(), } } diff --git a/sway-core/src/semantic_analysis/coins_analysis.rs b/sway-core/src/semantic_analysis/coins_analysis.rs index 83c28f091cd..1e6d4123d11 100644 --- a/sway-core/src/semantic_analysis/coins_analysis.rs +++ b/sway-core/src/semantic_analysis/coins_analysis.rs @@ -75,7 +75,6 @@ pub fn possibly_nonzero_u64_expression( | Break | Continue | Reassignment(_) - | Return(_) - | StorageReassignment(_) => true, + | Return(_) => true, } } diff --git a/sway-core/src/semantic_analysis/program.rs b/sway-core/src/semantic_analysis/program.rs index eec15196e53..0594079e858 100644 --- a/sway-core/src/semantic_analysis/program.rs +++ b/sway-core/src/semantic_analysis/program.rs @@ -20,22 +20,14 @@ impl ty::TyProgram { parsed: &ParseProgram, initial_namespace: namespace::Module, package_name: &str, - experimental_storage: bool, ) -> CompileResult { let mut namespace = Namespace::init_root(initial_namespace); - let ctx = TypeCheckContext::from_root(&mut namespace, engines) - .with_kind(parsed.kind.clone()) - .with_experimental_storage(experimental_storage); + let ctx = + TypeCheckContext::from_root(&mut namespace, engines).with_kind(parsed.kind.clone()); let ParseProgram { root, kind } = parsed; let mod_res = ty::TyModule::type_check(ctx, root); mod_res.flat_map(|root| { - let res = Self::validate_root( - engines, - &root, - kind.clone(), - package_name, - experimental_storage, - ); + let res = Self::validate_root(engines, &root, kind.clone(), package_name); res.map(|(kind, declarations, configurables)| Self { kind, root, @@ -54,7 +46,6 @@ impl ty::TyProgram { context: &mut Context, md_mgr: &mut MetadataManager, module: Module, - experimental_storage: bool, ) -> CompileResult { let mut warnings = vec![]; let mut errors = vec![]; @@ -75,13 +66,7 @@ impl ty::TyProgram { })) => { let decl = decl_engine.get_storage(decl_id); let mut storage_slots = check!( - decl.get_initialized_storage_slots( - engines, - context, - md_mgr, - module, - experimental_storage - ), + decl.get_initialized_storage_slots(engines, context, md_mgr, module,), return err(warnings, errors), warnings, errors, diff --git a/sway-core/src/semantic_analysis/storage_only_types.rs b/sway-core/src/semantic_analysis/storage_only_types.rs deleted file mode 100644 index 961052a8ec3..00000000000 --- a/sway-core/src/semantic_analysis/storage_only_types.rs +++ /dev/null @@ -1,420 +0,0 @@ -use sway_error::error::CompileError; -use sway_error::warning::CompileWarning; -use sway_types::{Span, Spanned}; - -use crate::{ - decl_engine::DeclId, - engine_threading::*, - error::*, - language::ty::{self, TyConstantDecl, TyFunctionDecl}, - type_system::*, -}; - -fn ast_node_validate(engines: Engines<'_>, x: &ty::TyAstNodeContent) -> CompileResult<()> { - let errors: Vec = vec![]; - let warnings: Vec = vec![]; - match x { - ty::TyAstNodeContent::Expression(expr) - | ty::TyAstNodeContent::ImplicitReturnExpression(expr) => expr_validate(engines, expr), - ty::TyAstNodeContent::Declaration(decl) => decl_validate(engines, decl), - ty::TyAstNodeContent::SideEffect(_) => ok((), warnings, errors), - } -} - -fn expr_validate(engines: Engines<'_>, expr: &ty::TyExpression) -> CompileResult<()> { - let mut errors: Vec = vec![]; - let mut warnings: Vec = vec![]; - match &expr.expression { - ty::TyExpressionVariant::Literal(_) - | ty::TyExpressionVariant::ConstantExpression { .. } - | ty::TyExpressionVariant::VariableExpression { .. } - | ty::TyExpressionVariant::FunctionParameter - | ty::TyExpressionVariant::AsmExpression { .. } - | ty::TyExpressionVariant::StorageAccess(_) - | ty::TyExpressionVariant::AbiName(_) => (), - ty::TyExpressionVariant::FunctionApplication { arguments, .. } => { - for f in arguments { - check!(expr_validate(engines, &f.1), continue, warnings, errors); - } - } - ty::TyExpressionVariant::LazyOperator { - lhs: expr1, - rhs: expr2, - .. - } - | ty::TyExpressionVariant::ArrayIndex { - prefix: expr1, - index: expr2, - } => { - check!(expr_validate(engines, expr1), (), warnings, errors); - check!(expr_validate(engines, expr2), (), warnings, errors); - } - ty::TyExpressionVariant::IntrinsicFunction(ty::TyIntrinsicFunctionKind { - arguments: exprvec, - .. - }) - | ty::TyExpressionVariant::Tuple { fields: exprvec } - | ty::TyExpressionVariant::Array { - elem_type: _, - contents: exprvec, - } => { - for f in exprvec { - check!(expr_validate(engines, f), continue, warnings, errors) - } - } - ty::TyExpressionVariant::StructExpression { fields, .. } => { - for f in fields { - check!(expr_validate(engines, &f.value), continue, warnings, errors); - } - } - ty::TyExpressionVariant::CodeBlock(cb) => { - check!( - validate_decls_for_storage_only_types_in_codeblock(engines, cb), - (), - warnings, - errors - ); - } - ty::TyExpressionVariant::MatchExp { desugared, .. } => { - check!(expr_validate(engines, desugared), (), warnings, errors) - } - ty::TyExpressionVariant::IfExp { - condition, - then, - r#else, - } => { - check!(expr_validate(engines, condition), (), warnings, errors); - check!(expr_validate(engines, then), (), warnings, errors); - if let Some(r#else) = r#else { - check!(expr_validate(engines, r#else), (), warnings, errors); - } - } - ty::TyExpressionVariant::StructFieldAccess { prefix: exp, .. } - | ty::TyExpressionVariant::TupleElemAccess { prefix: exp, .. } - | ty::TyExpressionVariant::AbiCast { address: exp, .. } - | ty::TyExpressionVariant::EnumTag { exp } - | ty::TyExpressionVariant::UnsafeDowncast { exp, .. } => { - check!(expr_validate(engines, exp), (), warnings, errors) - } - ty::TyExpressionVariant::EnumInstantiation { contents, .. } => { - if let Some(f) = contents { - check!(expr_validate(engines, f), (), warnings, errors); - } - } - ty::TyExpressionVariant::WhileLoop { condition, body } => { - check!(expr_validate(engines, condition), (), warnings, errors); - check!( - validate_decls_for_storage_only_types_in_codeblock(engines, body), - (), - warnings, - errors - ); - } - ty::TyExpressionVariant::Break => (), - ty::TyExpressionVariant::Continue => (), - ty::TyExpressionVariant::Reassignment(reassignment) => { - let ty::TyReassignment { - lhs_base_name, rhs, .. - } = &**reassignment; - check!( - check_type(engines, rhs.return_type, lhs_base_name.span(), false), - (), - warnings, - errors, - ); - check!(expr_validate(engines, rhs), (), warnings, errors) - } - ty::TyExpressionVariant::StorageReassignment(storage_reassignment) => { - let span = storage_reassignment.span(); - let rhs = &storage_reassignment.rhs; - check!( - check_type(engines, rhs.return_type, span, false), - (), - warnings, - errors, - ); - check!(expr_validate(engines, rhs), (), warnings, errors) - } - ty::TyExpressionVariant::Return(exp) => { - check!(expr_validate(engines, exp), (), warnings, errors) - } - } - ok((), warnings, errors) -} - -fn check_type( - engines: Engines<'_>, - ty: TypeId, - span: Span, - ignore_self: bool, -) -> CompileResult<()> { - let mut warnings: Vec = vec![]; - let mut errors: Vec = vec![]; - - let ty_engine = engines.te(); - let decl_engine = engines.de(); - - let type_info = check!( - CompileResult::from(ty_engine.to_typeinfo(ty, &span).map_err(CompileError::from)), - TypeInfo::ErrorRecovery, - warnings, - errors - ); - let nested_types = type_info.clone().extract_nested_types(engines); - for ty in nested_types { - if ignore_self && ty.eq(&type_info, engines) { - continue; - } - if ty_engine.is_type_info_storage_only(decl_engine, &ty) { - errors.push(CompileError::InvalidStorageOnlyTypeDecl { - ty: engines.help_out(ty).to_string(), - span: span.clone(), - }); - } - } - ok((), warnings, errors) -} - -fn decl_validate(engines: Engines<'_>, decl: &ty::TyDecl) -> CompileResult<()> { - let mut warnings: Vec = vec![]; - let mut errors: Vec = vec![]; - let decl_engine = engines.de(); - match decl { - ty::TyDecl::VariableDecl(decl) => { - check!( - check_type(engines, decl.body.return_type, decl.name.span(), false), - (), - warnings, - errors - ); - check!(expr_validate(engines, &decl.body), (), warnings, errors) - } - ty::TyDecl::ConstantDecl(ty::ConstantDecl { decl_id, .. }) => { - check!( - validate_const_decl(engines, decl_id), - return err(warnings, errors), - warnings, - errors - ); - } - ty::TyDecl::FunctionDecl(ty::FunctionDecl { decl_id, .. }) => { - check!( - validate_fn_decl(engines, decl_id), - return err(warnings, errors), - warnings, - errors - ); - } - ty::TyDecl::AbiDecl(_) | ty::TyDecl::TraitDecl(_) => { - // These methods are not typed. They are however handled from ImplTrait. - } - ty::TyDecl::ImplTrait(ty::ImplTrait { decl_id, .. }) => { - let ty::TyImplTrait { items, .. } = decl_engine.get_impl_trait(decl_id); - for item in items { - match item { - ty::TyImplItem::Fn(decl_ref) => { - check!( - validate_fn_decl(engines, &decl_ref.id().clone()), - (), - warnings, - errors - ); - } - ty::TyImplItem::Constant(decl_ref) => { - check!( - validate_const_decl(engines, decl_ref.id()), - return err(warnings, errors), - warnings, - errors - ); - } - } - } - } - ty::TyDecl::StructDecl(ty::StructDecl { decl_id, .. }) => { - let ty::TyStructDecl { fields, .. } = decl_engine.get_struct(decl_id); - for field in fields { - check!( - check_type( - engines, - field.type_argument.type_id, - field.span.clone(), - false - ), - continue, - warnings, - errors - ); - } - } - ty::TyDecl::EnumDecl(ty::EnumDecl { decl_id, .. }) => { - let ty::TyEnumDecl { variants, .. } = decl_engine.get_enum(decl_id); - for variant in variants { - check!( - check_type( - engines, - variant.type_argument.type_id, - variant.span.clone(), - false - ), - continue, - warnings, - errors - ); - } - } - ty::TyDecl::EnumVariantDecl(ty::EnumVariantDecl { - enum_ref, - variant_name, - .. - }) => { - let enum_decl = decl_engine.get_enum(enum_ref.id()); - let variant = check!( - enum_decl.expect_variant_from_name(variant_name), - return err(warnings, errors), - warnings, - errors - ); - check!( - check_type( - engines, - variant.type_argument.type_id, - variant.span.clone(), - false - ), - (), - warnings, - errors - ); - } - ty::TyDecl::StorageDecl(ty::StorageDecl { - decl_id, - decl_span: _, - }) => { - let ty::TyStorageDecl { fields, .. } = decl_engine.get_storage(decl_id); - for field in fields { - check!( - check_type( - engines, - field.type_argument.type_id, - field.name.span().clone(), - true - ), - continue, - warnings, - errors - ); - } - } - ty::TyDecl::TypeAliasDecl(ty::TypeAliasDecl { decl_id, .. }) => { - let ty::TyTypeAliasDecl { ty, span, .. } = decl_engine.get_type_alias(decl_id); - check!( - check_type(engines, ty.type_id, span, false), - (), - warnings, - errors - ); - } - ty::TyDecl::GenericTypeForFunctionScope(_) | ty::TyDecl::ErrorRecovery(_) => {} - } - if errors.is_empty() { - ok((), warnings, errors) - } else { - err(warnings, errors) - } -} - -pub fn validate_const_decl( - engines: Engines<'_>, - decl_id: &DeclId, -) -> CompileResult<()> { - let mut warnings: Vec = vec![]; - let mut errors: Vec = vec![]; - let decl_engine = engines.de(); - let ty::TyConstantDecl { - value: expr, - call_path, - .. - } = decl_engine.get_constant(decl_id); - if let Some(expr) = expr { - check!( - check_type(engines, expr.return_type, call_path.suffix.span(), false), - (), - warnings, - errors - ); - check!(expr_validate(engines, &expr), (), warnings, errors) - } - if errors.is_empty() { - ok((), warnings, errors) - } else { - err(warnings, errors) - } -} - -pub fn validate_fn_decl( - engines: Engines<'_>, - decl_id: &DeclId, -) -> CompileResult<()> { - let mut warnings: Vec = vec![]; - let mut errors: Vec = vec![]; - let decl_engine = engines.de(); - let ty::TyFunctionDecl { - body, - parameters, - return_type, - .. - } = decl_engine.get_function(decl_id); - check!( - validate_decls_for_storage_only_types_in_codeblock(engines, &body), - (), - warnings, - errors - ); - for param in parameters { - if !param.is_self() { - check!( - check_type( - engines, - param.type_argument.type_id, - param.type_argument.span.clone(), - false - ), - continue, - warnings, - errors - ); - } - } - check!( - check_type(engines, return_type.type_id, return_type.span, false), - return err(warnings, errors), - warnings, - errors - ); - ok((), warnings, errors) -} - -pub fn validate_decls_for_storage_only_types_in_ast( - engines: Engines<'_>, - ast_n: &ty::TyAstNodeContent, -) -> CompileResult<()> { - ast_node_validate(engines, ast_n) -} - -pub fn validate_decls_for_storage_only_types_in_codeblock( - engines: Engines<'_>, - cb: &ty::TyCodeBlock, -) -> CompileResult<()> { - let mut warnings: Vec = vec![]; - let mut errors: Vec = vec![]; - for x in &cb.contents { - check!( - ast_node_validate(engines, &x.content), - continue, - warnings, - errors - ) - } - ok((), warnings, errors) -} diff --git a/sway-core/src/semantic_analysis/type_check_context.rs b/sway-core/src/semantic_analysis/type_check_context.rs index b946a0cf296..fd57fffdfc9 100644 --- a/sway-core/src/semantic_analysis/type_check_context.rs +++ b/sway-core/src/semantic_analysis/type_check_context.rs @@ -62,9 +62,6 @@ pub struct TypeCheckContext<'a> { /// disallowing functions from being defined inside of another function /// body). disallow_functions: bool, - - /// Enable the experimental storage implementation and UI. - experimental_storage: bool, } impl<'a> TypeCheckContext<'a> { @@ -94,7 +91,6 @@ impl<'a> TypeCheckContext<'a> { purity: Purity::default(), kind: TreeType::Contract, disallow_functions: false, - experimental_storage: false, } } @@ -118,7 +114,6 @@ impl<'a> TypeCheckContext<'a> { type_engine: self.type_engine, decl_engine: self.decl_engine, disallow_functions: self.disallow_functions, - experimental_storage: self.experimental_storage, } } @@ -135,7 +130,6 @@ impl<'a> TypeCheckContext<'a> { type_engine: self.type_engine, decl_engine: self.decl_engine, disallow_functions: self.disallow_functions, - experimental_storage: self.experimental_storage, } } @@ -189,14 +183,6 @@ impl<'a> TypeCheckContext<'a> { Self { kind, ..self } } - /// Map this `TypeCheckContext` instance to a new one with the given module kind. - pub(crate) fn with_experimental_storage(self, experimental_storage: bool) -> Self { - Self { - experimental_storage, - ..self - } - } - /// Map this `TypeCheckContext` instance to a new one with the given purity. pub(crate) fn with_self_type(self, self_type: TypeId) -> Self { Self { self_type, ..self } @@ -251,10 +237,6 @@ impl<'a> TypeCheckContext<'a> { self.disallow_functions } - pub(crate) fn experimental_storage_enabled(&self) -> bool { - self.experimental_storage - } - // Provide some convenience functions around the inner context. /// Short-hand for calling the `monomorphize` function in the type engine diff --git a/sway-core/src/transform/to_parsed_lang/convert_parse_tree.rs b/sway-core/src/transform/to_parsed_lang/convert_parse_tree.rs index 60c05e69d32..4c147cac28f 100644 --- a/sway-core/src/transform/to_parsed_lang/convert_parse_tree.rs +++ b/sway-core/src/transform/to_parsed_lang/convert_parse_tree.rs @@ -3728,13 +3728,7 @@ fn assignable_to_reassignment_target( idents.push(name); base = target; } - Assignable::Var(name) => { - if name.as_str() == "storage" { - let idents = idents.into_iter().rev().cloned().collect(); - return Ok(ReassignmentTarget::StorageField(name.span(), idents)); - } - break; - } + Assignable::Var(_) => break, Assignable::Index { .. } => break, Assignable::TupleFieldProjection { .. } => break, } diff --git a/sway-core/src/type_system/engine.rs b/sway-core/src/type_system/engine.rs index bf1d42da2e7..d542107f4f9 100644 --- a/sway-core/src/type_system/engine.rs +++ b/sway-core/src/type_system/engine.rs @@ -16,7 +16,6 @@ use sway_types::{span::Span, Ident, Spanned}; #[derive(Debug, Default)] pub struct TypeEngine { pub(super) slab: ConcurrentSlab, - storage_only_types: ConcurrentSlab, id_map: RwLock>, } @@ -62,21 +61,6 @@ impl TypeEngine { } } - /// Denotes the given [TypeId] as being used with storage. - pub(crate) fn set_type_as_storage_only(&self, id: TypeId) { - self.storage_only_types.insert(self.get(id)); - } - - /// Checks if the given [TypeInfo] is a storage only type. - pub(crate) fn is_type_info_storage_only( - &self, - decl_engine: &DeclEngine, - ti: &TypeInfo, - ) -> bool { - self.storage_only_types - .exists(|x| ti.is_subset_of(x, Engines::new(self, decl_engine))) - } - /// Given a `value` of type `T` that is able to be monomorphized and a set /// of `type_arguments`, monomorphize `value` with the `type_arguments`. /// diff --git a/sway-ir/src/instruction.rs b/sway-ir/src/instruction.rs index 9a445caed6b..18eb6d9c501 100644 --- a/sway-ir/src/instruction.rs +++ b/sway-ir/src/instruction.rs @@ -103,8 +103,6 @@ pub enum Instruction { #[derive(Debug, Clone, DebugWithContext)] pub enum FuelVmInstruction { - /// Generate a unique integer value - GetStorageKey(Type), Gtf { index: Value, tx_field_id: u64, @@ -226,7 +224,6 @@ impl Instruction { Instruction::CastPtr(_val, ty) => Some(*ty), Instruction::Cmp(..) => Some(Type::get_bool(context)), Instruction::ContractCall { return_type, .. } => Some(*return_type), - Instruction::FuelVm(FuelVmInstruction::GetStorageKey(key_ptr_ty)) => Some(*key_ptr_ty), Instruction::FuelVm(FuelVmInstruction::Gtf { .. }) => Some(Type::get_uint64(context)), Instruction::FuelVm(FuelVmInstruction::Log { .. }) => Some(Type::get_unit(context)), Instruction::FuelVm(FuelVmInstruction::ReadRegister(_)) => { @@ -345,7 +342,6 @@ impl Instruction { } Instruction::FuelVm(fuel_vm_instr) => match fuel_vm_instr { - FuelVmInstruction::GetStorageKey(_ty) => vec![], FuelVmInstruction::Gtf { index, tx_field_id: _, @@ -470,7 +466,6 @@ impl Instruction { } Instruction::FuelVm(fuel_vm_instr) => match fuel_vm_instr { - FuelVmInstruction::GetStorageKey(_ty) => (), FuelVmInstruction::Gtf { index, .. } => replace(index), FuelVmInstruction::Log { log_val, log_id, .. @@ -548,7 +543,6 @@ impl Instruction { | Instruction::CastPtr { .. } | Instruction::Cmp(..) | Instruction::ConditionalBranch { .. } - | Instruction::FuelVm(FuelVmInstruction::GetStorageKey(_)) | Instruction::FuelVm(FuelVmInstruction::Gtf { .. }) | Instruction::FuelVm(FuelVmInstruction::ReadRegister(_)) | Instruction::FuelVm(FuelVmInstruction::Revert(..)) @@ -754,15 +748,6 @@ impl<'a> InstructionInserter<'a> { ) } - pub fn get_storage_key(self) -> Value { - let b256_ty = Type::get_b256(self.context); - let b256_ptr_ty = Type::new_ptr(self.context, b256_ty); - make_instruction!( - self, - Instruction::FuelVm(FuelVmInstruction::GetStorageKey(b256_ptr_ty)) - ) - } - pub fn gtf(self, index: Value, tx_field_id: u64) -> Value { make_instruction!( self, diff --git a/sway-ir/src/optimize/inline.rs b/sway-ir/src/optimize/inline.rs index 72ebb16d482..b61bc4d39c7 100644 --- a/sway-ir/src/optimize/inline.rs +++ b/sway-ir/src/optimize/inline.rs @@ -556,7 +556,6 @@ fn inline_instruction( map_value(gas), ), Instruction::FuelVm(fuel_vm_instr) => match fuel_vm_instr { - FuelVmInstruction::GetStorageKey(_ty) => new_block.ins(context).get_storage_key(), FuelVmInstruction::Gtf { index, tx_field_id } => { new_block.ins(context).gtf(map_value(index), tx_field_id) } diff --git a/sway-ir/src/parser.rs b/sway-ir/src/parser.rs index 5b898c916d9..8e3d3b726c0 100644 --- a/sway-ir/src/parser.rs +++ b/sway-ir/src/parser.rs @@ -175,7 +175,6 @@ mod ir_builder { / op_const() / op_contract_call() / op_get_elem_ptr() - / op_get_storage_key() / op_get_local() / op_gtf() / op_int_to_ptr() @@ -262,11 +261,6 @@ mod ir_builder { IrAstOperation::GetElemPtr(base, ty, idcs) } - rule op_get_storage_key() -> IrAstOperation - = "get_storage_key" _ { - IrAstOperation::GetStorageKey() - } - rule op_get_local() -> IrAstOperation = "get_local" _ ast_ty() comma() name:id() { IrAstOperation::GetLocal(name) @@ -671,7 +665,6 @@ mod ir_builder { Const(IrAstTy, IrAstConst), ContractCall(IrAstTy, String, String, String, String, String), GetElemPtr(String, IrAstTy, Vec), - GetStorageKey(), GetLocal(String), Gtf(String, u64), IntToPtr(String, IrAstTy), @@ -1150,10 +1143,6 @@ mod ir_builder { ) .add_metadatum(context, opt_metadata) } - IrAstOperation::GetStorageKey() => block - .ins(context) - .get_storage_key() - .add_metadatum(context, opt_metadata), IrAstOperation::GetLocal(local_name) => block .ins(context) .get_local(*local_map.get(&local_name).unwrap()) diff --git a/sway-ir/src/printer.rs b/sway-ir/src/printer.rs index 9a409774d55..6261ec38a0b 100644 --- a/sway-ir/src/printer.rs +++ b/sway-ir/src/printer.rs @@ -555,13 +555,6 @@ fn instruction_to_doc<'a>( .append(md_namer.md_idx_to_doc(context, metadata)), )), Instruction::FuelVm(fuel_vm_instr) => match fuel_vm_instr { - FuelVmInstruction::GetStorageKey(_ty) => Doc::line( - Doc::text(format!( - "{} = get_storage_key", - namer.name(context, ins_value), - )) - .append(md_namer.md_idx_to_doc(context, metadata)), - ), FuelVmInstruction::Gtf { index, tx_field_id } => { maybe_constant_to_doc(context, md_namer, namer, index).append(Doc::line( Doc::text(format!( diff --git a/sway-ir/src/verify.rs b/sway-ir/src/verify.rs index 7df6277cdbb..55de245c874 100644 --- a/sway-ir/src/verify.rs +++ b/sway-ir/src/verify.rs @@ -198,7 +198,6 @@ impl<'a> InstructionVerifier<'a> { // XXX move the fuelvm verification into a module Instruction::FuelVm(fuel_vm_instr) => match fuel_vm_instr { - FuelVmInstruction::GetStorageKey(_ty) => (), FuelVmInstruction::Gtf { index, tx_field_id } => { self.verify_gtf(index, tx_field_id)? } diff --git a/sway-ir/tests/inline/get_storage_key.ir b/sway-ir/tests/inline/get_storage_key.ir deleted file mode 100644 index 2d9f8184dce..00000000000 --- a/sway-ir/tests/inline/get_storage_key.ir +++ /dev/null @@ -1,47 +0,0 @@ -// all -// -// regex: VAR=v\d+ -// regex: MD=!\d+ -// regex: LABEL=[[:alpha:]0-9_]+ - -contract { - fn test<58d7eb51>() -> ptr b256, !1 { - local { } __anon_0 - - entry(): - v0 = get_local ptr { }, __anon_0 - v1 = call f(v0), !5 - ret ptr b256 v1 - } - - fn f(self !6: ptr { }) -> ptr b256, !8 { - entry(self: ptr { }): - v0 = get_storage_key, !9 - ret ptr b256 v0 - } -} - -!0 = "get_storage_key.sw" -!1 = span !0 218 265 -!2 = span !0 254 255 -!3 = span !0 246 259 -!4 = state_index 42 -!5 = (!3 !4) -!6 = span !0 42 46 -!7 = span !0 51 55 -!8 = span !0 37 91 -!9 = span !0 66 85 - -// check: fn test<58d7eb51>() -> ptr b256 - -// not: call -// check: $(stk_val=$VAR) = get_storage_key, $(stk_md=$MD) - -// check: br $(ret_block=$LABEL)($stk_val) - -// check: $ret_block($(ret_val=$VAR): ptr b256): -// check: ret ptr b256 $ret_val - -// check: $(si_md=$MD) = state_index 42 -// check: $stk_md = ( -// sameln: $si_md diff --git a/sway-lib-core/src/experimental.sw b/sway-lib-core/src/experimental.sw deleted file mode 100644 index 59de4fa0a4a..00000000000 --- a/sway-lib-core/src/experimental.sw +++ /dev/null @@ -1,3 +0,0 @@ -library; - -mod r#storage; diff --git a/sway-lib-core/src/lib.sw b/sway-lib-core/src/lib.sw index 410bee8412a..dcbb46180f1 100644 --- a/sway-lib-core/src/lib.sw +++ b/sway-lib-core/src/lib.sw @@ -1,9 +1,9 @@ library; -mod experimental; mod primitives; mod raw_ptr; mod raw_slice; mod ops; mod never; +mod r#storage; mod prelude; diff --git a/sway-lib-core/src/prelude.sw b/sway-lib-core/src/prelude.sw index fde25089376..6c3a1553123 100644 --- a/sway-lib-core/src/prelude.sw +++ b/sway-lib-core/src/prelude.sw @@ -8,3 +8,4 @@ use ::raw_ptr::*; use ::raw_slice::*; use ::never::*; use ::ops::*; +use ::storage::*; diff --git a/sway-lib-core/src/experimental/storage.sw b/sway-lib-core/src/storage.sw similarity index 100% rename from sway-lib-core/src/experimental/storage.sw rename to sway-lib-core/src/storage.sw diff --git a/sway-lib-std/src/experimental/storage.sw b/sway-lib-std/src/experimental/storage.sw deleted file mode 100644 index 55b6d98d032..00000000000 --- a/sway-lib-std/src/experimental/storage.sw +++ /dev/null @@ -1,287 +0,0 @@ -//! Experimental storage types. -library; - -use ::alloc::{alloc, realloc_bytes}; -use ::hash::sha256; -use ::option::Option; -use core::experimental::storage::StorageKey; - -/// Store a stack value in storage. Will not work for heap values. -/// -/// ### Arguments -/// -/// * `slot` - The storage slot at which the variable will be stored. -/// * `value` - The value to be stored. -/// * `offset` - An offset, in words, from the beginning of `slot`, at which `value` should be -/// stored. -/// -/// ### Examples -/// -/// ```sway -/// let five = 5_u64; -/// write(ZERO_B256, 2, five); -/// let stored_five = read::(ZERO_B256, 2).unwrap(); -/// assert(five == stored_five); -/// ``` -#[storage(read, write)] -pub fn write(slot: b256, offset: u64, value: T) { - // Get the number of storage slots needed based on the size of `T` - let number_of_slots = (offset * 8 + __size_of::() + 31) >> 5; - - // Allocate enough memory on the heap for `value` as well as any potential padding required due - // to `offset`. - let padded_value = alloc::(number_of_slots * 32); - - // Read the values that currently exist in the affected storage slots. - // NOTE: we can do better here by only reading from the slots that we know could be affected. - // These are the two slots where the start and end of `T` fall in considering `offset`. - // However, doing so requires that we perform addition on `b256` to compute the corresponding - // keys, and that is not possible today. - let _ = __state_load_quad(slot, padded_value, number_of_slots); - - // Copy the value to be stored to `padded_value + offset`. - padded_value.add::(offset).write::(value); - - // Now store back the data at `padded_value` which now contains the old data but partially - // overwritten by the new data in the desired locations. - let _ = __state_store_quad(slot, padded_value, number_of_slots); -} - -/// Reads a value of type `T` starting at the location specified by `slot` and `offset`. If the -/// value crosses the boundary of a storage slot, reading continues at the following slot. -/// -/// Returns `Option(value)` if the storage slots read were valid and contain `value`. Otherwise, -/// return `None`. -/// -/// ### Arguments -/// -/// * `slot` - The storage slot to load the value from. -/// * `offset` - An offset, in words, from the start of `slot`, from which the value should be read. -/// -/// ### Examples -/// -/// ```sway -/// let five = 5_u64; -/// write(ZERO_B256, 2, five); -/// let stored_five = read::(ZERO_B256, 2); -/// assert(five == stored_five); -/// ``` -#[storage(read)] -pub fn read(slot: b256, offset: u64) -> Option { - // NOTE: we are leaking this value on the heap. - // Get the number of storage slots needed based on the size of `T` - let number_of_slots = (offset * 8 + __size_of::() + 31) >> 5; - - // Allocate a buffer for the result. Its size needs to be a multiple of 32 bytes so we can - // make the 'quad' storage instruction read without overflowing. - let result_ptr = alloc::(number_of_slots * 32); - - // Read `number_of_slots * 32` bytes starting at storage slot `slot` and return an `Option` - // wrapping the value stored at `result_ptr + offset` if all the slots are valid. Otherwise, - // return `Option::None`. - if __state_load_quad(slot, result_ptr, number_of_slots) { - Option::Some(result_ptr.add::(offset).read::()) - } else { - Option::None - } -} - -/// Clear a sequence of consecutive storage slots starting at a some slot. Returns a Boolean -/// indicating whether all of the storage slots cleared were previously set. -/// -/// ### Arguments -/// -/// * `slot` - The key of the first storage slot that will be cleared -/// -/// ### Examples -/// -/// ```sway -/// let five = 5_u64; -/// write(ZERO_B256, 0, five); -/// let cleared = clear::(ZERO_B256); -/// assert(cleared); -/// assert(read::(ZERO_B256, 0).is_none()); -/// ``` -#[storage(write)] -pub fn clear(slot: b256) -> bool { - // Get the number of storage slots needed based on the size of `T` as the ceiling of - // `__size_of::() / 32` - let number_of_slots = (__size_of::() + 31) >> 5; - - // Clear `number_of_slots * 32` bytes starting at storage slot `slot`. - __state_clear(slot, number_of_slots) -} - -impl StorageKey { - /// Reads a value of type `T` starting at the location specified by `self`. If the value - /// crosses the boundary of a storage slot, reading continues at the following slot. - /// - /// Returns the value previously stored if a the storage slots read were - /// valid and contain `value`. Panics otherwise. - /// - /// ### Arguments - /// - /// None - /// - /// ### Examples - /// - /// ```sway - /// fn foo() { - /// let r: StorageKey = StorageKey { - /// slot: 0x0000000000000000000000000000000000000000000000000000000000000000, - /// offset: 2, - /// }; - /// - /// // Reads the third word from storage slot with key 0x000...0 - /// let x: u64 = r.read(); - /// } - /// ``` - #[storage(read)] - pub fn read(self) -> T { - read::(self.slot, self.offset).unwrap() - } - - /// Reads a value of type `T` starting at the location specified by `self`. If the value - /// crosses the boundary of a storage slot, reading continues at the following slot. - /// - /// Returns `Some(value)` if a the storage slots read were valid and contain `value`. - /// Otherwise, return `None`. - /// - /// ### Arguments - /// - /// None - /// - /// ### Examples - /// - /// ```sway - /// fn foo() { - /// let r: StorageKey = StorageKey { - /// slot: 0x0000000000000000000000000000000000000000000000000000000000000000, - /// offset: 2, - /// }; - /// - /// // Reads the third word from storage slot with key 0x000...0 - /// let x: Option = r.try_read(); - /// } - /// ``` - #[storage(read)] - pub fn try_read(self) -> Option { - read(self.slot, self.offset) - } - - /// Writes a value of type `T` starting at the location specified by `self`. If the value - /// crosses the boundary of a storage slot, writing continues at the following slot. - /// - /// ### Arguments - /// - /// * value: the value of type `T` to write - /// - /// ### Examples - /// - /// ```sway - /// fn foo() { - /// let r: StorageKey = StorageKey { - /// slot: 0x0000000000000000000000000000000000000000000000000000000000000000, - /// offset: 2, - /// }; - /// let x = r.write(42); // Writes 42 at the third word of storage slot with key 0x000...0 - /// } - /// ``` - #[storage(read, write)] - pub fn write(self, value: T) { - write(self.slot, self.offset, value); - } -} - -/// A persistent key-value pair mapping struct. -pub struct StorageMap {} - -impl StorageKey> { - /// Inserts a key-value pair into the map. - /// - /// ### Arguments - /// - /// * `key` - The key to which the value is paired. - /// * `value` - The value to be stored. - /// - /// ### 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(key).read(); - /// assert(value == retrieved_value); - /// } - /// ``` - #[storage(read, write)] - pub fn insert(self, key: K, value: V) { - let key = sha256((key, self.slot)); - write::(key, 0, value); - } - - /// Retrieves the `StorageKey` 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(key).read(); - /// assert(value == retrieved_value); - /// } - /// ``` - #[storage(read)] - pub fn get(self, key: K) -> StorageKey { - StorageKey { - slot: sha256((key, self.slot)), - offset: 0, - } - } - - /// Clears a value previously stored using a key - /// - /// Return a Boolean indicating whether there was a value previously stored at `key`. - /// - /// ### 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 removed = storage.map.remove(key); - /// assert(removed); - /// assert(storage.map.get(key).is_none()); - /// } - /// ``` - #[storage(write)] - pub fn remove(self, key: K) -> bool { - let key = sha256((key, self.slot)); - clear::(key) - } -} diff --git a/sway-lib-std/src/lib.sw b/sway-lib-std/src/lib.sw index b949cd3a9c4..12591778d0a 100644 --- a/sway-lib-std/src/lib.sw +++ b/sway-lib-std/src/lib.sw @@ -1,6 +1,3 @@ -//! The official standard library for the Sway smart contract language. -//! -//! Source: https://github.com/FuelLabs/sway/tree/master/sway-lib-std library; mod error_signals; @@ -25,7 +22,6 @@ mod identity; mod vec; mod bytes; mod r#storage; -mod experimental; mod b256; mod tx; mod inputs; diff --git a/sway-lib-std/src/prelude.sw b/sway-lib-std/src/prelude.sw index 05c611b8224..24b40ffcf79 100644 --- a/sway-lib-std/src/prelude.sw +++ b/sway-lib-std/src/prelude.sw @@ -8,8 +8,11 @@ use ::address::Address; use ::contract_id::{ContractId, AssetId}; use ::identity::Identity; +// `StorageKey` API +use ::storage::storage_key::*; + // Collections -use ::storage::StorageMap; +use ::storage::storage_map::*; use ::vec::Vec; // Error handling diff --git a/sway-lib-std/src/storage.sw b/sway-lib-std/src/storage.sw index f77789d7f54..6f153e51291 100644 --- a/sway-lib-std/src/storage.sw +++ b/sway-lib-std/src/storage.sw @@ -1,1185 +1,9 @@ //! Contract storage utilities. library; -use ::alloc::{alloc, alloc_bytes, realloc_bytes}; -use ::assert::assert; -use ::hash::sha256; -use ::option::Option; -use ::bytes::Bytes; - -/// Store a stack value in storage. Will not work for heap values. -/// -/// ### Arguments -/// -/// * `key` - The storage slot at which the variable will be stored. -/// * `value` - The value to be stored. -/// -/// ### Examples -/// -/// ```sway -/// use std::{storage::{store, get}, constants::ZERO_B256}; -/// -/// let five = 5_u64; -/// store(ZERO_B256, five); -/// let stored_five = get::(ZERO_B256).unwrap(); -/// assert(five == stored_five); -/// ``` -#[storage(write)] -pub fn store(key: b256, value: T) { - if !__is_reference_type::() { - // If `T` is a copy type, then `value` fits in a single word. - let value = asm(v: value) { v: u64 }; - let _ = __state_store_word(key, value); - } else { - // If `T` is a reference type, then `value` can be larger than a word, so we need to use - // `__state_store_quad`. - // Get the number of storage slots needed based on the size of `T` - let number_of_slots = (__size_of::() + 31) >> 5; - - // Cast the pointer to `value` to a `raw_ptr`. - let mut ptr_to_value = asm(ptr: value) { ptr: raw_ptr }; - - // Store `number_of_slots * 32` bytes starting at storage slot `key`. - let _ = __state_store_quad(key, ptr_to_value, number_of_slots); - }; -} - -/// Load a value from storage. -/// -/// If the value size is larger than 8 bytes it is read to a heap buffer which is leaked for the -/// duration of the program. -/// -/// If no value was previously stored at `key`, `Option::None` is returned. Otherwise, -/// `Option::Some(value)` is returned, where `value` is the value stored at `key`. -/// -/// ### Arguments -/// -/// * `key` - The storage slot to load the value from. -/// -/// ### Examples -/// -/// ```sway -/// use std::{storage::{store, get}, constants::ZERO_B256}; -/// -/// let five = 5_u64; -/// store(ZERO_B256, five); -/// let stored_five = get::(ZERO_B256); -/// assert(five == stored_five); -/// ``` -#[storage(read)] -pub fn get(key: b256) -> Option { - let (previously_set, value) = if !__is_reference_type::() { - // If `T` is a copy type, then we can use `srw` to read from storage. `srw` writes two - // registers: the loaded word as well as flag indicating whether the storage slot was - // written before. We store the two registers on the heap and return the result as a tuple - // `(bool, T)` which contains the two values we need. - // NOTE: we should eventually be using `__state_load_word` here but we are currently unable - // to make that intrinsic return two things due to some limitations in IR/codegen. - let temp_pair = (false, 0_u64); // Using a `u64` as a placeholder for copy-type `T` value. - asm(key: key, result_ptr: temp_pair, loaded_word, previously_set) { - srw loaded_word previously_set key; - sw result_ptr previously_set i0; - sw result_ptr loaded_word i1; - result_ptr: (bool, T) - } - } else { - // If `T` is a reference type, then we need to use `__state_load_quad` because the result - // might be larger than a word. - // NOTE: we are leaking this value on the heap. - - // Get the number of storage slots needed based on the size of `T` as the ceiling of - // `__size_of::() / 32` - let number_of_slots = (__size_of::() + 31) >> 5; - - // Allocate a buffer for the result. Its size needs to be a multiple of 32 bytes so we can - // make the 'quad' storage instruction read without overflowing. - let result_ptr = alloc::(number_of_slots * 32); - - // Read `number_of_slots * 32` bytes starting at storage slot `key`. - // The return `bool` indicates if all the slots have been set before. - let previously_set = __state_load_quad(key, result_ptr, number_of_slots); - - // Cast the final result to `T` - (previously_set, asm(res: result_ptr) { res: T }) - }; - - if previously_set { - Option::Some(value) - } else { - Option::None - } -} - -/// Clear a sequence of consecutive storage slots starting at a some key. Returns a Boolean -/// indicating whether all of the storage slots cleared were previously set. -/// -/// ### Arguments -/// -/// * `key` - The key of the first storage slot that will be cleared -/// -/// ### Examples -/// -/// ```sway -/// use std::{storage::{clear, get, store}, constants::ZERO_B256}; -/// -/// let five = 5_u64; -/// store(ZERO_B256, five); -/// let cleared = clear::(ZERO_B256); -/// assert(cleared); -/// assert(get::(ZERO_B256).is_none()); -/// ``` -#[storage(write)] -pub fn clear(key: b256) -> bool { - // Get the number of storage slots needed based on the size of `T` as the ceiling of - // `__size_of::() / 32` - let number_of_slots = (__size_of::() + 31) >> 5; - - // Clear `number_of_slots * 32` bytes starting at storage slot `key`. - __state_clear(key, number_of_slots) -} - -/// Store a raw_slice from the heap into storage. -/// -/// ### Arguments -/// -/// * `key` - The storage slot at which the variable will be stored. -/// * `slice` - The raw_slice to be stored. -/// -/// ### Examples -/// -/// ```sway -/// use std::{alloc::alloc_bytes, storage::{store_slice, get_slice}, constants::ZERO_B256}; -/// -/// let slice = asm(ptr: (alloc_bytes(1), 1)) { ptr: raw_slice }; -/// assert(get_slice(ZERO_B256).is_none()); -/// store_slice(ZERO_B256, slice); -/// let stored_slice = get_slice(ZERO_B256).unwrap(); -/// assert(slice == stored_slice); -/// ``` -#[storage(write)] -pub fn store_slice(key: b256, slice: raw_slice) { - // Get the number of storage slots needed based on the size of bytes. - let number_of_bytes = slice.number_of_bytes(); - let number_of_slots = (number_of_bytes + 31) >> 5; - let mut ptr = slice.ptr(); - - // The capacity needs to be a multiple of 32 bytes so we can - // make the 'quad' storage instruction store without accessing unallocated heap memory. - ptr = realloc_bytes(ptr, number_of_bytes, number_of_slots * 32); - - // Store `number_of_slots * 32` bytes starting at storage slot `key`. - let _ = __state_store_quad(sha256(key), ptr, number_of_slots); - - // Store the length of the bytes - store(key, number_of_bytes); -} - -/// Load a raw_slice from storage. -/// -/// If no value was previously stored at `key`, `Option::None` is returned. Otherwise, -/// `Option::Some(value)` is returned, where `value` is the value stored at `key`. -/// -/// ### Arguments -/// -/// * `key` - The storage slot to load the value from. -/// -/// ### Examples -/// -/// ```sway -/// use std::{alloc::alloc_bytes, storage::{store_slice, get_slice}, constants::ZERO_B256}; -/// -/// let slice = asm(ptr: (alloc_bytes(1), 1)) { ptr: raw_slice }; -/// assert(get_slice(ZERO_B256).is_none()); -/// store_slice(ZERO_B256, slice); -/// let stored_slice = get_slice(ZERO_B256).unwrap(); -/// assert(slice == stored_slice); -/// ``` -#[storage(read)] -pub fn get_slice(key: b256) -> Option { - // Get the length of the slice that is stored. - match get::(key).unwrap_or(0) { - 0 => Option::None, - len => { - // Get the number of storage slots needed based on the size. - let number_of_slots = (len + 31) >> 5; - let ptr = alloc_bytes(number_of_slots * 32); - // Load the stored slice into the pointer. - let _ = __state_load_quad(sha256(key), ptr, number_of_slots); - Option::Some(asm(ptr: (ptr, len)) { ptr: raw_slice }) - } - } -} - -/// Clear a sequence of storage slots starting at a some key. Returns a Boolean -/// indicating whether all of the storage slots cleared were previously set. -/// -/// ### Arguments -/// -/// * `key` - The key of the first storage slot that will be cleared -/// -/// ### Examples -/// -/// ```sway -/// use std::{alloc::alloc_bytes, storage::{clear_slice, store_slice, get_slice}, constants::ZERO_B256}; -/// -/// let slice = asm(ptr: (alloc_bytes(1), 1)) { ptr: raw_slice }; -/// store_slice(ZERO_B256, slice); -/// assert(get_slice(ZERO_B256).is_some()); -/// let cleared = clear_slice(ZERO_B256); -/// assert(cleared); -/// assert(get_slice(ZERO_B256).is_none()); -/// ``` -#[storage(read, write)] -pub fn clear_slice(key: b256) -> bool { - // Get the number of storage slots needed based on the ceiling of `len / 32` - let len = get::(key).unwrap_or(0); - let number_of_slots = (len + 31) >> 5; - - // Clear length and `number_of_slots` bytes starting at storage slot `sha256(key)` - let _ = __state_clear(key, 1); - __state_clear(sha256(key), number_of_slots) -} - -/// A general way to persistently store heap types. -pub trait StorableSlice { - #[storage(write)] - fn store(self, argument: T); - #[storage(read)] - fn load(self) -> Option; - #[storage(read, write)] - fn clear(self) -> bool; - #[storage(read)] - fn len(self) -> u64; -} - -/// A persistent key-value pair mapping struct. -pub struct StorageMap {} - -impl StorageMap { - /// Inserts a key-value pair into the map. - /// - /// ### Arguments - /// - /// * `key` - The key to which the value is paired. - /// * `value` - The value to be stored. - /// - /// ### 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(key); - /// assert(value == retrieved_value); - /// } - /// ``` - #[storage(write)] - pub fn insert(self, key: K, value: V) { - let key = sha256((key, __get_storage_key())); - store::(key, value); - } - - /// Retrieves a value previously stored using a key. - /// - /// If no value was previously stored at `key`, `Option::None` is returned. Otherwise, - /// `Option::Some(value)` is returned, where `value` is the value stored at `key`. - /// - /// ### 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(key).unwrap(); - /// assert(value == retrieved_value); - /// } - /// ``` - #[storage(read)] - pub fn get(self, key: K) -> Option { - let key = sha256((key, __get_storage_key())); - get::(key) - } - - /// Clears a value previously stored using a key - /// - /// Return a Boolean indicating whether there was a value previously stored at `key`. - /// - /// ### 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 removed = storage.map.remove(key); - /// assert(removed); - /// assert(storage.map.get(key).is_none()); - /// } - /// ``` - #[storage(write)] - pub fn remove(self, key: K) -> bool { - let key = sha256((key, __get_storage_key())); - clear::(key) - } -} - -/// A persistant vector struct. -pub struct StorageVec {} - -impl StorageVec { - /// Appends the value to the end of the vector. - /// - /// ### Arguments - /// - /// * `value` - The item being added to the end of the vector. - /// - /// ### Number of Storage Accesses - /// - /// * Reads: `1` - /// * Writes: `2` - /// - /// ### Examples - /// - /// ```sway - /// use std::storage::StorageVec; - /// - /// storage { - /// vec: StorageVec = StorageVec {} - /// } - /// - /// fn foo() { - /// let five = 5_u64; - /// storage.vec.push(five); - /// assert(five == storage.vec.get(0).unwrap()); - /// } - /// ``` - #[storage(read, write)] - pub fn push(self, value: V) { - // The length of the vec is stored in the __get_storage_key() slot - let len = get::(__get_storage_key()).unwrap_or(0); - - // Storing the value at the current length index (if this is the first item, starts off at 0) - let key = sha256((len, __get_storage_key())); - store::(key, value); - - // Incrementing the length - store(__get_storage_key(), len + 1); - } - - /// Removes the last element of the vector and returns it, `None` if empty. - /// - /// ### Number of Storage Accesses - /// - /// * Reads: `2` - /// * Writes: `1` - /// - /// ### Examples - /// - /// ```sway - /// use std::storage::StorageVec; - /// - /// storage { - /// vec: StorageVec = StorageVec {} - /// } - /// - /// fn foo() { - /// let five = 5_u64; - /// storage.vec.push(five); - /// let popped_value = storage.vec.pop().unwrap(); - /// assert(five == popped_value); - /// let none_value = storage.vec.pop(); - /// assert(none_value.is_none()) - /// } - /// ``` - #[storage(read, write)] - pub fn pop(self) -> Option { - let len = get::(__get_storage_key()).unwrap_or(0); - - // if the length is 0, there is no item to pop from the vec - if len == 0 { - return Option::None; - } - - // reduces len by 1, effectively removing the last item in the vec - store(__get_storage_key(), len - 1); - - let key = sha256((len - 1, __get_storage_key())); - get::(key) - } - - /// Gets the value in the given index, `None` if index is out of bounds. - /// - /// ### Arguments - /// - /// * `index` - The index of the vec to retrieve the item from. - /// - /// ### Number of Storage Accesses - /// - /// * Reads: `2` - /// - /// ### Examples - /// - /// ```sway - /// use std::storage::StorageVec; - /// - /// storage { - /// vec: StorageVec = StorageVec {} - /// } - /// - /// fn foo() { - /// let five = 5_u64; - /// storage.vec.push(five); - /// assert(five == storage.vec.get(0).unwrap()); - /// assert(storage.vec.get(1).is_none()) - /// } - /// ``` - #[storage(read)] - pub fn get(self, index: u64) -> Option { - let len = get::(__get_storage_key()).unwrap_or(0); - - // if the index is larger or equal to len, there is no item to return - if len <= index { - return Option::None; - } - - get::(sha256((index, __get_storage_key()))) - } - - /// Removes the element in the given index and moves all the elements in the following indexes - /// down one index. Also returns the element. - /// - /// > **_WARNING:_** Expensive for larger vecs. - /// - /// ### Arguments - /// - /// * `index` - The index of the vec to remove the item from. - /// - /// ### Reverts - /// - /// Reverts if index is larger or equal to length of the vec. - /// - /// ### Number of Storage Accesses - /// - /// * Reads: `2 + self.len() - index` - /// * Writes: `self.len() - index` - /// - /// ### Examples - /// - /// ```sway - /// use std::storage::StorageVec; - /// - /// storage { - /// vec: StorageVec = StorageVec {} - /// } - /// - /// fn foo() { - /// storage.vec.push(5); - /// storage.vec.push(10); - /// storage.vec.push(15); - /// let removed_value = storage.vec.remove(1); - /// assert(10 == removed_value); - /// assert(storage.vec.len() == 2); - /// } - /// ``` - #[storage(read, write)] - pub fn remove(self, index: u64) -> V { - let len = get::(__get_storage_key()).unwrap_or(0); - - // if the index is larger or equal to len, there is no item to remove - assert(index < len); - - // gets the element before removing it, so it can be returned - let removed_element = get::(sha256((index, __get_storage_key()))).unwrap(); - - // for every element in the vec with an index greater than the input index, - // shifts the index for that element down one - let mut count = index + 1; - while count < len { - // gets the storage location for the previous index - let key = sha256((count - 1, __get_storage_key())); - // moves the element of the current index into the previous index - store::(key, get::(sha256((count, __get_storage_key()))).unwrap()); - - count += 1; - } - - // decrements len by 1 - store(__get_storage_key(), len - 1); - - removed_element - } - - /// Removes the element at the specified index and fills it with the last element. - /// This does not preserve ordering and returns the element. - /// - /// ### Arguments - /// - /// * `index` - The index of the vec to remove the item from. - /// - /// ### Reverts - /// - /// Reverts if index is larger or equal to length of the vec. - /// - /// ### Number of Storage Accesses - /// - /// * Reads: `3` - /// * Writes: `2` - /// - /// ### Examples - /// - /// ```sway - /// use std::storage::StorageVec; - /// - /// storage { - /// vec: StorageVec = StorageVec {} - /// } - /// - /// fn foo() { - /// storage.vec.push(5); - /// storage.vec.push(10); - /// storage.vec.push(15); - /// let removed_value = storage.vec.swap_remove(0); - /// assert(5 == removed_value); - /// let swapped_value = storage.vec.get(0).unwrap(); - /// assert(15 == swapped_value); - /// } - /// ``` - #[storage(read, write)] - pub fn swap_remove(self, index: u64) -> V { - let len = get::(__get_storage_key()).unwrap_or(0); - - // if the index is larger or equal to len, there is no item to remove - assert(index < len); - - let hash_of_to_be_removed = sha256((index, __get_storage_key())); - // gets the element before removing it, so it can be returned - let element_to_be_removed = get::(hash_of_to_be_removed).unwrap(); - - let last_element = get::(sha256((len - 1, __get_storage_key()))).unwrap(); - store::(hash_of_to_be_removed, last_element); - - // decrements len by 1 - store(__get_storage_key(), len - 1); - - element_to_be_removed - } - - /// Sets or mutates the value at the given index. - /// - /// ### Arguments - /// - /// * `index` - The index of the vec to set the value at - /// * `value` - The value to be set - /// - /// ### Reverts - /// - /// Reverts if index is larger than or equal to the length of the vec. - /// - /// ### Number of Storage Accesses - /// - /// * Reads: `1` - /// * Writes: `1` - /// - /// ### Examples - /// - /// ```sway - /// use std::storage::StorageVec; - /// - /// storage { - /// vec: StorageVec = StorageVec {} - /// } - /// - /// fn foo() { - /// storage.vec.push(5); - /// storage.vec.push(10); - /// storage.vec.push(15); - /// - /// storage.vec.set(0, 20); - /// let set_value = storage.vec.get(0).unwrap(); - /// assert(20 == set_value); - /// } - /// ``` - #[storage(read, write)] - pub fn set(self, index: u64, value: V) { - let len = get::(__get_storage_key()).unwrap_or(0); - - // if the index is higher than or equal len, there is no element to set - assert(index < len); - - let key = sha256((index, __get_storage_key())); - store::(key, value); - } - - /// Inserts the value at the given index, moving the current index's value - /// as well as the following index's value up by one index. - /// - /// > **_WARNING:_** Expensive for larger vecs. - /// - /// ### Arguments - /// - /// * `index` - The index of the vec to insert the item into. - /// * `value` - The value to insert into the vec. - /// - /// ### Reverts - /// - /// Reverts if index is larger than the length of the vec. - /// - /// ### Number of Storage Accesses - /// - /// * Reads: `if self.len() == index { 1 } else { 1 + self.len() - index }` - /// * Writes: `if self.len() == index { 2 } else { 2 + self.len() - index }` - /// - /// ### Examples - /// - /// ```sway - /// use std::storage::StorageVec; - /// - /// storage { - /// vec: StorageVec = StorageVec {} - /// } - /// - /// fn foo() { - /// storage.vec.push(5); - /// storage.vec.push(15); - /// - /// storage.vec.insert(1, 10); - /// - /// assert(5 == storage.vec.get(0).unwrap()); - /// assert(10 == storage.vec.get(1).unwrap()); - /// assert(15 == storage.vec.get(2).unwrap()); - /// } - /// ``` - #[storage(read, write)] - pub fn insert(self, index: u64, value: V) { - let len = get::(__get_storage_key()).unwrap_or(0); - - // if the index is larger than len, there is no space to insert - assert(index <= len); - - // if len is 0, index must also be 0 due to above check - if len == index { - let key = sha256((index, __get_storage_key())); - store::(key, value); - - // increments len by 1 - store(__get_storage_key(), len + 1); - - return; - } - - // for every element in the vec with an index larger than the input index, - // move the element up one index. - // performed in reverse to prevent data overwriting - let mut count = len - 1; - while count >= index { - let key = sha256((count + 1, __get_storage_key())); - // shifts all the values up one index - store::(key, get::(sha256((count, __get_storage_key()))).unwrap()); - - count -= 1 - } - - // inserts the value into the now unused index - let key = sha256((index, __get_storage_key())); - store::(key, value); - - // increments len by 1 - store(__get_storage_key(), len + 1); - } - - /// Returns the length of the vector. - /// - /// ### Number of Storage Accesses - /// - /// * Reads: `1` - /// - /// ### Examples - /// - /// ```sway - /// use std::storage::StorageVec; - /// - /// storage { - /// vec: StorageVec = StorageVec {} - /// } - /// - /// fn foo() { - /// assert(0 == storage.vec.len()); - /// storage.vec.push(5); - /// assert(1 == storage.vec.len()); - /// storage.vec.push(10); - /// assert(2 == storage.vec.len()); - /// } - /// ``` - #[storage(read)] - pub fn len(self) -> u64 { - get::(__get_storage_key()).unwrap_or(0) - } - - /// Checks whether the len is zero or not. - /// - /// ### Number of Storage Accesses - /// - /// * Reads: `1` - /// - /// ### Examples - /// - /// ```sway - /// use std::storage::StorageVec; - /// - /// storage { - /// vec: StorageVec = StorageVec {} - /// } - /// - /// fn foo() { - /// assert(true == storage.vec.is_empty()); - /// - /// storage.vec.push(5); - /// - /// assert(false == storage.vec.is_empty()); - /// - /// storage.vec.clear(); - /// - /// assert(true == storage.vec.is_empty()); - /// } - /// ``` - #[storage(read)] - pub fn is_empty(self) -> bool { - get::(__get_storage_key()).unwrap_or(0) == 0 - } - - /// Sets the len to zero. - /// - /// ### Number of Storage Accesses - /// - /// * Clears: `1` - /// - /// ### Examples - /// - /// ```sway - /// use std::storage::StorageVec; - /// - /// storage { - /// vec: StorageVec = StorageVec {} - /// } - /// - /// fn foo() { - /// assert(0 == storage.vec.len()); - /// storage.vec.push(5); - /// assert(1 == storage.vec.len()); - /// storage.vec.clear(); - /// assert(0 == storage.vec.len()); - /// } - /// ``` - #[storage(write)] - pub fn clear(self) { - let _ = clear::(__get_storage_key()); - } - - /// Swaps two elements. - /// - /// ### Arguments - /// - /// * element1_index - The index of the first element. - /// * element2_index - The index of the second element. - /// - /// ### Reverts - /// - /// * If `element1_index` or `element2_index` is greater than the length of the vector. - /// - /// ### Number of Storage Accesses - /// - /// * Reads: `3` - /// * Writes: `2` - /// - /// ### Examples - /// - /// ```sway - /// use std::storage::StorageVec; - /// - /// storage { - /// vec: StorageVec = StorageVec {} - /// } - /// - /// fn foo() { - /// storage.vec.push(5); - /// storage.vec.push(10); - /// storage.vec.push(15); - /// - /// storage.vec.swap(0, 2); - /// assert(15 == storage.vec.get(0).unwrap()); - /// assert(10 == storage.vec.get(1).unwrap()); - /// assert(5 == storage.vec.get(2).unwrap()); - /// ``` - #[storage(read, write)] - pub fn swap(self, element1_index: u64, element2_index: u64) { - let len = get::(__get_storage_key()).unwrap_or(0); - assert(element1_index < len); - assert(element2_index < len); - - if element1_index == element2_index { - return; - } - - let element1_key = sha256((element1_index, __get_storage_key())); - let element2_key = sha256((element2_index, __get_storage_key())); - - let element1_value = get::(element1_key).unwrap(); - store::(element1_key, get::(element2_key).unwrap()); - store::(element2_key, element1_value); - } - - /// Returns the first element of the vector, or `None` if it is empty. - /// - /// ### Number of Storage Accesses - /// - /// * Reads: `2` - /// - /// ### Examples - /// - /// ```sway - /// storage { - /// vec: StorageVec = StorageVec {}, - /// } - /// - /// fn foo() { - /// assert(storage.vec.first().is_none()); - /// - /// storage.vec.push(5); - /// - /// assert(5 == storage.vec.first().unwrwap()); - /// } - /// ``` - #[storage(read)] - pub fn first(self) -> Option { - match get::(__get_storage_key()).unwrap_or(0) { - 0 => Option::None, - _ => get::(sha256((0, __get_storage_key()))), - } - } - - /// Returns the last element of the vector, or `None` if it is empty. - /// - /// ### Number of Storage Accesses - /// - /// * Reads: `2` - /// - /// ### Examples - /// - /// ```sway - /// storage { - /// vec: StorageVec = StorageVec {}, - /// } - /// - /// fn foo() { - /// assert(storage.vec.last().is_none()); - /// - /// storage.vec.push(5); - /// storage.vec.push(10); - /// - /// assert(10 == storage.vec.last().unwrap()); - /// } - /// ``` - #[storage(read)] - pub fn last(self) -> Option { - match get::(__get_storage_key()).unwrap_or(0) { - 0 => Option::None, - len => get::(sha256((len - 1, __get_storage_key()))), - } - } - - /// Reverses the order of elements in the vector, in place. - /// - /// ### Number of Storage Accesses - /// - /// * Reads: `1 + (2 * (self.len() / 2))` - /// * Writes: `2 * (self.len() / 2)` - /// - /// ### Examples - /// - /// ```sway - /// storage { - /// vec: StorageVec = StorageVec {}, - /// } - /// - /// fn foo() { - /// storage.vec.push(5); - /// storage.vec.push(10); - /// storage.vec.push(15); - /// storage.vec.reverse(); - /// - /// assert(15 == storage.vec.get(0).unwrap()); - /// assert(10 == storage.vec.get(1).unwrap()); - /// assert(5 == storage.vec.get(2).unwrap()); - /// } - /// ``` - #[storage(read, write)] - pub fn reverse(self) { - let len = get::(__get_storage_key()).unwrap_or(0); - - if len < 2 { - return; - } - - let mid = len / 2; - let mut i = 0; - while i < mid { - let element1_key = sha256((i, __get_storage_key())); - let element2_key = sha256((len - i - 1, __get_storage_key())); - - let element1_value = get::(element1_key).unwrap(); - store::(element1_key, get::(element2_key).unwrap()); - store::(element2_key, element1_value); - - i += 1; - } - } - - /// Fills `self` with elements by cloning `value`. - /// - /// ### Arguments - /// - /// * value - Value to copy to each element of the vector. - /// - /// ### Number of Storage Accesses - /// - /// * Reads: `1` - /// * Writes: `self.len()` - /// - /// ### Examples - /// - /// ```sway - /// storage { - /// vec: StorageVec = StorageVec {}, - /// } - /// - /// fn foo() { - /// storage.vec.push(5); - /// storage.vec.push(10); - /// storage.vec.push(15); - /// storage.vec.fill(20); - /// - /// assert(20 == storage.vec.get(0).unwrap()); - /// assert(20 == storage.vec.get(1).unwrap()); - /// assert(20 == storage.vec.get(2).unwrap()); - /// } - /// ``` - #[storage(read, write)] - pub fn fill(self, value: V) { - let len = get::(__get_storage_key()).unwrap_or(0); - - let mut i = 0; - while i < len { - store::(sha256((i, __get_storage_key())), value); - i += 1; - } - } - - /// Resizes `self` in place so that `len` is equal to `new_len`. - /// - /// If `new_len` is greater than `len`, `self` is extended by the difference, with each - /// additional slot being filled with `value`. If the `new_len` is less than `len`, `self` is - /// simply truncated. - /// - /// ### Arguments - /// - /// * new_len - The new length to expand or truncate to - /// * value - The value to fill into new slots if the `new_len` is greater than the current length - /// - /// ### Number of Storage Accesses - /// - /// * Reads - `1` - /// * Writes - `if new_len > self.len() { new_len - len + 1 } else { 1 }` - /// - /// ### Examples - /// - /// ```sway - /// storage { - /// vec: StorageVec = StorageVec {}, - /// } - /// - /// fn foo() { - /// storage.vec.push(5); - /// storage.vec.push(10); - /// storage.vec.resize(4, 20); - /// - /// assert(5 == storage.vec.get(0).unwrap()); - /// assert(10 == storage.vec.get(1).unwrap()); - /// assert(20 == storage.vec.get(2).unwrap()); - /// assert(20 == storage.vec.get(3).unwrap()); - /// - /// storage.vec.resize(2, 0); - /// - /// assert(5 == storage.vec.get(0).unwrap()); - /// assert(10 == storage.vec.get(1).unwrap()); - /// assert(Option::None == storage.vec.get(2)); - /// assert(Option::None == storage.vec.get(3)); - /// } - /// ``` - #[storage(read, write)] - pub fn resize(self, new_len: u64, value: V) { - let mut len = get::(__get_storage_key()).unwrap_or(0); - while len < new_len { - store::(sha256((len, __get_storage_key())), value); - len += 1; - } - store::(__get_storage_key(), new_len); - } -} - -/// A persistent storage type to store a collection of tightly packed bytes. -pub struct StorageBytes {} - -impl StorableSlice for StorageBytes { - /// Takes a `Bytes` type and stores the underlying collection of tightly packed bytes. - /// - /// ### Arguments - /// - /// * `bytes` - The bytes which will be stored. - /// - /// ### Number of Storage Accesses - /// - /// * Writes: `2` - /// - /// ### Examples - /// - /// ```sway - /// storage { - /// stored_bytes: StorageBytes = StorageBytes {} - /// } - /// - /// fn foo() { - /// let mut bytes = Bytes::new(); - /// bytes.push(5_u8); - /// bytes.push(7_u8); - /// bytes.push(9_u8); - /// - /// storage.stored_bytes.store(bytes); - /// } - /// ``` - #[storage(write)] - fn store(self, bytes: Bytes) { - let key = __get_storage_key(); - store_slice(key, bytes.as_raw_slice()); - } - - /// Constructs a `Bytes` type from a collection of tightly packed bytes in storage. - /// - /// ### Number of Storage Accesses - /// - /// * Reads: `2` - /// - /// ### Examples - /// - /// ```sway - /// storage { - /// stored_bytes: StorageBytes = StorageBytes {} - /// } - /// - /// fn foo() { - /// let mut bytes = Bytes::new(); - /// bytes.push(5_u8); - /// bytes.push(7_u8); - /// bytes.push(9_u8); - /// - /// assert(storage.stored_bytes.load(key).is_none()); - /// storage.stored_bytes.store(bytes); - /// let retrieved_bytes = storage.stored_bytes.load(key).unwrap(); - /// assert(bytes == retrieved_bytes); - /// } - /// ``` - #[storage(read)] - fn load(self) -> Option { - let key = __get_storage_key(); - match get_slice(key) { - Option::Some(slice) => { - Option::Some(Bytes::from_raw_slice(slice)) - }, - Option::None => Option::None, - } - } - - /// Clears a collection of tightly packed bytes in storage. - /// - /// ### Number of Storage Accesses - /// - /// * Reads: `1` - /// * Clears: `2` - /// - /// ### Examples - /// - /// ```sway - /// storage { - /// stored_bytes: StorageBytes = StorageBytes {} - /// } - /// - /// fn foo() { - /// let mut bytes = Bytes::new(); - /// bytes.push(5_u8); - /// bytes.push(7_u8); - /// bytes.push(9_u8); - /// storage.stored_bytes.store(bytes); - /// - /// assert(storage.stored_bytes.load(key).is_some()); - /// let cleared = storage.stored_bytes.clear(); - /// assert(cleared); - /// let retrieved_bytes = storage.stored_bytes.load(key); - /// assert(retrieved_bytes.is_none()); - /// } - /// ``` - #[storage(read, write)] - fn clear(self) -> bool { - let key = __get_storage_key(); - clear_slice(key) - } - - /// Returns the length of tightly packed bytes in storage. - /// - /// ### Number of Storage Accesses - /// - /// * Reads: `1` - /// - /// ### Examples - /// - /// ```sway - /// storage { - /// stored_bytes: StorageBytes = StorageBytes {} - /// } - /// - /// fn foo() { - /// let mut bytes = Bytes::new(); - /// bytes.push(5_u8); - /// bytes.push(7_u8); - /// bytes.push(9_u8); - /// - /// assert(storage.stored_bytes.len() == 0) - /// storage.stored_bytes.store(bytes); - /// assert(storage.stored_bytes.len() == 3); - /// } - /// ``` - #[storage(read)] - fn len(self) -> u64 { - get::(__get_storage_key()).unwrap_or(0) - } -} +mod storage_api; +mod storage_key; +mod storable_slice; +mod storage_map; +mod storage_vec; +mod storage_bytes; diff --git a/sway-lib-std/src/storage/storable_slice.sw b/sway-lib-std/src/storage/storable_slice.sw new file mode 100644 index 00000000000..445db05b1ef --- /dev/null +++ b/sway-lib-std/src/storage/storable_slice.sw @@ -0,0 +1,120 @@ +library; + +use ::alloc::{alloc, alloc_bytes, realloc_bytes}; +use ::hash::sha256; +use ::option::Option; +use ::storage::storage_api::*; + +/// Store a raw_slice from the heap into storage. +/// +/// ### Arguments +/// +/// * `key` - The storage slot at which the variable will be stored. +/// * `slice` - The raw_slice to be stored. +/// +/// ### Examples +/// +/// ```sway +/// use std::{alloc::alloc_bytes, storage::{store_slice, get_slice}, constants::ZERO_B256}; +/// +/// let slice = asm(ptr: (alloc_bytes(1), 1)) { ptr: raw_slice }; +/// assert(get_slice(ZERO_B256).is_none()); +/// store_slice(ZERO_B256, slice); +/// let stored_slice = get_slice(ZERO_B256).unwrap(); +/// assert(slice == stored_slice); +/// ``` +#[storage(read, write)] +pub fn store_slice(key: b256, slice: raw_slice) { + // Get the number of storage slots needed based on the size of bytes. + let number_of_bytes = slice.number_of_bytes(); + let number_of_slots = (number_of_bytes + 31) >> 5; + let mut ptr = slice.ptr(); + + // The capacity needs to be a multiple of 32 bytes so we can + // make the 'quad' storage instruction store without accessing unallocated heap memory. + ptr = realloc_bytes(ptr, number_of_bytes, number_of_slots * 32); + + // Store `number_of_slots * 32` bytes starting at storage slot `key`. + let _ = __state_store_quad(sha256(key), ptr, number_of_slots); + + // Store the length of the bytes + write(key, 0, number_of_bytes); +} + +/// Load a raw_slice from storage. +/// +/// If no value was previously stored at `key`, `Option::None` is returned. Otherwise, +/// `Option::Some(value)` is returned, where `value` is the value stored at `key`. +/// +/// ### Arguments +/// +/// * `key` - The storage slot to load the value from. +/// +/// ### Examples +/// +/// ```sway +/// use std::{alloc::alloc_bytes, storage::{store_slice, get_slice}, constants::ZERO_B256}; +/// +/// let slice = asm(ptr: (alloc_bytes(1), 1)) { ptr: raw_slice }; +/// assert(get_slice(ZERO_B256).is_none()); +/// store_slice(ZERO_B256, slice); +/// let stored_slice = get_slice(ZERO_B256).unwrap(); +/// assert(slice == stored_slice); +/// ``` +#[storage(read)] +pub fn get_slice(key: b256) -> Option { + // Get the length of the slice that is stored. + match read::(key, 0).unwrap_or(0) { + 0 => Option::None, + len => { + // Get the number of storage slots needed based on the size. + let number_of_slots = (len + 31) >> 5; + let ptr = alloc_bytes(number_of_slots * 32); + // Load the stored slice into the pointer. + let _ = __state_load_quad(sha256(key), ptr, number_of_slots); + Option::Some(asm(ptr: (ptr, len)) { ptr: raw_slice }) + } + } +} + +/// Clear a sequence of storage slots starting at a some key. Returns a Boolean +/// indicating whether all of the storage slots cleared were previously set. +/// +/// ### Arguments +/// +/// * `key` - The key of the first storage slot that will be cleared +/// +/// ### Examples +/// +/// ```sway +/// use std::{alloc::alloc_bytes, storage::{clear_slice, store_slice, get_slice}, constants::ZERO_B256}; +/// +/// let slice = asm(ptr: (alloc_bytes(1), 1)) { ptr: raw_slice }; +/// store_slice(ZERO_B256, slice); +/// assert(get_slice(ZERO_B256).is_some()); +/// let cleared = clear_slice(ZERO_B256); +/// assert(cleared); +/// assert(get_slice(ZERO_B256).is_none()); +/// ``` +#[storage(read, write)] +pub fn clear_slice(key: b256) -> bool { + // Get the number of storage slots needed based on the ceiling of `len / 32` + let len = read::(key, 0).unwrap_or(0); + let number_of_slots = (len + 31) >> 5; + + // Clear length and `number_of_slots` bytes starting at storage slot `sha256(key)` + let _ = __state_clear(key, 1); + __state_clear(sha256(key), number_of_slots) +} + +/// A general way to persistently store heap types. +pub trait StorableSlice { + #[storage(read, write)] + fn store(self, argument: T); + #[storage(read)] + fn load(self) -> Option; + #[storage(read, write)] + fn clear(self) -> bool; + #[storage(read)] + fn len(self) -> u64; +} diff --git a/sway-lib-std/src/storage/storage_api.sw b/sway-lib-std/src/storage/storage_api.sw new file mode 100644 index 00000000000..2532fb4b297 --- /dev/null +++ b/sway-lib-std/src/storage/storage_api.sw @@ -0,0 +1,118 @@ +library; + +use ::alloc::alloc; +use ::option::Option; + +/// Store a stack value in storage. Will not work for heap values. +/// +/// ### Arguments +/// +/// * `slot` - The storage slot at which the variable will be stored. +/// * `value` - The value to be stored. +/// * `offset` - An offset, in words, from the beginning of `slot`, at which `value` should be +/// stored. +/// +/// ### Examples +/// +/// ```sway +/// let five = 5_u64; +/// write(ZERO_B256, 2, five); +/// let stored_five = read::(ZERO_B256, 2).unwrap(); +/// assert(five == stored_five); +/// ``` +#[storage(read, write)] +pub fn write(slot: b256, offset: u64, value: T) { + if __size_of::() == 0 { + return; + } + + // Get the number of storage slots needed based on the size of `T` + let number_of_slots = (offset * 8 + __size_of::() + 31) >> 5; + + // Allocate enough memory on the heap for `value` as well as any potential padding required due + // to `offset`. + let padded_value = alloc::(number_of_slots * 32); + + // Read the values that currently exist in the affected storage slots. + // NOTE: we can do better here by only reading from the slots that we know could be affected. + // These are the two slots where the start and end of `T` fall in considering `offset`. + // However, doing so requires that we perform addition on `b256` to compute the corresponding + // keys, and that is not possible today. + let _ = __state_load_quad(slot, padded_value, number_of_slots); + + // Copy the value to be stored to `padded_value + offset`. + padded_value.add::(offset).write::(value); + + // Now store back the data at `padded_value` which now contains the old data but partially + // overwritten by the new data in the desired locations. + let _ = __state_store_quad(slot, padded_value, number_of_slots); +} + +/// Reads a value of type `T` starting at the location specified by `slot` and `offset`. If the +/// value crosses the boundary of a storage slot, reading continues at the following slot. +/// +/// Returns `Option(value)` if the storage slots read were valid and contain `value`. Otherwise, +/// return `None`. +/// +/// ### Arguments +/// +/// * `slot` - The storage slot to load the value from. +/// * `offset` - An offset, in words, from the start of `slot`, from which the value should be read. +/// +/// ### Examples +/// +/// ```sway +/// let five = 5_u64; +/// write(ZERO_B256, 2, five); +/// let stored_five = read::(ZERO_B256, 2); +/// assert(five == stored_five); +/// ``` +#[storage(read)] +pub fn read(slot: b256, offset: u64) -> Option { + if __size_of::() == 0 { + return Option::None; + } + + // NOTE: we are leaking this value on the heap. + // Get the number of storage slots needed based on the size of `T` + let number_of_slots = (offset * 8 + __size_of::() + 31) >> 5; + + // Allocate a buffer for the result. Its size needs to be a multiple of 32 bytes so we can + // make the 'quad' storage instruction read without overflowing. + let result_ptr = alloc::(number_of_slots * 32); + + // Read `number_of_slots * 32` bytes starting at storage slot `slot` and return an `Option` + // wrapping the value stored at `result_ptr + offset` if all the slots are valid. Otherwise, + // return `Option::None`. + if __state_load_quad(slot, result_ptr, number_of_slots) { + Option::Some(result_ptr.add::(offset).read::()) + } else { + Option::None + } +} + +/// Clear a sequence of consecutive storage slots starting at a some slot. Returns a Boolean +/// indicating whether all of the storage slots cleared were previously set. +/// +/// ### Arguments +/// +/// * `slot` - The key of the first storage slot that will be cleared +/// +/// ### Examples +/// +/// ```sway +/// let five = 5_u64; +/// write(ZERO_B256, 0, five); +/// let cleared = clear::(ZERO_B256); +/// assert(cleared); +/// assert(read::(ZERO_B256, 0).is_none()); +/// ``` +#[storage(write)] +pub fn clear(slot: b256) -> bool { + // Get the number of storage slots needed based on the size of `T` as the ceiling of + // `__size_of::() / 32` + let number_of_slots = (__size_of::() + 31) >> 5; + + // Clear `number_of_slots * 32` bytes starting at storage slot `slot`. + __state_clear(slot, number_of_slots) +} diff --git a/sway-lib-std/src/storage/storage_bytes.sw b/sway-lib-std/src/storage/storage_bytes.sw new file mode 100644 index 00000000000..8a74a2c49dd --- /dev/null +++ b/sway-lib-std/src/storage/storage_bytes.sw @@ -0,0 +1,142 @@ +library; + +use ::bytes::Bytes; +use ::option::Option; +use ::storage::storable_slice::*; +use ::storage::storage_api::*; + +/// A persistent storage type to store a collection of tightly packed bytes. +pub struct StorageBytes {} + +impl StorableSlice for StorageKey { + /// Takes a `Bytes` type and stores the underlying collection of tightly packed bytes. + /// + /// ### Arguments + /// + /// * `bytes` - The bytes which will be stored. + /// + /// ### Number of Storage Accesses + /// + /// * Writes: `2` + /// + /// ### Examples + /// + /// ```sway + /// storage { + /// stored_bytes: StorageBytes = StorageBytes {} + /// } + /// + /// fn foo() { + /// let mut bytes = Bytes::new(); + /// bytes.push(5_u8); + /// bytes.push(7_u8); + /// bytes.push(9_u8); + /// + /// storage.stored_bytes.store(bytes); + /// } + /// ``` + #[storage(read, write)] + fn store(self, bytes: Bytes) { + let key = self.slot; + store_slice(key, bytes.as_raw_slice()); + } + + /// Constructs a `Bytes` type from a collection of tightly packed bytes in storage. + /// + /// ### Number of Storage Accesses + /// + /// * Reads: `2` + /// + /// ### Examples + /// + /// ```sway + /// storage { + /// stored_bytes: StorageBytes = StorageBytes {} + /// } + /// + /// fn foo() { + /// let mut bytes = Bytes::new(); + /// bytes.push(5_u8); + /// bytes.push(7_u8); + /// bytes.push(9_u8); + /// + /// assert(storage.stored_bytes.load(key).is_none()); + /// storage.stored_bytes.store(bytes); + /// let retrieved_bytes = storage.stored_bytes.load(key).unwrap(); + /// assert(bytes == retrieved_bytes); + /// } + /// ``` + #[storage(read)] + fn load(self) -> Option { + let key = self.slot; + match get_slice(key) { + Option::Some(slice) => { + Option::Some(Bytes::from_raw_slice(slice)) + }, + Option::None => Option::None, + } + } + + /// Clears a collection of tightly packed bytes in storage. + /// + /// ### Number of Storage Accesses + /// + /// * Reads: `1` + /// * Clears: `2` + /// + /// ### Examples + /// + /// ```sway + /// storage { + /// stored_bytes: StorageBytes = StorageBytes {} + /// } + /// + /// fn foo() { + /// let mut bytes = Bytes::new(); + /// bytes.push(5_u8); + /// bytes.push(7_u8); + /// bytes.push(9_u8); + /// storage.stored_bytes.store(bytes); + /// + /// assert(storage.stored_bytes.load(key).is_some()); + /// let cleared = storage.stored_bytes.clear(); + /// assert(cleared); + /// let retrieved_bytes = storage.stored_bytes.load(key); + /// assert(retrieved_bytes.is_none()); + /// } + /// ``` + #[storage(read, write)] + fn clear(self) -> bool { + let key = self.slot; + clear_slice(key) + } + + /// Returns the length of tightly packed bytes in storage. + /// + /// ### Number of Storage Accesses + /// + /// * Reads: `1` + /// + /// ### Examples + /// + /// ```sway + /// storage { + /// stored_bytes: StorageBytes = StorageBytes {} + /// } + /// + /// fn foo() { + /// let mut bytes = Bytes::new(); + /// bytes.push(5_u8); + /// bytes.push(7_u8); + /// bytes.push(9_u8); + /// + /// assert(storage.stored_bytes.len() == 0) + /// storage.stored_bytes.store(bytes); + /// assert(storage.stored_bytes.len() == 3); + /// } + /// ``` + #[storage(read)] + fn len(self) -> u64 { + read::(self.slot, 0).unwrap_or(0) + } +} diff --git a/sway-lib-std/src/storage/storage_key.sw b/sway-lib-std/src/storage/storage_key.sw new file mode 100644 index 00000000000..4c86e6777f8 --- /dev/null +++ b/sway-lib-std/src/storage/storage_key.sw @@ -0,0 +1,85 @@ +library; + +use ::option::Option; +use ::storage::storage_api::*; + +impl StorageKey { + /// Reads a value of type `T` starting at the location specified by `self`. If the value + /// crosses the boundary of a storage slot, reading continues at the following slot. + /// + /// Returns the value previously stored if a the storage slots read were + /// valid and contain `value`. Panics otherwise. + /// + /// ### Arguments + /// + /// None + /// + /// ### Examples + /// + /// ```sway + /// fn foo() { + /// let r: StorageKey = StorageKey { + /// slot: 0x0000000000000000000000000000000000000000000000000000000000000000, + /// offset: 2, + /// }; + /// + /// // Reads the third word from storage slot with key 0x000...0 + /// let x: u64 = r.read(); + /// } + /// ``` + #[storage(read)] + pub fn read(self) -> T { + read::(self.slot, self.offset).unwrap() + } + + /// Reads a value of type `T` starting at the location specified by `self`. If the value + /// crosses the boundary of a storage slot, reading continues at the following slot. + /// + /// Returns `Some(value)` if a the storage slots read were valid and contain `value`. + /// Otherwise, return `None`. + /// + /// ### Arguments + /// + /// None + /// + /// ### Examples + /// + /// ```sway + /// fn foo() { + /// let r: StorageKey = StorageKey { + /// slot: 0x0000000000000000000000000000000000000000000000000000000000000000, + /// offset: 2, + /// }; + /// + /// // Reads the third word from storage slot with key 0x000...0 + /// let x: Option = r.try_read(); + /// } + /// ``` + #[storage(read)] + pub fn try_read(self) -> Option { + read(self.slot, self.offset) + } + + /// Writes a value of type `T` starting at the location specified by `self`. If the value + /// crosses the boundary of a storage slot, writing continues at the following slot. + /// + /// ### Arguments + /// + /// * value: the value of type `T` to write + /// + /// ### Examples + /// + /// ```sway + /// fn foo() { + /// let r: StorageKey = StorageKey { + /// slot: 0x0000000000000000000000000000000000000000000000000000000000000000, + /// offset: 2, + /// }; + /// let x = r.write(42); // Writes 42 at the third word of storage slot with key 0x000...0 + /// } + /// ``` + #[storage(read, write)] + pub fn write(self, value: T) { + write(self.slot, self.offset, value); + } +} diff --git a/sway-lib-std/src/storage/storage_map.sw b/sway-lib-std/src/storage/storage_map.sw new file mode 100644 index 00000000000..0b2f113202a --- /dev/null +++ b/sway-lib-std/src/storage/storage_map.sw @@ -0,0 +1,97 @@ +library; + +use ::hash::sha256; +use ::storage::storage_api::*; +use ::storage::storage_key::*; + +/// A persistent key-value pair mapping struct. +pub struct StorageMap {} + +impl StorageKey> { + /// Inserts a key-value pair into the map. + /// + /// ### Arguments + /// + /// * `key` - The key to which the value is paired. + /// * `value` - The value to be stored. + /// + /// ### 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(key).read(); + /// assert(value == retrieved_value); + /// } + /// ``` + #[storage(read, write)] + pub fn insert(self, key: K, value: V) { + let key = sha256((key, self.slot)); + write::(key, 0, value); + } + + /// Retrieves the `StorageKey` 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(key).read(); + /// assert(value == retrieved_value); + /// } + /// ``` + pub fn get(self, key: K) -> StorageKey { + StorageKey { + slot: sha256((key, self.slot)), + offset: 0, + } + } + + /// Clears a value previously stored using a key + /// + /// Return a Boolean indicating whether there was a value previously stored at `key`. + /// + /// ### 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 removed = storage.map.remove(key); + /// assert(removed); + /// assert(storage.map.get(key).is_none()); + /// } + /// ``` + #[storage(write)] + pub fn remove(self, key: K) -> bool { + let key = sha256((key, self.slot)); + clear::(key) + } +} diff --git a/sway-lib-std/src/storage/storage_vec.sw b/sway-lib-std/src/storage/storage_vec.sw new file mode 100644 index 00000000000..260a215a543 --- /dev/null +++ b/sway-lib-std/src/storage/storage_vec.sw @@ -0,0 +1,719 @@ +library; + +use ::alloc::alloc; +use ::assert::assert; +use ::hash::sha256; +use ::option::Option; +use ::storage::storage_api::*; +use ::storage::storage_key::*; + +/// A persistant vector struct. +pub struct StorageVec {} + +impl StorageKey> { + /// Appends the value to the end of the vector. + /// + /// ### Arguments + /// + /// * `value` - The item being added to the end of the vector. + /// + /// ### Number of Storage Accesses + /// + /// * Reads: `1` + /// * Writes: `2` + /// + /// ### Examples + /// + /// ```sway + /// use std::storage::StorageVec; + /// + /// storage { + /// vec: StorageVec = StorageVec {} + /// } + /// + /// fn foo() { + /// let five = 5_u64; + /// storage.vec.push(five); + /// assert(five == storage.vec.get(0).unwrap()); + /// } + /// ``` + #[storage(read, write)] + pub fn push(self, value: V) { + let len = read::(self.slot, 0).unwrap_or(0); + + // Storing the value at the current length index (if this is the first item, starts off at 0) + let key = sha256((len, self.slot)); + write::(key, 0, value); + + // Incrementing the length + write(self.slot, 0, len + 1); + } + + /// Removes the last element of the vector and returns it, `None` if empty. + /// + /// ### Number of Storage Accesses + /// + /// * Reads: `2` + /// * Writes: `1` + /// + /// ### Examples + /// + /// ```sway + /// use std::storage::StorageVec; + /// + /// storage { + /// vec: StorageVec = StorageVec {} + /// } + /// + /// fn foo() { + /// let five = 5_u64; + /// storage.vec.push(five); + /// let popped_value = storage.vec.pop().unwrap(); + /// assert(five == popped_value); + /// let none_value = storage.vec.pop(); + /// assert(none_value.is_none()) + /// } + /// ``` + #[storage(read, write)] + pub fn pop(self) -> Option { + let len = read::(self.slot, 0).unwrap_or(0); + + // if the length is 0, there is no item to pop from the vec + if len == 0 { + return Option::None; + } + + // reduces len by 1, effectively removing the last item in the vec + write(self.slot, 0, len - 1); + + let key = sha256((len - 1, self.slot)); + read::(key, 0) + } + + /// Gets the value in the given index, `None` if index is out of bounds. + /// + /// ### Arguments + /// + /// * `index` - The index of the vec to retrieve the item from. + /// + /// ### Number of Storage Accesses + /// + /// * Reads: `2` + /// + /// ### Examples + /// + /// ```sway + /// use std::storage::StorageVec; + /// + /// storage { + /// vec: StorageVec = StorageVec {} + /// } + /// + /// fn foo() { + /// let five = 5_u64; + /// storage.vec.push(five); + /// assert(five == storage.vec.get(0).unwrap()); + /// assert(storage.vec.get(1).is_none()) + /// } + /// ``` + #[storage(read)] + pub fn get(self, index: u64) -> Option> { + let len = read::(self.slot, 0).unwrap_or(0); + + // if the index is larger or equal to len, there is no item to return + if len <= index { + return Option::None; + } + + Option::Some(StorageKey { + slot: sha256((index, self.slot)), + offset: 0, + }) + } + + /// Removes the element in the given index and moves all the elements in the following indexes + /// down one index. Also returns the element. + /// + /// > **_WARNING:_** Expensive for larger vecs. + /// + /// ### Arguments + /// + /// * `index` - The index of the vec to remove the item from. + /// + /// ### Reverts + /// + /// Reverts if index is larger or equal to length of the vec. + /// + /// ### Number of Storage Accesses + /// + /// * Reads: `2 + self.len() - index` + /// * Writes: `self.len() - index` + /// + /// ### Examples + /// + /// ```sway + /// use std::storage::StorageVec; + /// + /// storage { + /// vec: StorageVec = StorageVec {} + /// } + /// + /// fn foo() { + /// storage.vec.push(5); + /// storage.vec.push(10); + /// storage.vec.push(15); + /// let removed_value = storage.vec.remove(1); + /// assert(10 == removed_value); + /// assert(storage.vec.len() == 2); + /// } + /// ``` + #[storage(read, write)] + pub fn remove(self, index: u64) -> V { + let len = read::(self.slot, 0).unwrap_or(0); + + // if the index is larger or equal to len, there is no item to remove + assert(index < len); + + // gets the element before removing it, so it can be returned + let removed_element = read::(sha256((index, self.slot)), 0).unwrap(); + + // for every element in the vec with an index greater than the input index, + // shifts the index for that element down one + let mut count = index + 1; + while count < len { + // gets the storage location for the previous index + let key = sha256((count - 1, self.slot)); + // moves the element of the current index into the previous index + write::(key, 0, read::(sha256((count, self.slot)), 0).unwrap()); + + count += 1; + } + + // decrements len by 1 + write(self.slot, 0, len - 1); + + removed_element + } + + /// Removes the element at the specified index and fills it with the last element. + /// This does not preserve ordering and returns the element. + /// + /// ### Arguments + /// + /// * `index` - The index of the vec to remove the item from. + /// + /// ### Reverts + /// + /// Reverts if index is larger or equal to length of the vec. + /// + /// ### Number of Storage Accesses + /// + /// * Reads: `3` + /// * Writes: `2` + /// + /// ### Examples + /// + /// ```sway + /// use std::storage::StorageVec; + /// + /// storage { + /// vec: StorageVec = StorageVec {} + /// } + /// + /// fn foo() { + /// storage.vec.push(5); + /// storage.vec.push(10); + /// storage.vec.push(15); + /// let removed_value = storage.vec.swap_remove(0); + /// assert(5 == removed_value); + /// let swapped_value = storage.vec.get(0).unwrap(); + /// assert(15 == swapped_value); + /// } + /// ``` + #[storage(read, write)] + pub fn swap_remove(self, index: u64) -> V { + let len = read::(self.slot, 0).unwrap_or(0); + + // if the index is larger or equal to len, there is no item to remove + assert(index < len); + + let hash_of_to_be_removed = sha256((index, self.slot)); + // gets the element before removing it, so it can be returned + let element_to_be_removed = read::(hash_of_to_be_removed, 0).unwrap(); + + let last_element = read::(sha256((len - 1, self.slot)), 0).unwrap(); + write::(hash_of_to_be_removed, 0, last_element); + + // decrements len by 1 + write(self.slot, 0, len - 1); + + element_to_be_removed + } + + /// Sets or mutates the value at the given index. + /// + /// ### Arguments + /// + /// * `index` - The index of the vec to set the value at + /// * `value` - The value to be set + /// + /// ### Reverts + /// + /// Reverts if index is larger than or equal to the length of the vec. + /// + /// ### Number of Storage Accesses + /// + /// * Reads: `1` + /// * Writes: `1` + /// + /// ### Examples + /// + /// ```sway + /// use std::storage::StorageVec; + /// + /// storage { + /// vec: StorageVec = StorageVec {} + /// } + /// + /// fn foo() { + /// storage.vec.push(5); + /// storage.vec.push(10); + /// storage.vec.push(15); + /// + /// storage.vec.set(0, 20); + /// let set_value = storage.vec.get(0).unwrap(); + /// assert(20 == set_value); + /// } + /// ``` + #[storage(read, write)] + pub fn set(self, index: u64, value: V) { + let len = read::(self.slot, 0).unwrap_or(0); + + // if the index is higher than or equal len, there is no element to set + assert(index < len); + + let key = sha256((index, self.slot)); + write::(key, 0, value); + } + + /// Inserts the value at the given index, moving the current index's value + /// as well as the following index's value up by one index. + /// + /// > **_WARNING:_** Expensive for larger vecs. + /// + /// ### Arguments + /// + /// * `index` - The index of the vec to insert the item into. + /// * `value` - The value to insert into the vec. + /// + /// ### Reverts + /// + /// Reverts if index is larger than the length of the vec. + /// + /// ### Number of Storage Accesses + /// + /// * Reads: `if self.len() == index { 1 } else { 1 + self.len() - index }` + /// * Writes: `if self.len() == index { 2 } else { 2 + self.len() - index }` + /// + /// ### Examples + /// + /// ```sway + /// use std::storage::StorageVec; + /// + /// storage { + /// vec: StorageVec = StorageVec {} + /// } + /// + /// fn foo() { + /// storage.vec.push(5); + /// storage.vec.push(15); + /// + /// storage.vec.insert(1, 10); + /// + /// assert(5 == storage.vec.get(0).unwrap()); + /// assert(10 == storage.vec.get(1).unwrap()); + /// assert(15 == storage.vec.get(2).unwrap()); + /// } + /// ``` + #[storage(read, write)] + pub fn insert(self, index: u64, value: V) { + let len = read::(self.slot, 0).unwrap_or(0); + + // if the index is larger than len, there is no space to insert + assert(index <= len); + + // if len is 0, index must also be 0 due to above check + if len == index { + let key = sha256((index, self.slot)); + write::(key, 0, value); + + // increments len by 1 + write(self.slot, 0, len + 1); + + return; + } + + // for every element in the vec with an index larger than the input index, + // move the element up one index. + // performed in reverse to prevent data overwriting + let mut count = len - 1; + while count >= index { + let key = sha256((count + 1, self.slot)); + // shifts all the values up one index + write::(key, 0, read::(sha256((count, self.slot)), 0).unwrap()); + + count -= 1 + } + + // inserts the value into the now unused index + let key = sha256((index, self.slot)); + write::(key, 0, value); + + // increments len by 1 + write(self.slot, 0, len + 1); + } + + /// Returns the length of the vector. + /// + /// ### Number of Storage Accesses + /// + /// * Reads: `1` + /// + /// ### Examples + /// + /// ```sway + /// use std::storage::StorageVec; + /// + /// storage { + /// vec: StorageVec = StorageVec {} + /// } + /// + /// fn foo() { + /// assert(0 == storage.vec.len()); + /// storage.vec.push(5); + /// assert(1 == storage.vec.len()); + /// storage.vec.push(10); + /// assert(2 == storage.vec.len()); + /// } + /// ``` + #[storage(read)] + pub fn len(self) -> u64 { + read::(self.slot, 0).unwrap_or(0) + } + + /// Checks whether the len is zero or not. + /// + /// ### Number of Storage Accesses + /// + /// * Reads: `1` + /// + /// ### Examples + /// + /// ```sway + /// use std::storage::StorageVec; + /// + /// storage { + /// vec: StorageVec = StorageVec {} + /// } + /// + /// fn foo() { + /// assert(true == storage.vec.is_empty()); + /// + /// storage.vec.push(5); + /// + /// assert(false == storage.vec.is_empty()); + /// + /// storage.vec.clear(); + /// + /// assert(true == storage.vec.is_empty()); + /// } + /// ``` + #[storage(read)] + pub fn is_empty(self) -> bool { + read::(self.slot, 0).unwrap_or(0) == 0 + } + + /// Sets the len to zero. + /// + /// ### Number of Storage Accesses + /// + /// * Clears: `1` + /// + /// ### Examples + /// + /// ```sway + /// use std::storage::StorageVec; + /// + /// storage { + /// vec: StorageVec = StorageVec {} + /// } + /// + /// fn foo() { + /// assert(0 == storage.vec.len()); + /// storage.vec.push(5); + /// assert(1 == storage.vec.len()); + /// storage.vec.clear(); + /// assert(0 == storage.vec.len()); + /// } + /// ``` + #[storage(write)] + pub fn clear(self) { + let _ = clear::(self.slot); + } + + /// Swaps two elements. + /// + /// ### Arguments + /// + /// * element1_index - The index of the first element. + /// * element2_index - The index of the second element. + /// + /// ### Reverts + /// + /// * If `element1_index` or `element2_index` is greater than the length of the vector. + /// + /// ### Number of Storage Accesses + /// + /// * Reads: `3` + /// * Writes: `2` + /// + /// ### Examples + /// + /// ```sway + /// use std::storage::StorageVec; + /// + /// storage { + /// vec: StorageVec = StorageVec {} + /// } + /// + /// fn foo() { + /// storage.vec.push(5); + /// storage.vec.push(10); + /// storage.vec.push(15); + /// + /// storage.vec.swap(0, 2); + /// assert(15 == storage.vec.get(0).unwrap()); + /// assert(10 == storage.vec.get(1).unwrap()); + /// assert(5 == storage.vec.get(2).unwrap()); + /// ``` + #[storage(read, write)] + pub fn swap(self, element1_index: u64, element2_index: u64) { + let len = read::(self.slot, 0).unwrap_or(0); + assert(element1_index < len); + assert(element2_index < len); + + if element1_index == element2_index { + return; + } + + let element1_key = sha256((element1_index, self.slot)); + let element2_key = sha256((element2_index, self.slot)); + + let element1_value = read::(element1_key, 0).unwrap(); + write::(element1_key, 0, read::(element2_key, 0).unwrap()); + write::(element2_key, 0, element1_value); + } + + /// Returns the first element of the vector, or `None` if it is empty. + /// + /// ### Number of Storage Accesses + /// + /// * Reads: `2` + /// + /// ### Examples + /// + /// ```sway + /// storage { + /// vec: StorageVec = StorageVec {}, + /// } + /// + /// fn foo() { + /// assert(storage.vec.first().is_none()); + /// + /// storage.vec.push(5); + /// + /// assert(5 == storage.vec.first().unwrwap()); + /// } + /// ``` + #[storage(read)] + pub fn first(self) -> Option> { + match read::(self.slot, 0).unwrap_or(0) { + 0 => Option::None, + _ => Option::Some(StorageKey { + slot: sha256((0, self.slot)), + offset: 0, + }), + } + } + + /// Returns the last element of the vector, or `None` if it is empty. + /// + /// ### Number of Storage Accesses + /// + /// * Reads: `2` + /// + /// ### Examples + /// + /// ```sway + /// storage { + /// vec: StorageVec = StorageVec {}, + /// } + /// + /// fn foo() { + /// assert(storage.vec.last().is_none()); + /// + /// storage.vec.push(5); + /// storage.vec.push(10); + /// + /// assert(10 == storage.vec.last().unwrap()); + /// } + /// ``` + #[storage(read)] + pub fn last(self) -> Option> { + match read::(self.slot, 0).unwrap_or(0) { + 0 => Option::None, + len => Option::Some(StorageKey { + slot: sha256((len - 1, self.slot)), + offset: 0, + }), + } + } + + /// Reverses the order of elements in the vector, in place. + /// + /// ### Number of Storage Accesses + /// + /// * Reads: `1 + (2 * (self.len() / 2))` + /// * Writes: `2 * (self.len() / 2)` + /// + /// ### Examples + /// + /// ```sway + /// storage { + /// vec: StorageVec = StorageVec {}, + /// } + /// + /// fn foo() { + /// storage.vec.push(5); + /// storage.vec.push(10); + /// storage.vec.push(15); + /// storage.vec.reverse(); + /// + /// assert(15 == storage.vec.get(0).unwrap()); + /// assert(10 == storage.vec.get(1).unwrap()); + /// assert(5 == storage.vec.get(2).unwrap()); + /// } + /// ``` + #[storage(read, write)] + pub fn reverse(self) { + let len = read::(self.slot, 0).unwrap_or(0); + + if len < 2 { + return; + } + + let mid = len / 2; + let mut i = 0; + while i < mid { + let element1_key = sha256((i, self.slot)); + let element2_key = sha256((len - i - 1, self.slot)); + + let element1_value = read::(element1_key, 0).unwrap(); + write::(element1_key, 0, read::(element2_key, 0).unwrap()); + write::(element2_key, 0, element1_value); + + i += 1; + } + } + + /// Fills `self` with elements by cloning `value`. + /// + /// ### Arguments + /// + /// * value - Value to copy to each element of the vector. + /// + /// ### Number of Storage Accesses + /// + /// * Reads: `1` + /// * Writes: `self.len()` + /// + /// ### Examples + /// + /// ```sway + /// storage { + /// vec: StorageVec = StorageVec {}, + /// } + /// + /// fn foo() { + /// storage.vec.push(5); + /// storage.vec.push(10); + /// storage.vec.push(15); + /// storage.vec.fill(20); + /// + /// assert(20 == storage.vec.get(0).unwrap()); + /// assert(20 == storage.vec.get(1).unwrap()); + /// assert(20 == storage.vec.get(2).unwrap()); + /// } + /// ``` + #[storage(read, write)] + pub fn fill(self, value: V) { + let len = read::(self.slot, 0).unwrap_or(0); + + let mut i = 0; + while i < len { + write::(sha256((i, self.slot)), 0, value); + i += 1; + } + } + + /// Resizes `self` in place so that `len` is equal to `new_len`. + /// + /// If `new_len` is greater than `len`, `self` is extended by the difference, with each + /// additional slot being filled with `value`. If the `new_len` is less than `len`, `self` is + /// simply truncated. + /// + /// ### Arguments + /// + /// * new_len - The new length to expand or truncate to + /// * value - The value to fill into new slots if the `new_len` is greater than the current length + /// + /// ### Number of Storage Accesses + /// + /// * Reads - `1` + /// * Writes - `if new_len > self.len() { new_len - len + 1 } else { 1 }` + /// + /// ### Examples + /// + /// ```sway + /// storage { + /// vec: StorageVec = StorageVec {}, + /// } + /// + /// fn foo() { + /// storage.vec.push(5); + /// storage.vec.push(10); + /// storage.vec.resize(4, 20); + /// + /// assert(5 == storage.vec.get(0).unwrap()); + /// assert(10 == storage.vec.get(1).unwrap()); + /// assert(20 == storage.vec.get(2).unwrap()); + /// assert(20 == storage.vec.get(3).unwrap()); + /// + /// storage.vec.resize(2, 0); + /// + /// assert(5 == storage.vec.get(0).unwrap()); + /// assert(10 == storage.vec.get(1).unwrap()); + /// assert(Option::None == storage.vec.get(2)); + /// assert(Option::None == storage.vec.get(3)); + /// } + /// ``` + #[storage(read, write)] + pub fn resize(self, new_len: u64, value: V) { + let mut len = read::(self.slot, 0).unwrap_or(0); + while len < new_len { + write::(sha256((len, self.slot)), 0, value); + len += 1; + } + write::(self.slot, 0, new_len); + } +} diff --git a/sway-lsp/src/capabilities/document_symbol.rs b/sway-lsp/src/capabilities/document_symbol.rs index 2a164da294c..27ec7e30f03 100644 --- a/sway-lsp/src/capabilities/document_symbol.rs +++ b/sway-lsp/src/capabilities/document_symbol.rs @@ -26,7 +26,7 @@ pub(crate) fn symbol_kind(symbol_kind: &SymbolKind) -> lsp_types::SymbolKind { } SymbolKind::Const => lsp_types::SymbolKind::CONSTANT, SymbolKind::Struct => lsp_types::SymbolKind::STRUCT, - SymbolKind::Trait | SymbolKind::Storage => lsp_types::SymbolKind::INTERFACE, + SymbolKind::Trait => lsp_types::SymbolKind::INTERFACE, SymbolKind::Module => lsp_types::SymbolKind::MODULE, SymbolKind::Enum => lsp_types::SymbolKind::ENUM, SymbolKind::Variant => lsp_types::SymbolKind::ENUM_MEMBER, diff --git a/sway-lsp/src/capabilities/semantic_tokens.rs b/sway-lsp/src/capabilities/semantic_tokens.rs index d442737d9b8..ceea766b823 100644 --- a/sway-lsp/src/capabilities/semantic_tokens.rs +++ b/sway-lsp/src/capabilities/semantic_tokens.rs @@ -158,7 +158,7 @@ fn semantic_token_type(kind: &SymbolKind) -> SemanticTokenType { SymbolKind::Struct => SemanticTokenType::STRUCT, SymbolKind::Enum => SemanticTokenType::ENUM, SymbolKind::Variant => SemanticTokenType::ENUM_MEMBER, - SymbolKind::Trait | SymbolKind::Storage => SemanticTokenType::INTERFACE, + SymbolKind::Trait => SemanticTokenType::INTERFACE, SymbolKind::TypeParameter => SemanticTokenType::TYPE_PARAMETER, SymbolKind::Module => SemanticTokenType::NAMESPACE, SymbolKind::StringLiteral => SemanticTokenType::STRING, diff --git a/sway-lsp/src/core/token.rs b/sway-lsp/src/core/token.rs index e414e378e19..71841a40c7d 100644 --- a/sway-lsp/src/core/token.rs +++ b/sway-lsp/src/core/token.rs @@ -69,9 +69,7 @@ pub enum TypedAstToken { TypedTraitFn(ty::TyTraitFn), TypedSupertrait(Supertrait), TypedStorageField(ty::TyStorageField), - TyStorageResassignment(Box), TyStorageAccessDescriptor(ty::TyStorageAccessDescriptor), - TypeCheckedStorageReassignDescriptor(ty::TyStorageReassignDescriptor), TypedReassignment(ty::TyReassignment), TypedArgument(TypeArgument), TypedParameter(TypeParameter), @@ -112,8 +110,6 @@ pub enum SymbolKind { SelfKeyword, /// Emitted for the Self type parameter. SelfTypeKeyword, - /// Emitted for storage. - Storage, /// Emitted for string literals. StringLiteral, /// Emitted for structs. diff --git a/sway-lsp/src/traverse/parsed_tree.rs b/sway-lsp/src/traverse/parsed_tree.rs index ca436bdb24d..de22a9f5d46 100644 --- a/sway-lsp/src/traverse/parsed_tree.rs +++ b/sway-lsp/src/traverse/parsed_tree.rs @@ -322,20 +322,6 @@ impl Parse for ReassignmentExpression { ReassignmentTarget::VariableExpression(exp) => { exp.parse(ctx); } - ReassignmentTarget::StorageField(storage_keyword_span, idents) => { - let storage_ident = Ident::new(storage_keyword_span.clone()); - ctx.tokens.insert( - to_ident_key(&storage_ident), - Token::from_parsed(AstToken::Ident(storage_ident), SymbolKind::Storage), - ); - - for ident in idents { - ctx.tokens.insert( - to_ident_key(ident), - Token::from_parsed(AstToken::Ident(ident.clone()), SymbolKind::Field), - ); - } - } } } } diff --git a/sway-lsp/src/traverse/typed_tree.rs b/sway-lsp/src/traverse/typed_tree.rs index 4696388e0dd..543adb695fc 100644 --- a/sway-lsp/src/traverse/typed_tree.rs +++ b/sway-lsp/src/traverse/typed_tree.rs @@ -507,9 +507,6 @@ impl Parse for ty::TyExpression { ty::TyExpressionVariant::Reassignment(reassignment) => { reassignment.parse(ctx); } - ty::TyExpressionVariant::StorageReassignment(storage_reassignment) => { - storage_reassignment.parse(ctx); - } ty::TyExpressionVariant::Return(exp) => exp.parse(ctx), } } @@ -1069,88 +1066,6 @@ impl Parse for ty::TyReassignment { } } -impl Parse for ty::TyStorageReassignment { - fn parse(&self, ctx: &ParseContext) { - // collect storage keyword - if let Some(mut token) = ctx - .tokens - .try_get_mut(&to_ident_key(&Ident::new( - self.storage_keyword_span.clone(), - ))) - .try_unwrap() - { - token.typed = Some(TypedAstToken::TyStorageResassignment(Box::new( - self.clone(), - ))); - if let Some(storage) = ctx.namespace.get_declared_storage(ctx.engines.de()) { - token.type_def = Some(TypeDefinition::Ident(storage.storage_keyword)); - } - } - if let Some((head_field, tail_fields)) = self.fields.split_first() { - // collect the first ident as a field of the storage definition - if let Some(mut token) = ctx - .tokens - .try_get_mut(&to_ident_key(&head_field.name)) - .try_unwrap() - { - token.typed = Some(TypedAstToken::TypeCheckedStorageReassignDescriptor( - head_field.clone(), - )); - if let Some(storage_field) = ctx - .namespace - .get_declared_storage(ctx.engines.de()) - .and_then(|storage| { - // find the corresponding field in the storage declaration - storage - .fields - .into_iter() - .find(|f| f.name.as_str() == head_field.name.as_str()) - }) - { - token.type_def = Some(TypeDefinition::Ident(storage_field.name)); - } - } - // collect the rest of the idents as fields of their respective types - for (field, container_type_id) in tail_fields - .iter() - .zip(self.fields.iter().map(|f| f.type_id)) - { - if let Some(mut token) = ctx - .tokens - .try_get_mut(&to_ident_key(&field.name)) - .try_unwrap() - { - token.typed = Some(TypedAstToken::TypeCheckedStorageReassignDescriptor( - field.clone(), - )); - match ctx.engines.te().get(container_type_id) { - TypeInfo::Struct(decl_ref) => { - if let Some(field_name) = ctx - .engines - .de() - .get_struct(&decl_ref) - .fields - .iter() - .find(|struct_field| { - // find the corresponding field in the containing type declaration - struct_field.name.as_str() == field.name.as_str() - }) - .map(|struct_field| struct_field.name.clone()) - { - token.type_def = Some(TypeDefinition::Ident(field_name)); - } - } - _ => { - token.type_def = Some(TypeDefinition::TypeId(field.type_id)); - } - } - } - } - } - self.rhs.parse(ctx); - } -} - fn assign_type_to_token( mut token: RefMut<(Ident, Span), Token>, symbol_kind: SymbolKind, diff --git a/test/src/e2e_vm_tests/test_programs/should_fail/storage_types/Forc.lock b/sway-lsp/tests/fixtures/tokens/storage/Forc.lock similarity index 54% rename from test/src/e2e_vm_tests/test_programs/should_fail/storage_types/Forc.lock rename to sway-lsp/tests/fixtures/tokens/storage/Forc.lock index 8fcae54f95d..b9dcc7b2ed1 100644 --- a/test/src/e2e_vm_tests/test_programs/should_fail/storage_types/Forc.lock +++ b/sway-lsp/tests/fixtures/tokens/storage/Forc.lock @@ -1,13 +1,13 @@ [[package]] name = 'core' -source = 'path+from-root-B427A21A0EB5F683' +source = 'path+from-root-37E4B1588712FA61' [[package]] name = 'std' -source = 'path+from-root-B427A21A0EB5F683' +source = 'path+from-root-37E4B1588712FA61' dependencies = ['core'] [[package]] -name = 'storage_types' +name = 'storage' source = 'member' dependencies = ['std'] diff --git a/sway-lsp/tests/fixtures/tokens/storage/.gitignore b/sway-lsp/tests/fixtures/tokens/storage/src/.gitignore similarity index 100% rename from sway-lsp/tests/fixtures/tokens/storage/.gitignore rename to sway-lsp/tests/fixtures/tokens/storage/src/.gitignore diff --git a/sway-lsp/tests/fixtures/tokens/storage/src/main.sw b/sway-lsp/tests/fixtures/tokens/storage/src/main.sw index c7369cdbe8e..d6345155212 100644 --- a/sway-lsp/tests/fixtures/tokens/storage/src/main.sw +++ b/sway-lsp/tests/fixtures/tokens/storage/src/main.sw @@ -22,8 +22,8 @@ abi StorageExample { impl StorageExample for Contract { #[storage(write)] fn store_something() { - storage.var1.x = 42; - storage.var1.y = true; - storage.var1.z.x = 1337; + storage.var1.x.write(42); + storage.var1.y.write(true); + storage.var1.z.x.write(1337); } } diff --git a/sway-lsp/tests/lib.rs b/sway-lsp/tests/lib.rs index d0e9834d600..46121dd40b8 100644 --- a/sway-lsp/tests/lib.rs +++ b/sway-lsp/tests/lib.rs @@ -913,95 +913,6 @@ async fn go_to_definition_for_traits() { shutdown_and_exit(&mut service).await; } -#[tokio::test] -async fn go_to_definition_for_storage() { - let (mut service, _) = LspService::new(Backend::new); - let uri = init_and_open( - &mut service, - test_fixtures_dir().join("tokens/storage/src/main.sw"), - ) - .await; - let mut i = 0..; - - let mut go_to = GotoDefinition { - req_uri: &uri, - req_line: 24, - req_char: 9, - def_line: 12, - def_start_char: 0, - def_end_char: 7, - def_path: "sway-lsp/tests/fixtures/tokens/storage/src/main.sw", - }; - // storage - let _ = lsp::definition_check(&mut service, &go_to, &mut i).await; - definition_check_with_req_offset(&mut service, &mut go_to, 25, 8, &mut i).await; - definition_check_with_req_offset(&mut service, &mut go_to, 26, 8, &mut i).await; - - let mut go_to = GotoDefinition { - req_uri: &uri, - req_line: 24, - req_char: 17, - def_line: 13, - def_start_char: 4, - def_end_char: 8, - def_path: "sway-lsp/tests/fixtures/tokens/storage/src/main.sw", - }; - // storage.var1 - let _ = lsp::definition_check(&mut service, &go_to, &mut i).await; - definition_check_with_req_offset(&mut service, &mut go_to, 25, 17, &mut i).await; - definition_check_with_req_offset(&mut service, &mut go_to, 26, 17, &mut i).await; - - let go_to = GotoDefinition { - req_uri: &uri, - req_line: 24, - req_char: 21, - def_line: 3, - def_start_char: 4, - def_end_char: 5, - def_path: "sway-lsp/tests/fixtures/tokens/storage/src/main.sw", - }; - // storage.var1.x - let _ = lsp::definition_check(&mut service, &go_to, &mut i).await; - - let go_to = GotoDefinition { - req_uri: &uri, - req_line: 25, - req_char: 21, - def_line: 4, - def_start_char: 4, - def_end_char: 5, - def_path: "sway-lsp/tests/fixtures/tokens/storage/src/main.sw", - }; - // storage.var1.y - let _ = lsp::definition_check(&mut service, &go_to, &mut i).await; - - let go_to = GotoDefinition { - req_uri: &uri, - req_line: 26, - req_char: 21, - def_line: 5, - def_start_char: 4, - def_end_char: 5, - def_path: "sway-lsp/tests/fixtures/tokens/storage/src/main.sw", - }; - // storage.var1.z - let _ = lsp::definition_check(&mut service, &go_to, &mut i).await; - - let go_to = GotoDefinition { - req_uri: &uri, - req_line: 26, - req_char: 23, - def_line: 9, - def_start_char: 4, - def_end_char: 5, - def_path: "sway-lsp/tests/fixtures/tokens/storage/src/main.sw", - }; - // storage.var1.z.x - let _ = lsp::definition_check(&mut service, &go_to, &mut i).await; - - shutdown_and_exit(&mut service).await; -} - #[tokio::test] async fn go_to_definition_for_variables() { let (mut service, _) = LspService::new(Backend::new); @@ -1651,7 +1562,7 @@ async fn hover_docs_for_boolean_keywords() { let _ = lsp::hover_request(&mut service, &hover, &mut i).await; hover.req_line = 25; - hover.req_char = 27; + hover.req_char = 31; hover.documentation = "\n```sway\ntrue\n```\n\n---\n\n A value of type [`bool`] representing logical **true**.\n\n Logically `true` is not equal to [`false`].\n\n ## Control structures that check for **true**\n\n Several of Sway's control structures will check for a `bool` condition evaluating to **true**.\n\n * The condition in an [`if`] expression must be of type `bool`.\n Whenever that condition evaluates to **true**, the `if` expression takes\n on the value of the first block. If however, the condition evaluates\n to `false`, the expression takes on value of the `else` block if there is one.\n\n * [`while`] is another control flow construct expecting a `bool`-typed condition.\n As long as the condition evaluates to **true**, the `while` loop will continually\n evaluate its associated block.\n\n * [`match`] arms can have guard clauses on them."; let _ = lsp::hover_request(&mut service, &hover, &mut i).await; } diff --git a/test/src/e2e_vm_tests/test_programs/should_fail/generics_in_contract/Forc.toml b/test/src/e2e_vm_tests/test_programs/should_fail/generics_in_contract/Forc.toml index bbcb95f27fc..c700ddd2969 100644 --- a/test/src/e2e_vm_tests/test_programs/should_fail/generics_in_contract/Forc.toml +++ b/test/src/e2e_vm_tests/test_programs/should_fail/generics_in_contract/Forc.toml @@ -1,7 +1,6 @@ [project] authors = ["Fuel Labs "] entry = "main.sw" -implicit-std = false license = "Apache-2.0" name = "generics_in_contract" diff --git a/test/src/e2e_vm_tests/test_programs/should_fail/generics_in_contract/src/main.sw b/test/src/e2e_vm_tests/test_programs/should_fail/generics_in_contract/src/main.sw index 71cae9d14da..a8988ff1daa 100644 --- a/test/src/e2e_vm_tests/test_programs/should_fail/generics_in_contract/src/main.sw +++ b/test/src/e2e_vm_tests/test_programs/should_fail/generics_in_contract/src/main.sw @@ -1,21 +1,21 @@ contract; -use std::{hash::sha256, storage::get}; +use std::{hash::sha256, storage::storage_api::read}; struct MyStorageMap {} -impl MyStorageMap { +impl StorageKey> { // This version puts the err on the `vec.push` statement because `vec` is // annotated with `Vec`. #[storage(read)] fn to_vec1(self, key: K) -> Vec { - let k = sha256((key, __get_storage_key())); - let len = get::(k).unwrap_or(0); + let k = sha256((key, self.slot)); + let len = read::(k, 0).unwrap_or(0); let mut i = 0; let mut vec: Vec = Vec::new(); while len > i { - let k = sha256((key, i, __get_storage_key())); - let item = get::(k).unwrap(); + let k = sha256((key, i, self.slot)); + let item = read::(k, 0).unwrap(); vec.push(item); // <----- i += 1; } @@ -26,13 +26,13 @@ impl MyStorageMap { // the type of `vec` (`Vec`) is taken from the `vec.push` statement. #[storage(read)] fn to_vec2(self, key: K) -> Vec { - let k = sha256((key, __get_storage_key())); - let len = get::(k).unwrap_or(0); + let k = sha256((key, self.slot)); + let len = read::(k, 0).unwrap_or(0); let mut i = 0; let mut vec/*: Vec*/ = Vec::new(); while len > i { - let k = sha256((key, i, __get_storage_key())); - let item = get::(k).unwrap(); + let k = sha256((key, i, self.slot)); + let item = read::(k, 0).unwrap(); vec.push(item); // <----- i += 1; } diff --git a/test/src/e2e_vm_tests/test_programs/should_fail/nonconst_storage_init/Forc.lock b/test/src/e2e_vm_tests/test_programs/should_fail/nonconst_storage_init/Forc.lock index f378d047ede..4df8b711f03 100644 --- a/test/src/e2e_vm_tests/test_programs/should_fail/nonconst_storage_init/Forc.lock +++ b/test/src/e2e_vm_tests/test_programs/should_fail/nonconst_storage_init/Forc.lock @@ -5,4 +5,9 @@ source = 'path+from-root-BC4E87DB22234D76' [[package]] name = 'repeated_storage_field' source = 'member' +dependencies = ['std'] + +[[package]] +name = 'std' +source = 'path+from-root-BC4E87DB22234D76' dependencies = ['core'] diff --git a/test/src/e2e_vm_tests/test_programs/should_fail/nonconst_storage_init/Forc.toml b/test/src/e2e_vm_tests/test_programs/should_fail/nonconst_storage_init/Forc.toml index 38cf33b2e6f..53982aa2b7d 100644 --- a/test/src/e2e_vm_tests/test_programs/should_fail/nonconst_storage_init/Forc.toml +++ b/test/src/e2e_vm_tests/test_programs/should_fail/nonconst_storage_init/Forc.toml @@ -5,4 +5,4 @@ license = "Apache-2.0" name = "repeated_storage_field" [dependencies] -core = { path = "../../../../../../sway-lib-core" } +std = { path = "../../../../../../sway-lib-std" } diff --git a/test/src/e2e_vm_tests/test_programs/should_fail/nonconst_storage_init/src/main.sw b/test/src/e2e_vm_tests/test_programs/should_fail/nonconst_storage_init/src/main.sw index 76a2f1ce081..1293e028274 100644 --- a/test/src/e2e_vm_tests/test_programs/should_fail/nonconst_storage_init/src/main.sw +++ b/test/src/e2e_vm_tests/test_programs/should_fail/nonconst_storage_init/src/main.sw @@ -1,7 +1,5 @@ contract; -use core::*; - storage { x: u64 = 18446744073709551615 + 1, y: u64 = 5 + 5, @@ -15,7 +13,7 @@ abi Test { impl Test for Contract { #[storage(read, write)] fn foo() { - storage.x += 1; - storage.y += 1; + storage.x.write(storage.x.read() + 1); + storage.y.write(storage.y.read() + 1); } } diff --git a/test/src/e2e_vm_tests/test_programs/should_fail/storage_clear_incorrect_purity_annotation/src/main.sw b/test/src/e2e_vm_tests/test_programs/should_fail/storage_clear_incorrect_purity_annotation/src/main.sw index d21be5584ef..c498c6f1d9e 100644 --- a/test/src/e2e_vm_tests/test_programs/should_fail/storage_clear_incorrect_purity_annotation/src/main.sw +++ b/test/src/e2e_vm_tests/test_programs/should_fail/storage_clear_incorrect_purity_annotation/src/main.sw @@ -6,6 +6,6 @@ abi MyContract { impl MyContract for Contract { fn test_function() { - std::storage::clear(0x0000000000000000000000000000000000000000000000000000000000000000); + std::storage::storage_api::clear(0x0000000000000000000000000000000000000000000000000000000000000000); } } diff --git a/test/src/e2e_vm_tests/test_programs/should_fail/storage_types/src/main.sw b/test/src/e2e_vm_tests/test_programs/should_fail/storage_types/src/main.sw deleted file mode 100644 index a45f8fe4237..00000000000 --- a/test/src/e2e_vm_tests/test_programs/should_fail/storage_types/src/main.sw +++ /dev/null @@ -1,86 +0,0 @@ -contract; - -use std::storage::StorageVec; - -struct Wrapper { - map1: StorageMap, - vec2: StorageVec, -} - -storage { - w: Wrapper = Wrapper { map1: StorageMap {}, vec2: StorageVec {} }, - v: StorageVec = StorageVec {}, - u: StorageVec> = StorageVec {}, - map1: StorageMap = StorageMap{}, - bad_type: StorageVec> = StorageVec {}, -} - -abi MyContract { - #[storage(read, write)] - fn main() -> u64; - - #[storage(read)] - fn return_storage_map() -> StorageMap; - - #[storage(read)] - fn return_storage_vec() -> StorageVec; -} - -impl MyContract for Contract { - #[storage(read, write)] - fn main() -> u64 { - let local_map1: StorageMap = StorageMap {}; - let local_vec1: StorageVec = StorageVec {}; - - local_map1.insert(1, 2); - local_vec1.push(1); - storage.w.map1.insert(1, 2); - storage.w.vec2.push(1); - - let local_map2 = storage.map1; - local_map2.insert(11, 11); - - 1 - } - - #[storage(read)] - fn return_storage_map() -> StorageMap { - storage.map1 - } - - #[storage(read)] - fn return_storage_vec() -> StorageVec { - storage.v - } -} - -#[storage(write)] -fn insert(mapping: StorageMap) { - mapping.insert(1, 1); -} - -#[storage(read)] -fn return_storage_vec_standalone_fn() -> StorageVec { - storage.v -} - -pub struct MyStruct { } - -impl MyStruct { - #[storage(read, write)] - pub fn takes_storage_struct_in_impl(self, my_struct: StorageVec) { - my_struct.push(5); - } -} - -pub trait MyTrait { - #[storage(read, write)] - fn takes_storage_struct_in_trait_impl(self, my_struct: StorageVec); -} - -impl MyTrait for MyStruct { - #[storage(read, write)] - fn takes_storage_struct_in_trait_impl(self, my_struct: StorageVec) { - my_struct.push(5); - } -} diff --git a/test/src/e2e_vm_tests/test_programs/should_fail/storage_types/test.toml b/test/src/e2e_vm_tests/test_programs/should_fail/storage_types/test.toml deleted file mode 100644 index 78069bfa4c9..00000000000 --- a/test/src/e2e_vm_tests/test_programs/should_fail/storage_types/test.toml +++ /dev/null @@ -1,66 +0,0 @@ -category = "fail" - -# check: $()error -# check: $()struct Wrapper { -# nextln: $()map1: StorageMap -# nextln: $()Type StorageMap can only be declared directly as a storage field - -# check: $()error -# check: $()map1: StorageMap -# nextln: $()vec2: StorageVec -# nextln: $()Type StorageVec can only be declared directly as a storage field - -# check: $()error -# check: $()storage { -# nextln: $()w: Wrapper = Wrapper { map1: StorageMap {}, vec2: StorageVec {} } -# nextln: $()Type StorageMap can only be declared directly as a storage field - -# check: $()error -# check: $()storage { -# nextln: $()w: Wrapper = Wrapper { map1: StorageMap {}, vec2: StorageVec {} } -# nextln: $()Type StorageVec can only be declared directly as a storage field - -# check: $()error -# check: $()v: StorageVec = StorageVec {} -# nextln: $()u: StorageVec> = StorageVec {} -# nextln: $()Type StorageVec can only be declared directly as a storage field - -# check: $()error -# check: $()let local_map1: StorageMap = StorageMap {}; -# nextln: $()Type StorageMap can only be declared directly as a storage field - -# check: $()error -# check: $()let local_vec1: StorageVec = StorageVec {}; -# nextln: $()Type StorageVec can only be declared directly as a storage field - -# check: $()error -# check: $()let local_map2 = storage.map1; -# nextln: $()Type StorageMap can only be declared directly as a storage field - -# check: $()error -# check: $()fn return_storage_map() -> StorageMap { -# nextln: $()Type StorageMap can only be declared directly as a storage field - -# check: $()error -# check: $()fn return_storage_vec() -> StorageVec { -# nextln: $()Type StorageVec can only be declared directly as a storage field - -# check: $()error -# check: $()fn insert(mapping: StorageMap) { -# nextln: $()Type StorageMap can only be declared directly as a storage field - -# check: $()error -# check: $()fn return_storage_vec_standalone_fn() -> StorageVec { -# nextln: $()Type StorageVec can only be declared directly as a storage field - -# check: $()error -# check: $()pub fn takes_storage_struct_in_impl(self, my_struct: StorageVec) { -# nextln: $()Type StorageVec can only be declared directly as a storage field - -# check: $()error -# check: $()fn takes_storage_struct_in_trait_impl(self, my_struct: StorageVec) { -# nextln: $()Type StorageVec can only be declared directly as a storage field - -# check: $()error -# check: $()bad_type: StorageVec> = StorageVec {}, -# nextln: $()The type "StorageVec>" is not allowed in storage. diff --git a/test/src/e2e_vm_tests/test_programs/should_pass/non_payable_implicit_zero_coins/src/wallet.sw b/test/src/e2e_vm_tests/test_programs/should_pass/non_payable_implicit_zero_coins/src/wallet.sw index af8a50904a8..56d07058103 100644 --- a/test/src/e2e_vm_tests/test_programs/should_pass/non_payable_implicit_zero_coins/src/wallet.sw +++ b/test/src/e2e_vm_tests/test_programs/should_pass/non_payable_implicit_zero_coins/src/wallet.sw @@ -24,7 +24,7 @@ impl Wallet for Contract { #[payable, storage(read, write)] fn receive_funds() { if msg_asset_id() == BASE_ASSET_ID { - storage.balance += msg_amount(); + storage.balance.write(storage.balance.read() + msg_amount()); } } @@ -36,10 +36,10 @@ impl Wallet for Contract { _ => revert(0), }; - let current_balance = storage.balance; + let current_balance = storage.balance.read(); assert(current_balance >= amount_to_send); - storage.balance = current_balance - amount_to_send; + storage.balance.write(current_balance - amount_to_send); transfer_to_address(amount_to_send, BASE_ASSET_ID, recipient_address); } diff --git a/test/src/e2e_vm_tests/test_programs/should_pass/non_payable_zero_coins_let_binding/src/wallet.sw b/test/src/e2e_vm_tests/test_programs/should_pass/non_payable_zero_coins_let_binding/src/wallet.sw index af8a50904a8..56d07058103 100644 --- a/test/src/e2e_vm_tests/test_programs/should_pass/non_payable_zero_coins_let_binding/src/wallet.sw +++ b/test/src/e2e_vm_tests/test_programs/should_pass/non_payable_zero_coins_let_binding/src/wallet.sw @@ -24,7 +24,7 @@ impl Wallet for Contract { #[payable, storage(read, write)] fn receive_funds() { if msg_asset_id() == BASE_ASSET_ID { - storage.balance += msg_amount(); + storage.balance.write(storage.balance.read() + msg_amount()); } } @@ -36,10 +36,10 @@ impl Wallet for Contract { _ => revert(0), }; - let current_balance = storage.balance; + let current_balance = storage.balance.read(); assert(current_balance >= amount_to_send); - storage.balance = current_balance - amount_to_send; + storage.balance.write(current_balance - amount_to_send); transfer_to_address(amount_to_send, BASE_ASSET_ID, recipient_address); } diff --git a/test/src/e2e_vm_tests/test_programs/should_pass/payable_non_zero_coins/src/wallet.sw b/test/src/e2e_vm_tests/test_programs/should_pass/payable_non_zero_coins/src/wallet.sw index af8a50904a8..56d07058103 100644 --- a/test/src/e2e_vm_tests/test_programs/should_pass/payable_non_zero_coins/src/wallet.sw +++ b/test/src/e2e_vm_tests/test_programs/should_pass/payable_non_zero_coins/src/wallet.sw @@ -24,7 +24,7 @@ impl Wallet for Contract { #[payable, storage(read, write)] fn receive_funds() { if msg_asset_id() == BASE_ASSET_ID { - storage.balance += msg_amount(); + storage.balance.write(storage.balance.read() + msg_amount()); } } @@ -36,10 +36,10 @@ impl Wallet for Contract { _ => revert(0), }; - let current_balance = storage.balance; + let current_balance = storage.balance.read(); assert(current_balance >= amount_to_send); - storage.balance = current_balance - amount_to_send; + storage.balance.write(current_balance - amount_to_send); transfer_to_address(amount_to_send, BASE_ASSET_ID, recipient_address); } diff --git a/test/src/e2e_vm_tests/test_programs/should_pass/require_contract_deployment/call_basic_storage/src/main.sw b/test/src/e2e_vm_tests/test_programs/should_pass/require_contract_deployment/call_basic_storage/src/main.sw index fd02c728e16..7d984e9f9c9 100644 --- a/test/src/e2e_vm_tests/test_programs/should_pass/require_contract_deployment/call_basic_storage/src/main.sw +++ b/test/src/e2e_vm_tests/test_programs/should_pass/require_contract_deployment/call_basic_storage/src/main.sw @@ -2,8 +2,8 @@ script; use basic_storage_abi::{BasicStorage, Quad}; fn main() -> u64 { - let addr = abi(BasicStorage, 0x6906bdbccb7ca8e66c11ce16518c2f946da094d3e2c8561ca38d5a6d9a13e996); - let key = 0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff; + let addr = abi(BasicStorage, 0x47ddf698943d2327a24e9ef44c8d21f752d5d9eedd8d5f29c1835c3ba0092f28); + let key = 0x0fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff; let value = 4242; /* Simple test using `store` and `get` from `std::storage */ diff --git a/test/src/e2e_vm_tests/test_programs/should_pass/require_contract_deployment/call_increment_contract/src/main.sw b/test/src/e2e_vm_tests/test_programs/should_pass/require_contract_deployment/call_increment_contract/src/main.sw index a670332f4ab..5cc6cd8747c 100644 --- a/test/src/e2e_vm_tests/test_programs/should_pass/require_contract_deployment/call_increment_contract/src/main.sw +++ b/test/src/e2e_vm_tests/test_programs/should_pass/require_contract_deployment/call_increment_contract/src/main.sw @@ -3,7 +3,7 @@ script; use increment_abi::Incrementor; fn main() -> bool { - let the_abi = abi(Incrementor, 0x6b259c454583b3995b9e35effa476f8cb2155ff44d1d8d567a83108b4fe65444); + let the_abi = abi(Incrementor, 0xa99b5dd42245f9d214f8066a2bb92439cc3e2282625d1980b50552b2f64de2b1); the_abi.increment(5); the_abi.increment(5); let result = the_abi.get(); diff --git a/test/src/e2e_vm_tests/test_programs/should_pass/require_contract_deployment/get_storage_key_caller/Forc.lock b/test/src/e2e_vm_tests/test_programs/should_pass/require_contract_deployment/get_storage_key_caller/Forc.lock deleted file mode 100644 index e9214ef6cdc..00000000000 --- a/test/src/e2e_vm_tests/test_programs/should_pass/require_contract_deployment/get_storage_key_caller/Forc.lock +++ /dev/null @@ -1,20 +0,0 @@ -[[package]] -name = 'core' -source = 'path+from-root-B3844A485BCDB5F7' - -[[package]] -name = 'get_storage_key_abi' -source = 'path+from-root-B3844A485BCDB5F7' - -[[package]] -name = 'get_storage_key_caller' -source = 'member' -dependencies = [ - 'get_storage_key_abi', - 'std', -] - -[[package]] -name = 'std' -source = 'path+from-root-B3844A485BCDB5F7' -dependencies = ['core'] diff --git a/test/src/e2e_vm_tests/test_programs/should_pass/require_contract_deployment/get_storage_key_caller/Forc.toml b/test/src/e2e_vm_tests/test_programs/should_pass/require_contract_deployment/get_storage_key_caller/Forc.toml deleted file mode 100644 index f902d59c081..00000000000 --- a/test/src/e2e_vm_tests/test_programs/should_pass/require_contract_deployment/get_storage_key_caller/Forc.toml +++ /dev/null @@ -1,9 +0,0 @@ -[project] -authors = ["Fuel Labs "] -entry = "main.sw" -license = "Apache-2.0" -name = "get_storage_key_caller" - -[dependencies] -get_storage_key_abi = { path = "../../test_abis/get_storage_key_abi" } -std = { path = "../../../../../../../sway-lib-std" } diff --git a/test/src/e2e_vm_tests/test_programs/should_pass/require_contract_deployment/get_storage_key_caller/json_abi_oracle.json b/test/src/e2e_vm_tests/test_programs/should_pass/require_contract_deployment/get_storage_key_caller/json_abi_oracle.json deleted file mode 100644 index 0637a088a01..00000000000 --- a/test/src/e2e_vm_tests/test_programs/should_pass/require_contract_deployment/get_storage_key_caller/json_abi_oracle.json +++ /dev/null @@ -1 +0,0 @@ -[] \ No newline at end of file diff --git a/test/src/e2e_vm_tests/test_programs/should_pass/require_contract_deployment/get_storage_key_caller/src/main.sw b/test/src/e2e_vm_tests/test_programs/should_pass/require_contract_deployment/get_storage_key_caller/src/main.sw deleted file mode 100644 index 7b108518e93..00000000000 --- a/test/src/e2e_vm_tests/test_programs/should_pass/require_contract_deployment/get_storage_key_caller/src/main.sw +++ /dev/null @@ -1,42 +0,0 @@ -script; - -use get_storage_key_abi::TestContract; - -fn main() -> u64 { - let caller = abi(TestContract, 0xfd77b8770d4b9ad2402e8d6c838c8a837d2a56dd02ec4445c4c212bfce66b143); - - // Get the storage keys directly by calling the contract methods from_f1, - // from_f2, from_f3, from_f4. The keys correspond to different entries in - // the storage block so they should return different values. - let f1 = caller.from_f1(); - assert(f1 == caller.from_f1()); - - let f2 = caller.from_f2(); - assert(f2 == caller.from_f2()); - - let f3 = caller.from_f3(); - assert(f3 == caller.from_f3()); - - let f4 = caller.from_f4(); - assert(f4 == caller.from_f4()); - - assert(f1 != f2); - assert(f1 != f3); - assert(f1 != f4); - - assert(f2 != f3); - assert(f2 != f4); - - assert(f3 != f4); - - // Get the storage keys but using from_callers. This should work and the - // same keys as above should be returned. This checks that inlining is - // working as intended. - let(caller_f1, caller_f2, caller_f3, caller_f4) = caller.from_callers(); - assert(f1 == caller_f1); - assert(f2 == caller_f2); - assert(f3 == caller_f3); - assert(f4 == caller_f4); - - 1 -} diff --git a/test/src/e2e_vm_tests/test_programs/should_pass/require_contract_deployment/get_storage_key_caller/test.toml b/test/src/e2e_vm_tests/test_programs/should_pass/require_contract_deployment/get_storage_key_caller/test.toml deleted file mode 100644 index 559f02e1da5..00000000000 --- a/test/src/e2e_vm_tests/test_programs/should_pass/require_contract_deployment/get_storage_key_caller/test.toml +++ /dev/null @@ -1,3 +0,0 @@ -category = "run_on_node" -expected_result = { action = "result", value = 1 } -contracts = ["should_pass/test_contracts/get_storage_key_contract"] diff --git a/test/src/e2e_vm_tests/test_programs/should_pass/require_contract_deployment/storage_access_caller/src/main.sw b/test/src/e2e_vm_tests/test_programs/should_pass/require_contract_deployment/storage_access_caller/src/main.sw index a1eefc7fee2..92bd51e9585 100644 --- a/test/src/e2e_vm_tests/test_programs/should_pass/require_contract_deployment/storage_access_caller/src/main.sw +++ b/test/src/e2e_vm_tests/test_programs/should_pass/require_contract_deployment/storage_access_caller/src/main.sw @@ -4,7 +4,7 @@ use storage_access_abi::*; use std::hash::sha256; fn main() -> bool { - let contract_id = 0x8982d742b1f313818d24516f7410519ca4fd4bbab470012809ffde710c45c0a4; + let contract_id = 0x0d2dcfa21906257722b0a983429c70ebfb543a4905e4913bd1f844bf7ae8f9ed; let caller = abi(StorageAccess, contract_id); // Test initializers @@ -163,25 +163,6 @@ fn main() -> bool { assert(t.y == 12); assert(t.z == 0x0000000000000000000000000000000000000000000000000000000000000006); - // Test operations on `s.t.x` - caller.add_to_s_dot_t_dot_x(15); - assert(caller.get_s_dot_t_dot_x() == 26); // 11 + 15 - - caller.subtract_from_s_dot_t_dot_x(6); - assert(caller.get_s_dot_t_dot_x() == 20); // 26 - 6 - - caller.multiply_by_s_dot_t_dot_x(5); - assert(caller.get_s_dot_t_dot_x() == 100); // 20 * 5 - - caller.divide_s_dot_t_dot_x(2); - assert(caller.get_s_dot_t_dot_x() == 50); // 100 / 2 - - caller.shift_left_s_dot_t_dot_x(3); - assert(caller.get_s_dot_t_dot_x() == 400); // 50 << 3 - - caller.shift_right_s_dot_t_dot_x(2); - assert(caller.get_s_dot_t_dot_x() == 100); // 400 >> 2 - // Test 13 caller.set_e(E::A(42)); let e = caller.get_e(); diff --git a/test/src/e2e_vm_tests/test_programs/should_pass/static_analysis/cei_pattern_violation/src/main.sw b/test/src/e2e_vm_tests/test_programs/should_pass/static_analysis/cei_pattern_violation/src/main.sw index f92044bef63..77b54ee15e4 100644 --- a/test/src/e2e_vm_tests/test_programs/should_pass/static_analysis/cei_pattern_violation/src/main.sw +++ b/test/src/e2e_vm_tests/test_programs/should_pass/static_analysis/cei_pattern_violation/src/main.sw @@ -1,6 +1,6 @@ contract; -use std::storage::store; +use std::storage::storage_api::write; abi TestAbi { #[storage(write)] @@ -16,6 +16,6 @@ impl TestAbi for Contract { other_contract.deposit(); // effect -- therefore violation of CEI where effect should go before interaction let storage_key = 0x3dba0a4455b598b7655a7fb430883d96c9527ef275b49739e7b0ad12f8280eae; - store(storage_key, ()); + write(storage_key, 0, ()); } } diff --git a/test/src/e2e_vm_tests/test_programs/should_pass/static_analysis/cei_pattern_violation/test.toml b/test/src/e2e_vm_tests/test_programs/should_pass/static_analysis/cei_pattern_violation/test.toml index b6e8c1960bd..d61220251df 100644 --- a/test/src/e2e_vm_tests/test_programs/should_pass/static_analysis/cei_pattern_violation/test.toml +++ b/test/src/e2e_vm_tests/test_programs/should_pass/static_analysis/cei_pattern_violation/test.toml @@ -1,4 +1,4 @@ category = "compile" # check: $()Storage write after external contract interaction in function or method "deposit". Consider making all storage writes before calling another contract -expected_warnings = 1 +expected_warnings = 2 diff --git a/test/src/e2e_vm_tests/test_programs/should_pass/static_analysis/cei_pattern_violation_in_codeblocks_other_than_in_functions/src/main.sw b/test/src/e2e_vm_tests/test_programs/should_pass/static_analysis/cei_pattern_violation_in_codeblocks_other_than_in_functions/src/main.sw index 6e502d06b8f..512e9e044b0 100644 --- a/test/src/e2e_vm_tests/test_programs/should_pass/static_analysis/cei_pattern_violation_in_codeblocks_other_than_in_functions/src/main.sw +++ b/test/src/e2e_vm_tests/test_programs/should_pass/static_analysis/cei_pattern_violation_in_codeblocks_other_than_in_functions/src/main.sw @@ -1,6 +1,6 @@ contract; -use std::storage::store; +use std::storage::storage_api::write; abi TestAbi { #[storage(write)] @@ -19,7 +19,7 @@ impl TestAbi for Contract { // effect -- therefore violation of CEI where effect should go before interaction let storage_key = 0x3dba0a4455b598b7655a7fb430883d96c9527ef275b49739e7b0ad12f8280eae; - store(storage_key, ()); + write(storage_key, 0, ()); } } } diff --git a/test/src/e2e_vm_tests/test_programs/should_pass/static_analysis/cei_pattern_violation_in_codeblocks_other_than_in_functions/test.toml b/test/src/e2e_vm_tests/test_programs/should_pass/static_analysis/cei_pattern_violation_in_codeblocks_other_than_in_functions/test.toml index b6e8c1960bd..d61220251df 100644 --- a/test/src/e2e_vm_tests/test_programs/should_pass/static_analysis/cei_pattern_violation_in_codeblocks_other_than_in_functions/test.toml +++ b/test/src/e2e_vm_tests/test_programs/should_pass/static_analysis/cei_pattern_violation_in_codeblocks_other_than_in_functions/test.toml @@ -1,4 +1,4 @@ category = "compile" # check: $()Storage write after external contract interaction in function or method "deposit". Consider making all storage writes before calling another contract -expected_warnings = 1 +expected_warnings = 2 diff --git a/test/src/e2e_vm_tests/test_programs/should_pass/static_analysis/cei_pattern_violation_in_func_app-1/src/main.sw b/test/src/e2e_vm_tests/test_programs/should_pass/static_analysis/cei_pattern_violation_in_func_app-1/src/main.sw index 25e38213332..cb84c81ba2a 100644 --- a/test/src/e2e_vm_tests/test_programs/should_pass/static_analysis/cei_pattern_violation_in_func_app-1/src/main.sw +++ b/test/src/e2e_vm_tests/test_programs/should_pass/static_analysis/cei_pattern_violation_in_func_app-1/src/main.sw @@ -1,6 +1,6 @@ contract; -use std::storage::store; +use std::storage::storage_api::write; abi TestAbi { #[storage(write)] @@ -20,7 +20,7 @@ impl TestAbi for Contract { // interaction abi(TestAbi, 0x3dba0a4455b598b7655a7fb430883d96c9527ef275b49739e7b0ad12f8280eae).deposit(amount); // effect -- therefore violation of CEI where effect should go before interaction - store(0x3dba0a4455b598b7655a7fb430883d96c9527ef275b49739e7b0ad12f8280eae, ()); + write(0x3dba0a4455b598b7655a7fb430883d96c9527ef275b49739e7b0ad12f8280eae, 0, ()); 42 } ); diff --git a/test/src/e2e_vm_tests/test_programs/should_pass/static_analysis/cei_pattern_violation_in_func_app-1/test.toml b/test/src/e2e_vm_tests/test_programs/should_pass/static_analysis/cei_pattern_violation_in_func_app-1/test.toml index d61220251df..7105f663a21 100644 --- a/test/src/e2e_vm_tests/test_programs/should_pass/static_analysis/cei_pattern_violation_in_func_app-1/test.toml +++ b/test/src/e2e_vm_tests/test_programs/should_pass/static_analysis/cei_pattern_violation_in_func_app-1/test.toml @@ -1,4 +1,4 @@ category = "compile" # check: $()Storage write after external contract interaction in function or method "deposit". Consider making all storage writes before calling another contract -expected_warnings = 2 +expected_warnings = 3 diff --git a/test/src/e2e_vm_tests/test_programs/should_pass/static_analysis/cei_pattern_violation_in_func_app-2/src/main.sw b/test/src/e2e_vm_tests/test_programs/should_pass/static_analysis/cei_pattern_violation_in_func_app-2/src/main.sw index 2c6a8059a80..1e1e31029bb 100644 --- a/test/src/e2e_vm_tests/test_programs/should_pass/static_analysis/cei_pattern_violation_in_func_app-2/src/main.sw +++ b/test/src/e2e_vm_tests/test_programs/should_pass/static_analysis/cei_pattern_violation_in_func_app-2/src/main.sw @@ -1,6 +1,6 @@ contract; -use std::storage::store; +use std::storage::storage_api::write; abi TestAbi { #[storage(write)] @@ -25,7 +25,7 @@ impl TestAbi for Contract { { // effect -- therefore violation of CEI where effect should go before interaction // (assuming left-to-right function argument evaluation) - store(0x3dba0a4455b598b7655a7fb430883d96c9527ef275b49739e7b0ad12f8280eae, ()); + write(0x3dba0a4455b598b7655a7fb430883d96c9527ef275b49739e7b0ad12f8280eae, 0, ()); 43 } ); diff --git a/test/src/e2e_vm_tests/test_programs/should_pass/static_analysis/cei_pattern_violation_in_func_app-2/test.toml b/test/src/e2e_vm_tests/test_programs/should_pass/static_analysis/cei_pattern_violation_in_func_app-2/test.toml index d61220251df..7105f663a21 100644 --- a/test/src/e2e_vm_tests/test_programs/should_pass/static_analysis/cei_pattern_violation_in_func_app-2/test.toml +++ b/test/src/e2e_vm_tests/test_programs/should_pass/static_analysis/cei_pattern_violation_in_func_app-2/test.toml @@ -1,4 +1,4 @@ category = "compile" # check: $()Storage write after external contract interaction in function or method "deposit". Consider making all storage writes before calling another contract -expected_warnings = 2 +expected_warnings = 3 diff --git a/test/src/e2e_vm_tests/test_programs/should_pass/static_analysis/cei_pattern_violation_in_func_app-3/src/main.sw b/test/src/e2e_vm_tests/test_programs/should_pass/static_analysis/cei_pattern_violation_in_func_app-3/src/main.sw index adcf72a74f5..7d8e01f2239 100644 --- a/test/src/e2e_vm_tests/test_programs/should_pass/static_analysis/cei_pattern_violation_in_func_app-3/src/main.sw +++ b/test/src/e2e_vm_tests/test_programs/should_pass/static_analysis/cei_pattern_violation_in_func_app-3/src/main.sw @@ -1,6 +1,6 @@ contract; -use std::storage::store; +use std::storage::storage_api::write; abi TestAbi { #[storage(write)] @@ -10,7 +10,7 @@ abi TestAbi { #[storage(write)] fn do_something(_x: u64) { // effect - store(0x3dba0a4455b598b7655a7fb430883d96c9527ef275b49739e7b0ad12f8280eae, ()); + write(0x3dba0a4455b598b7655a7fb430883d96c9527ef275b49739e7b0ad12f8280eae, 0, ()); } impl TestAbi for Contract { diff --git a/test/src/e2e_vm_tests/test_programs/should_pass/static_analysis/cei_pattern_violation_in_func_app-3/test.toml b/test/src/e2e_vm_tests/test_programs/should_pass/static_analysis/cei_pattern_violation_in_func_app-3/test.toml index b6e8c1960bd..d61220251df 100644 --- a/test/src/e2e_vm_tests/test_programs/should_pass/static_analysis/cei_pattern_violation_in_func_app-3/test.toml +++ b/test/src/e2e_vm_tests/test_programs/should_pass/static_analysis/cei_pattern_violation_in_func_app-3/test.toml @@ -1,4 +1,4 @@ category = "compile" # check: $()Storage write after external contract interaction in function or method "deposit". Consider making all storage writes before calling another contract -expected_warnings = 1 +expected_warnings = 2 diff --git a/test/src/e2e_vm_tests/test_programs/should_pass/static_analysis/cei_pattern_violation_in_if_statement-1/src/main.sw b/test/src/e2e_vm_tests/test_programs/should_pass/static_analysis/cei_pattern_violation_in_if_statement-1/src/main.sw index 8bad15ef342..95e6996a6c4 100644 --- a/test/src/e2e_vm_tests/test_programs/should_pass/static_analysis/cei_pattern_violation_in_if_statement-1/src/main.sw +++ b/test/src/e2e_vm_tests/test_programs/should_pass/static_analysis/cei_pattern_violation_in_if_statement-1/src/main.sw @@ -1,6 +1,6 @@ contract; -use std::storage::store; +use std::storage::storage_api::write; abi TestAbi { #[storage(write)] @@ -18,7 +18,7 @@ impl TestAbi for Contract { if amount == 42 { // effect -- therefore violation of CEI where effect should go before interaction let storage_key = 0x3dba0a4455b598b7655a7fb430883d96c9527ef275b49739e7b0ad12f8280eae; - store(storage_key, ()); + write(storage_key, 0, ()); } } } diff --git a/test/src/e2e_vm_tests/test_programs/should_pass/static_analysis/cei_pattern_violation_in_if_statement-1/test.toml b/test/src/e2e_vm_tests/test_programs/should_pass/static_analysis/cei_pattern_violation_in_if_statement-1/test.toml index b6e8c1960bd..d61220251df 100644 --- a/test/src/e2e_vm_tests/test_programs/should_pass/static_analysis/cei_pattern_violation_in_if_statement-1/test.toml +++ b/test/src/e2e_vm_tests/test_programs/should_pass/static_analysis/cei_pattern_violation_in_if_statement-1/test.toml @@ -1,4 +1,4 @@ category = "compile" # check: $()Storage write after external contract interaction in function or method "deposit". Consider making all storage writes before calling another contract -expected_warnings = 1 +expected_warnings = 2 diff --git a/test/src/e2e_vm_tests/test_programs/should_pass/static_analysis/cei_pattern_violation_in_if_statement-2/src/main.sw b/test/src/e2e_vm_tests/test_programs/should_pass/static_analysis/cei_pattern_violation_in_if_statement-2/src/main.sw index 6c1de25447a..6eeb4b034c4 100644 --- a/test/src/e2e_vm_tests/test_programs/should_pass/static_analysis/cei_pattern_violation_in_if_statement-2/src/main.sw +++ b/test/src/e2e_vm_tests/test_programs/should_pass/static_analysis/cei_pattern_violation_in_if_statement-2/src/main.sw @@ -1,6 +1,6 @@ contract; -use std::storage::store; +use std::storage::storage_api::write; abi TestAbi { #[storage(write)] @@ -19,7 +19,7 @@ impl TestAbi for Contract { } { // effect -- therefore violation of CEI where effect should go before interaction - store(0x3dba0a4455b598b7655a7fb430883d96c9527ef275b49739e7b0ad12f8280eae, ()) + write(0x3dba0a4455b598b7655a7fb430883d96c9527ef275b49739e7b0ad12f8280eae, 0, ()) } } } diff --git a/test/src/e2e_vm_tests/test_programs/should_pass/static_analysis/cei_pattern_violation_in_if_statement-2/test.toml b/test/src/e2e_vm_tests/test_programs/should_pass/static_analysis/cei_pattern_violation_in_if_statement-2/test.toml index b6e8c1960bd..d61220251df 100644 --- a/test/src/e2e_vm_tests/test_programs/should_pass/static_analysis/cei_pattern_violation_in_if_statement-2/test.toml +++ b/test/src/e2e_vm_tests/test_programs/should_pass/static_analysis/cei_pattern_violation_in_if_statement-2/test.toml @@ -1,4 +1,4 @@ category = "compile" # check: $()Storage write after external contract interaction in function or method "deposit". Consider making all storage writes before calling another contract -expected_warnings = 1 +expected_warnings = 2 diff --git a/test/src/e2e_vm_tests/test_programs/should_pass/static_analysis/cei_pattern_violation_in_intrinsic_call/src/main.sw b/test/src/e2e_vm_tests/test_programs/should_pass/static_analysis/cei_pattern_violation_in_intrinsic_call/src/main.sw index 6dea3fe6c4f..f746aa57d98 100644 --- a/test/src/e2e_vm_tests/test_programs/should_pass/static_analysis/cei_pattern_violation_in_intrinsic_call/src/main.sw +++ b/test/src/e2e_vm_tests/test_programs/should_pass/static_analysis/cei_pattern_violation_in_intrinsic_call/src/main.sw @@ -1,6 +1,6 @@ contract; -use std::storage::store; +use std::storage::storage_api::write; abi TestAbi { #[storage(write)] @@ -21,7 +21,7 @@ impl TestAbi for Contract { { // effect -- therefore violation of CEI where effect should go before interaction // (assuming left-to-right function argument evaluation) - store(0x3dba0a4455b598b7655a7fb430883d96c9527ef275b49739e7b0ad12f8280eae, ()); + write(0x3dba0a4455b598b7655a7fb430883d96c9527ef275b49739e7b0ad12f8280eae, 0, ()); 21 } ); diff --git a/test/src/e2e_vm_tests/test_programs/should_pass/static_analysis/cei_pattern_violation_in_intrinsic_call/test.toml b/test/src/e2e_vm_tests/test_programs/should_pass/static_analysis/cei_pattern_violation_in_intrinsic_call/test.toml index d61220251df..7105f663a21 100644 --- a/test/src/e2e_vm_tests/test_programs/should_pass/static_analysis/cei_pattern_violation_in_intrinsic_call/test.toml +++ b/test/src/e2e_vm_tests/test_programs/should_pass/static_analysis/cei_pattern_violation_in_intrinsic_call/test.toml @@ -1,4 +1,4 @@ category = "compile" # check: $()Storage write after external contract interaction in function or method "deposit". Consider making all storage writes before calling another contract -expected_warnings = 2 +expected_warnings = 3 diff --git a/test/src/e2e_vm_tests/test_programs/should_pass/static_analysis/cei_pattern_violation_in_match_statement-1/src/main.sw b/test/src/e2e_vm_tests/test_programs/should_pass/static_analysis/cei_pattern_violation_in_match_statement-1/src/main.sw index 71093b71b58..1e7a21996ce 100644 --- a/test/src/e2e_vm_tests/test_programs/should_pass/static_analysis/cei_pattern_violation_in_match_statement-1/src/main.sw +++ b/test/src/e2e_vm_tests/test_programs/should_pass/static_analysis/cei_pattern_violation_in_match_statement-1/src/main.sw @@ -1,6 +1,6 @@ contract; -use std::storage::store; +use std::storage::storage_api::write; enum MyEnum { A: (), @@ -32,7 +32,7 @@ impl TestAbi for Contract { MyEnum::C => { // effect -- therefore violation of CEI where effect should go before interaction { - store(0x3dba0a4455b598b7655a7fb430883d96c9527ef275b49739e7b0ad12f8280eae, ()) + write(0x3dba0a4455b598b7655a7fb430883d96c9527ef275b49739e7b0ad12f8280eae, 0, ()) } }, } diff --git a/test/src/e2e_vm_tests/test_programs/should_pass/static_analysis/cei_pattern_violation_in_match_statement-1/test.toml b/test/src/e2e_vm_tests/test_programs/should_pass/static_analysis/cei_pattern_violation_in_match_statement-1/test.toml index 803c14c99f8..98d23f803f9 100644 --- a/test/src/e2e_vm_tests/test_programs/should_pass/static_analysis/cei_pattern_violation_in_match_statement-1/test.toml +++ b/test/src/e2e_vm_tests/test_programs/should_pass/static_analysis/cei_pattern_violation_in_match_statement-1/test.toml @@ -1,4 +1,5 @@ category = "compile" # check: $()Storage write after external contract interaction in function or method "deposit". Consider making all storage writes before calling another contract -expected_warnings = 4 +expected_warnings = 5 + diff --git a/test/src/e2e_vm_tests/test_programs/should_pass/static_analysis/cei_pattern_violation_in_standalone_function/src/main.sw b/test/src/e2e_vm_tests/test_programs/should_pass/static_analysis/cei_pattern_violation_in_standalone_function/src/main.sw index 9ec8ad73c50..f446b44dc8c 100644 --- a/test/src/e2e_vm_tests/test_programs/should_pass/static_analysis/cei_pattern_violation_in_standalone_function/src/main.sw +++ b/test/src/e2e_vm_tests/test_programs/should_pass/static_analysis/cei_pattern_violation_in_standalone_function/src/main.sw @@ -1,6 +1,6 @@ contract; -use std::storage::store; +use std::storage::storage_api::write; abi TestAbi { #[storage(write)] @@ -15,7 +15,7 @@ fn standalone_function() { other_contract.deposit(); // effect -- therefore violation of CEI where effect should go before interaction let storage_key = 0x3dba0a4455b598b7655a7fb430883d96c9527ef275b49739e7b0ad12f8280eae; - store(storage_key, ()); + write(storage_key, 0, ()); } impl TestAbi for Contract { diff --git a/test/src/e2e_vm_tests/test_programs/should_pass/static_analysis/cei_pattern_violation_in_standalone_function/test.toml b/test/src/e2e_vm_tests/test_programs/should_pass/static_analysis/cei_pattern_violation_in_standalone_function/test.toml index 52bd24b51fb..119103b452a 100644 --- a/test/src/e2e_vm_tests/test_programs/should_pass/static_analysis/cei_pattern_violation_in_standalone_function/test.toml +++ b/test/src/e2e_vm_tests/test_programs/should_pass/static_analysis/cei_pattern_violation_in_standalone_function/test.toml @@ -1,4 +1,4 @@ category = "compile" # check: $()Storage write after external contract interaction in function or method "standalone_function". Consider making all storage writes before calling another contract -expected_warnings = 1 +expected_warnings = 2 diff --git a/test/src/e2e_vm_tests/test_programs/should_pass/static_analysis/cei_pattern_violation_in_struct/src/main.sw b/test/src/e2e_vm_tests/test_programs/should_pass/static_analysis/cei_pattern_violation_in_struct/src/main.sw index 33a9dedb690..ba4faecb0c5 100644 --- a/test/src/e2e_vm_tests/test_programs/should_pass/static_analysis/cei_pattern_violation_in_struct/src/main.sw +++ b/test/src/e2e_vm_tests/test_programs/should_pass/static_analysis/cei_pattern_violation_in_struct/src/main.sw @@ -1,6 +1,6 @@ contract; -use std::storage::store; +use std::storage::storage_api::write; abi TestAbi { #[storage(write)] @@ -26,7 +26,7 @@ impl TestAbi for Contract { field2: { // effect -- therefore violation of CEI where effect should go before interaction // (assuming left-to-right struct fields evaluation) - store(0x3dba0a4455b598b7655a7fb430883d96c9527ef275b49739e7b0ad12f8280eae, ()); + write(0x3dba0a4455b598b7655a7fb430883d96c9527ef275b49739e7b0ad12f8280eae, 0, ()); 43 }, }; diff --git a/test/src/e2e_vm_tests/test_programs/should_pass/static_analysis/cei_pattern_violation_in_struct/test.toml b/test/src/e2e_vm_tests/test_programs/should_pass/static_analysis/cei_pattern_violation_in_struct/test.toml index 7105f663a21..803c14c99f8 100644 --- a/test/src/e2e_vm_tests/test_programs/should_pass/static_analysis/cei_pattern_violation_in_struct/test.toml +++ b/test/src/e2e_vm_tests/test_programs/should_pass/static_analysis/cei_pattern_violation_in_struct/test.toml @@ -1,4 +1,4 @@ category = "compile" # check: $()Storage write after external contract interaction in function or method "deposit". Consider making all storage writes before calling another contract -expected_warnings = 3 +expected_warnings = 4 diff --git a/test/src/e2e_vm_tests/test_programs/should_pass/static_analysis/cei_pattern_violation_in_tuple/src/main.sw b/test/src/e2e_vm_tests/test_programs/should_pass/static_analysis/cei_pattern_violation_in_tuple/src/main.sw index 3b5abf56135..9aea91bbe32 100644 --- a/test/src/e2e_vm_tests/test_programs/should_pass/static_analysis/cei_pattern_violation_in_tuple/src/main.sw +++ b/test/src/e2e_vm_tests/test_programs/should_pass/static_analysis/cei_pattern_violation_in_tuple/src/main.sw @@ -1,6 +1,6 @@ contract; -use std::storage::store; +use std::storage::storage_api::write; abi TestAbi { #[storage(write)] @@ -22,7 +22,7 @@ impl TestAbi for Contract { { // effect -- therefore violation of CEI where effect should go before interaction // (assuming left-to-right tuple component evaluation) - store(0x3dba0a4455b598b7655a7fb430883d96c9527ef275b49739e7b0ad12f8280eae, ()); + write(0x3dba0a4455b598b7655a7fb430883d96c9527ef275b49739e7b0ad12f8280eae, 0, ()); 43 } ); diff --git a/test/src/e2e_vm_tests/test_programs/should_pass/static_analysis/cei_pattern_violation_in_tuple/test.toml b/test/src/e2e_vm_tests/test_programs/should_pass/static_analysis/cei_pattern_violation_in_tuple/test.toml index b6e8c1960bd..d61220251df 100644 --- a/test/src/e2e_vm_tests/test_programs/should_pass/static_analysis/cei_pattern_violation_in_tuple/test.toml +++ b/test/src/e2e_vm_tests/test_programs/should_pass/static_analysis/cei_pattern_violation_in_tuple/test.toml @@ -1,4 +1,4 @@ category = "compile" # check: $()Storage write after external contract interaction in function or method "deposit". Consider making all storage writes before calling another contract -expected_warnings = 1 +expected_warnings = 2 diff --git a/test/src/e2e_vm_tests/test_programs/should_pass/static_analysis/cei_pattern_violation_in_while_loop-1/src/main.sw b/test/src/e2e_vm_tests/test_programs/should_pass/static_analysis/cei_pattern_violation_in_while_loop-1/src/main.sw index 16e55c7f524..19a58e1e7d3 100644 --- a/test/src/e2e_vm_tests/test_programs/should_pass/static_analysis/cei_pattern_violation_in_while_loop-1/src/main.sw +++ b/test/src/e2e_vm_tests/test_programs/should_pass/static_analysis/cei_pattern_violation_in_while_loop-1/src/main.sw @@ -1,6 +1,6 @@ contract; -use std::storage::store; +use std::storage::storage_api::write; abi TestAbi { #[storage(write)] @@ -15,7 +15,7 @@ impl TestAbi for Contract { abi(TestAbi, 0x3dba0a4455b598b7655a7fb430883d96c9527ef275b49739e7b0ad12f8280eae).deposit(amount); // effect -- therefore violation of CEI where effect should go before interaction { - store(0x3dba0a4455b598b7655a7fb430883d96c9527ef275b49739e7b0ad12f8280eae, ()) + write(0x3dba0a4455b598b7655a7fb430883d96c9527ef275b49739e7b0ad12f8280eae, 0, ()) } } } diff --git a/test/src/e2e_vm_tests/test_programs/should_pass/static_analysis/cei_pattern_violation_in_while_loop-1/test.toml b/test/src/e2e_vm_tests/test_programs/should_pass/static_analysis/cei_pattern_violation_in_while_loop-1/test.toml index d61220251df..803c14c99f8 100644 --- a/test/src/e2e_vm_tests/test_programs/should_pass/static_analysis/cei_pattern_violation_in_while_loop-1/test.toml +++ b/test/src/e2e_vm_tests/test_programs/should_pass/static_analysis/cei_pattern_violation_in_while_loop-1/test.toml @@ -1,4 +1,4 @@ category = "compile" # check: $()Storage write after external contract interaction in function or method "deposit". Consider making all storage writes before calling another contract -expected_warnings = 2 +expected_warnings = 4 diff --git a/test/src/e2e_vm_tests/test_programs/should_pass/static_analysis/cei_pattern_violation_in_while_loop-2/src/main.sw b/test/src/e2e_vm_tests/test_programs/should_pass/static_analysis/cei_pattern_violation_in_while_loop-2/src/main.sw index 538de0b3fab..7c7d9ae3618 100644 --- a/test/src/e2e_vm_tests/test_programs/should_pass/static_analysis/cei_pattern_violation_in_while_loop-2/src/main.sw +++ b/test/src/e2e_vm_tests/test_programs/should_pass/static_analysis/cei_pattern_violation_in_while_loop-2/src/main.sw @@ -1,6 +1,6 @@ contract; -use std::storage::store; +use std::storage::storage_api::write; abi TestAbi { #[storage(write)] @@ -15,7 +15,7 @@ impl TestAbi for Contract { // effect -- violation of CEI where effect should go before interaction // this can happen here because this is a loop and the interaction happens // at the end of the loop body - store(0x3dba0a4455b598b7655a7fb430883d96c9527ef275b49739e7b0ad12f8280eae, ()); + write(0x3dba0a4455b598b7655a7fb430883d96c9527ef275b49739e7b0ad12f8280eae, 0, ()); // interaction abi(TestAbi, 0x3dba0a4455b598b7655a7fb430883d96c9527ef275b49739e7b0ad12f8280eae).deposit(amount); } diff --git a/test/src/e2e_vm_tests/test_programs/should_pass/static_analysis/cei_pattern_violation_in_while_loop-2/test.toml b/test/src/e2e_vm_tests/test_programs/should_pass/static_analysis/cei_pattern_violation_in_while_loop-2/test.toml index b6e8c1960bd..d61220251df 100644 --- a/test/src/e2e_vm_tests/test_programs/should_pass/static_analysis/cei_pattern_violation_in_while_loop-2/test.toml +++ b/test/src/e2e_vm_tests/test_programs/should_pass/static_analysis/cei_pattern_violation_in_while_loop-2/test.toml @@ -1,4 +1,4 @@ category = "compile" # check: $()Storage write after external contract interaction in function or method "deposit". Consider making all storage writes before calling another contract -expected_warnings = 1 +expected_warnings = 2 diff --git a/test/src/e2e_vm_tests/test_programs/should_pass/static_analysis/cei_pattern_violation_in_while_loop-3/src/main.sw b/test/src/e2e_vm_tests/test_programs/should_pass/static_analysis/cei_pattern_violation_in_while_loop-3/src/main.sw index 3749d1961d1..7d8958fc114 100644 --- a/test/src/e2e_vm_tests/test_programs/should_pass/static_analysis/cei_pattern_violation_in_while_loop-3/src/main.sw +++ b/test/src/e2e_vm_tests/test_programs/should_pass/static_analysis/cei_pattern_violation_in_while_loop-3/src/main.sw @@ -1,6 +1,6 @@ contract; -use std::storage::store; +use std::storage::storage_api::write; abi TestAbi { #[storage(write)] @@ -19,7 +19,7 @@ impl TestAbi for Contract { // interaction // effect -- therefore violation of CEI where effect should go before interaction { - store(0x3dba0a4455b598b7655a7fb430883d96c9527ef275b49739e7b0ad12f8280eae, ()) + write(0x3dba0a4455b598b7655a7fb430883d96c9527ef275b49739e7b0ad12f8280eae, 0, ()) } } } diff --git a/test/src/e2e_vm_tests/test_programs/should_pass/static_analysis/cei_pattern_violation_in_while_loop-3/test.toml b/test/src/e2e_vm_tests/test_programs/should_pass/static_analysis/cei_pattern_violation_in_while_loop-3/test.toml index b6e8c1960bd..d61220251df 100644 --- a/test/src/e2e_vm_tests/test_programs/should_pass/static_analysis/cei_pattern_violation_in_while_loop-3/test.toml +++ b/test/src/e2e_vm_tests/test_programs/should_pass/static_analysis/cei_pattern_violation_in_while_loop-3/test.toml @@ -1,4 +1,4 @@ category = "compile" # check: $()Storage write after external contract interaction in function or method "deposit". Consider making all storage writes before calling another contract -expected_warnings = 1 +expected_warnings = 2 diff --git a/test/src/e2e_vm_tests/test_programs/should_pass/static_analysis/cei_pattern_violation_in_while_loop-4/src/main.sw b/test/src/e2e_vm_tests/test_programs/should_pass/static_analysis/cei_pattern_violation_in_while_loop-4/src/main.sw index b21cb2877b0..dfdd405bdd3 100644 --- a/test/src/e2e_vm_tests/test_programs/should_pass/static_analysis/cei_pattern_violation_in_while_loop-4/src/main.sw +++ b/test/src/e2e_vm_tests/test_programs/should_pass/static_analysis/cei_pattern_violation_in_while_loop-4/src/main.sw @@ -1,6 +1,6 @@ contract; -use std::storage::store; +use std::storage::storage_api::write; abi TestAbi { #[storage(write)] @@ -12,7 +12,7 @@ impl TestAbi for Contract { fn deposit(amount: u64) { while { - store(0x3dba0a4455b598b7655a7fb430883d96c9527ef275b49739e7b0ad12f8280eae, ()); + write(0x3dba0a4455b598b7655a7fb430883d96c9527ef275b49739e7b0ad12f8280eae, 0, ()); true } { diff --git a/test/src/e2e_vm_tests/test_programs/should_pass/static_analysis/cei_pattern_violation_in_while_loop-4/test.toml b/test/src/e2e_vm_tests/test_programs/should_pass/static_analysis/cei_pattern_violation_in_while_loop-4/test.toml index b6e8c1960bd..d61220251df 100644 --- a/test/src/e2e_vm_tests/test_programs/should_pass/static_analysis/cei_pattern_violation_in_while_loop-4/test.toml +++ b/test/src/e2e_vm_tests/test_programs/should_pass/static_analysis/cei_pattern_violation_in_while_loop-4/test.toml @@ -1,4 +1,4 @@ category = "compile" # check: $()Storage write after external contract interaction in function or method "deposit". Consider making all storage writes before calling another contract -expected_warnings = 1 +expected_warnings = 2 diff --git a/test/src/e2e_vm_tests/test_programs/should_pass/static_analysis/cei_pattern_violation_more_complex_logic/src/main.sw b/test/src/e2e_vm_tests/test_programs/should_pass/static_analysis/cei_pattern_violation_more_complex_logic/src/main.sw index 94a7c7ace3a..f66cc0375b6 100644 --- a/test/src/e2e_vm_tests/test_programs/should_pass/static_analysis/cei_pattern_violation_more_complex_logic/src/main.sw +++ b/test/src/e2e_vm_tests/test_programs/should_pass/static_analysis/cei_pattern_violation_more_complex_logic/src/main.sw @@ -48,13 +48,13 @@ pub fn transfer_nft(asset: u64, from: Identity, to: Identity) { impl EnglishAuction for Contract { #[storage(read, write)] fn bid(auction_id: u64, _bid_asset: AuctionAsset) { - let auction = storage.auctions.get(auction_id); + let auction = storage.auctions.get(auction_id).try_read(); require(auction.is_some(), 42); let mut _auction = auction.unwrap(); let sender = msg_sender().unwrap(); - let sender_deposit = storage.deposits.get((sender, auction_id)); + let sender_deposit = storage.deposits.get((sender, auction_id)).try_read(); let total_bid: AuctionAsset = match sender_deposit { Option::Some(_) => { AuctionAsset::TokenAsset(42) @@ -113,11 +113,11 @@ impl EnglishAuction for Contract { let auction = 42; - let total_auctions = storage.total_auctions; + let total_auctions = storage.total_auctions.read(); storage.deposits.insert((seller, total_auctions), Option::Some(sell_asset)); storage.auctions.insert(total_auctions, Option::Some(auction)); - storage.total_auctions += 1; + storage.total_auctions.write(storage.total_auctions.read() + 1); total_auctions } diff --git a/test/src/e2e_vm_tests/test_programs/should_pass/static_analysis/cei_pattern_violation_more_complex_logic/test.toml b/test/src/e2e_vm_tests/test_programs/should_pass/static_analysis/cei_pattern_violation_more_complex_logic/test.toml index 52f545b2d03..4338be272f6 100644 --- a/test/src/e2e_vm_tests/test_programs/should_pass/static_analysis/cei_pattern_violation_more_complex_logic/test.toml +++ b/test/src/e2e_vm_tests/test_programs/should_pass/static_analysis/cei_pattern_violation_more_complex_logic/test.toml @@ -5,4 +5,4 @@ category = "compile" # check: $()Storage read after external contract interaction in function or method "create". Consider making all storage reads before calling another contract # check: $()Storage write after external contract interaction in function or method "create". Consider making all storage writes before calling another contract -expected_warnings = 6 +expected_warnings = 9 diff --git a/test/src/e2e_vm_tests/test_programs/should_pass/static_analysis/cei_pattern_violation_storage_map_and_vec/src/main.sw b/test/src/e2e_vm_tests/test_programs/should_pass/static_analysis/cei_pattern_violation_storage_map_and_vec/src/main.sw index 0ee39376864..d6775620702 100644 --- a/test/src/e2e_vm_tests/test_programs/should_pass/static_analysis/cei_pattern_violation_storage_map_and_vec/src/main.sw +++ b/test/src/e2e_vm_tests/test_programs/should_pass/static_analysis/cei_pattern_violation_storage_map_and_vec/src/main.sw @@ -1,7 +1,7 @@ contract; use std::auth::msg_sender; -use std::storage::StorageVec; +use std::storage::storage_vec::*; abi MyContract { #[storage(read, write)] @@ -17,7 +17,7 @@ impl MyContract for Contract { #[storage(read, write)] fn withdraw() { let sender = msg_sender().unwrap(); - let bal = storage.balances.get(sender).unwrap_or(0); + let bal = storage.balances.get(sender).try_read().unwrap_or(0); assert(bal > 0); diff --git a/test/src/e2e_vm_tests/test_programs/should_pass/static_analysis/cei_pattern_violation_storage_map_and_vec/test.toml b/test/src/e2e_vm_tests/test_programs/should_pass/static_analysis/cei_pattern_violation_storage_map_and_vec/test.toml index 3fbbb871866..cc4604fe858 100644 --- a/test/src/e2e_vm_tests/test_programs/should_pass/static_analysis/cei_pattern_violation_storage_map_and_vec/test.toml +++ b/test/src/e2e_vm_tests/test_programs/should_pass/static_analysis/cei_pattern_violation_storage_map_and_vec/test.toml @@ -2,5 +2,4 @@ category = "compile" # check: $()Storage write after external contract interaction in function or method "withdraw". Consider making all storage writes before calling another contract # check: $()Storage write after external contract interaction in function or method "withdraw". Consider making all storage writes before calling another contract -# not: $()Storage read after external contract interaction in function or method -expected_warnings = 2 +expected_warnings = 4 diff --git a/test/src/e2e_vm_tests/test_programs/should_pass/static_analysis/cei_pattern_violation_storage_struct_read/src/main.sw b/test/src/e2e_vm_tests/test_programs/should_pass/static_analysis/cei_pattern_violation_storage_struct_read/src/main.sw index c5e8cee229f..1d7c19fe24e 100644 --- a/test/src/e2e_vm_tests/test_programs/should_pass/static_analysis/cei_pattern_violation_storage_struct_read/src/main.sw +++ b/test/src/e2e_vm_tests/test_programs/should_pass/static_analysis/cei_pattern_violation_storage_struct_read/src/main.sw @@ -1,7 +1,7 @@ contract; use std::auth::msg_sender; -use std::storage::StorageVec; +use std::storage::storage_vec::StorageVec; abi MyContract { #[storage(read)] @@ -22,7 +22,7 @@ impl MyContract for Contract { fn withdraw() { let caller = abi(MyContract, 0x3dba0a4455b598b7655a7fb430883d96c9527ef275b49739e7b0ad12f8280eae); caller.withdraw(); - storage.var1; + storage.var1.read(); } } diff --git a/test/src/e2e_vm_tests/test_programs/should_pass/static_analysis/cei_pattern_violation_storage_var_read/Forc.lock b/test/src/e2e_vm_tests/test_programs/should_pass/static_analysis/cei_pattern_violation_storage_var_read/Forc.lock index ea8e4907a57..f23b03e6600 100644 --- a/test/src/e2e_vm_tests/test_programs/should_pass/static_analysis/cei_pattern_violation_storage_var_read/Forc.lock +++ b/test/src/e2e_vm_tests/test_programs/should_pass/static_analysis/cei_pattern_violation_storage_var_read/Forc.lock @@ -1,3 +1,13 @@ [[package]] name = 'cei_pattern_violation_storage_var_read' source = 'member' +dependencies = ['std'] + +[[package]] +name = 'core' +source = 'path+from-root-26DB879E78D43907' + +[[package]] +name = 'std' +source = 'path+from-root-26DB879E78D43907' +dependencies = ['core'] diff --git a/test/src/e2e_vm_tests/test_programs/should_pass/static_analysis/cei_pattern_violation_storage_var_read/Forc.toml b/test/src/e2e_vm_tests/test_programs/should_pass/static_analysis/cei_pattern_violation_storage_var_read/Forc.toml index 261c013024b..7b6af324981 100644 --- a/test/src/e2e_vm_tests/test_programs/should_pass/static_analysis/cei_pattern_violation_storage_var_read/Forc.toml +++ b/test/src/e2e_vm_tests/test_programs/should_pass/static_analysis/cei_pattern_violation_storage_var_read/Forc.toml @@ -3,4 +3,6 @@ name = "cei_pattern_violation_storage_var_read" authors = ["Fuel Labs "] entry = "main.sw" license = "Apache-2.0" -implicit-std = false + +[dependencies] +std = { path = "../../../../../../../sway-lib-std" } diff --git a/test/src/e2e_vm_tests/test_programs/should_pass/static_analysis/cei_pattern_violation_storage_var_read/src/main.sw b/test/src/e2e_vm_tests/test_programs/should_pass/static_analysis/cei_pattern_violation_storage_var_read/src/main.sw index 7bca58f5f38..0f304fc297d 100644 --- a/test/src/e2e_vm_tests/test_programs/should_pass/static_analysis/cei_pattern_violation_storage_var_read/src/main.sw +++ b/test/src/e2e_vm_tests/test_programs/should_pass/static_analysis/cei_pattern_violation_storage_var_read/src/main.sw @@ -17,6 +17,6 @@ impl TestAbi for Contract { // interaction other_contract.deposit(); // effect -- therefore violation of CEI where effect should go before interaction - storage.var + storage.var.read() } } diff --git a/test/src/e2e_vm_tests/test_programs/should_pass/static_analysis/cei_pattern_violation_storage_var_update/Forc.lock b/test/src/e2e_vm_tests/test_programs/should_pass/static_analysis/cei_pattern_violation_storage_var_update/Forc.lock index 54cef5bcd4d..c77aa80fa3d 100644 --- a/test/src/e2e_vm_tests/test_programs/should_pass/static_analysis/cei_pattern_violation_storage_var_update/Forc.lock +++ b/test/src/e2e_vm_tests/test_programs/should_pass/static_analysis/cei_pattern_violation_storage_var_update/Forc.lock @@ -1,3 +1,13 @@ [[package]] name = 'cei_pattern_violation_storage_var_update' source = 'member' +dependencies = ['std'] + +[[package]] +name = 'core' +source = 'path+from-root-0B085CF179DC32DD' + +[[package]] +name = 'std' +source = 'path+from-root-0B085CF179DC32DD' +dependencies = ['core'] diff --git a/test/src/e2e_vm_tests/test_programs/should_pass/static_analysis/cei_pattern_violation_storage_var_update/Forc.toml b/test/src/e2e_vm_tests/test_programs/should_pass/static_analysis/cei_pattern_violation_storage_var_update/Forc.toml index c514e30b52c..80aeed69db8 100644 --- a/test/src/e2e_vm_tests/test_programs/should_pass/static_analysis/cei_pattern_violation_storage_var_update/Forc.toml +++ b/test/src/e2e_vm_tests/test_programs/should_pass/static_analysis/cei_pattern_violation_storage_var_update/Forc.toml @@ -3,4 +3,6 @@ name = "cei_pattern_violation_storage_var_update" authors = ["Fuel Labs "] entry = "main.sw" license = "Apache-2.0" -implicit-std = false + +[dependencies] +std = { path = "../../../../../../../sway-lib-std" } diff --git a/test/src/e2e_vm_tests/test_programs/should_pass/static_analysis/cei_pattern_violation_storage_var_update/src/main.sw b/test/src/e2e_vm_tests/test_programs/should_pass/static_analysis/cei_pattern_violation_storage_var_update/src/main.sw index 4c734fce69e..d040860359d 100644 --- a/test/src/e2e_vm_tests/test_programs/should_pass/static_analysis/cei_pattern_violation_storage_var_update/src/main.sw +++ b/test/src/e2e_vm_tests/test_programs/should_pass/static_analysis/cei_pattern_violation_storage_var_update/src/main.sw @@ -17,6 +17,6 @@ impl TestAbi for Contract { // interaction other_contract.deposit(); // effect -- therefore violation of CEI where effect should go before interaction - storage.var = 42; + storage.var.write(42); } } diff --git a/test/src/e2e_vm_tests/test_programs/should_pass/supertraits_for_abis_ownable/src/main.sw b/test/src/e2e_vm_tests/test_programs/should_pass/supertraits_for_abis_ownable/src/main.sw index 42a3b66f2c4..638c7f995d7 100644 --- a/test/src/e2e_vm_tests/test_programs/should_pass/supertraits_for_abis_ownable/src/main.sw +++ b/test/src/e2e_vm_tests/test_programs/should_pass/supertraits_for_abis_ownable/src/main.sw @@ -16,12 +16,12 @@ abi MyAbi : Ownable { impl StorageHelpers for Contract { #[storage(read)] fn get_owner() -> b256 { - storage.owner + storage.owner.read() } #[storage(write)] fn set_owner(owner: b256) { - storage.owner = owner + storage.owner.write(owner) } } @@ -31,6 +31,6 @@ impl MyAbi for Contract { #[storage(read, write)] fn set_data_if_owner(new_value: u64) { Self::only_owner(); - storage.data = new_value + storage.data.write(new_value); } } diff --git a/test/src/e2e_vm_tests/test_programs/should_pass/test_abis/get_storage_key_abi/Forc.lock b/test/src/e2e_vm_tests/test_programs/should_pass/test_abis/get_storage_key_abi/Forc.lock deleted file mode 100644 index d3f9658bdd1..00000000000 --- a/test/src/e2e_vm_tests/test_programs/should_pass/test_abis/get_storage_key_abi/Forc.lock +++ /dev/null @@ -1,3 +0,0 @@ -[[package]] -name = 'array_of_structs_abi' -dependencies = [] diff --git a/test/src/e2e_vm_tests/test_programs/should_pass/test_abis/get_storage_key_abi/Forc.toml b/test/src/e2e_vm_tests/test_programs/should_pass/test_abis/get_storage_key_abi/Forc.toml deleted file mode 100644 index f67ca7cf2c1..00000000000 --- a/test/src/e2e_vm_tests/test_programs/should_pass/test_abis/get_storage_key_abi/Forc.toml +++ /dev/null @@ -1,6 +0,0 @@ -[project] -authors = ["Fuel Labs "] -entry = "main.sw" -implicit-std = false -license = "Apache-2.0" -name = "get_storage_key_abi" diff --git a/test/src/e2e_vm_tests/test_programs/should_pass/test_abis/get_storage_key_abi/json_abi_oracle.json b/test/src/e2e_vm_tests/test_programs/should_pass/test_abis/get_storage_key_abi/json_abi_oracle.json deleted file mode 100644 index 0637a088a01..00000000000 --- a/test/src/e2e_vm_tests/test_programs/should_pass/test_abis/get_storage_key_abi/json_abi_oracle.json +++ /dev/null @@ -1 +0,0 @@ -[] \ No newline at end of file diff --git a/test/src/e2e_vm_tests/test_programs/should_pass/test_abis/get_storage_key_abi/src/main.sw b/test/src/e2e_vm_tests/test_programs/should_pass/test_abis/get_storage_key_abi/src/main.sw deleted file mode 100644 index ae82b5c54c5..00000000000 --- a/test/src/e2e_vm_tests/test_programs/should_pass/test_abis/get_storage_key_abi/src/main.sw +++ /dev/null @@ -1,9 +0,0 @@ -library; - -abi TestContract { - fn from_f1() -> b256; - fn from_f2() -> b256; - fn from_f3() -> b256; - fn from_f4() -> b256; - fn from_callers() -> (b256, b256, b256, b256); -} diff --git a/test/src/e2e_vm_tests/test_programs/should_pass/test_abis/storage_access_abi/src/main.sw b/test/src/e2e_vm_tests/test_programs/should_pass/test_abis/storage_access_abi/src/main.sw index 622028bc382..ad839560303 100644 --- a/test/src/e2e_vm_tests/test_programs/should_pass/test_abis/storage_access_abi/src/main.sw +++ b/test/src/e2e_vm_tests/test_programs/should_pass/test_abis/storage_access_abi/src/main.sw @@ -108,18 +108,4 @@ abi StorageAccess { fn get_e2() -> E; #[storage(read)] fn get_string() -> str[40]; - - // Operations - #[storage(read, write)] - fn add_to_s_dot_t_dot_x(k: u64); - #[storage(read, write)] - fn subtract_from_s_dot_t_dot_x(k: u64); - #[storage(read, write)] - fn multiply_by_s_dot_t_dot_x(k: u64); - #[storage(read, write)] - fn divide_s_dot_t_dot_x(k: u64); - #[storage(read, write)] - fn shift_left_s_dot_t_dot_x(k: u64); - #[storage(read, write)] - fn shift_right_s_dot_t_dot_x(k: u64); } diff --git a/test/src/e2e_vm_tests/test_programs/should_pass/test_contracts/basic_storage/src/main.sw b/test/src/e2e_vm_tests/test_programs/should_pass/test_contracts/basic_storage/src/main.sw index 9d4b544137d..534e2df1c16 100644 --- a/test/src/e2e_vm_tests/test_programs/should_pass/test_contracts/basic_storage/src/main.sw +++ b/test/src/e2e_vm_tests/test_programs/should_pass/test_contracts/basic_storage/src/main.sw @@ -1,5 +1,5 @@ contract; -use std::{hash::sha256, storage::*}; +use std::{hash::sha256, storage::storage_api::{read, write}}; use basic_storage_abi::*; const C1 = 1; @@ -23,12 +23,12 @@ storage { impl BasicStorage for Contract { #[storage(read)] fn get_u64(storage_key: b256) -> Option { - get(storage_key) + read(storage_key, 0) } #[storage(write)] fn store_u64(key: b256, value: u64) { - store(key, value); + write(key, 0, value); } #[storage(read)] @@ -99,12 +99,12 @@ fn test_storage() { let key: b256 = 0x0101010101010101010101010101010101010101010101010101010101010101; let x: u64 = 64; - store(key, x); - assert(x == get::(key).unwrap()); + write(key, 0, x); + assert(x == read::(key, 0).unwrap()); let y: b256 = 0x1101010101010101010101010101010101010101010101010101010101010101; - store(key, y); - assert(y == get::(key).unwrap()); + write(key, 0, y); + assert(y == read::(key, 0).unwrap()); let s: S = S { x: 1, @@ -120,27 +120,27 @@ fn test_storage() { int32: 9, }, }; - store(key, s); - let s_ = get::(key).unwrap(); + write(key, 0, s); + let s_ = read::(key, 0).unwrap(); assert(s.x == s_.x && s.y == s_.y && s.z == s_.z); assert(s.t.x == s_.t.x && s.t.y == s_.t.y && s.t.z == s_.t.z && s.t.boolean == s_.t.boolean); assert(s.t.int8 == s_.t.int8 && s.t.int16 == s_.t.int16 && s.t.int32 == s_.t.int32); let boolean: bool = true; - store(key, boolean); - assert(boolean == get::(key).unwrap()); + write(key, 0, boolean); + assert(boolean == read::(key, 0).unwrap()); let int8: u8 = 8; - store(key, int8); - assert(int8 == get::(key).unwrap()); + write(key, 0, int8); + assert(int8 == read::(key, 0).unwrap()); let int16: u16 = 16; - store(key, int16); - assert(int16 == get::(key).unwrap()); + write(key, 0, int16); + assert(int16 == read::(key, 0).unwrap()); let int32: u32 = 32; - store(key, int32); - assert(int32 == get::(key).unwrap()); + write(key, 0, int32); + assert(int32 == read::(key, 0).unwrap()); let e: E = E::B(T { x: 1, @@ -151,8 +151,8 @@ fn test_storage() { int16: 5, int32: 6, }); - store(key, e); - let e_ = get::(key).unwrap(); + write(key, 0, e); + let e_ = read::(key, 0).unwrap(); match (e, e_) { ( @@ -182,8 +182,8 @@ fn test_storage() { } let e2: E = E::A(777); - store(key, e2); - let e2_ = get::(key).unwrap(); + write(key, 0, e2); + let e2_ = read::(key, 0).unwrap(); match (e2, e2_) { (E::A(i1), E::A(i2)) => { assert(i1 == i2); @@ -191,18 +191,18 @@ fn test_storage() { _ => assert(false), } - assert_streq(storage.str0, ""); - - assert_streq(storage.str1, "a"); - assert_streq(storage.str2, "aa"); - assert_streq(storage.str3, "aaa"); - assert_streq(storage.str4, "aaaa"); - assert_streq(storage.str5, "aaaaa"); - assert_streq(storage.str6, "aaaaaa"); - assert_streq(storage.str7, "aaaaaaa"); - assert_streq(storage.str8, "aaaaaaaa"); - assert_streq(storage.str9, "aaaaaaaaa"); - assert_streq(storage.str10, "aaaaaaaaaa"); + assert(storage.str0.try_read().is_none()); + + assert_streq(storage.str1.read(), "a"); + assert_streq(storage.str2.read(), "aa"); + assert_streq(storage.str3.read(), "aaa"); + assert_streq(storage.str4.read(), "aaaa"); + assert_streq(storage.str5.read(), "aaaaa"); + assert_streq(storage.str6.read(), "aaaaaa"); + assert_streq(storage.str7.read(), "aaaaaaa"); + assert_streq(storage.str8.read(), "aaaaaaaa"); + assert_streq(storage.str9.read(), "aaaaaaaaa"); + assert_streq(storage.str10.read(), "aaaaaaaaaa"); } // If these comparisons are done inline just above then it blows out the register allocator due to diff --git a/test/src/e2e_vm_tests/test_programs/should_pass/test_contracts/get_storage_key_contract/Forc.lock b/test/src/e2e_vm_tests/test_programs/should_pass/test_contracts/get_storage_key_contract/Forc.lock deleted file mode 100644 index 0c386944f8f..00000000000 --- a/test/src/e2e_vm_tests/test_programs/should_pass/test_contracts/get_storage_key_contract/Forc.lock +++ /dev/null @@ -1,8 +0,0 @@ -[[package]] -name = 'get_storage_key_abi' -source = 'path+from-root-35549077EBF4FDB5' - -[[package]] -name = 'get_storage_key_contract' -source = 'member' -dependencies = ['get_storage_key_abi'] diff --git a/test/src/e2e_vm_tests/test_programs/should_pass/test_contracts/get_storage_key_contract/Forc.toml b/test/src/e2e_vm_tests/test_programs/should_pass/test_contracts/get_storage_key_contract/Forc.toml deleted file mode 100644 index 6d99dc99420..00000000000 --- a/test/src/e2e_vm_tests/test_programs/should_pass/test_contracts/get_storage_key_contract/Forc.toml +++ /dev/null @@ -1,9 +0,0 @@ -[project] -authors = ["Fuel Labs "] -entry = "main.sw" -implicit-std = false -license = "Apache-2.0" -name = "get_storage_key_contract" - -[dependencies] -get_storage_key_abi = { path = "../../test_abis/get_storage_key_abi" } diff --git a/test/src/e2e_vm_tests/test_programs/should_pass/test_contracts/get_storage_key_contract/json_abi_oracle.json b/test/src/e2e_vm_tests/test_programs/should_pass/test_contracts/get_storage_key_contract/json_abi_oracle.json deleted file mode 100644 index 7a03dcf3cc3..00000000000 --- a/test/src/e2e_vm_tests/test_programs/should_pass/test_contracts/get_storage_key_contract/json_abi_oracle.json +++ /dev/null @@ -1,92 +0,0 @@ -{ - "configurables": [], - "functions": [ - { - "attributes": null, - "inputs": [], - "name": "from_callers", - "output": { - "name": "", - "type": 0, - "typeArguments": null - } - }, - { - "attributes": null, - "inputs": [], - "name": "from_f1", - "output": { - "name": "", - "type": 1, - "typeArguments": null - } - }, - { - "attributes": null, - "inputs": [], - "name": "from_f2", - "output": { - "name": "", - "type": 1, - "typeArguments": null - } - }, - { - "attributes": null, - "inputs": [], - "name": "from_f3", - "output": { - "name": "", - "type": 1, - "typeArguments": null - } - }, - { - "attributes": null, - "inputs": [], - "name": "from_f4", - "output": { - "name": "", - "type": 1, - "typeArguments": null - } - } - ], - "loggedTypes": [], - "messagesTypes": [], - "types": [ - { - "components": [ - { - "name": "__tuple_element", - "type": 1, - "typeArguments": null - }, - { - "name": "__tuple_element", - "type": 1, - "typeArguments": null - }, - { - "name": "__tuple_element", - "type": 1, - "typeArguments": null - }, - { - "name": "__tuple_element", - "type": 1, - "typeArguments": null - } - ], - "type": "(_, _, _, _)", - "typeId": 0, - "typeParameters": null - }, - { - "components": null, - "type": "b256", - "typeId": 1, - "typeParameters": null - } - ] -} \ No newline at end of file diff --git a/test/src/e2e_vm_tests/test_programs/should_pass/test_contracts/get_storage_key_contract/json_abi_oracle_flat.json b/test/src/e2e_vm_tests/test_programs/should_pass/test_contracts/get_storage_key_contract/json_abi_oracle_flat.json deleted file mode 100644 index bae57a00e57..00000000000 --- a/test/src/e2e_vm_tests/test_programs/should_pass/test_contracts/get_storage_key_contract/json_abi_oracle_flat.json +++ /dev/null @@ -1,89 +0,0 @@ -{ - "functions": [ - { - "attributes": null, - "inputs": [], - "name": "from_f1", - "output": { - "name": "", - "type": 1, - "typeArguments": null - } - }, - { - "attributes": null, - "inputs": [], - "name": "from_f2", - "output": { - "name": "", - "type": 1, - "typeArguments": null - } - }, - { - "attributes": null, - "inputs": [], - "name": "from_f3", - "output": { - "name": "", - "type": 1, - "typeArguments": null - } - }, - { - "attributes": null, - "inputs": [], - "name": "from_f4", - "output": { - "name": "", - "type": 1, - "typeArguments": null - } - }, - { - "attributes": null, - "inputs": [], - "name": "from_callers", - "output": { - "name": "", - "type": 0, - "typeArguments": null - } - } - ], - "types": [ - { - "components": [ - { - "name": "__tuple_element", - "type": 1, - "typeArguments": null - }, - { - "name": "__tuple_element", - "type": 1, - "typeArguments": null - }, - { - "name": "__tuple_element", - "type": 1, - "typeArguments": null - }, - { - "name": "__tuple_element", - "type": 1, - "typeArguments": null - } - ], - "type": "(_, _, _, _)", - "typeId": 0, - "typeParameters": null - }, - { - "components": null, - "type": "b256", - "typeId": 1, - "typeParameters": null - } - ] -} \ No newline at end of file diff --git a/test/src/e2e_vm_tests/test_programs/should_pass/test_contracts/get_storage_key_contract/json_storage_slots_oracle.json b/test/src/e2e_vm_tests/test_programs/should_pass/test_contracts/get_storage_key_contract/json_storage_slots_oracle.json deleted file mode 100644 index ceddf3126c0..00000000000 --- a/test/src/e2e_vm_tests/test_programs/should_pass/test_contracts/get_storage_key_contract/json_storage_slots_oracle.json +++ /dev/null @@ -1,10 +0,0 @@ -[ - { - "key": "02dac99c283f16bc91b74f6942db7f012699a2ad51272b15207b9cc14a70dbae", - "value": "0000000000000000000000000000000000000000000000000000000000000000" - }, - { - "key": "f383b0ce51358be57daa3b725fe44acdb2d880604e367199080b4379c41bb6ed", - "value": "0000000000000000000000000000000000000000000000000000000000000000" - } -] \ No newline at end of file diff --git a/test/src/e2e_vm_tests/test_programs/should_pass/test_contracts/get_storage_key_contract/src/main.sw b/test/src/e2e_vm_tests/test_programs/should_pass/test_contracts/get_storage_key_contract/src/main.sw deleted file mode 100644 index bc1c6fbb9a2..00000000000 --- a/test/src/e2e_vm_tests/test_programs/should_pass/test_contracts/get_storage_key_contract/src/main.sw +++ /dev/null @@ -1,47 +0,0 @@ -contract; - -use get_storage_key_abi::TestContract; - -struct Foo { -} - -impl Foo { - fn foo(self) -> b256 { - __get_storage_key() - } -} - -storage { - x: u64 = 0, - f1: Foo = Foo { }, - f2: Foo = Foo { }, - y: u64 = 0, - f3: Foo = Foo { }, - f4: Foo = Foo { }, -} - -fn calls_foo() -> (b256, b256, b256, b256) { - (storage.f1.foo(), storage.f2.foo(), storage.f3.foo(), storage.f4.foo()) -} - -fn calls_calls_foo() -> (b256, b256, b256, b256) { - calls_foo() -} - -impl TestContract for Contract { - fn from_f1() -> b256 { - storage.f1.foo() - } - fn from_f2() -> b256 { - storage.f2.foo() - } - fn from_f3() -> b256 { - storage.f3.foo() - } - fn from_f4() -> b256 { - storage.f4.foo() - } - fn from_callers() -> (b256, b256, b256, b256) { - calls_calls_foo() - } -} diff --git a/test/src/e2e_vm_tests/test_programs/should_pass/test_contracts/get_storage_key_contract/test.toml b/test/src/e2e_vm_tests/test_programs/should_pass/test_contracts/get_storage_key_contract/test.toml deleted file mode 100644 index 43040c58805..00000000000 --- a/test/src/e2e_vm_tests/test_programs/should_pass/test_contracts/get_storage_key_contract/test.toml +++ /dev/null @@ -1,4 +0,0 @@ -category = "compile" -validate_abi = true -validate_storage_slots = true -expected_warnings = 2 diff --git a/test/src/e2e_vm_tests/test_programs/should_pass/test_contracts/increment_contract/src/main.sw b/test/src/e2e_vm_tests/test_programs/should_pass/test_contracts/increment_contract/src/main.sw index 89a50176bc7..71ea4eba658 100644 --- a/test/src/e2e_vm_tests/test_programs/should_pass/test_contracts/increment_contract/src/main.sw +++ b/test/src/e2e_vm_tests/test_programs/should_pass/test_contracts/increment_contract/src/main.sw @@ -9,13 +9,13 @@ storage { impl Incrementor for Contract { #[storage(read, write)] fn increment(increment_by: u64) -> u64 { - let new_val = storage.value + increment_by; - storage.value = new_val; + let new_val = storage.value.read() + increment_by; + storage.value.write(new_val); new_val } #[storage(read)] fn get() -> u64 { - storage.value + storage.value.read() } } diff --git a/test/src/e2e_vm_tests/test_programs/should_pass/test_contracts/return_struct/src/main.sw b/test/src/e2e_vm_tests/test_programs/should_pass/test_contracts/return_struct/src/main.sw index aad1b5f3895..03d6681a150 100644 --- a/test/src/e2e_vm_tests/test_programs/should_pass/test_contracts/return_struct/src/main.sw +++ b/test/src/e2e_vm_tests/test_programs/should_pass/test_contracts/return_struct/src/main.sw @@ -13,6 +13,6 @@ storage { impl MyContract for Contract { #[storage(read)] fn test_function() -> Option { - storage.a.get(1) + storage.a.get(1).try_read() } } diff --git a/test/src/e2e_vm_tests/test_programs/should_pass/test_contracts/storage_access_contract/json_abi_oracle.json b/test/src/e2e_vm_tests/test_programs/should_pass/test_contracts/storage_access_contract/json_abi_oracle.json index 054eaddbca7..2f0bd25530e 100644 --- a/test/src/e2e_vm_tests/test_programs/should_pass/test_contracts/storage_access_contract/json_abi_oracle.json +++ b/test/src/e2e_vm_tests/test_programs/should_pass/test_contracts/storage_access_contract/json_abi_oracle.json @@ -1,54 +1,6 @@ { "configurables": [], "functions": [ - { - "attributes": [ - { - "arguments": [ - "read", - "write" - ], - "name": "storage" - } - ], - "inputs": [ - { - "name": "k", - "type": 9, - "typeArguments": null - } - ], - "name": "add_to_s_dot_t_dot_x", - "output": { - "name": "", - "type": 0, - "typeArguments": null - } - }, - { - "attributes": [ - { - "arguments": [ - "read", - "write" - ], - "name": "storage" - } - ], - "inputs": [ - { - "name": "k", - "type": 9, - "typeArguments": null - } - ], - "name": "divide_s_dot_t_dot_x", - "output": { - "name": "", - "type": 0, - "typeArguments": null - } - }, { "attributes": [ { @@ -406,30 +358,6 @@ "typeArguments": null } }, - { - "attributes": [ - { - "arguments": [ - "read", - "write" - ], - "name": "storage" - } - ], - "inputs": [ - { - "name": "k", - "type": 9, - "typeArguments": null - } - ], - "name": "multiply_by_s_dot_t_dot_x", - "output": { - "name": "", - "type": 0, - "typeArguments": null - } - }, { "attributes": [ { @@ -889,78 +817,6 @@ "type": 0, "typeArguments": null } - }, - { - "attributes": [ - { - "arguments": [ - "read", - "write" - ], - "name": "storage" - } - ], - "inputs": [ - { - "name": "k", - "type": 9, - "typeArguments": null - } - ], - "name": "shift_left_s_dot_t_dot_x", - "output": { - "name": "", - "type": 0, - "typeArguments": null - } - }, - { - "attributes": [ - { - "arguments": [ - "read", - "write" - ], - "name": "storage" - } - ], - "inputs": [ - { - "name": "k", - "type": 9, - "typeArguments": null - } - ], - "name": "shift_right_s_dot_t_dot_x", - "output": { - "name": "", - "type": 0, - "typeArguments": null - } - }, - { - "attributes": [ - { - "arguments": [ - "read", - "write" - ], - "name": "storage" - } - ], - "inputs": [ - { - "name": "k", - "type": 9, - "typeArguments": null - } - ], - "name": "subtract_from_s_dot_t_dot_x", - "output": { - "name": "", - "type": 0, - "typeArguments": null - } } ], "loggedTypes": [], diff --git a/test/src/e2e_vm_tests/test_programs/should_pass/test_contracts/storage_access_contract/json_storage_slots_oracle.json b/test/src/e2e_vm_tests/test_programs/should_pass/test_contracts/storage_access_contract/json_storage_slots_oracle.json index 08c003c88c8..68be877e4b5 100644 --- a/test/src/e2e_vm_tests/test_programs/should_pass/test_contracts/storage_access_contract/json_storage_slots_oracle.json +++ b/test/src/e2e_vm_tests/test_programs/should_pass/test_contracts/storage_access_contract/json_storage_slots_oracle.json @@ -3,77 +3,57 @@ "key": "02dac99c283f16bc91b74f6942db7f012699a2ad51272b15207b9cc14a70dbae", "value": "0000000000000001000000000000000000000000000000000000000000000000" }, - { - "key": "126435532f2d2faed6fdd08cea385e77766b42cebae52c892908ba163ffd9484", - "value": "0000000000000000000000000000000000000000000000000000000000000003" - }, - { - "key": "2e92e2a58ff87833010c4cb205f65aa14fa39f799ffc3809bd4a7014b131bc93", - "value": "0000000000000001000000000000000000000000000000000000000000000000" - }, - { - "key": "57bba8e7ea11ac802968230c7c3c09485b488cc84009e80055f938a2cebeb0e6", - "value": "0000000000000001000000000000000200000000000000000000000000000000" - }, - { - "key": "57bba8e7ea11ac802968230c7c3c09485b488cc84009e80055f938a2cebeb0e7", - "value": "0000000000000000000000000000000300000000000000010000000000000004" - }, - { - "key": "57bba8e7ea11ac802968230c7c3c09485b488cc84009e80055f938a2cebeb0e8", - "value": "0000000000000005000000000000000600000000000000000000000000000000" - }, { "key": "6294951dcb0a9111a517be5cf4785670ff4e166fb5ab9c33b17e6881b48e964f", "value": "0000000000000008000000000000000000000000000000000000000000000000" }, - { - "key": "678de5d61f6f4690357e7868bca285aa8faf5bc9d2126bd8e5006a3ee54f0003", - "value": "0000000000000005000000000000000000000000000000000000000000000000" - }, - { - "key": "71c50136ce909d575b4bd2b1505b9b166ace9d514e92b0e6f9a04abfea8e649d", - "value": "0000000000000002000000000000000000000000000000000000000000000000" - }, { "key": "7f91d1a929dce734e7f930bbb279ccfccdb5474227502ea8845815c74bd930a7", "value": "0000000000000020000000000000000000000000000000000000000000000000" }, { - "key": "94b2b70d20da552763c7614981b2a4d984380d7ed4e54c01b28c914e79e44bd5", - "value": "0000000000000010000000000000000000000000000000000000000000000000" + "key": "8a89a0cce819e0426e565819a9a98711329087da5a802fb16edd223c47fa44ef", + "value": "0000000000000001000000000000000100000000000000020000000000000000" }, { - "key": "9d9209c41faa2ab13bef277e30c3d85b2b95a81816d51614e5816c182ac0a66e", - "value": "0000000000000001000000000000000000000000000000000000000000000000" + "key": "8a89a0cce819e0426e565819a9a98711329087da5a802fb16edd223c47fa44f0", + "value": "0000000000000000000000000000000000000000000000030000000000000001" }, { - "key": "ad7293bc17e2debf737147d46a68be4c2487150275ed02c8a59c58d1452e9052", - "value": "0000000000000009000000000000000000000000000000000000000000000000" + "key": "8a89a0cce819e0426e565819a9a98711329087da5a802fb16edd223c47fa44f1", + "value": "0000000000000004000000000000000500000000000000060000000000000000" }, { - "key": "af75026d46742957dd1a310d00030e0c7099f07760a0f18d84a541ebf8a0c244", - "value": "0000000000000000000000000000000000000000000000000000000000000006" + "key": "94b2b70d20da552763c7614981b2a4d984380d7ed4e54c01b28c914e79e44bd5", + "value": "0000000000000010000000000000000000000000000000000000000000000000" }, { - "key": "b0cfa187f470ad0b95c1e20154630783abb9019127755afbe4fb5e2382888ba6", + "key": "a9203bbb8366ca9d708705dce980acbb54d44fb753370ffe4c7d351b46b2abbc", "value": "0000000000000000000000000000000000000000000000000000000000000000" }, { - "key": "b0cfa187f470ad0b95c1e20154630783abb9019127755afbe4fb5e2382888ba7", + "key": "a9203bbb8366ca9d708705dce980acbb54d44fb753370ffe4c7d351b46b2abbd", "value": "0000000000000000000000000000000000000000000000000000000000000000" }, { - "key": "b0cfa187f470ad0b95c1e20154630783abb9019127755afbe4fb5e2382888ba8", - "value": "0000000000000000000000000000030900000000000000000000000000000000" + "key": "a9203bbb8366ca9d708705dce980acbb54d44fb753370ffe4c7d351b46b2abbe", + "value": "0000000000000000000000000000000000000000000003090000000000000000" }, { - "key": "c28432da64bb717a7d85e34191fc1e50f031b9689c808b653ef3a8328a8e1002", - "value": "0000000000000004000000000000000000000000000000000000000000000000" + "key": "b48b753af346966d0d169c0b2e3234611f65d5cfdb57c7b6e7cd6ca93707bee0", + "value": "0000000000000001000000000000000200000000000000000000000000000000" + }, + { + "key": "b48b753af346966d0d169c0b2e3234611f65d5cfdb57c7b6e7cd6ca93707bee1", + "value": "0000000000000000000000000000000300000000000000040000000000000005" + }, + { + "key": "b48b753af346966d0d169c0b2e3234611f65d5cfdb57c7b6e7cd6ca93707bee2", + "value": "0000000000000000000000000000000000000000000000000000000000000006" }, { - "key": "c497c29a5cb465e7baae51571dfdcd1d47dae5fb4258de06d4f395487d441468", - "value": "0000000000000007000000000000000000000000000000000000000000000000" + "key": "b48b753af346966d0d169c0b2e3234611f65d5cfdb57c7b6e7cd6ca93707bee3", + "value": "0000000000000001000000000000000700000000000000080000000000000009" }, { "key": "c5e69153be998bc6f957aeb6f8fd46a0e9c5bc2d3dff421a73e02f64a3012fbb", @@ -83,22 +63,10 @@ "key": "c5e69153be998bc6f957aeb6f8fd46a0e9c5bc2d3dff421a73e02f64a3012fbc", "value": "4141414141414141000000000000000000000000000000000000000000000000" }, - { - "key": "d55bcd857a8d6a72e6ba8a7aacbf56161e266c2418af5c06c9d1907bbca2624b", - "value": "0000000000000001000000000000000000000000000000000000000000000000" - }, { "key": "de9090cb50e71c2588c773487d1da7066d0c719849a7e58dc8b6397a25c567c0", "value": "0101010101010101010101010101010101010101010101010101010101010101" }, - { - "key": "e945e3646bf99ebf2a70bf0c8151349dab2a54abac6450f0ee9fad896c308871", - "value": "0000000000000008000000000000000000000000000000000000000000000000" - }, - { - "key": "ea9d1ab55216336383fedadabe3c23a4df23267279ea294a547ca1006371746f", - "value": "0000000000000000000000000000000000000000000000000000000000000000" - }, { "key": "f383b0ce51358be57daa3b725fe44acdb2d880604e367199080b4379c41bb6ed", "value": "0000000000000040000000000000000000000000000000000000000000000000" diff --git a/test/src/e2e_vm_tests/test_programs/should_pass/test_contracts/storage_access_contract/src/main.sw b/test/src/e2e_vm_tests/test_programs/should_pass/test_contracts/storage_access_contract/src/main.sw index 6b064d88e05..ad18de34a1c 100644 --- a/test/src/e2e_vm_tests/test_programs/should_pass/test_contracts/storage_access_contract/src/main.sw +++ b/test/src/e2e_vm_tests/test_programs/should_pass/test_contracts/storage_access_contract/src/main.sw @@ -39,148 +39,128 @@ storage { impl StorageAccess for Contract { // Setters #[storage(write)]fn set_x(x: u64) { - storage.x = x; + storage.x.write(x); } #[storage(write)]fn set_y(y: b256) { - storage.y = y; + storage.y.write(y); } #[storage(write)]fn set_s(s: S) { - storage.s = s; + storage.s.write(s); } #[storage(write)]fn set_boolean(boolean: bool) { - storage.boolean = boolean; + storage.boolean.write(boolean); } #[storage(write)]fn set_int8(int8: u8) { - storage.int8 = int8; + storage.int8.write(int8); } #[storage(write)]fn set_int16(int16: u16) { - storage.int16 = int16; + storage.int16.write(int16); } #[storage(write)]fn set_int32(int32: u32) { - storage.int32 = int32; + storage.int32.write(int32); } #[storage(write)]fn set_s_dot_x(x: u64) { - storage.s.x = x; + storage.s.x.write(x); } #[storage(write)]fn set_s_dot_y(y: u64) { - storage.s.y = y; + storage.s.y.write(y); } #[storage(write)]fn set_s_dot_z(z: b256) { - storage.s.z = z; + storage.s.z.write(z); } #[storage(write)]fn set_s_dot_t(t: T) { - storage.s.t = t; + storage.s.t.write(t); } #[storage(write)]fn set_s_dot_t_dot_x(x: u64) { - storage.s.t.x = x; + storage.s.t.x.write(x); } #[storage(write)]fn set_s_dot_t_dot_y(y: u64) { - storage.s.t.y = y; + storage.s.t.y.write(y); } #[storage(write)]fn set_s_dot_t_dot_z(z: b256) { - storage.s.t.z = z; + storage.s.t.z.write(z); } #[storage(write)]fn set_s_dot_t_dot_boolean(boolean: bool) { - storage.s.t.boolean = boolean; + storage.s.t.boolean.write(boolean); } #[storage(write)]fn set_s_dot_t_dot_int8(int8: u8) { - storage.s.t.int8 = int8; + storage.s.t.int8.write(int8); } #[storage(write)]fn set_s_dot_t_dot_int16(int16: u16) { - storage.s.t.int16 = int16; + storage.s.t.int16.write(int16); } #[storage(write)]fn set_s_dot_t_dot_int32(int32: u32) { - storage.s.t.int32 = int32; + storage.s.t.int32.write(int32); } #[storage(write)]fn set_e(e: E) { - storage.e = e; + storage.e.write(e); } #[storage(write)]fn set_string(string: str[40]) { - storage.string = string; + storage.string.write(string); } // Getters #[storage(read)]fn get_x() -> u64 { - storage.x + storage.x.read() } #[storage(read)]fn get_y() -> b256 { - storage.y + storage.y.read() } #[storage(read)]fn get_s() -> S { - storage.s + storage.s.read() } #[storage(read)]fn get_boolean() -> bool { - storage.boolean + storage.boolean.read() } #[storage(read)]fn get_int8() -> u8 { - storage.int8 + storage.int8.read() } #[storage(read)]fn get_int16() -> u16 { - storage.int16 + storage.int16.read() } #[storage(read)]fn get_int32() -> u32 { - storage.int32 + storage.int32.read() } #[storage(read)]fn get_s_dot_x() -> u64 { - storage.s.x + storage.s.x.read() } #[storage(read)]fn get_s_dot_y() -> u64 { - storage.s.y + storage.s.y.read() } #[storage(read)]fn get_s_dot_z() -> b256 { - storage.s.z + storage.s.z.read() } #[storage(read)]fn get_s_dot_t() -> T { - storage.s.t + storage.s.t.read() } #[storage(read)]fn get_s_dot_t_dot_x() -> u64 { - storage.s.t.x + storage.s.t.x.read() } #[storage(read)]fn get_s_dot_t_dot_y() -> u64 { - storage.s.t.y + storage.s.t.y.read() } #[storage(read)]fn get_s_dot_t_dot_z() -> b256 { - storage.s.t.z + storage.s.t.z.read() } #[storage(read)]fn get_s_dot_t_dot_boolean() -> bool { - storage.s.t.boolean + storage.s.t.boolean.read() } #[storage(read)]fn get_s_dot_t_dot_int8() -> u8 { - storage.s.t.int8 + storage.s.t.int8.read() } #[storage(read)]fn get_s_dot_t_dot_int16() -> u16 { - storage.s.t.int16 + storage.s.t.int16.read() } #[storage(read)]fn get_s_dot_t_dot_int32() -> u32 { - storage.s.t.int32 + storage.s.t.int32.read() } #[storage(read)]fn get_e() -> E { - storage.e + storage.e.read() } #[storage(read)]fn get_e2() -> E { - storage.e2 + storage.e2.read() } #[storage(read)]fn get_string() -> str[40] { - storage.string - } - - // Operations - #[storage(read, write)]fn add_to_s_dot_t_dot_x(k: u64) { - storage.s.t.x += k; - } - #[storage(read, write)]fn subtract_from_s_dot_t_dot_x(k: u64) { - storage.s.t.x -= k; - } - #[storage(read, write)]fn multiply_by_s_dot_t_dot_x(k: u64) { - storage.s.t.x *= k; - } - #[storage(read, write)]fn divide_s_dot_t_dot_x(k: u64) { - storage.s.t.x /= k; - } - #[storage(read, write)]fn shift_left_s_dot_t_dot_x(k: u64) { - storage.s.t.x <<= k; - } - #[storage(read, write)]fn shift_right_s_dot_t_dot_x(k: u64) { - storage.s.t.x >>= k; + storage.string.read() } } diff --git a/test/src/e2e_vm_tests/test_programs/should_pass/test_contracts/storage_configurable/json_storage_slots_oracle.json b/test/src/e2e_vm_tests/test_programs/should_pass/test_contracts/storage_configurable/json_storage_slots_oracle.json index 0feb249a7b0..53131c4aef8 100644 --- a/test/src/e2e_vm_tests/test_programs/should_pass/test_contracts/storage_configurable/json_storage_slots_oracle.json +++ b/test/src/e2e_vm_tests/test_programs/should_pass/test_contracts/storage_configurable/json_storage_slots_oracle.json @@ -1,14 +1,10 @@ [ { - "key": "c4f29cca5a7266ecbc35c82c55dd2b0059a3db4c83a3410653ec33aded8e9840", + "key": "f383b0ce51358be57daa3b725fe44acdb2d880604e367199080b4379c41bb6ed", "value": "0000000000000000000000000000000000000000000000000000000000000000" }, { - "key": "c4f29cca5a7266ecbc35c82c55dd2b0059a3db4c83a3410653ec33aded8e9841", - "value": "0000000000000000000000000000000000000000000000000000000000000000" - }, - { - "key": "d625ff6d8e88efd7bb3476e748e5d5935618d78bfc7eedf584fe909ce0809fc3", + "key": "f383b0ce51358be57daa3b725fe44acdb2d880604e367199080b4379c41bb6ee", "value": "0000000000000000000000000000000000000000000000000000000000000000" } ] \ No newline at end of file diff --git a/test/src/ir_generation/mod.rs b/test/src/ir_generation/mod.rs index 4bce366c56c..3fac395242e 100644 --- a/test/src/ir_generation/mod.rs +++ b/test/src/ir_generation/mod.rs @@ -158,7 +158,7 @@ pub(super) async fn run(filter_regex: Option<®ex::Regex>) -> Result<()> { // Compile to IR. let include_tests = true; - let mut ir = compile_program(&typed_program, include_tests, engines, false) + let mut ir = compile_program(&typed_program, include_tests, engines) .unwrap_or_else(|e| { panic!("Failed to compile test {}:\n{e}", path.display()); }) diff --git a/test/src/ir_generation/tests/enum_in_storage_read.sw b/test/src/ir_generation/tests/enum_in_storage_read.sw deleted file mode 100644 index b7f92ad7679..00000000000 --- a/test/src/ir_generation/tests/enum_in_storage_read.sw +++ /dev/null @@ -1,59 +0,0 @@ -contract; - -struct S { - x: u64, - y: u64, - z: u64, - w: u64, - b: u64, -} - -pub enum E { - A: S, - B: u64, -} - -abi StorageAccess { - fn get_e() -> (E, E); -} - -storage { - e1: E = E::B(0), - e2: E = E::B(0), -} - -impl StorageAccess for Contract { - fn get_e() -> (E, E) { - (storage.e1, storage.e2) - } -} - -// check: fn get_e<01665bf4>() -> { { u64, ( { u64, u64, u64, u64, u64 } | u64 ) }, { u64, ( { u64, u64, u64, u64, u64 } | u64 ) } } - -// check: local b256 key_for_0_0 -// check: local b256 key_for_0_1 -// check: local b256 key_for_1_0 -// check: local b256 key_for_1_1 -// check: local [b256; 2] val_for_0_1 -// check: local [b256; 2] val_for_1_1 - -// check: $(enum_undef=$VAL) = get_local ptr { u64, ( { u64, u64, u64, u64, u64 } | u64 ) }, $ID -// check: $(local_key_var=$VAL) = get_local ptr b256, key_for_0_0 -// check: $(key=$VAL) = const b256 0xd625ff6d8e88efd7bb3476e748e5d5935618d78bfc7eedf584fe909ce0809fc3 -// check: store $key to $local_key_var -// check: $(stored_tag_ptr=$VAL) = state_load_word key $local_key_var -// check: $(stored_tag=$VAL) = bitcast $stored_tag_ptr to u64 - -// check: $(idx_0=$VAL) = const u64 0 -// check: $(tag_ptr=$VAL) = get_elem_ptr v0, ptr u64, $idx_0 -// check: store $stored_tag to $tag_ptr - -// check: $(local_key_var2=$VAL) = get_local ptr b256, key_for_0_1 -// check: $(key2=$VAL) = const b256 0xc4f29cca5a7266ecbc35c82c55dd2b0059a3db4c83a3410653ec33aded8e9840 -// check: store $key2 to $local_key_var2 - -// check: $VAL = get_local ptr [b256; 2], val_for_0_1 - -// check: $(storage_val_var=$VAL) = get_local ptr [b256; 2], val_for_0_1 -// check: $(storage_val_var_as_b256=$VAL) = cast_ptr $storage_val_var to ptr b256 -// check: state_load_quad_word $storage_val_var_as_b256, key $local_key_var2 diff --git a/test/src/ir_generation/tests/enum_in_storage_write.sw b/test/src/ir_generation/tests/enum_in_storage_write.sw deleted file mode 100644 index 9893ab4a33c..00000000000 --- a/test/src/ir_generation/tests/enum_in_storage_write.sw +++ /dev/null @@ -1,71 +0,0 @@ -contract; - -struct S { - x: u64, - y: u64, - z: u64, - w: u64, - b: u64, -} - -pub enum E { - A: S, - B: u64, -} - -abi StorageAccess { - fn set_e(s: S, u: u64); -} - -storage { - e1: E = E::B(0), - e2: E = E::B(0), -} - -impl StorageAccess for Contract { - fn set_e(s: S, u: u64) { - storage.e1 = E::A(s); - storage.e2 = E::B(u); - } -} - -// check: fn set_e(s $MD: { u64, u64, u64, u64, u64 }, u $MD: u64) -> () - -// check: local b256 key_for_0_0 -// check: local b256 key_for_0_1 -// check: local b256 key_for_1_0 -// check: local b256 key_for_1_1 -// check: local [b256; 2] val_for_0_1 -// check: local [b256; 2] val_for_1_1 - -// At the moment IRgen is a bit inefficient and it initialises the enum, then makes a copy which it -// then stores. - -// check: $VAL = get_local ptr { u64, ( { u64, u64, u64, u64, u64 } | u64 ) }, $ID -// check: $(copy_val=$VAL) = get_local ptr { u64, ( { u64, u64, u64, u64, u64 } | u64 ) }, $ID - -// check: $(tag_idx=$VAL) = const u64 0 -// check: $(tag_ptr=$VAL) = get_elem_ptr $copy_val, ptr u64, $tag_idx -// check: $(enum_tag=$VAL) = load $tag_ptr - -// check: $(key_0_0_var=$VAL) = get_local ptr b256, key_for_0_0 -// check: $(key_0_0_val=$VAL) = const b256 0xd625ff6d8e88efd7bb3476e748e5d5935618d78bfc7eedf584fe909ce0809fc3 -// check: store $key_0_0_val to $key_0_0_var - -// check: $(enum_tag_u64=$VAL) = bitcast $enum_tag to u64 -// check: state_store_word $enum_tag_u64, key $key_0_0_var - -// check: $(val_idx=$VAL) = const u64 1 -// check: $(val_ptr=$VAL) = get_elem_ptr $copy_val, ptr ( { u64, u64, u64, u64, u64 } | u64 ), $val_idx -// check: $(enum_val=$VAL) = load $val_ptr - -// check: $(key_0_1_var=$VAL) = get_local ptr b256, key_for_0_1 -// check: $(key_0_1_val=$VAL) = const b256 0xc4f29cca5a7266ecbc35c82c55dd2b0059a3db4c83a3410653ec33aded8e9840 -// check: store $key_0_1_val to $key_0_1_var - -// check: $(val_0_1_var=$VAL) = get_local ptr [b256; 2], val_for_0_1 -// check: $(cast_val_0_1=$VAL) = cast_ptr $val_0_1_var to ptr ( { u64, u64, u64, u64, u64 } | u64 ) -// check: store $enum_val to $cast_val_0_1 -// check: $(val_0_1_var_b256=$VAL) = get_local ptr [b256; 2], val_for_0_1 -// check: $(cast_val_0_1_var_b256=$VAL) = cast_ptr $val_0_1_var_b256 to ptr b256 -// check: state_store_quad_word $cast_val_0_1_var_b256, key $key_0_1_var diff --git a/test/src/ir_generation/tests/get_storage_key.sw b/test/src/ir_generation/tests/get_storage_key.sw deleted file mode 100644 index d6955a22ce5..00000000000 --- a/test/src/ir_generation/tests/get_storage_key.sw +++ /dev/null @@ -1,40 +0,0 @@ -contract; - -struct Empty {} - -impl Empty { - fn bar(self) -> b256 { - __get_storage_key() - } -} - -storage { - e1: Empty = Empty { }, - e2: Empty = Empty { }, -} - -abi GetStorageKeyTest { - fn foo1() -> b256; - fn foo2() -> b256; -} - -impl GetStorageKeyTest for Contract { - fn foo1() -> b256 { - storage.e1.bar() - } - fn foo2() -> b256 { - storage.e2.bar() - } -} - -// check: fn foo1<2994c98e>() -> b256 -// check: entry(): -// nextln: $(empty_struct_val=$VAL) = get_local ptr { }, $ID -// nextln: $(loaded=$VAL) = load $empty_struct_val -// nextln: call $(fn_name=$ID)($loaded) - -// check: fn $fn_name(self $MD: { }) -> b256 -// nextln: entry(self: { } -// nextln: $(key_val=$VAL) = get_storage_key -// nextln: $(ret_val=$VAL) = load $key_val -// nextln: ret b256 $ret_val diff --git a/test/src/ir_generation/tests/strings_in_storage.sw b/test/src/ir_generation/tests/strings_in_storage.sw deleted file mode 100644 index 29b0dd281d8..00000000000 --- a/test/src/ir_generation/tests/strings_in_storage.sw +++ /dev/null @@ -1,57 +0,0 @@ -contract; - -abi StorageAccess { - // Setters - fn set_s(s: str[40]); - fn get_s() -> str[40]; -} - -storage { - s: str[40] = "0000000000000000000000000000000000000000", -} - -impl StorageAccess for Contract { - fn set_s(s: str[40]) { - storage.s = s; - } - - fn get_s() -> str[40] { - storage.s - } -} - -// check: fn get_s -// check: local b256 $(key=$ID) -// check: local [b256; 2] $(val_ary=$ID) - -// check: $(key_var=$VAL) = get_local ptr b256, $key -// check: $(key_val=$VAL) = const b256 0xf383b0ce51358be57daa3b725fe44acdb2d880604e367199080b4379c41bb6ed -// check: store $key_val to $key_var - -// check: $(val_ary_var=$VAL) = get_local ptr [b256; 2], $val_ary -// check: $(val_ary_as_string_ptr=$VAL) = cast_ptr $val_ary_var to ptr string<40> - -// check: $(val_ary_0_var=$VAL) = get_local ptr [b256; 2], $val_ary -// check: $(val_ary_0_as_b256=$VAL) = cast_ptr $val_ary_0_var to ptr b256 -// check: $(slot_count=$VAL) = const u64 2 -// check: state_load_quad_word $val_ary_0_as_b256, key $key_var, $slot_count - -// check: $(val_ary_as_string=$VAL) = load $val_ary_as_string_ptr -// check: ret string<40> $val_ary_as_string - -// check: fn set_s -// check: local b256 $(key=$ID) -// check: local [b256; 2] $(val_ary=$ID) - -// check: $(key_var=$VAL) = get_local ptr b256, $key -// check: $(key_val=$VAL) = const b256 0xf383b0ce51358be57daa3b725fe44acdb2d880604e367199080b4379c41bb6ed -// check: store $key_val to $key_var - -// check: $(val_ary_var=$VAL) = get_local ptr [b256; 2], $val_ary -// check: $(val_ary_var_as_str=$VAL) = cast_ptr $val_ary_var to ptr string<40> -// check: store s to $val_ary_var_as_str - -// check: $(val_ary_0_var=$VAL) = get_local ptr [b256; 2], $val_ary -// check: $(val_ary_0_as_b256=$VAL) = cast_ptr $val_ary_0_var to ptr b256 -// check: $(slot_count=$VAL) = const u64 2 -// check: state_store_quad_word $val_ary_0_as_b256, key $key_var, $slot_count diff --git a/test/src/sdk-harness/Forc.lock b/test/src/sdk-harness/Forc.lock index 1ccb7446f94..c1db6ba98ac 100644 --- a/test/src/sdk-harness/Forc.lock +++ b/test/src/sdk-harness/Forc.lock @@ -226,16 +226,36 @@ name = 'storage' source = 'member' dependencies = ['std'] +[[package]] +name = 'storage_access' +source = 'member' +dependencies = ['std'] + [[package]] name = 'storage_bytes' source = 'member' dependencies = ['std'] +[[package]] +name = 'storage_init' +source = 'member' +dependencies = ['std'] + [[package]] name = 'storage_map' source = 'member' dependencies = ['std'] +[[package]] +name = 'storage_map_nested' +source = 'member' +dependencies = ['std'] + +[[package]] +name = 'storage_vec_nested' +source = 'member' +dependencies = ['std'] + [[package]] name = 'svec_array' source = 'member' diff --git a/test/src/sdk-harness/Forc.toml b/test/src/sdk-harness/Forc.toml index 6cf05fbb2cf..f9ba79d19a3 100644 --- a/test/src/sdk-harness/Forc.toml +++ b/test/src/sdk-harness/Forc.toml @@ -25,8 +25,12 @@ members = [ "test_projects/script_bytecode", "test_projects/script_data", "test_projects/storage", + "test_projects/storage_access", "test_projects/storage_bytes", + "test_projects/storage_init", "test_projects/storage_map", + "test_projects/storage_map_nested", + "test_projects/storage_vec_nested", "test_projects/token_ops", "test_projects/tx_fields", "test_projects/type_aliases", diff --git a/test/src/sdk-harness/build.sh b/test/src/sdk-harness/build.sh new file mode 100755 index 00000000000..638675782bc --- /dev/null +++ b/test/src/sdk-harness/build.sh @@ -0,0 +1,46 @@ +#!/usr/bin/env bash + +# Pass `--locked` when running this script in CI to ensure both cargo and forc +# lock files are up to date. +locked="$1" + +# Cross platform version of `realpath` or `readlink`. +abs_path() { + (cd "$1"; pwd) +} + +# Grab the absolute path to this script. +base_dir="$(abs_path $(dirname $0))" + +# Search for the parent Cargo manifest for Forc. +parent_manifest_dir="${base_dir}" +while true; do + parent_manifest_dir=$(abs_path "${parent_manifest_dir}/..") + if [[ -f "${parent_manifest_dir}/Cargo.toml" ]]; then + forc="cargo run $locked --manifest-path ${parent_manifest_dir}/Cargo.toml --package forc --" + break + fi + if [[ "${parent_manifest_dir}" = "/" ]]; then + # Not found for some reason. Default to an installed binary. + forc="forc" + break + fi +done + +test_dirs="${base_dir}/test_artifacts/* ${base_dir}/test_projects/* ${base_dir}/test_artifacts/*/*" + +for test_dir in $test_dirs; do + if [[ -f "${test_dir}/Forc.toml" ]]; then + echo "Building test $test_dir..." + ${forc} build $locked -o temp -p "${test_dir}" && echo ✔ + if ! [[ -f temp ]]; then + echo "❌ Failed to build $test_dir" + exit 1 + fi + rm -f temp + else + echo "Skipping test $test_dir..." + fi +done + +echo "Successfully built all projects." diff --git a/test/src/sdk-harness/test_artifacts/low_level_callee_contract/src/main.sw b/test/src/sdk-harness/test_artifacts/low_level_callee_contract/src/main.sw index ccdc59dde4c..005440019a5 100644 --- a/test/src/sdk-harness/test_artifacts/low_level_callee_contract/src/main.sw +++ b/test/src/sdk-harness/test_artifacts/low_level_callee_contract/src/main.sw @@ -36,44 +36,44 @@ storage { impl CalledContract for Contract { #[storage(write)] fn set_value(new_value: u64) { - storage.value = new_value; + storage.value.write(new_value); } #[storage(write)] fn set_value_multiple(a: u64, b: u64) { - storage.value = a + b; + storage.value.write(a + b); } #[storage(write)] fn set_value_multiple_complex(a: MyStruct, b: str[4]) { //revert(999); - storage.value = a.b[1]; - storage.value_str = b; - storage.value_bool = a.a; + storage.value.write(a.b[1]); + storage.value_str.write(b); + storage.value_bool.write(a.a); } #[storage(read)] fn get_value() -> u64 { - storage.value + storage.value.read() } #[storage(write)] fn set_b256_value(new_value: b256) { - storage.value_b256 = new_value; + storage.value_b256.write(new_value); } #[storage(read)] fn get_b256_value() -> b256 { - storage.value_b256 + storage.value_b256.read() } #[storage(read)] fn get_str_value() -> str[4] { - storage.value_str + storage.value_str.read() } #[storage(read)] fn get_bool_value() -> bool { - storage.value_bool + storage.value_bool.read() } } diff --git a/test/src/sdk-harness/test_artifacts/methods_contract/src/main.sw b/test/src/sdk-harness/test_artifacts/methods_contract/src/main.sw index ab53faa9545..13f7f36aa00 100644 --- a/test/src/sdk-harness/test_artifacts/methods_contract/src/main.sw +++ b/test/src/sdk-harness/test_artifacts/methods_contract/src/main.sw @@ -28,10 +28,10 @@ impl MethodsContract for Contract { fn test_function() -> bool { let identity = bogus(); let identity2 = bogus2(); - storage.stored_struct = MyStruct { + storage.stored_struct.write(MyStruct { int_option: Option::Some(99u64), - }; - let stored_struct = storage.stored_struct; + }); + let stored_struct = storage.stored_struct.read(); let stored_option_in_struct = stored_struct.int_option; require(stored_option_in_struct.is_some(), "Error"); true diff --git a/test/src/sdk-harness/test_artifacts/storage_vec/svec_array/src/main.sw b/test/src/sdk-harness/test_artifacts/storage_vec/svec_array/src/main.sw index 7e07473ee76..5ee11715d83 100644 --- a/test/src/sdk-harness/test_artifacts/storage_vec/svec_array/src/main.sw +++ b/test/src/sdk-harness/test_artifacts/storage_vec/svec_array/src/main.sw @@ -1,6 +1,6 @@ contract; -use std::storage::StorageVec; +use std::storage::storage_vec::*; abi MyContract { #[storage(read, write)] @@ -69,7 +69,7 @@ impl MyContract for Contract { #[storage(read)] fn get(index: u64) -> [u8; 3] { - storage.my_vec.get(index).unwrap() + storage.my_vec.get(index).unwrap().read() } #[storage(read, write)] @@ -114,12 +114,12 @@ impl MyContract for Contract { #[storage(read)] fn first() -> [u8; 3] { - storage.my_vec.first().unwrap() + storage.my_vec.first().unwrap().read() } #[storage(read)] fn last() -> [u8; 3] { - storage.my_vec.last().unwrap() + storage.my_vec.last().unwrap().read() } #[storage(read, write)] diff --git a/test/src/sdk-harness/test_artifacts/storage_vec/svec_b256/src/main.sw b/test/src/sdk-harness/test_artifacts/storage_vec/svec_b256/src/main.sw index c32557d2f03..baa9916af8f 100644 --- a/test/src/sdk-harness/test_artifacts/storage_vec/svec_b256/src/main.sw +++ b/test/src/sdk-harness/test_artifacts/storage_vec/svec_b256/src/main.sw @@ -1,6 +1,6 @@ contract; -use std::storage::StorageVec; +use std::storage::storage_vec::*; abi MyContract { #[storage(read, write)] @@ -69,7 +69,7 @@ impl MyContract for Contract { #[storage(read)] fn get(index: u64) -> b256 { - storage.my_vec.get(index).unwrap() + storage.my_vec.get(index).unwrap().read() } #[storage(read, write)] @@ -114,12 +114,12 @@ impl MyContract for Contract { #[storage(read)] fn first() -> b256 { - storage.my_vec.first().unwrap() + storage.my_vec.first().unwrap().read() } #[storage(read)] fn last() -> b256 { - storage.my_vec.last().unwrap() + storage.my_vec.last().unwrap().read() } #[storage(read, write)] diff --git a/test/src/sdk-harness/test_artifacts/storage_vec/svec_bool/src/main.sw b/test/src/sdk-harness/test_artifacts/storage_vec/svec_bool/src/main.sw index d2493b36616..9a94cf72bef 100644 --- a/test/src/sdk-harness/test_artifacts/storage_vec/svec_bool/src/main.sw +++ b/test/src/sdk-harness/test_artifacts/storage_vec/svec_bool/src/main.sw @@ -1,6 +1,6 @@ contract; -use std::storage::StorageVec; +use std::storage::storage_vec::*; abi MyContract { #[storage(read, write)] @@ -69,7 +69,7 @@ impl MyContract for Contract { #[storage(read)] fn get(index: u64) -> bool { - storage.my_vec.get(index).unwrap() + storage.my_vec.get(index).unwrap().read() } #[storage(read, write)] @@ -114,12 +114,12 @@ impl MyContract for Contract { #[storage(read)] fn first() -> bool { - storage.my_vec.first().unwrap() + storage.my_vec.first().unwrap().read() } #[storage(read)] fn last() -> bool { - storage.my_vec.last().unwrap() + storage.my_vec.last().unwrap().read() } #[storage(read, write)] diff --git a/test/src/sdk-harness/test_artifacts/storage_vec/svec_enum/src/main.sw b/test/src/sdk-harness/test_artifacts/storage_vec/svec_enum/src/main.sw index 8eac64b0b6c..fb11fbfa148 100644 --- a/test/src/sdk-harness/test_artifacts/storage_vec/svec_enum/src/main.sw +++ b/test/src/sdk-harness/test_artifacts/storage_vec/svec_enum/src/main.sw @@ -1,6 +1,6 @@ contract; -use std::storage::StorageVec; +use std::storage::storage_vec::*; enum TestEnum { A: bool, @@ -74,7 +74,7 @@ impl MyContract for Contract { #[storage(read)] fn get(index: u64) -> TestEnum { - storage.my_vec.get(index).unwrap() + storage.my_vec.get(index).unwrap().read() } #[storage(read, write)] @@ -119,12 +119,12 @@ impl MyContract for Contract { #[storage(read)] fn first() -> TestEnum { - storage.my_vec.first().unwrap() + storage.my_vec.first().unwrap().read() } #[storage(read)] fn last() -> TestEnum { - storage.my_vec.last().unwrap() + storage.my_vec.last().unwrap().read() } #[storage(read, write)] diff --git a/test/src/sdk-harness/test_artifacts/storage_vec/svec_str/src/main.sw b/test/src/sdk-harness/test_artifacts/storage_vec/svec_str/src/main.sw index a9e46f03c25..79aef83bcfe 100644 --- a/test/src/sdk-harness/test_artifacts/storage_vec/svec_str/src/main.sw +++ b/test/src/sdk-harness/test_artifacts/storage_vec/svec_str/src/main.sw @@ -1,6 +1,6 @@ contract; -use std::storage::StorageVec; +use std::storage::storage_vec::*; abi MyContract { #[storage(read, write)] @@ -69,7 +69,7 @@ impl MyContract for Contract { #[storage(read)] fn get(index: u64) -> str[4] { - storage.my_vec.get(index).unwrap() + storage.my_vec.get(index).unwrap().read() } #[storage(read, write)] @@ -114,12 +114,12 @@ impl MyContract for Contract { #[storage(read)] fn first() -> str[4] { - storage.my_vec.first().unwrap() + storage.my_vec.first().unwrap().read() } #[storage(read)] fn last() -> str[4] { - storage.my_vec.last().unwrap() + storage.my_vec.last().unwrap().read() } #[storage(read, write)] diff --git a/test/src/sdk-harness/test_artifacts/storage_vec/svec_struct/src/main.sw b/test/src/sdk-harness/test_artifacts/storage_vec/svec_struct/src/main.sw index e209025b5d8..fc00640b781 100644 --- a/test/src/sdk-harness/test_artifacts/storage_vec/svec_struct/src/main.sw +++ b/test/src/sdk-harness/test_artifacts/storage_vec/svec_struct/src/main.sw @@ -1,6 +1,6 @@ contract; -use std::storage::StorageVec; +use std::storage::storage_vec::*; struct TestStruct { a: bool, @@ -74,7 +74,7 @@ impl MyContract for Contract { #[storage(read)] fn get(index: u64) -> TestStruct { - storage.my_vec.get(index).unwrap() + storage.my_vec.get(index).unwrap().read() } #[storage(read, write)] @@ -119,12 +119,12 @@ impl MyContract for Contract { #[storage(read)] fn first() -> TestStruct { - storage.my_vec.first().unwrap() + storage.my_vec.first().unwrap().read() } #[storage(read)] fn last() -> TestStruct { - storage.my_vec.last().unwrap() + storage.my_vec.last().unwrap().read() } #[storage(read, write)] diff --git a/test/src/sdk-harness/test_artifacts/storage_vec/svec_tuple/src/main.sw b/test/src/sdk-harness/test_artifacts/storage_vec/svec_tuple/src/main.sw index 18604ee538f..4849e2be23e 100644 --- a/test/src/sdk-harness/test_artifacts/storage_vec/svec_tuple/src/main.sw +++ b/test/src/sdk-harness/test_artifacts/storage_vec/svec_tuple/src/main.sw @@ -1,6 +1,6 @@ contract; -use std::storage::StorageVec; +use std::storage::storage_vec::*; abi MyContract { #[storage(read, write)] @@ -69,7 +69,7 @@ impl MyContract for Contract { #[storage(read)] fn get(index: u64) -> (u8, u8, u8) { - storage.my_vec.get(index).unwrap() + storage.my_vec.get(index).unwrap().read() } #[storage(read, write)] @@ -114,12 +114,12 @@ impl MyContract for Contract { #[storage(read)] fn first() -> (u8, u8, u8) { - storage.my_vec.first().unwrap() + storage.my_vec.first().unwrap().read() } #[storage(read)] fn last() -> (u8, u8, u8) { - storage.my_vec.last().unwrap() + storage.my_vec.last().unwrap().read() } #[storage(read, write)] diff --git a/test/src/sdk-harness/test_artifacts/storage_vec/svec_u16/src/main.sw b/test/src/sdk-harness/test_artifacts/storage_vec/svec_u16/src/main.sw index 68e06fbdfb3..a4b638c0945 100644 --- a/test/src/sdk-harness/test_artifacts/storage_vec/svec_u16/src/main.sw +++ b/test/src/sdk-harness/test_artifacts/storage_vec/svec_u16/src/main.sw @@ -1,6 +1,6 @@ contract; -use std::storage::StorageVec; +use std::storage::storage_vec::*; abi MyContract { #[storage(read, write)] @@ -69,7 +69,7 @@ impl MyContract for Contract { #[storage(read)] fn get(index: u64) -> u16 { - storage.my_vec.get(index).unwrap() + storage.my_vec.get(index).unwrap().read() } #[storage(read, write)] @@ -114,12 +114,12 @@ impl MyContract for Contract { #[storage(read)] fn first() -> u16 { - storage.my_vec.first().unwrap() + storage.my_vec.first().unwrap().read() } #[storage(read)] fn last() -> u16 { - storage.my_vec.last().unwrap() + storage.my_vec.last().unwrap().read() } #[storage(read, write)] diff --git a/test/src/sdk-harness/test_artifacts/storage_vec/svec_u32/src/main.sw b/test/src/sdk-harness/test_artifacts/storage_vec/svec_u32/src/main.sw index 132175a6a72..3d668873e3b 100644 --- a/test/src/sdk-harness/test_artifacts/storage_vec/svec_u32/src/main.sw +++ b/test/src/sdk-harness/test_artifacts/storage_vec/svec_u32/src/main.sw @@ -1,6 +1,6 @@ contract; -use std::storage::StorageVec; +use std::storage::storage_vec::*; abi MyContract { #[storage(read, write)] @@ -69,7 +69,7 @@ impl MyContract for Contract { #[storage(read)] fn get(index: u64) -> u32 { - storage.my_vec.get(index).unwrap() + storage.my_vec.get(index).unwrap().read() } #[storage(read, write)] @@ -114,12 +114,12 @@ impl MyContract for Contract { #[storage(read)] fn first() -> u32 { - storage.my_vec.first().unwrap() + storage.my_vec.first().unwrap().read() } #[storage(read)] fn last() -> u32 { - storage.my_vec.last().unwrap() + storage.my_vec.last().unwrap().read() } #[storage(read, write)] diff --git a/test/src/sdk-harness/test_artifacts/storage_vec/svec_u64/src/main.sw b/test/src/sdk-harness/test_artifacts/storage_vec/svec_u64/src/main.sw index 60f8ee3dd7d..e4f40ecec9c 100644 --- a/test/src/sdk-harness/test_artifacts/storage_vec/svec_u64/src/main.sw +++ b/test/src/sdk-harness/test_artifacts/storage_vec/svec_u64/src/main.sw @@ -1,6 +1,6 @@ contract; -use std::storage::StorageVec; +use std::storage::storage_vec::*; abi MyContract { #[storage(read, write)] @@ -69,7 +69,7 @@ impl MyContract for Contract { #[storage(read)] fn get(index: u64) -> u64 { - storage.my_vec.get(index).unwrap() + storage.my_vec.get(index).unwrap().read() } #[storage(read, write)] @@ -114,12 +114,12 @@ impl MyContract for Contract { #[storage(read)] fn first() -> u64 { - storage.my_vec.first().unwrap() + storage.my_vec.first().unwrap().read() } #[storage(read)] fn last() -> u64 { - storage.my_vec.last().unwrap() + storage.my_vec.last().unwrap().read() } #[storage(read, write)] diff --git a/test/src/sdk-harness/test_artifacts/storage_vec/svec_u8/src/main.sw b/test/src/sdk-harness/test_artifacts/storage_vec/svec_u8/src/main.sw index 29a0a4b7e4a..c66a6aaa069 100644 --- a/test/src/sdk-harness/test_artifacts/storage_vec/svec_u8/src/main.sw +++ b/test/src/sdk-harness/test_artifacts/storage_vec/svec_u8/src/main.sw @@ -1,6 +1,6 @@ contract; -use std::storage::StorageVec; +use std::storage::storage_vec::*; abi MyContract { #[storage(read, write)] @@ -69,7 +69,7 @@ impl MyContract for Contract { #[storage(read)] fn get(index: u64) -> u8 { - storage.my_vec.get(index).unwrap() + storage.my_vec.get(index).unwrap().read() } #[storage(read, write)] @@ -114,12 +114,12 @@ impl MyContract for Contract { #[storage(read)] fn first() -> u8 { - storage.my_vec.first().unwrap() + storage.my_vec.first().unwrap().read() } #[storage(read)] fn last() -> u8 { - storage.my_vec.last().unwrap() + storage.my_vec.last().unwrap().read() } #[storage(read, write)] diff --git a/test/src/sdk-harness/test_projects/experimental_storage_init/mod.rs b/test/src/sdk-harness/test_projects/experimental_storage_init/mod.rs deleted file mode 100644 index eaf97ec123a..00000000000 --- a/test/src/sdk-harness/test_projects/experimental_storage_init/mod.rs +++ /dev/null @@ -1,29 +0,0 @@ -use fuels::prelude::*; - -abigen!(Contract( - name = "TestExperimentalStorageInitContract", - abi = "test_projects/experimental_storage_init/out/debug/experimental_storage_init-abi.json", -)); - -async fn test_experimental_storage_init_instance( -) -> TestExperimentalStorageInitContract { - let wallet = launch_provider_and_get_wallet().await; - let id = Contract::deploy( - "test_projects/experimental_storage_init/out/debug/experimental_storage_init.bin", - &wallet, - DeployConfiguration::default() - .set_storage_configuration(StorageConfiguration::default().set_storage_path( - "test_projects/experimental_storage_init/out/debug/experimental_storage_init-storage_slots.json".to_string() - )) - ) - .await - .unwrap(); - - TestExperimentalStorageInitContract::new(id.clone(), wallet) -} - -#[tokio::test] -async fn test_initializers() { - let methods = test_experimental_storage_init_instance().await.methods(); - assert!(methods.test_initializers().call().await.unwrap().value); -} diff --git a/test/src/sdk-harness/test_projects/experimental_storage_map/mod.rs b/test/src/sdk-harness/test_projects/experimental_storage_map/mod.rs deleted file mode 100644 index 3fb9187615c..00000000000 --- a/test/src/sdk-harness/test_projects/experimental_storage_map/mod.rs +++ /dev/null @@ -1,1788 +0,0 @@ -use fuels::{ - prelude::*, - types::{Bits256, SizedAsciiString}, -}; - -abigen!(Contract( - name = "TestExperimentalStorageMapContract", - abi = "test_projects/experimental_storage_map/out/debug/experimental_storage_map-abi.json", -)); - -async fn test_experimental_storage_map_instance( -) -> TestExperimentalStorageMapContract { - let wallet = launch_provider_and_get_wallet().await; - let id = Contract::deploy( - "test_projects/experimental_storage_map/out/debug/experimental_storage_map.bin", - &wallet, - DeployConfiguration::default(), - ) - .await - .unwrap(); - - TestExperimentalStorageMapContract::new(id.clone(), wallet) -} - -mod u64_to { - - use super::*; - - #[tokio::test] - async fn bool_map() { - let instance = test_experimental_storage_map_instance().await; - - let (key1, key2, key3) = (1, 2, 3); - let (val1, val2, val3) = (true, false, true); - - // Nothing to read just yet - assert_eq!( - instance - .methods() - .get_from_u64_to_bool_map(key1) - .call() - .await - .unwrap() - .value, - None - ); - - // Insert into u64 -> T storage maps - instance - .methods() - .insert_into_u64_to_bool_map(key1, val1) - .call() - .await - .unwrap(); - instance - .methods() - .insert_into_u64_to_bool_map(key2, val2) - .call() - .await - .unwrap(); - instance - .methods() - .insert_into_u64_to_bool_map(key3, val3) - .call() - .await - .unwrap(); - - // Get from u64 -> T storage maps - assert_eq!( - instance - .methods() - .get_from_u64_to_bool_map(key1) - .call() - .await - .unwrap() - .value, - Some(val1) - ); - assert_eq!( - instance - .methods() - .get_from_u64_to_bool_map(key2) - .call() - .await - .unwrap() - .value, - Some(val2) - ); - assert_eq!( - instance - .methods() - .get_from_u64_to_bool_map(key3) - .call() - .await - .unwrap() - .value, - Some(val3) - ); - - // Test `remove` - assert_eq!( - instance - .methods() - .remove_from_u64_to_bool_map(key1) - .call() - .await - .unwrap() - .value, - true - ); - - assert_eq!( - instance - .methods() - .get_from_u64_to_bool_map(key1) - .call() - .await - .unwrap() - .value, - None - ); - } - - #[tokio::test] - async fn u8_map() { - let instance = test_experimental_storage_map_instance().await; - - let (key1, key2, key3) = (1, 2, 3); - let (val1, val2, val3) = (8, 66, 99); - - // Nothing to read just yet - assert_eq!( - instance - .methods() - .get_from_u64_to_u8_map(key1) - .call() - .await - .unwrap() - .value, - None - ); - - instance - .methods() - .insert_into_u64_to_u8_map(key1, val1) - .call() - .await - .unwrap(); - instance - .methods() - .insert_into_u64_to_u8_map(key2, val2) - .call() - .await - .unwrap(); - instance - .methods() - .insert_into_u64_to_u8_map(key3, val3) - .call() - .await - .unwrap(); - - assert_eq!( - instance - .methods() - .get_from_u64_to_u8_map(key1) - .call() - .await - .unwrap() - .value, - Some(val1) - ); - assert_eq!( - instance - .methods() - .get_from_u64_to_u8_map(key2) - .call() - .await - .unwrap() - .value, - Some(val2) - ); - assert_eq!( - instance - .methods() - .get_from_u64_to_u8_map(key3) - .call() - .await - .unwrap() - .value, - Some(val3) - ); - - // Test `remove` - assert_eq!( - instance - .methods() - .remove_from_u64_to_u8_map(key1) - .call() - .await - .unwrap() - .value, - true - ); - - assert_eq!( - instance - .methods() - .get_from_u64_to_u8_map(key1) - .call() - .await - .unwrap() - .value, - None - ); - } - - #[tokio::test] - async fn u16_map() { - let instance = test_experimental_storage_map_instance().await; - - let (key1, key2, key3) = (6, 9, 1); - let (val1, val2, val3) = (9, 42, 100); - - // Nothing to read just yet - assert_eq!( - instance - .methods() - .get_from_u64_to_u16_map(key1) - .call() - .await - .unwrap() - .value, - None - ); - - instance - .methods() - .insert_into_u64_to_u16_map(key1, val1) - .call() - .await - .unwrap(); - instance - .methods() - .insert_into_u64_to_u16_map(key2, val2) - .call() - .await - .unwrap(); - instance - .methods() - .insert_into_u64_to_u16_map(key3, val3) - .call() - .await - .unwrap(); - - assert_eq!( - instance - .methods() - .get_from_u64_to_u16_map(key1) - .call() - .await - .unwrap() - .value, - Some(val1) - ); - assert_eq!( - instance - .methods() - .get_from_u64_to_u16_map(key2) - .call() - .await - .unwrap() - .value, - Some(val2) - ); - assert_eq!( - instance - .methods() - .get_from_u64_to_u16_map(key3) - .call() - .await - .unwrap() - .value, - Some(val3) - ); - - // Test `remove` - assert_eq!( - instance - .methods() - .remove_from_u64_to_u16_map(key1) - .call() - .await - .unwrap() - .value, - true - ); - - assert_eq!( - instance - .methods() - .get_from_u64_to_u16_map(key1) - .call() - .await - .unwrap() - .value, - None - ); - } - - #[tokio::test] - async fn u32_map() { - let instance = test_experimental_storage_map_instance().await; - - let (key1, key2, key3) = (5, 99, 10); - let (val1, val2, val3) = (90, 2, 100); - - // Nothing to read just yet - assert_eq!( - instance - .methods() - .get_from_u64_to_u32_map(key1) - .call() - .await - .unwrap() - .value, - None - ); - - instance - .methods() - .insert_into_u64_to_u32_map(key1, val1) - .call() - .await - .unwrap(); - instance - .methods() - .insert_into_u64_to_u32_map(key2, val2) - .call() - .await - .unwrap(); - instance - .methods() - .insert_into_u64_to_u32_map(key3, val3) - .call() - .await - .unwrap(); - - assert_eq!( - instance - .methods() - .get_from_u64_to_u32_map(key1) - .call() - .await - .unwrap() - .value, - Some(val1) - ); - assert_eq!( - instance - .methods() - .get_from_u64_to_u32_map(key2) - .call() - .await - .unwrap() - .value, - Some(val2) - ); - assert_eq!( - instance - .methods() - .get_from_u64_to_u32_map(key3) - .call() - .await - .unwrap() - .value, - Some(val3) - ); - - // Test `remove` - assert_eq!( - instance - .methods() - .remove_from_u64_to_u32_map(key1) - .call() - .await - .unwrap() - .value, - true - ); - - assert_eq!( - instance - .methods() - .get_from_u64_to_u32_map(key1) - .call() - .await - .unwrap() - .value, - None - ); - } - - #[tokio::test] - async fn u64_map() { - let instance = test_experimental_storage_map_instance().await; - - let (key1, key2, key3) = (50, 99, 1); - let (val1, val2, val3) = (90, 20, 10); - - // Nothing to read just yet - assert_eq!( - instance - .methods() - .get_from_u64_to_u64_map(key1) - .call() - .await - .unwrap() - .value, - None - ); - - instance - .methods() - .insert_into_u64_to_u64_map(key1, val1) - .call() - .await - .unwrap(); - instance - .methods() - .insert_into_u64_to_u64_map(key2, val2) - .call() - .await - .unwrap(); - instance - .methods() - .insert_into_u64_to_u64_map(key3, val3) - .call() - .await - .unwrap(); - - assert_eq!( - instance - .methods() - .get_from_u64_to_u64_map(key1) - .call() - .await - .unwrap() - .value, - Some(val1) - ); - assert_eq!( - instance - .methods() - .get_from_u64_to_u64_map(key2) - .call() - .await - .unwrap() - .value, - Some(val2) - ); - assert_eq!( - instance - .methods() - .get_from_u64_to_u64_map(key3) - .call() - .await - .unwrap() - .value, - Some(val3) - ); - - // Test `remove` - assert_eq!( - instance - .methods() - .remove_from_u64_to_u64_map(key1) - .call() - .await - .unwrap() - .value, - true - ); - - assert_eq!( - instance - .methods() - .get_from_u64_to_u64_map(key1) - .call() - .await - .unwrap() - .value, - None - ); - } - - #[tokio::test] - async fn tuple_map() { - let instance = test_experimental_storage_map_instance().await; - - let (key1, key2, key3) = (50, 99, 10); - let (val1, val2, val3) = ( - (Bits256([1; 32]), 42, true), - (Bits256([2; 32]), 24, true), - (Bits256([3; 32]), 99, true), - ); - - // Nothing to read just yet - assert_eq!( - instance - .methods() - .get_from_u64_to_tuple_map(key1) - .call() - .await - .unwrap() - .value, - None - ); - - instance - .methods() - .insert_into_u64_to_tuple_map(key1, val1) - .call() - .await - .unwrap(); - instance - .methods() - .insert_into_u64_to_tuple_map(key2, val2) - .call() - .await - .unwrap(); - instance - .methods() - .insert_into_u64_to_tuple_map(key3, val3) - .call() - .await - .unwrap(); - - assert_eq!( - instance - .methods() - .get_from_u64_to_tuple_map(key1) - .call() - .await - .unwrap() - .value, - Some(val1) - ); - assert_eq!( - instance - .methods() - .get_from_u64_to_tuple_map(key2) - .call() - .await - .unwrap() - .value, - Some(val2) - ); - assert_eq!( - instance - .methods() - .get_from_u64_to_tuple_map(key3) - .call() - .await - .unwrap() - .value, - Some(val3) - ); - - // Test `remove` - assert_eq!( - instance - .methods() - .remove_from_u64_to_tuple_map(key1) - .call() - .await - .unwrap() - .value, - true - ); - - assert_eq!( - instance - .methods() - .get_from_u64_to_tuple_map(key1) - .call() - .await - .unwrap() - .value, - None - ); - } - - #[tokio::test] - async fn struct_map() { - let instance = test_experimental_storage_map_instance().await; - - let (key1, key2, key3) = (5, 9, 1); - let (val1, val2, val3) = ( - Struct { - x: 42, - y: Bits256([66; 32]), - z: Bits256([99; 32]), - }, - Struct { - x: 24, - y: Bits256([11; 32]), - z: Bits256([90; 32]), - }, - Struct { - x: 77, - y: Bits256([55; 32]), - z: Bits256([12; 32]), - }, - ); - - // Nothing to read just yet - assert_eq!( - instance - .methods() - .get_from_u64_to_struct_map(key1) - .call() - .await - .unwrap() - .value, - None - ); - - instance - .methods() - .insert_into_u64_to_struct_map(key1, val1.clone()) - .call() - .await - .unwrap(); - instance - .methods() - .insert_into_u64_to_struct_map(key2, val2.clone()) - .call() - .await - .unwrap(); - instance - .methods() - .insert_into_u64_to_struct_map(key3, val3.clone()) - .call() - .await - .unwrap(); - - assert_eq!( - instance - .methods() - .get_from_u64_to_struct_map(key1) - .call() - .await - .unwrap() - .value, - Some(val1) - ); - assert_eq!( - instance - .methods() - .get_from_u64_to_struct_map(key2) - .call() - .await - .unwrap() - .value, - Some(val2) - ); - assert_eq!( - instance - .methods() - .get_from_u64_to_struct_map(key3) - .call() - .await - .unwrap() - .value, - Some(val3) - ); - - // Test `remove` - assert_eq!( - instance - .methods() - .remove_from_u64_to_struct_map(key1) - .call() - .await - .unwrap() - .value, - true - ); - - assert_eq!( - instance - .methods() - .get_from_u64_to_struct_map(key1) - .call() - .await - .unwrap() - .value, - None - ); - } - - #[tokio::test] - async fn enum_map() { - let instance = test_experimental_storage_map_instance().await; - - let (key1, key2, key3) = (44, 17, 1000); - let (val1, val2, val3) = ( - Enum::V1(Bits256([66; 32])), - Enum::V2(42), - Enum::V3(Bits256([42; 32])), - ); - - // Nothing to read just yet - assert_eq!( - instance - .methods() - .get_from_u64_to_enum_map(key1) - .call() - .await - .unwrap() - .value, - None - ); - - instance - .methods() - .insert_into_u64_to_enum_map(key1, val1.clone()) - .call() - .await - .unwrap(); - instance - .methods() - .insert_into_u64_to_enum_map(key2, val2.clone()) - .call() - .await - .unwrap(); - instance - .methods() - .insert_into_u64_to_enum_map(key3, val3.clone()) - .call() - .await - .unwrap(); - - assert_eq!( - instance - .methods() - .get_from_u64_to_enum_map(key1) - .call() - .await - .unwrap() - .value, - Some(val1) - ); - assert_eq!( - instance - .methods() - .get_from_u64_to_enum_map(key2) - .call() - .await - .unwrap() - .value, - Some(val2) - ); - assert_eq!( - instance - .methods() - .get_from_u64_to_enum_map(key3) - .call() - .await - .unwrap() - .value, - Some(val3) - ); - - // Test `remove` - assert_eq!( - instance - .methods() - .remove_from_u64_to_enum_map(key1) - .call() - .await - .unwrap() - .value, - true - ); - - assert_eq!( - instance - .methods() - .get_from_u64_to_enum_map(key1) - .call() - .await - .unwrap() - .value, - None - ); - } - - #[tokio::test] - async fn string_map() { - let instance = test_experimental_storage_map_instance().await; - - let (key1, key2, key3) = (9001, 1980, 1000); - let (val1, val2, val3) = ( - "fastest_modular_execution_layer_A", - "fastest_modular_execution_layer_B", - "fastest_modular_execution_layer_C", - ); - - // Nothing to read just yet - assert_eq!( - instance - .methods() - .get_from_u64_to_str_map(key1) - .call() - .await - .unwrap() - .value, - None - ); - - instance - .methods() - .insert_into_u64_to_str_map(key1, SizedAsciiString::try_from(val1).unwrap()) - .call() - .await - .unwrap(); - instance - .methods() - .insert_into_u64_to_str_map(key2, SizedAsciiString::try_from(val2).unwrap()) - .call() - .await - .unwrap(); - instance - .methods() - .insert_into_u64_to_str_map(key3, SizedAsciiString::try_from(val3).unwrap()) - .call() - .await - .unwrap(); - - assert_eq!( - instance - .methods() - .get_from_u64_to_str_map(key1) - .call() - .await - .unwrap() - .value, - Some(SizedAsciiString::try_from(val1).unwrap()) - ); - assert_eq!( - instance - .methods() - .get_from_u64_to_str_map(key2) - .call() - .await - .unwrap() - .value, - Some(SizedAsciiString::try_from(val2).unwrap()) - ); - assert_eq!( - instance - .methods() - .get_from_u64_to_str_map(key3) - .call() - .await - .unwrap() - .value, - Some(SizedAsciiString::try_from(val3).unwrap()) - ); - - // Test `remove` - assert_eq!( - instance - .methods() - .remove_from_u64_to_str_map(key1) - .call() - .await - .unwrap() - .value, - true - ); - - assert_eq!( - instance - .methods() - .get_from_u64_to_str_map(key1) - .call() - .await - .unwrap() - .value, - None - ); - } -} - -mod to_u64_map { - - use super::*; - - #[tokio::test] - async fn from_bool() { - let instance = test_experimental_storage_map_instance().await; - - let (key1, key2) = (true, false); - let (val1, val2) = (1, 2); - - // Nothing to read just yet - assert_eq!( - instance - .methods() - .get_from_bool_to_u64_map(key1) - .call() - .await - .unwrap() - .value, - None - ); - - instance - .methods() - .insert_into_bool_to_u64_map(key1, val1) - .call() - .await - .unwrap(); - instance - .methods() - .insert_into_bool_to_u64_map(key2, val2) - .call() - .await - .unwrap(); - - assert_eq!( - instance - .methods() - .get_from_bool_to_u64_map(key1) - .call() - .await - .unwrap() - .value, - Some(val1) - ); - assert_eq!( - instance - .methods() - .get_from_bool_to_u64_map(key2) - .call() - .await - .unwrap() - .value, - Some(val2) - ); - - // Test `remove` - assert_eq!( - instance - .methods() - .remove_from_bool_to_u64_map(key1) - .call() - .await - .unwrap() - .value, - true - ); - - assert_eq!( - instance - .methods() - .get_from_bool_to_u64_map(key1) - .call() - .await - .unwrap() - .value, - None - ); - } - - #[tokio::test] - async fn from_u8() { - let instance = test_experimental_storage_map_instance().await; - - let (key1, key2, key3) = (8, 66, 99); - let (val1, val2, val3) = (1, 2, 3); - - // Nothing to read just yet - assert_eq!( - instance - .methods() - .get_from_u8_to_u64_map(key1) - .call() - .await - .unwrap() - .value, - None - ); - - instance - .methods() - .insert_into_u8_to_u64_map(key1, val1) - .call() - .await - .unwrap(); - instance - .methods() - .insert_into_u8_to_u64_map(key2, val2) - .call() - .await - .unwrap(); - instance - .methods() - .insert_into_u8_to_u64_map(key3, val3) - .call() - .await - .unwrap(); - - assert_eq!( - instance - .methods() - .get_from_u8_to_u64_map(key1) - .call() - .await - .unwrap() - .value, - Some(val1) - ); - assert_eq!( - instance - .methods() - .get_from_u8_to_u64_map(key2) - .call() - .await - .unwrap() - .value, - Some(val2) - ); - assert_eq!( - instance - .methods() - .get_from_u8_to_u64_map(key3) - .call() - .await - .unwrap() - .value, - Some(val3) - ); - - // Test `remove` - assert_eq!( - instance - .methods() - .remove_from_u8_to_u64_map(key1) - .call() - .await - .unwrap() - .value, - true - ); - - assert_eq!( - instance - .methods() - .get_from_u8_to_u64_map(key1) - .call() - .await - .unwrap() - .value, - None - ); - } - - #[tokio::test] - async fn from_u16() { - let instance = test_experimental_storage_map_instance().await; - - let (key1, key2, key3) = (9, 42, 100); - let (val1, val2, val3) = (6, 9, 1); - - // Nothing to read just yet - assert_eq!( - instance - .methods() - .get_from_u16_to_u64_map(key1) - .call() - .await - .unwrap() - .value, - None - ); - - instance - .methods() - .insert_into_u16_to_u64_map(key1, val1) - .call() - .await - .unwrap(); - instance - .methods() - .insert_into_u16_to_u64_map(key2, val2) - .call() - .await - .unwrap(); - instance - .methods() - .insert_into_u16_to_u64_map(key3, val3) - .call() - .await - .unwrap(); - - assert_eq!( - instance - .methods() - .get_from_u16_to_u64_map(key1) - .call() - .await - .unwrap() - .value, - Some(val1) - ); - assert_eq!( - instance - .methods() - .get_from_u16_to_u64_map(key2) - .call() - .await - .unwrap() - .value, - Some(val2) - ); - assert_eq!( - instance - .methods() - .get_from_u16_to_u64_map(key3) - .call() - .await - .unwrap() - .value, - Some(val3) - ); - - // Test `remove` - assert_eq!( - instance - .methods() - .remove_from_u16_to_u64_map(key1) - .call() - .await - .unwrap() - .value, - true - ); - - assert_eq!( - instance - .methods() - .get_from_u16_to_u64_map(key1) - .call() - .await - .unwrap() - .value, - None - ); - } - - #[tokio::test] - async fn from_u32() { - let instance = test_experimental_storage_map_instance().await; - - let (key1, key2, key3) = (90, 2, 100); - let (val1, val2, val3) = (5, 99, 10); - - // Nothing to read just yet - assert_eq!( - instance - .methods() - .get_from_u32_to_u64_map(key1) - .call() - .await - .unwrap() - .value, - None - ); - - instance - .methods() - .insert_into_u32_to_u64_map(key1, val1) - .call() - .await - .unwrap(); - instance - .methods() - .insert_into_u32_to_u64_map(key2, val2) - .call() - .await - .unwrap(); - instance - .methods() - .insert_into_u32_to_u64_map(key3, val3) - .call() - .await - .unwrap(); - - assert_eq!( - instance - .methods() - .get_from_u32_to_u64_map(key1) - .call() - .await - .unwrap() - .value, - Some(val1) - ); - assert_eq!( - instance - .methods() - .get_from_u32_to_u64_map(key2) - .call() - .await - .unwrap() - .value, - Some(val2) - ); - assert_eq!( - instance - .methods() - .get_from_u32_to_u64_map(key3) - .call() - .await - .unwrap() - .value, - Some(val3) - ); - - // Test `remove` - assert_eq!( - instance - .methods() - .remove_from_u32_to_u64_map(key1) - .call() - .await - .unwrap() - .value, - true - ); - - assert_eq!( - instance - .methods() - .get_from_u32_to_u64_map(key1) - .call() - .await - .unwrap() - .value, - None - ); - } - - #[tokio::test] - async fn from_tuple() { - let instance = test_experimental_storage_map_instance().await; - - let (key1, key2, key3) = ( - (Bits256([1; 32]), 42, true), - (Bits256([2; 32]), 24, true), - (Bits256([3; 32]), 99, true), - ); - let (val1, val2, val3) = (50, 99, 10); - - // Nothing to read just yet - assert_eq!( - instance - .methods() - .get_from_tuple_to_u64_map(key1) - .call() - .await - .unwrap() - .value, - None - ); - - instance - .methods() - .insert_into_tuple_to_u64_map(key1, val1) - .call() - .await - .unwrap(); - instance - .methods() - .insert_into_tuple_to_u64_map(key2, val2) - .call() - .await - .unwrap(); - instance - .methods() - .insert_into_tuple_to_u64_map(key3, val3) - .call() - .await - .unwrap(); - - assert_eq!( - instance - .methods() - .get_from_tuple_to_u64_map(key1) - .call() - .await - .unwrap() - .value, - Some(val1) - ); - assert_eq!( - instance - .methods() - .get_from_tuple_to_u64_map(key2) - .call() - .await - .unwrap() - .value, - Some(val2) - ); - assert_eq!( - instance - .methods() - .get_from_tuple_to_u64_map(key3) - .call() - .await - .unwrap() - .value, - Some(val3) - ); - - // Test `remove` - assert_eq!( - instance - .methods() - .remove_from_tuple_to_u64_map(key1) - .call() - .await - .unwrap() - .value, - true - ); - - assert_eq!( - instance - .methods() - .get_from_tuple_to_u64_map(key1) - .call() - .await - .unwrap() - .value, - None - ); - } - - #[tokio::test] - async fn from_struct() { - let instance = test_experimental_storage_map_instance().await; - - let (key1, key2, key3) = ( - Struct { - x: 42, - y: Bits256([66; 32]), - z: Bits256([99; 32]), - }, - Struct { - x: 24, - y: Bits256([11; 32]), - z: Bits256([90; 32]), - }, - Struct { - x: 77, - y: Bits256([55; 32]), - z: Bits256([12; 32]), - }, - ); - - let (val1, val2, val3) = (5, 9, 1); - - // Nothing to read just yet - assert_eq!( - instance - .methods() - .get_from_struct_to_u64_map(key1.clone()) - .call() - .await - .unwrap() - .value, - None - ); - - instance - .methods() - .insert_into_struct_to_u64_map(key1.clone(), val1.clone()) - .call() - .await - .unwrap(); - instance - .methods() - .insert_into_struct_to_u64_map(key2.clone(), val2.clone()) - .call() - .await - .unwrap(); - instance - .methods() - .insert_into_struct_to_u64_map(key3.clone(), val3.clone()) - .call() - .await - .unwrap(); - - assert_eq!( - instance - .methods() - .get_from_struct_to_u64_map(key1.clone()) - .call() - .await - .unwrap() - .value, - Some(val1) - ); - assert_eq!( - instance - .methods() - .get_from_struct_to_u64_map(key2) - .call() - .await - .unwrap() - .value, - Some(val2) - ); - assert_eq!( - instance - .methods() - .get_from_struct_to_u64_map(key3) - .call() - .await - .unwrap() - .value, - Some(val3) - ); - - // Test `remove` - assert_eq!( - instance - .methods() - .remove_from_struct_to_u64_map(key1.clone()) - .call() - .await - .unwrap() - .value, - true - ); - - assert_eq!( - instance - .methods() - .get_from_struct_to_u64_map(key1) - .call() - .await - .unwrap() - .value, - None - ); - } - - #[tokio::test] - async fn from_enum() { - let instance = test_experimental_storage_map_instance().await; - - let (key1, key2, key3) = ( - Enum::V1(Bits256([66; 32])), - Enum::V2(42), - Enum::V3(Bits256([42; 32])), - ); - let (val1, val2, val3) = (44, 17, 1000); - - // Nothing to read just yet - assert_eq!( - instance - .methods() - .get_from_enum_to_u64_map(key1.clone()) - .call() - .await - .unwrap() - .value, - None - ); - - instance - .methods() - .insert_into_enum_to_u64_map(key1.clone(), val1.clone()) - .call() - .await - .unwrap(); - instance - .methods() - .insert_into_enum_to_u64_map(key2.clone(), val2.clone()) - .call() - .await - .unwrap(); - instance - .methods() - .insert_into_enum_to_u64_map(key3.clone(), val3.clone()) - .call() - .await - .unwrap(); - - assert_eq!( - instance - .methods() - .get_from_enum_to_u64_map(key1.clone()) - .call() - .await - .unwrap() - .value, - Some(val1) - ); - assert_eq!( - instance - .methods() - .get_from_enum_to_u64_map(key2) - .call() - .await - .unwrap() - .value, - Some(val2) - ); - assert_eq!( - instance - .methods() - .get_from_enum_to_u64_map(key3) - .call() - .await - .unwrap() - .value, - Some(val3) - ); - - // Test `remove` - assert_eq!( - instance - .methods() - .remove_from_enum_to_u64_map(key1.clone()) - .call() - .await - .unwrap() - .value, - true - ); - - assert_eq!( - instance - .methods() - .get_from_enum_to_u64_map(key1) - .call() - .await - .unwrap() - .value, - None - ); - } - - #[tokio::test] - async fn from_string() { - let instance = test_experimental_storage_map_instance().await; - - let (key1, key2, key3) = ( - "fastest_modular_execution_layer_A", - "fastest_modular_execution_layer_B", - "fastest_modular_execution_layer_C", - ); - let (val1, val2, val3) = (9001, 1980, 1000); - - // Nothing to read just yet - assert_eq!( - instance - .methods() - .get_from_str_to_u64_map(SizedAsciiString::try_from(key1).unwrap()) - .call() - .await - .unwrap() - .value, - None - ); - - instance - .methods() - .insert_into_str_to_u64_map(SizedAsciiString::try_from(key1).unwrap(), val1) - .call() - .await - .unwrap(); - instance - .methods() - .insert_into_str_to_u64_map(SizedAsciiString::try_from(key2).unwrap(), val2) - .call() - .await - .unwrap(); - instance - .methods() - .insert_into_str_to_u64_map(SizedAsciiString::try_from(key3).unwrap(), val3) - .call() - .await - .unwrap(); - - assert_eq!( - instance - .methods() - .get_from_str_to_u64_map(SizedAsciiString::try_from(key1).unwrap()) - .call() - .await - .unwrap() - .value, - Some(val1) - ); - assert_eq!( - instance - .methods() - .get_from_str_to_u64_map(SizedAsciiString::try_from(key2).unwrap()) - .call() - .await - .unwrap() - .value, - Some(val2) - ); - assert_eq!( - instance - .methods() - .get_from_str_to_u64_map(SizedAsciiString::try_from(key3).unwrap()) - .call() - .await - .unwrap() - .value, - Some(val3) - ); - - // Test `remove` - assert_eq!( - instance - .methods() - .remove_from_str_to_u64_map(SizedAsciiString::try_from(key1).unwrap()) - .call() - .await - .unwrap() - .value, - true - ); - - assert_eq!( - instance - .methods() - .get_from_str_to_u64_map(SizedAsciiString::try_from(key1).unwrap()) - .call() - .await - .unwrap() - .value, - None - ); - } -} - -#[tokio::test] -async fn test_multiple_maps() { - let instance = test_experimental_storage_map_instance().await; - - let (key1, key2, key3) = (1, 2, 3); - let (val1_1, val2_1, val3_1) = (8, 66, 99); - let (val1_2, val2_2, val3_2) = (9, 42, 100); - - // Nothing to read just yet - assert_eq!( - instance - .methods() - .get_from_u64_to_u8_map(key1) - .call() - .await - .unwrap() - .value, - None - ); - assert_eq!( - instance - .methods() - .get_from_u64_to_u16_map(key1) - .call() - .await - .unwrap() - .value, - None - ); - - instance - .methods() - .insert_into_u64_to_u8_map(key1, val1_1) - .call() - .await - .unwrap(); - instance - .methods() - .insert_into_u64_to_u8_map(key2, val2_1) - .call() - .await - .unwrap(); - instance - .methods() - .insert_into_u64_to_u8_map(key3, val3_1) - .call() - .await - .unwrap(); - - instance - .methods() - .insert_into_u64_to_u16_map(key1, val1_2) - .call() - .await - .unwrap(); - instance - .methods() - .insert_into_u64_to_u16_map(key2, val2_2) - .call() - .await - .unwrap(); - instance - .methods() - .insert_into_u64_to_u16_map(key3, val3_2) - .call() - .await - .unwrap(); - - assert_eq!( - instance - .methods() - .get_from_u64_to_u8_map(key1) - .call() - .await - .unwrap() - .value, - Some(val1_1) - ); - assert_eq!( - instance - .methods() - .get_from_u64_to_u8_map(key2) - .call() - .await - .unwrap() - .value, - Some(val2_1) - ); - assert_eq!( - instance - .methods() - .get_from_u64_to_u8_map(key3) - .call() - .await - .unwrap() - .value, - Some(val3_1) - ); - - assert_eq!( - instance - .methods() - .get_from_u64_to_u16_map(key1) - .call() - .await - .unwrap() - .value, - Some(val1_2) - ); - assert_eq!( - instance - .methods() - .get_from_u64_to_u16_map(key2) - .call() - .await - .unwrap() - .value, - Some(val2_2) - ); - assert_eq!( - instance - .methods() - .get_from_u64_to_u16_map(key3) - .call() - .await - .unwrap() - .value, - Some(val3_2) - ); -} diff --git a/test/src/sdk-harness/test_projects/experimental_storage_map/src/main.sw b/test/src/sdk-harness/test_projects/experimental_storage_map/src/main.sw deleted file mode 100644 index e99c8dec752..00000000000 --- a/test/src/sdk-harness/test_projects/experimental_storage_map/src/main.sw +++ /dev/null @@ -1,475 +0,0 @@ -contract; - -use core::experimental::storage::*; -use std::experimental::storage::*; - -pub struct Struct { - x: u32, - y: b256, - z: b256, -} - -pub enum Enum { - V1: b256, - V2: u64, - V3: b256, -} - -storage { - map1: StorageMap = StorageMap {}, - map2: StorageMap = StorageMap {}, - map3: StorageMap = StorageMap {}, - map4: StorageMap = StorageMap {}, - map5: StorageMap = StorageMap {}, - map6: StorageMap = StorageMap {}, - map7: StorageMap = StorageMap {}, - map8: StorageMap = StorageMap {}, - map9: StorageMap = StorageMap {}, - map10: StorageMap = StorageMap {}, - map11: StorageMap = StorageMap {}, - map12: StorageMap = StorageMap {}, - map13: StorageMap = StorageMap {}, - map14: StorageMap = StorageMap {}, - map15: StorageMap<(b256, u8, bool), u64> = StorageMap {}, - map16: StorageMap = StorageMap {}, - map17: StorageMap = StorageMap {}, - map18: StorageMap = StorageMap {}, - map19: StorageMap<[b256; 3], u64> = StorageMap {}, -} - -abi StorageMapTest { - #[storage(read, write)] - fn insert_into_u64_to_bool_map(key: u64, value: bool); - #[storage(read)] - fn get_from_u64_to_bool_map(key: u64) -> Option; - #[storage(read, write)] - fn remove_from_u64_to_bool_map(key: u64) -> bool; - - #[storage(read, write)] - fn insert_into_u64_to_u8_map(key: u64, value: u8); - #[storage(read)] - fn get_from_u64_to_u8_map(key: u64) -> Option; - #[storage(read, write)] - fn remove_from_u64_to_u8_map(key: u64) -> bool; - - #[storage(read, write)] - fn insert_into_u64_to_u16_map(key: u64, value: u16); - #[storage(read)] - fn get_from_u64_to_u16_map(key: u64) -> Option; - #[storage(read, write)] - fn remove_from_u64_to_u16_map(key: u64) -> bool; - - #[storage(read, write)] - fn insert_into_u64_to_u32_map(key: u64, value: u32); - #[storage(read)] - fn get_from_u64_to_u32_map(key: u64) -> Option; - #[storage(read, write)] - fn remove_from_u64_to_u32_map(key: u64) -> bool; - - #[storage(read, write)] - fn insert_into_u64_to_u64_map(key: u64, value: u64); - #[storage(read)] - fn get_from_u64_to_u64_map(key: u64) -> Option; - #[storage(read, write)] - fn remove_from_u64_to_u64_map(key: u64) -> bool; - - #[storage(read, write)] - fn insert_into_u64_to_tuple_map(key: u64, value: (b256, u8, bool)); - #[storage(read)] - fn get_from_u64_to_tuple_map(key: u64) -> Option<(b256, u8, bool)>; - #[storage(read, write)] - fn remove_from_u64_to_tuple_map(key: u64) -> bool; - - #[storage(read, write)] - fn insert_into_u64_to_struct_map(key: u64, value: Struct); - #[storage(read)] - fn get_from_u64_to_struct_map(key: u64) -> Option; - #[storage(read, write)] - fn remove_from_u64_to_struct_map(key: u64) -> bool; - - #[storage(read, write)] - fn insert_into_u64_to_enum_map(key: u64, value: Enum); - #[storage(read)] - fn get_from_u64_to_enum_map(key: u64) -> Option; - #[storage(read, write)] - fn remove_from_u64_to_enum_map(key: u64) -> bool; - - #[storage(read, write)] - fn insert_into_u64_to_str_map(key: u64, value: str[33]); - #[storage(read)] - fn get_from_u64_to_str_map(key: u64) -> Option; - #[storage(read, write)] - fn remove_from_u64_to_str_map(key: u64) -> bool; - - #[storage(read, write)] - fn insert_into_u64_to_array_map(key: u64, value: [b256; 3]); - #[storage(read)] - fn get_from_u64_to_array_map(key: u64) -> Option<[b256; 3]>; - #[storage(read, write)] - fn remove_from_u64_to_array_map(key: u64) -> bool; - - #[storage(read, write)] - fn insert_into_bool_to_u64_map(key: bool, value: u64); - #[storage(read)] - fn get_from_bool_to_u64_map(key: bool) -> Option; - #[storage(read, write)] - fn remove_from_bool_to_u64_map(key: bool) -> bool; - - #[storage(read, write)] - fn insert_into_u8_to_u64_map(key: u8, value: u64); - #[storage(read)] - fn get_from_u8_to_u64_map(key: u8) -> Option; - #[storage(read, write)] - fn remove_from_u8_to_u64_map(key: u8) -> bool; - - #[storage(read, write)] - fn insert_into_u16_to_u64_map(key: u16, value: u64); - #[storage(read)] - fn get_from_u16_to_u64_map(key: u16) -> Option; - #[storage(read, write)] - fn remove_from_u16_to_u64_map(key: u16) -> bool; - - #[storage(read, write)] - fn insert_into_u32_to_u64_map(key: u32, value: u64); - #[storage(read)] - fn get_from_u32_to_u64_map(key: u32) -> Option; - #[storage(read, write)] - fn remove_from_u32_to_u64_map(key: u32) -> bool; - - #[storage(read, write)] - fn insert_into_tuple_to_u64_map(key: (b256, u8, bool), value: u64); - #[storage(read)] - fn get_from_tuple_to_u64_map(key: (b256, u8, bool)) -> Option; - #[storage(read, write)] - fn remove_from_tuple_to_u64_map(key: (b256, u8, bool)) -> bool; - - #[storage(read, write)] - fn insert_into_struct_to_u64_map(key: Struct, value: u64); - #[storage(read)] - fn get_from_struct_to_u64_map(key: Struct) -> Option; - #[storage(read, write)] - fn remove_from_struct_to_u64_map(key: Struct) -> bool; - - #[storage(read, write)] - fn insert_into_enum_to_u64_map(key: Enum, value: u64); - #[storage(read)] - fn get_from_enum_to_u64_map(key: Enum) -> Option; - #[storage(read, write)] - fn remove_from_enum_to_u64_map(key: Enum) -> bool; - - #[storage(read, write)] - fn insert_into_str_to_u64_map(key: str[33], value: u64); - #[storage(read)] - fn get_from_str_to_u64_map(key: str[33]) -> Option; - #[storage(read, write)] - fn remove_from_str_to_u64_map(key: str[33]) -> bool; - - #[storage(read, write)] - fn insert_into_array_to_u64_map(key: [b256; 3], value: u64); - #[storage(read)] - fn get_from_array_to_u64_map(key: [b256; 3]) -> Option; - #[storage(read, write)] - fn remove_from_array_to_u64_map(key: [b256; 3]) -> bool; -} - -#[storage(read, write)] -fn _insert_into_u64_to_bool_map_inner(key: u64, value: bool) { - storage.map1.insert(key, value); -} - -#[storage(read)] -fn _get_from_u64_to_bool_map_inner(key: u64) -> Option { - storage.map1.get(key).try_read() -} - -#[storage(read, write)] -fn _remove_from_u64_to_bool_map_inner(key: u64) -> bool { - storage.map1.remove(key) -} - -impl StorageMapTest for Contract { - #[storage(read, write)] - fn insert_into_u64_to_bool_map(key: u64, value: bool) { - _insert_into_u64_to_bool_map_inner(key, value) - } - - #[storage(read)] - fn get_from_u64_to_bool_map(key: u64) -> Option { - _get_from_u64_to_bool_map_inner(key) - } - - #[storage(read, write)] - fn remove_from_u64_to_bool_map(key: u64) -> bool { - _remove_from_u64_to_bool_map_inner(key) - } - - #[storage(read, write)] - fn insert_into_u64_to_u8_map(key: u64, value: u8) { - storage.map2.insert(key, value); - } - - #[storage(read)] - fn get_from_u64_to_u8_map(key: u64) -> Option { - storage.map2.get(key).try_read() - } - - #[storage(read, write)] - fn remove_from_u64_to_u8_map(key: u64) -> bool { - storage.map2.remove(key) - } - - #[storage(read, write)] - fn insert_into_u64_to_u16_map(key: u64, value: u16) { - storage.map3.insert(key, value); - } - - #[storage(read)] - fn get_from_u64_to_u16_map(key: u64) -> Option { - storage.map3.get(key).try_read() - } - - #[storage(read, write)] - fn remove_from_u64_to_u16_map(key: u64) -> bool { - storage.map3.remove(key) - } - - #[storage(read, write)] - fn insert_into_u64_to_u32_map(key: u64, value: u32) { - storage.map4.insert(key, value); - } - - #[storage(read)] - fn get_from_u64_to_u32_map(key: u64) -> Option { - storage.map4.get(key).try_read() - } - - #[storage(read, write)] - fn remove_from_u64_to_u32_map(key: u64) -> bool { - storage.map4.remove(key) - } - - #[storage(read, write)] - fn insert_into_u64_to_u64_map(key: u64, value: u64) { - storage.map5.insert(key, value); - } - - #[storage(read)] - fn get_from_u64_to_u64_map(key: u64) -> Option { - storage.map5.get(key).try_read() - } - - #[storage(read, write)] - fn remove_from_u64_to_u64_map(key: u64) -> bool { - storage.map5.remove(key) - } - - #[storage(read, write)] - fn insert_into_u64_to_tuple_map(key: u64, value: (b256, u8, bool)) { - storage.map6.insert(key, value); - } - - #[storage(read)] - fn get_from_u64_to_tuple_map(key: u64) -> Option<(b256, u8, bool)> { - storage.map6.get(key).try_read() - } - - #[storage(read, write)] - fn remove_from_u64_to_tuple_map(key: u64) -> bool { - storage.map6.remove(key) - } - - #[storage(read, write)] - fn insert_into_u64_to_struct_map(key: u64, value: Struct) { - storage.map7.insert(key, value); - } - - #[storage(read)] - fn get_from_u64_to_struct_map(key: u64) -> Option { - storage.map7.get(key).try_read() - } - - #[storage(read, write)] - fn remove_from_u64_to_struct_map(key: u64) -> bool { - storage.map7.remove(key) - } - - #[storage(read, write)] - fn insert_into_u64_to_enum_map(key: u64, value: Enum) { - storage.map8.insert(key, value); - } - - #[storage(read)] - fn get_from_u64_to_enum_map(key: u64) -> Option { - storage.map8.get(key).try_read() - } - - #[storage(read, write)] - fn remove_from_u64_to_enum_map(key: u64) -> bool { - storage.map8.remove(key) - } - - #[storage(read, write)] - fn insert_into_u64_to_str_map(key: u64, value: str[33]) { - storage.map9.insert(key, value); - } - - #[storage(read)] - fn get_from_u64_to_str_map(key: u64) -> Option { - storage.map9.get(key).try_read() - } - - #[storage(read, write)] - fn remove_from_u64_to_str_map(key: u64) -> bool { - storage.map9.remove(key) - } - - #[storage(read, write)] - fn insert_into_u64_to_array_map(key: u64, value: [b256; 3]) { - storage.map10.insert(key, value); - } - - #[storage(read)] - fn get_from_u64_to_array_map(key: u64) -> Option<[b256; 3]> { - storage.map10.get(key).try_read() - } - - #[storage(read, write)] - fn remove_from_u64_to_array_map(key: u64) -> bool { - storage.map10.remove(key) - } - - #[storage(read, write)] - fn insert_into_bool_to_u64_map(key: bool, value: u64) { - storage.map11.insert(key, value); - } - - #[storage(read)] - fn get_from_bool_to_u64_map(key: bool) -> Option { - storage.map11.get(key).try_read() - } - - #[storage(read, write)] - fn remove_from_bool_to_u64_map(key: bool) -> bool { - storage.map11.remove(key) - } - - #[storage(read, write)] - fn insert_into_u8_to_u64_map(key: u8, value: u64) { - storage.map12.insert(key, value); - } - - #[storage(read)] - fn get_from_u8_to_u64_map(key: u8) -> Option { - storage.map12.get(key).try_read() - } - - #[storage(read, write)] - fn remove_from_u8_to_u64_map(key: u8) -> bool { - storage.map12.remove(key) - } - - #[storage(read, write)] - fn insert_into_u16_to_u64_map(key: u16, value: u64) { - storage.map13.insert(key, value); - } - - #[storage(read)] - fn get_from_u16_to_u64_map(key: u16) -> Option { - storage.map13.get(key).try_read() - } - - #[storage(read, write)] - fn remove_from_u16_to_u64_map(key: u16) -> bool { - storage.map13.remove(key) - } - - #[storage(read, write)] - fn insert_into_u32_to_u64_map(key: u32, value: u64) { - storage.map14.insert(key, value); - } - - #[storage(read)] - fn get_from_u32_to_u64_map(key: u32) -> Option { - storage.map14.get(key).try_read() - } - - #[storage(read, write)] - fn remove_from_u32_to_u64_map(key: u32) -> bool { - storage.map14.remove(key) - } - - #[storage(read, write)] - fn insert_into_tuple_to_u64_map(key: (b256, u8, bool), value: u64) { - storage.map15.insert(key, value); - } - - #[storage(read)] - fn get_from_tuple_to_u64_map(key: (b256, u8, bool)) -> Option { - storage.map15.get(key).try_read() - } - - #[storage(read, write)] - fn remove_from_tuple_to_u64_map(key: (b256, u8, bool)) -> bool { - storage.map15.remove(key) - } - - #[storage(read, write)] - fn insert_into_struct_to_u64_map(key: Struct, value: u64) { - storage.map16.insert(key, value); - } - - #[storage(read)] - fn get_from_struct_to_u64_map(key: Struct) -> Option { - storage.map16.get(key).try_read() - } - - #[storage(read, write)] - fn remove_from_struct_to_u64_map(key: Struct) -> bool { - storage.map16.remove(key) - } - - #[storage(read, write)] - fn insert_into_enum_to_u64_map(key: Enum, value: u64) { - storage.map17.insert(key, value); - } - - #[storage(read)] - fn get_from_enum_to_u64_map(key: Enum) -> Option { - storage.map17.get(key).try_read() - } - - #[storage(read, write)] - fn remove_from_enum_to_u64_map(key: Enum) -> bool { - storage.map17.remove(key) - } - - #[storage(read, write)] - fn insert_into_str_to_u64_map(key: str[33], value: u64) { - storage.map18.insert(key, value); - } - - #[storage(read)] - fn get_from_str_to_u64_map(key: str[33]) -> Option { - storage.map18.get(key).try_read() - } - - #[storage(read, write)] - fn remove_from_str_to_u64_map(key: str[33]) -> bool { - storage.map18.remove(key) - } - - #[storage(read, write)] - fn insert_into_array_to_u64_map(key: [b256; 3], value: u64) { - storage.map19.insert(key, value) - } - - #[storage(read)] - fn get_from_array_to_u64_map(key: [b256; 3]) -> Option { - storage.map19.get(key).try_read() - } - - #[storage(read, write)] - fn remove_from_array_to_u64_map(key: [b256; 3]) -> bool { - storage.map19.remove(key) - } -} diff --git a/test/src/sdk-harness/test_projects/harness.rs b/test/src/sdk-harness/test_projects/harness.rs index fac09311f03..83ed2b1d787 100644 --- a/test/src/sdk-harness/test_projects/harness.rs +++ b/test/src/sdk-harness/test_projects/harness.rs @@ -27,9 +27,13 @@ mod registers; mod result_in_abi; mod script_data; mod storage; +mod storage_access; mod storage_bytes; +mod storage_init; mod storage_map; +mod storage_map_nested; mod storage_vec; +mod storage_vec_nested; mod token_ops; mod tx_fields; mod type_aliases; diff --git a/test/src/sdk-harness/test_projects/option_field_order/src/main.sw b/test/src/sdk-harness/test_projects/option_field_order/src/main.sw index 5203bc7b0ce..77c5555a4ae 100644 --- a/test/src/sdk-harness/test_projects/option_field_order/src/main.sw +++ b/test/src/sdk-harness/test_projects/option_field_order/src/main.sw @@ -16,6 +16,6 @@ abi MyContract { impl MyContract for Contract { #[storage(read)] fn is_none() -> bool { - storage.value.get(0).is_none() + storage.value.get(0).try_read().is_none() } } diff --git a/test/src/sdk-harness/test_projects/storage/mod.rs b/test/src/sdk-harness/test_projects/storage/mod.rs index e30bface4d5..08ff039cfa4 100644 --- a/test/src/sdk-harness/test_projects/storage/mod.rs +++ b/test/src/sdk-harness/test_projects/storage/mod.rs @@ -30,12 +30,6 @@ async fn can_store_and_get_bool() { instance.methods().store_bool(b).call().await.unwrap(); let result = instance.methods().get_bool().call().await.unwrap(); assert_eq!(result.value, Some(b)); - - // Test clear - let result = instance.methods().clear_bool().call().await.unwrap(); - assert_eq!(result.value, true); - let result = instance.methods().get_bool().call().await.unwrap(); - assert_eq!(result.value, None); } #[tokio::test] @@ -47,12 +41,6 @@ async fn can_store_and_get_u8() { instance.methods().store_u8(n).call().await.unwrap(); let result = instance.methods().get_u8().call().await.unwrap(); assert_eq!(result.value, Some(n)); - - // Test clear - let result = instance.methods().clear_u8().call().await.unwrap(); - assert_eq!(result.value, true); - let result = instance.methods().get_u8().call().await.unwrap(); - assert_eq!(result.value, None); } #[tokio::test] @@ -64,12 +52,6 @@ async fn can_store_and_get_u16() { instance.methods().store_u16(n).call().await.unwrap(); let result = instance.methods().get_u16().call().await.unwrap(); assert_eq!(result.value, Some(n)); - - // Test clear - let result = instance.methods().clear_u16().call().await.unwrap(); - assert_eq!(result.value, true); - let result = instance.methods().get_u16().call().await.unwrap(); - assert_eq!(result.value, None); } #[tokio::test] @@ -81,12 +63,6 @@ async fn can_store_and_get_u32() { instance.methods().store_u32(n).call().await.unwrap(); let result = instance.methods().get_u32().call().await.unwrap(); assert_eq!(result.value, Some(n)); - - // Test clear - let result = instance.methods().clear_u32().call().await.unwrap(); - assert_eq!(result.value, true); - let result = instance.methods().get_u32().call().await.unwrap(); - assert_eq!(result.value, None); } #[tokio::test] @@ -98,12 +74,6 @@ async fn can_store_and_get_u64() { instance.methods().store_u64(n).call().await.unwrap(); let result = instance.methods().get_u64().call().await.unwrap(); assert_eq!(result.value, Some(n)); - - // Test clear - let result = instance.methods().clear_u64().call().await.unwrap(); - assert_eq!(result.value, true); - let result = instance.methods().get_u64().call().await.unwrap(); - assert_eq!(result.value, None); } #[tokio::test] @@ -115,12 +85,6 @@ async fn can_store_b256() { instance.methods().store_b256(n).call().await.unwrap(); let result = instance.methods().get_b256().call().await.unwrap(); assert_eq!(result.value, Some(n)); - - // Test clear - let result = instance.methods().clear_b256().call().await.unwrap(); - assert_eq!(result.value, true); - let result = instance.methods().get_b256().call().await.unwrap(); - assert_eq!(result.value, None); } #[tokio::test] @@ -137,17 +101,6 @@ async fn can_store_small_struct() { .unwrap(); let result = instance.methods().get_small_struct().call().await.unwrap(); assert_eq!(result.value, Some(s)); - - // Test clear - let result = instance - .methods() - .clear_small_struct() - .call() - .await - .unwrap(); - assert_eq!(result.value, true); - let result = instance.methods().get_small_struct().call().await.unwrap(); - assert_eq!(result.value, None); } #[tokio::test] @@ -164,17 +117,6 @@ async fn can_store_medium_struct() { .unwrap(); let result = instance.methods().get_medium_struct().call().await.unwrap(); assert_eq!(result.value, Some(s)); - - // Test clear - let result = instance - .methods() - .clear_medium_struct() - .call() - .await - .unwrap(); - assert_eq!(result.value, true); - let result = instance.methods().get_medium_struct().call().await.unwrap(); - assert_eq!(result.value, None); } #[tokio::test] @@ -195,17 +137,6 @@ async fn can_store_large_struct() { .unwrap(); let result = instance.methods().get_large_struct().call().await.unwrap(); assert_eq!(result.value, Some(s)); - - // Test clear - let result = instance - .methods() - .clear_large_struct() - .call() - .await - .unwrap(); - assert_eq!(result.value, true); - let result = instance.methods().get_large_struct().call().await.unwrap(); - assert_eq!(result.value, None); } #[tokio::test] @@ -229,21 +160,6 @@ async fn can_store_very_large_struct() { .await .unwrap(); assert_eq!(result.value, Some(s)); - - let result = instance - .methods() - .clear_very_large_struct() - .call() - .await - .unwrap(); - assert_eq!(result.value, true); - let result = instance - .methods() - .get_very_large_struct() - .call() - .await - .unwrap(); - assert_eq!(result.value, None); } #[tokio::test] @@ -280,12 +196,6 @@ async fn can_store_enum() { .unwrap(); let result = instance.methods().get_enum().call().await.unwrap(); assert_eq!(result.value, Some(e3)); - - // Test clear - let result = instance.methods().clear_enum().call().await.unwrap(); - assert_eq!(result.value, true); - let result = instance.methods().get_enum().call().await.unwrap(); - assert_eq!(result.value, None); } #[tokio::test] @@ -302,12 +212,6 @@ async fn can_store_tuple() { .unwrap(); let result = instance.methods().get_tuple().call().await.unwrap(); assert_eq!(result.value, Some(t)); - - // Test clear - let result = instance.methods().clear_tuple().call().await.unwrap(); - assert_eq!(result.value, true); - let result = instance.methods().get_tuple().call().await.unwrap(); - assert_eq!(result.value, None); } #[tokio::test] @@ -324,12 +228,6 @@ async fn can_store_string() { .unwrap(); let result = instance.methods().get_string().call().await.unwrap(); assert_eq!(result.value, Some(SizedAsciiString::try_from(s).unwrap())); - - // Test clear - let result = instance.methods().clear_string().call().await.unwrap(); - assert_eq!(result.value, true); - let result = instance.methods().get_string().call().await.unwrap(); - assert_eq!(result.value, None); } #[tokio::test] @@ -341,12 +239,6 @@ async fn can_store_array() { instance.methods().store_array().call().await.unwrap(); let result = instance.methods().get_array().call().await.unwrap(); assert_eq!(result.value, Some(a)); - - // Test clear - let result = instance.methods().clear_array().call().await.unwrap(); - assert_eq!(result.value, true); - let result = instance.methods().get_array().call().await.unwrap(); - assert_eq!(result.value, None); } #[tokio::test] diff --git a/test/src/sdk-harness/test_projects/storage/src/main.sw b/test/src/sdk-harness/test_projects/storage/src/main.sw index b2318cfc2ea..685ad83217b 100644 --- a/test/src/sdk-harness/test_projects/storage/src/main.sw +++ b/test/src/sdk-harness/test_projects/storage/src/main.sw @@ -1,6 +1,7 @@ contract; -use std::{registers::stack_ptr, storage::{clear, get, store}}; +use std::registers::stack_ptr; +use std::storage::storage_api::*; pub struct SmallStruct { x: u64, @@ -47,92 +48,64 @@ const S_14: b256 = 0x00000000000000000000000000000000000000000000000000000000000 const S_15: b256 = 0x0000000000000000000000000000000000000000000000000000000000000015; abi StorageTest { - #[storage(write)] - fn clear_bool() -> bool; - #[storage(write)] + #[storage(read, write)] fn store_bool(value: bool); #[storage(read)] fn get_bool() -> Option; - #[storage(write)] - fn clear_u8() -> bool; - #[storage(write)] + #[storage(read, write)] fn store_u8(value: u8); #[storage(read)] fn get_u8() -> Option; - #[storage(write)] - fn clear_u16() -> bool; - #[storage(write)] + #[storage(read, write)] fn store_u16(value: u16); #[storage(read)] fn get_u16() -> Option; - #[storage(write)] - fn clear_u32() -> bool; - #[storage(write)] + #[storage(read, write)] fn store_u32(value: u32); #[storage(read)] fn get_u32() -> Option; - #[storage(write)] - fn clear_u64() -> bool; - #[storage(write)] + #[storage(read, write)] fn store_u64(value: u64); #[storage(read)] fn get_u64() -> Option; - #[storage(write)] - fn clear_b256() -> bool; - #[storage(write)] + #[storage(read, write)] fn store_b256(value: b256); #[storage(read)] fn get_b256() -> Option; - #[storage(write)] - fn clear_small_struct() -> bool; - #[storage(write)] + #[storage(read, write)] fn store_small_struct(value: SmallStruct); #[storage(read)] fn get_small_struct() -> Option; - #[storage(write)] - fn clear_medium_struct() -> bool; - #[storage(write)] + #[storage(read, write)] fn store_medium_struct(value: MediumStruct); #[storage(read)] fn get_medium_struct() -> Option; - #[storage(write)] - fn clear_large_struct() -> bool; - #[storage(write)] + #[storage(read, write)] fn store_large_struct(value: LargeStruct); #[storage(read)] fn get_large_struct() -> Option; - #[storage(write)] - fn clear_very_large_struct() -> bool; - #[storage(write)] + #[storage(read, write)] fn store_very_large_struct(value: VeryLargeStruct); #[storage(read)] fn get_very_large_struct() -> Option; - #[storage(write)] - fn clear_enum() -> bool; - #[storage(write)] + #[storage(read, write)] fn store_enum(value: StorageEnum); #[storage(read)] fn get_enum() -> Option; - #[storage(write)] - fn clear_tuple() -> bool; - #[storage(write)] + #[storage(read, write)] fn store_tuple(value: (b256, u8, b256)); #[storage(read)] fn get_tuple() -> Option<(b256, u8, b256)>; - #[storage(write)] - fn clear_string() -> bool; - #[storage(write)] + #[storage(read, write)] fn store_string(value: str[31]); #[storage(read)] fn get_string() -> Option; - #[storage(write)] - fn clear_array() -> bool; - #[storage(write)] + #[storage(read, write)] fn store_array(); #[storage(read)] fn get_array() -> Option<[b256; 3]>; @@ -142,219 +115,149 @@ abi StorageTest { } impl StorageTest for Contract { - #[storage(write)] - fn clear_bool() -> bool { - clear::(S_1) - } - - #[storage(write)] + #[storage(read, write)] fn store_bool(value: bool) { - store(S_1, value); + write(S_1, 0, value); } #[storage(read)] fn get_bool() -> Option { - get::(S_1) + read::(S_1, 0) } - #[storage(write)] - fn clear_u8() -> bool { - clear::(S_2) - } - - #[storage(write)] + #[storage(read, write)] fn store_u8(value: u8) { - store(S_2, value); + write(S_2, 0, value); } #[storage(read)] fn get_u8() -> Option { - get::(S_2) - } - - #[storage(write)] - fn clear_u16() -> bool { - clear::(S_3) + read::(S_2, 0) } - #[storage(write)] + #[storage(read, write)] fn store_u16(value: u16) { - store(S_3, value); + write(S_3, 0, value); } #[storage(read)] fn get_u16() -> Option { - get::(S_3) - } - - #[storage(write)] - fn clear_u32() -> bool { - clear::(S_4) + read::(S_3, 0) } - #[storage(write)] + #[storage(read, write)] fn store_u32(value: u32) { - store(S_4, value); + write(S_4, 0, value); } #[storage(read)] fn get_u32() -> Option { - get::(S_4) - } - - #[storage(write)] - fn clear_u64() -> bool { - clear::(S_5) + read::(S_4, 0) } - #[storage(write)] + #[storage(read, write)] fn store_u64(value: u64) { - store(S_5, value); + write(S_5, 0, value); } #[storage(read)] fn get_u64() -> Option { - get::(S_5) - } - - #[storage(write)] - fn clear_b256() -> bool { - clear::(S_6) + read::(S_5, 0) } - #[storage(write)] + #[storage(read, write)] fn store_b256(value: b256) { - store(S_6, value); + write(S_6, 0, value); } #[storage(read)] fn get_b256() -> Option { - get::(S_6) + read::(S_6, 0) } - #[storage(write)] - fn clear_small_struct() -> bool { - clear::(S_8) - } - - #[storage(write)] + #[storage(read, write)] fn store_small_struct(value: SmallStruct) { - store(S_8, value); + write(S_7, 0, value); } #[storage(read)] fn get_small_struct() -> Option { - get::(S_8) + read::(S_7, 0) } - #[storage(write)] - fn clear_medium_struct() -> bool { - clear::(S_9) - } - - #[storage(write)] + #[storage(read, write)] fn store_medium_struct(value: MediumStruct) { - store(S_9, value); + write(S_8, 0, value); } #[storage(read)] fn get_medium_struct() -> Option { - get::(S_9) + read::(S_8, 0) } - #[storage(write)] - fn clear_large_struct() -> bool { - clear::(S_9) - } - - #[storage(write)] + #[storage(read, write)] fn store_large_struct(value: LargeStruct) { - store(S_9, value); + write(S_9, 0, value); } #[storage(read)] fn get_large_struct() -> Option { - get::(S_9) - } - - #[storage(write)] - fn clear_very_large_struct() -> bool { - clear::(S_10) + read::(S_9, 0) } - #[storage(write)] + #[storage(read, write)] fn store_very_large_struct(value: VeryLargeStruct) { - store(S_10, value); + write(S_10, 0, value); } #[storage(read)] fn get_very_large_struct() -> Option { - get::(S_10) - } - - #[storage(write)] - fn clear_enum() -> bool { - clear::(S_11) + read::(S_10, 0) } - #[storage(write)] + #[storage(read, write)] fn store_enum(value: StorageEnum) { - store(S_11, value); + write(S_11, 0, value); } #[storage(read)] fn get_enum() -> Option { - get::(S_11) - } - - #[storage(write)] - fn clear_tuple() -> bool { - clear::<(b256, u8, b256)>(S_12) + read::(S_11, 0) } - #[storage(write)] + #[storage(read, write)] fn store_tuple(value: (b256, u8, b256)) { - store(S_12, value); + write(S_12, 0, value); } #[storage(read)] fn get_tuple() -> Option<(b256, u8, b256)> { - get::<(b256, u8, b256)>(S_12) - } - - #[storage(write)] - fn clear_string() -> bool { - clear::(S_13) + read::<(b256, u8, b256)>(S_12, 0) } - #[storage(write)] + #[storage(read, write)] fn store_string(value: str[31]) { - store(S_13, value); + write(S_13, 0, value); } #[storage(read)] fn get_string() -> Option { - get::(S_13) + read::(S_13, 0) } - #[storage(write)] - fn clear_array() -> bool { - clear::<[b256; 3]>(S_14) - } - - #[storage(write)] + #[storage(read, write)] fn store_array() { let a = [ 0x9999999999999999999999999999999999999999999999999999999999999999, 0x8888888888888888888888888888888888888888888888888888888888888888, 0x7777777777777777777777777777777777777777777777777777777777777777, ]; - store(S_14, a); + write(S_14, 0, a); } #[storage(read)] fn get_array() -> Option<[b256; 3]> { - get::<[b256; 3]>(S_14) + read::<[b256; 3]>(S_14, 0) } #[storage(read, write)] @@ -384,12 +287,12 @@ fn non_inlined_function(arg: u32) -> bool { // By storing and reading from a large complex data structure we're ensuring that this function // is too large to be inlined. The stored value type must be a reference type too, to ensure // the use of memory (not a register) to read it back. - store(S_15, LargeStruct { + write(S_15, 0, LargeStruct { x: arg, y: 0x9999999999999999999999999999999999999999999999999999999999999999, z: arg, }); - let ls = get::(S_15).unwrap(); + let ls = read::(S_15, 0).unwrap(); ls.x == arg } diff --git a/test/src/sdk-harness/test_projects/experimental_storage/Forc.lock b/test/src/sdk-harness/test_projects/storage_access/Forc.lock similarity index 52% rename from test/src/sdk-harness/test_projects/experimental_storage/Forc.lock rename to test/src/sdk-harness/test_projects/storage_access/Forc.lock index ef5e14b9cfa..4278ae6aabf 100644 --- a/test/src/sdk-harness/test_projects/experimental_storage/Forc.lock +++ b/test/src/sdk-harness/test_projects/storage_access/Forc.lock @@ -1,13 +1,13 @@ [[package]] name = 'core' -source = 'path+from-root-74CC9BB8A5BDA72C' - -[[package]] -name = 'experimental_storage' -source = 'member' -dependencies = ['std'] +source = 'path+from-root-D44C3B35585CEC42' [[package]] name = 'std' -source = 'path+from-root-74CC9BB8A5BDA72C' +source = 'path+from-root-D44C3B35585CEC42' dependencies = ['core'] + +[[package]] +name = 'storage_access' +source = 'member' +dependencies = ['std'] diff --git a/test/src/sdk-harness/test_projects/experimental_storage/Forc.toml b/test/src/sdk-harness/test_projects/storage_access/Forc.toml similarity index 83% rename from test/src/sdk-harness/test_projects/experimental_storage/Forc.toml rename to test/src/sdk-harness/test_projects/storage_access/Forc.toml index b9134832a32..9dc7472c5fd 100644 --- a/test/src/sdk-harness/test_projects/experimental_storage/Forc.toml +++ b/test/src/sdk-harness/test_projects/storage_access/Forc.toml @@ -2,7 +2,7 @@ authors = ["Fuel Labs "] entry = "main.sw" license = "Apache-2.0" -name = "experimental_storage" +name = "storage_access" [dependencies] std = { path = "../../../../../sway-lib-std" } diff --git a/test/src/sdk-harness/test_projects/experimental_storage/mod.rs b/test/src/sdk-harness/test_projects/storage_access/mod.rs similarity index 82% rename from test/src/sdk-harness/test_projects/experimental_storage/mod.rs rename to test/src/sdk-harness/test_projects/storage_access/mod.rs index 9626bffaa9f..e9692321b57 100644 --- a/test/src/sdk-harness/test_projects/experimental_storage/mod.rs +++ b/test/src/sdk-harness/test_projects/storage_access/mod.rs @@ -1,26 +1,26 @@ use fuels::{prelude::*, types::Bits256}; abigen!(Contract( - name = "TestExperimentalStorageContract", - abi = "test_projects/experimental_storage/out/debug/experimental_storage-abi.json", + name = "TestStorageAccessContract", + abi = "test_projects/storage_access/out/debug/storage_access-abi.json", )); -async fn test_experimental_storage_instance() -> TestExperimentalStorageContract { +async fn test_storage_access_instance() -> TestStorageAccessContract { let wallet = launch_provider_and_get_wallet().await; let id = Contract::deploy( - "test_projects/experimental_storage/out/debug/experimental_storage.bin", + "test_projects/storage_access/out/debug/storage_access.bin", &wallet, DeployConfiguration::default(), ) .await .unwrap(); - TestExperimentalStorageContract::new(id.clone(), wallet) + TestStorageAccessContract::new(id.clone(), wallet) } #[tokio::test] async fn simple_access() { - let methods = test_experimental_storage_instance().await.methods(); + let methods = test_storage_access_instance().await.methods(); let input = 42; assert_eq!( @@ -47,7 +47,7 @@ async fn simple_access() { #[tokio::test] async fn struct_access_simple() { - let methods = test_experimental_storage_instance().await.methods(); + let methods = test_storage_access_instance().await.methods(); let input = Simple { x: 0, y: 0, @@ -68,7 +68,7 @@ async fn struct_access_simple() { #[tokio::test] async fn struct_access() { - let methods = test_experimental_storage_instance().await.methods(); + let methods = test_storage_access_instance().await.methods(); let input = S { a: 1, @@ -107,7 +107,7 @@ async fn struct_access() { #[tokio::test] async fn map_access() { - let methods = test_experimental_storage_instance().await.methods(); + let methods = test_storage_access_instance().await.methods(); let (key1, key2, key3) = (42, 69, 99); let (value1, value2, value3) = (1, 2, 3); @@ -132,7 +132,7 @@ async fn map_access() { #[tokio::test] async fn maps_in_struct_access() { - let methods = test_experimental_storage_instance().await.methods(); + let methods = test_storage_access_instance().await.methods(); let (key1, key2, key3) = ((42, 24), (69, 96), (99, 88)); let (value1, value2, value3) = ((1, 4), (2, 5), (3, 6)); diff --git a/test/src/sdk-harness/test_projects/experimental_storage/src/main.sw b/test/src/sdk-harness/test_projects/storage_access/src/main.sw similarity index 98% rename from test/src/sdk-harness/test_projects/experimental_storage/src/main.sw rename to test/src/sdk-harness/test_projects/storage_access/src/main.sw index ad7f8625fc3..f77de4ef2c3 100644 --- a/test/src/sdk-harness/test_projects/experimental_storage/src/main.sw +++ b/test/src/sdk-harness/test_projects/storage_access/src/main.sw @@ -1,8 +1,5 @@ contract; -use core::experimental::storage::*; -use std::experimental::storage::*; - struct M { u: b256, v: u64, diff --git a/test/src/sdk-harness/test_projects/storage_bytes/src/main.sw b/test/src/sdk-harness/test_projects/storage_bytes/src/main.sw index d219e30deb7..cb0a8ff32d2 100644 --- a/test/src/sdk-harness/test_projects/storage_bytes/src/main.sw +++ b/test/src/sdk-harness/test_projects/storage_bytes/src/main.sw @@ -1,6 +1,6 @@ contract; -use std::storage::StorageBytes; +use std::storage::storage_bytes::*; use std::bytes::Bytes; storage { @@ -8,7 +8,7 @@ storage { } abi StorageBytesTest { - #[storage(write)] + #[storage(read, write)] fn store_bytes(vec: Vec); #[storage(read)] fn assert_stored_bytes(vec: Vec); @@ -19,7 +19,7 @@ abi StorageBytesTest { } impl StorageBytesTest for Contract { - #[storage(write)] + #[storage(read, write)] fn store_bytes(vec: Vec) { let mut vec = vec; let bytes = Bytes::from_vec_u8(vec); diff --git a/test/src/sdk-harness/test_projects/experimental_storage_map/Forc.lock b/test/src/sdk-harness/test_projects/storage_init/Forc.lock similarity index 52% rename from test/src/sdk-harness/test_projects/experimental_storage_map/Forc.lock rename to test/src/sdk-harness/test_projects/storage_init/Forc.lock index c1c6e2b3aca..f36ab4f84c6 100644 --- a/test/src/sdk-harness/test_projects/experimental_storage_map/Forc.lock +++ b/test/src/sdk-harness/test_projects/storage_init/Forc.lock @@ -1,13 +1,13 @@ [[package]] name = 'core' -source = 'path+from-root-83B46F58807517BF' - -[[package]] -name = 'experimental_storage_map' -source = 'member' -dependencies = ['std'] +source = 'path+from-root-8DCC05DABA9F7828' [[package]] name = 'std' -source = 'path+from-root-83B46F58807517BF' +source = 'path+from-root-8DCC05DABA9F7828' dependencies = ['core'] + +[[package]] +name = 'storage_init' +source = 'member' +dependencies = ['std'] diff --git a/test/src/sdk-harness/test_projects/experimental_storage_map/Forc.toml b/test/src/sdk-harness/test_projects/storage_init/Forc.toml similarity index 82% rename from test/src/sdk-harness/test_projects/experimental_storage_map/Forc.toml rename to test/src/sdk-harness/test_projects/storage_init/Forc.toml index f866e4e520d..68f6916d914 100644 --- a/test/src/sdk-harness/test_projects/experimental_storage_map/Forc.toml +++ b/test/src/sdk-harness/test_projects/storage_init/Forc.toml @@ -2,7 +2,7 @@ authors = ["Fuel Labs "] entry = "main.sw" license = "Apache-2.0" -name = "experimental_storage_map" +name = "storage_init" [dependencies] std = { path = "../../../../../sway-lib-std" } diff --git a/test/src/sdk-harness/test_projects/storage_init/mod.rs b/test/src/sdk-harness/test_projects/storage_init/mod.rs new file mode 100644 index 00000000000..b0dfb941295 --- /dev/null +++ b/test/src/sdk-harness/test_projects/storage_init/mod.rs @@ -0,0 +1,29 @@ +use fuels::prelude::*; + +abigen!(Contract( + name = "TestStorageInitContract", + abi = "test_projects/storage_init/out/debug/storage_init-abi.json", +)); + +async fn test_storage_init_instance() -> TestStorageInitContract { + let wallet = launch_provider_and_get_wallet().await; + let id = Contract::deploy( + "test_projects/storage_init/out/debug/storage_init.bin", + &wallet, + DeployConfiguration::default().set_storage_configuration( + StorageConfiguration::default().set_storage_path( + "test_projects/storage_init/out/debug/storage_init-storage_slots.json".to_string(), + ), + ), + ) + .await + .unwrap(); + + TestStorageInitContract::new(id.clone(), wallet) +} + +#[tokio::test] +async fn test_initializers() { + let methods = test_storage_init_instance().await.methods(); + assert!(methods.test_initializers().call().await.unwrap().value); +} diff --git a/test/src/sdk-harness/test_projects/experimental_storage_init/src/main.sw b/test/src/sdk-harness/test_projects/storage_init/src/main.sw similarity index 98% rename from test/src/sdk-harness/test_projects/experimental_storage_init/src/main.sw rename to test/src/sdk-harness/test_projects/storage_init/src/main.sw index fa008ee9319..6abe3a823b5 100644 --- a/test/src/sdk-harness/test_projects/experimental_storage_init/src/main.sw +++ b/test/src/sdk-harness/test_projects/storage_init/src/main.sw @@ -1,8 +1,5 @@ contract; -use core::experimental::storage::*; -use std::experimental::storage::*; - pub struct S { x: u64, y: u64, diff --git a/test/src/sdk-harness/test_projects/storage_map/.gitignore b/test/src/sdk-harness/test_projects/storage_map/.gitignore deleted file mode 100644 index 77d3844f58c..00000000000 --- a/test/src/sdk-harness/test_projects/storage_map/.gitignore +++ /dev/null @@ -1,2 +0,0 @@ -out -target diff --git a/test/src/sdk-harness/test_projects/storage_map/src/main.sw b/test/src/sdk-harness/test_projects/storage_map/src/main.sw index 1a405887d47..ca5539d1e1e 100644 --- a/test/src/sdk-harness/test_projects/storage_map/src/main.sw +++ b/test/src/sdk-harness/test_projects/storage_map/src/main.sw @@ -35,133 +35,133 @@ storage { } abi StorageMapTest { - #[storage(write)] + #[storage(read, write)] fn insert_into_u64_to_bool_map(key: u64, value: bool); #[storage(read)] fn get_from_u64_to_bool_map(key: u64) -> Option; #[storage(write)] fn remove_from_u64_to_bool_map(key: u64) -> bool; - #[storage(write)] + #[storage(read, write)] fn insert_into_u64_to_u8_map(key: u64, value: u8); #[storage(read)] fn get_from_u64_to_u8_map(key: u64) -> Option; #[storage(write)] fn remove_from_u64_to_u8_map(key: u64) -> bool; - #[storage(write)] + #[storage(read, write)] fn insert_into_u64_to_u16_map(key: u64, value: u16); #[storage(read)] fn get_from_u64_to_u16_map(key: u64) -> Option; #[storage(write)] fn remove_from_u64_to_u16_map(key: u64) -> bool; - #[storage(write)] + #[storage(read, write)] fn insert_into_u64_to_u32_map(key: u64, value: u32); #[storage(read)] fn get_from_u64_to_u32_map(key: u64) -> Option; #[storage(write)] fn remove_from_u64_to_u32_map(key: u64) -> bool; - #[storage(write)] + #[storage(read, write)] fn insert_into_u64_to_u64_map(key: u64, value: u64); #[storage(read)] fn get_from_u64_to_u64_map(key: u64) -> Option; #[storage(write)] fn remove_from_u64_to_u64_map(key: u64) -> bool; - #[storage(write)] + #[storage(read, write)] fn insert_into_u64_to_tuple_map(key: u64, value: (b256, u8, bool)); #[storage(read)] fn get_from_u64_to_tuple_map(key: u64) -> Option<(b256, u8, bool)>; #[storage(write)] fn remove_from_u64_to_tuple_map(key: u64) -> bool; - #[storage(write)] + #[storage(read, write)] fn insert_into_u64_to_struct_map(key: u64, value: Struct); #[storage(read)] fn get_from_u64_to_struct_map(key: u64) -> Option; #[storage(write)] fn remove_from_u64_to_struct_map(key: u64) -> bool; - #[storage(write)] + #[storage(read, write)] fn insert_into_u64_to_enum_map(key: u64, value: Enum); #[storage(read)] fn get_from_u64_to_enum_map(key: u64) -> Option; #[storage(write)] fn remove_from_u64_to_enum_map(key: u64) -> bool; - #[storage(write)] + #[storage(read, write)] fn insert_into_u64_to_str_map(key: u64, value: str[33]); #[storage(read)] fn get_from_u64_to_str_map(key: u64) -> Option; #[storage(write)] fn remove_from_u64_to_str_map(key: u64) -> bool; - #[storage(write)] + #[storage(read, write)] fn insert_into_u64_to_array_map(key: u64, value: [b256; 3]); #[storage(read)] fn get_from_u64_to_array_map(key: u64) -> Option<[b256; 3]>; #[storage(write)] fn remove_from_u64_to_array_map(key: u64) -> bool; - #[storage(write)] + #[storage(read, write)] fn insert_into_bool_to_u64_map(key: bool, value: u64); #[storage(read)] fn get_from_bool_to_u64_map(key: bool) -> Option; #[storage(write)] fn remove_from_bool_to_u64_map(key: bool) -> bool; - #[storage(write)] + #[storage(read, write)] fn insert_into_u8_to_u64_map(key: u8, value: u64); #[storage(read)] fn get_from_u8_to_u64_map(key: u8) -> Option; #[storage(write)] fn remove_from_u8_to_u64_map(key: u8) -> bool; - #[storage(write)] + #[storage(read, write)] fn insert_into_u16_to_u64_map(key: u16, value: u64); #[storage(read)] fn get_from_u16_to_u64_map(key: u16) -> Option; #[storage(write)] fn remove_from_u16_to_u64_map(key: u16) -> bool; - #[storage(write)] + #[storage(read, write)] fn insert_into_u32_to_u64_map(key: u32, value: u64); #[storage(read)] fn get_from_u32_to_u64_map(key: u32) -> Option; #[storage(write)] fn remove_from_u32_to_u64_map(key: u32) -> bool; - #[storage(write)] + #[storage(read, write)] fn insert_into_tuple_to_u64_map(key: (b256, u8, bool), value: u64); #[storage(read)] fn get_from_tuple_to_u64_map(key: (b256, u8, bool)) -> Option; #[storage(write)] fn remove_from_tuple_to_u64_map(key: (b256, u8, bool)) -> bool; - #[storage(write)] + #[storage(read, write)] fn insert_into_struct_to_u64_map(key: Struct, value: u64); #[storage(read)] fn get_from_struct_to_u64_map(key: Struct) -> Option; #[storage(write)] fn remove_from_struct_to_u64_map(key: Struct) -> bool; - #[storage(write)] + #[storage(read, write)] fn insert_into_enum_to_u64_map(key: Enum, value: u64); #[storage(read)] fn get_from_enum_to_u64_map(key: Enum) -> Option; #[storage(write)] fn remove_from_enum_to_u64_map(key: Enum) -> bool; - #[storage(write)] + #[storage(read, write)] fn insert_into_str_to_u64_map(key: str[33], value: u64); #[storage(read)] fn get_from_str_to_u64_map(key: str[33]) -> Option; #[storage(write)] fn remove_from_str_to_u64_map(key: str[33]) -> bool; - #[storage(write)] + #[storage(read, write)] fn insert_into_array_to_u64_map(key: [b256; 3], value: u64); #[storage(read)] fn get_from_array_to_u64_map(key: [b256; 3]) -> Option; @@ -169,14 +169,14 @@ abi StorageMapTest { fn remove_from_array_to_u64_map(key: [b256; 3]) -> bool; } -#[storage(write)] +#[storage(read, write)] fn _insert_into_u64_to_bool_map_inner(key: u64, value: bool) { storage.map1.insert(key, value); } #[storage(read)] fn _get_from_u64_to_bool_map_inner(key: u64) -> Option { - storage.map1.get(key) + storage.map1.get(key).try_read() } #[storage(write)] @@ -185,7 +185,7 @@ fn _remove_from_u64_to_bool_map_inner(key: u64) -> bool { } impl StorageMapTest for Contract { - #[storage(write)] + #[storage(read, write)] fn insert_into_u64_to_bool_map(key: u64, value: bool) { _insert_into_u64_to_bool_map_inner(key, value) } @@ -200,14 +200,14 @@ impl StorageMapTest for Contract { _remove_from_u64_to_bool_map_inner(key) } - #[storage(write)] + #[storage(read, write)] fn insert_into_u64_to_u8_map(key: u64, value: u8) { storage.map2.insert(key, value); } #[storage(read)] fn get_from_u64_to_u8_map(key: u64) -> Option { - storage.map2.get(key) + storage.map2.get(key).try_read() } #[storage(write)] @@ -215,14 +215,14 @@ impl StorageMapTest for Contract { storage.map2.remove(key) } - #[storage(write)] + #[storage(read, write)] fn insert_into_u64_to_u16_map(key: u64, value: u16) { storage.map3.insert(key, value); } #[storage(read)] fn get_from_u64_to_u16_map(key: u64) -> Option { - storage.map3.get(key) + storage.map3.get(key).try_read() } #[storage(write)] @@ -230,14 +230,14 @@ impl StorageMapTest for Contract { storage.map3.remove(key) } - #[storage(write)] + #[storage(read, write)] fn insert_into_u64_to_u32_map(key: u64, value: u32) { storage.map4.insert(key, value); } #[storage(read)] fn get_from_u64_to_u32_map(key: u64) -> Option { - storage.map4.get(key) + storage.map4.get(key).try_read() } #[storage(write)] @@ -245,14 +245,14 @@ impl StorageMapTest for Contract { storage.map4.remove(key) } - #[storage(write)] + #[storage(read, write)] fn insert_into_u64_to_u64_map(key: u64, value: u64) { storage.map5.insert(key, value); } #[storage(read)] fn get_from_u64_to_u64_map(key: u64) -> Option { - storage.map5.get(key) + storage.map5.get(key).try_read() } #[storage(write)] @@ -260,14 +260,14 @@ impl StorageMapTest for Contract { storage.map5.remove(key) } - #[storage(write)] + #[storage(read, write)] fn insert_into_u64_to_tuple_map(key: u64, value: (b256, u8, bool)) { storage.map6.insert(key, value); } #[storage(read)] fn get_from_u64_to_tuple_map(key: u64) -> Option<(b256, u8, bool)> { - storage.map6.get(key) + storage.map6.get(key).try_read() } #[storage(write)] @@ -275,14 +275,14 @@ impl StorageMapTest for Contract { storage.map6.remove(key) } - #[storage(write)] + #[storage(read, write)] fn insert_into_u64_to_struct_map(key: u64, value: Struct) { storage.map7.insert(key, value); } #[storage(read)] fn get_from_u64_to_struct_map(key: u64) -> Option { - storage.map7.get(key) + storage.map7.get(key).try_read() } #[storage(write)] @@ -290,14 +290,14 @@ impl StorageMapTest for Contract { storage.map7.remove(key) } - #[storage(write)] + #[storage(read, write)] fn insert_into_u64_to_enum_map(key: u64, value: Enum) { storage.map8.insert(key, value); } #[storage(read)] fn get_from_u64_to_enum_map(key: u64) -> Option { - storage.map8.get(key) + storage.map8.get(key).try_read() } #[storage(write)] @@ -305,14 +305,14 @@ impl StorageMapTest for Contract { storage.map8.remove(key) } - #[storage(write)] + #[storage(read, write)] fn insert_into_u64_to_str_map(key: u64, value: str[33]) { storage.map9.insert(key, value); } #[storage(read)] fn get_from_u64_to_str_map(key: u64) -> Option { - storage.map9.get(key) + storage.map9.get(key).try_read() } #[storage(write)] @@ -320,14 +320,14 @@ impl StorageMapTest for Contract { storage.map9.remove(key) } - #[storage(write)] + #[storage(read, write)] fn insert_into_u64_to_array_map(key: u64, value: [b256; 3]) { storage.map10.insert(key, value); } #[storage(read)] fn get_from_u64_to_array_map(key: u64) -> Option<[b256; 3]> { - storage.map10.get(key) + storage.map10.get(key).try_read() } #[storage(write)] @@ -335,14 +335,14 @@ impl StorageMapTest for Contract { storage.map10.remove(key) } - #[storage(write)] + #[storage(read, write)] fn insert_into_bool_to_u64_map(key: bool, value: u64) { storage.map11.insert(key, value); } #[storage(read)] fn get_from_bool_to_u64_map(key: bool) -> Option { - storage.map11.get(key) + storage.map11.get(key).try_read() } #[storage(write)] @@ -350,14 +350,14 @@ impl StorageMapTest for Contract { storage.map11.remove(key) } - #[storage(write)] + #[storage(read, write)] fn insert_into_u8_to_u64_map(key: u8, value: u64) { storage.map12.insert(key, value); } #[storage(read)] fn get_from_u8_to_u64_map(key: u8) -> Option { - storage.map12.get(key) + storage.map12.get(key).try_read() } #[storage(write)] @@ -365,14 +365,14 @@ impl StorageMapTest for Contract { storage.map12.remove(key) } - #[storage(write)] + #[storage(read, write)] fn insert_into_u16_to_u64_map(key: u16, value: u64) { storage.map13.insert(key, value); } #[storage(read)] fn get_from_u16_to_u64_map(key: u16) -> Option { - storage.map13.get(key) + storage.map13.get(key).try_read() } #[storage(write)] @@ -380,14 +380,14 @@ impl StorageMapTest for Contract { storage.map13.remove(key) } - #[storage(write)] + #[storage(read, write)] fn insert_into_u32_to_u64_map(key: u32, value: u64) { storage.map14.insert(key, value); } #[storage(read)] fn get_from_u32_to_u64_map(key: u32) -> Option { - storage.map14.get(key) + storage.map14.get(key).try_read() } #[storage(write)] @@ -395,14 +395,14 @@ impl StorageMapTest for Contract { storage.map14.remove(key) } - #[storage(write)] + #[storage(read, write)] fn insert_into_tuple_to_u64_map(key: (b256, u8, bool), value: u64) { storage.map15.insert(key, value); } #[storage(read)] fn get_from_tuple_to_u64_map(key: (b256, u8, bool)) -> Option { - storage.map15.get(key) + storage.map15.get(key).try_read() } #[storage(write)] @@ -410,14 +410,14 @@ impl StorageMapTest for Contract { storage.map15.remove(key) } - #[storage(write)] + #[storage(read, write)] fn insert_into_struct_to_u64_map(key: Struct, value: u64) { storage.map16.insert(key, value); } #[storage(read)] fn get_from_struct_to_u64_map(key: Struct) -> Option { - storage.map16.get(key) + storage.map16.get(key).try_read() } #[storage(write)] @@ -425,14 +425,14 @@ impl StorageMapTest for Contract { storage.map16.remove(key) } - #[storage(write)] + #[storage(read, write)] fn insert_into_enum_to_u64_map(key: Enum, value: u64) { storage.map17.insert(key, value); } #[storage(read)] fn get_from_enum_to_u64_map(key: Enum) -> Option { - storage.map17.get(key) + storage.map17.get(key).try_read() } #[storage(write)] @@ -440,14 +440,14 @@ impl StorageMapTest for Contract { storage.map17.remove(key) } - #[storage(write)] + #[storage(read, write)] fn insert_into_str_to_u64_map(key: str[33], value: u64) { storage.map18.insert(key, value); } #[storage(read)] fn get_from_str_to_u64_map(key: str[33]) -> Option { - storage.map18.get(key) + storage.map18.get(key).try_read() } #[storage(write)] @@ -455,14 +455,14 @@ impl StorageMapTest for Contract { storage.map18.remove(key) } - #[storage(write)] + #[storage(read, write)] fn insert_into_array_to_u64_map(key: [b256; 3], value: u64) { storage.map19.insert(key, value) } #[storage(read)] fn get_from_array_to_u64_map(key: [b256; 3]) -> Option { - storage.map19.get(key) + storage.map19.get(key).try_read() } #[storage(write)] diff --git a/test/src/sdk-harness/test_projects/experimental_storage_init/Forc.lock b/test/src/sdk-harness/test_projects/storage_map_nested/Forc.lock similarity index 51% rename from test/src/sdk-harness/test_projects/experimental_storage_init/Forc.lock rename to test/src/sdk-harness/test_projects/storage_map_nested/Forc.lock index de621ed2ae3..d58f51d6ec9 100644 --- a/test/src/sdk-harness/test_projects/experimental_storage_init/Forc.lock +++ b/test/src/sdk-harness/test_projects/storage_map_nested/Forc.lock @@ -1,13 +1,13 @@ [[package]] name = 'core' -source = 'path+from-root-73CDE20FD60E0CD6' - -[[package]] -name = 'experimental_storage_init' -source = 'member' -dependencies = ['std'] +source = 'path+from-root-2D4FB64C341C97C5' [[package]] name = 'std' -source = 'path+from-root-73CDE20FD60E0CD6' +source = 'path+from-root-2D4FB64C341C97C5' dependencies = ['core'] + +[[package]] +name = 'storage_map_nested' +source = 'member' +dependencies = ['std'] diff --git a/test/src/sdk-harness/test_projects/experimental_storage_init/Forc.toml b/test/src/sdk-harness/test_projects/storage_map_nested/Forc.toml similarity index 81% rename from test/src/sdk-harness/test_projects/experimental_storage_init/Forc.toml rename to test/src/sdk-harness/test_projects/storage_map_nested/Forc.toml index 6f2eee5b356..bd26085fc16 100644 --- a/test/src/sdk-harness/test_projects/experimental_storage_init/Forc.toml +++ b/test/src/sdk-harness/test_projects/storage_map_nested/Forc.toml @@ -2,7 +2,7 @@ authors = ["Fuel Labs "] entry = "main.sw" license = "Apache-2.0" -name = "experimental_storage_init" +name = "storage_map_nested" [dependencies] std = { path = "../../../../../sway-lib-std" } diff --git a/test/src/sdk-harness/test_projects/storage_map_nested/mod.rs b/test/src/sdk-harness/test_projects/storage_map_nested/mod.rs new file mode 100644 index 00000000000..86523a63e16 --- /dev/null +++ b/test/src/sdk-harness/test_projects/storage_map_nested/mod.rs @@ -0,0 +1,40 @@ +use fuels::prelude::*; + +abigen!(Contract( + name = "TestStorageMapNestedContract", + abi = "test_projects/storage_map_nested/out/debug/storage_map_nested-abi.json", +)); + +async fn test_storage_map_nested_instance() -> TestStorageMapNestedContract { + let wallet = launch_provider_and_get_wallet().await; + let id = Contract::deploy( + "test_projects/storage_map_nested/out/debug/storage_map_nested.bin", + &wallet, + DeployConfiguration::default(), + ) + .await + .unwrap(); + + TestStorageMapNestedContract::new(id.clone(), wallet) +} + +#[tokio::test] +async fn nested_map_1_access() { + let methods = test_storage_map_nested_instance().await.methods(); + + methods.nested_map_1_access().call().await.unwrap(); +} + +#[tokio::test] +async fn nested_map_2_access() { + let methods = test_storage_map_nested_instance().await.methods(); + + methods.nested_map_2_access().call().await.unwrap(); +} + +#[tokio::test] +async fn nested_map_3_access() { + let methods = test_storage_map_nested_instance().await.methods(); + + methods.nested_map_3_access().call().await.unwrap(); +} diff --git a/test/src/sdk-harness/test_projects/storage_map_nested/src/main.sw b/test/src/sdk-harness/test_projects/storage_map_nested/src/main.sw new file mode 100644 index 00000000000..f8b8f0a91c7 --- /dev/null +++ b/test/src/sdk-harness/test_projects/storage_map_nested/src/main.sw @@ -0,0 +1,147 @@ +contract; + +use std::constants::ZERO_B256; + +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() { + // Map insert via `insert` + storage.nested_map_1.get(0).get(0).insert(0, 1); + storage.nested_map_1.get(0).get(0).insert(1, 2); + storage.nested_map_1.get(0).get(1).insert(0, 3); + storage.nested_map_1.get(0).get(1).insert(1, 4); + storage.nested_map_1.get(1).get(0).insert(0, 5); + storage.nested_map_1.get(1).get(0).insert(1, 6); + storage.nested_map_1.get(1).get(1).insert(0, 7); + storage.nested_map_1.get(1).get(1).insert(1, 8); + + // Map access via `get` + assert(storage.nested_map_1.get(0).get(0).get(0).read() == 1); + assert(storage.nested_map_1.get(0).get(0).get(1).read() == 2); + assert(storage.nested_map_1.get(0).get(1).get(0).read() == 3); + assert(storage.nested_map_1.get(0).get(1).get(1).read() == 4); + assert(storage.nested_map_1.get(1).get(0).get(0).read() == 5); + assert(storage.nested_map_1.get(1).get(0).get(1).read() == 6); + assert(storage.nested_map_1.get(1).get(1).get(0).read() == 7); + assert(storage.nested_map_1.get(1).get(1).get(1).read() == 8); + + // Thes combinations of keys are not set + assert(storage.nested_map_1.get(2).get(1).get(1).try_read().is_none()); + assert(storage.nested_map_1.get(1).get(2).get(1).try_read().is_none()); + assert(storage.nested_map_1.get(1).get(1).get(2).try_read().is_none()); + } + + #[storage(read, write)] + fn nested_map_2_access() { + let m1 = M { + u: 0x1111111111111111111111111111111111111111111111111111111111111111, + v: 1, + }; + let m2 = M { + u: 0x2222222222222222222222222222222222222222222222222222222222222222, + v: 2, + }; + + // Map insert via `insert` + storage.nested_map_2.get((0, 0)).get("0000").insert(0, m1); + storage.nested_map_2.get((0, 0)).get("0001").insert(1, m2); + storage.nested_map_2.get((0, 1)).get("0000").insert(0, m1); + storage.nested_map_2.get((0, 1)).get("0001").insert(1, m2); + + // Map insert via `get` + assert(storage.nested_map_2.get((0, 0)).get("0000").get(0).read() == m1); + assert(storage.nested_map_2.get((0, 0)).get("0001").get(1).read() == m2); + assert(storage.nested_map_2.get((0, 1)).get("0000").get(0).read() == m1); + assert(storage.nested_map_2.get((0, 1)).get("0001").get(1).read() == m2); + + // Thes combinations of keys are not set + assert(storage.nested_map_2.get((2, 0)).get("0001").get(1).try_read().is_none()); + assert(storage.nested_map_2.get((1, 1)).get("0002").get(0).try_read().is_none()); + assert(storage.nested_map_2.get((1, 1)).get("0001").get(2).try_read().is_none()); + } + + #[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); + + // Map insert via `insert` + storage.nested_map_3.get(0).get(m1).insert(0, e1); + storage.nested_map_3.get(0).get(m2).insert(1, e2); + storage.nested_map_3.get(0).get(m1).insert(0, e1); + storage.nested_map_3.get(0).get(m2).insert(1, e2); + storage.nested_map_3.get(1).get(m1).insert(0, e1); + storage.nested_map_3.get(1).get(m2).insert(1, e2); + storage.nested_map_3.get(1).get(m1).insert(0, e1); + storage.nested_map_3.get(1).get(m2).insert(1, e2); + + // Map insert via `get` + assert(storage.nested_map_3.get(0).get(m1).get(0).read() == e1); + assert(storage.nested_map_3.get(0).get(m2).get(1).read() == e2); + assert(storage.nested_map_3.get(0).get(m1).get(0).read() == e1); + assert(storage.nested_map_3.get(0).get(m2).get(1).read() == e2); + assert(storage.nested_map_3.get(1).get(m1).get(0).read() == e1); + assert(storage.nested_map_3.get(1).get(m2).get(1).read() == e2); + assert(storage.nested_map_3.get(1).get(m1).get(0).read() == e1); + assert(storage.nested_map_3.get(1).get(m2).get(1).read() == e2); + + // Thes combinations of keys are not set + assert(storage.nested_map_3.get(2).get(m2).get(1).try_read().is_none()); + assert(storage.nested_map_3.get(1).get(M { + u: ZERO_B256, + v: 3, + }).get(1).try_read().is_none()); + assert(storage.nested_map_3.get(1).get(m2).get(2).try_read().is_none()); + } +} diff --git a/test/src/sdk-harness/test_projects/storage_vec_nested/Forc.lock b/test/src/sdk-harness/test_projects/storage_vec_nested/Forc.lock new file mode 100644 index 00000000000..b1118d9c766 --- /dev/null +++ b/test/src/sdk-harness/test_projects/storage_vec_nested/Forc.lock @@ -0,0 +1,13 @@ +[[package]] +name = 'core' +source = 'path+from-root-0A73F145D8D4FEED' + +[[package]] +name = 'std' +source = 'path+from-root-0A73F145D8D4FEED' +dependencies = ['core'] + +[[package]] +name = 'storage_vec_nested' +source = 'member' +dependencies = ['std'] diff --git a/test/src/e2e_vm_tests/test_programs/should_fail/storage_types/Forc.toml b/test/src/sdk-harness/test_projects/storage_vec_nested/Forc.toml similarity index 53% rename from test/src/e2e_vm_tests/test_programs/should_fail/storage_types/Forc.toml rename to test/src/sdk-harness/test_projects/storage_vec_nested/Forc.toml index 9f309eee821..99675ba5ae4 100644 --- a/test/src/e2e_vm_tests/test_programs/should_fail/storage_types/Forc.toml +++ b/test/src/sdk-harness/test_projects/storage_vec_nested/Forc.toml @@ -1,9 +1,8 @@ [project] -name = "storage_types" authors = ["Fuel Labs "] entry = "main.sw" license = "Apache-2.0" -implicit-std = false +name = "storage_vec_nested" [dependencies] -std = { path = "../../../../../../sway-lib-std" } +std = { path = "../../../../../sway-lib-std" } diff --git a/test/src/sdk-harness/test_projects/storage_vec_nested/mod.rs b/test/src/sdk-harness/test_projects/storage_vec_nested/mod.rs new file mode 100644 index 00000000000..6f46034825d --- /dev/null +++ b/test/src/sdk-harness/test_projects/storage_vec_nested/mod.rs @@ -0,0 +1,26 @@ +use fuels::prelude::*; + +abigen!(Contract( + name = "TestStorageVecNestedContract", + abi = "test_projects/storage_vec_nested/out/debug/storage_vec_nested-abi.json", +)); + +async fn test_storage_vec_nested_instance() -> TestStorageVecNestedContract { + let wallet = launch_provider_and_get_wallet().await; + let id = Contract::deploy( + "test_projects/storage_vec_nested/out/debug/storage_vec_nested.bin", + &wallet, + DeployConfiguration::default(), + ) + .await + .unwrap(); + + TestStorageVecNestedContract::new(id.clone(), wallet) +} + +#[tokio::test] +async fn nested_vec_access() { + let methods = test_storage_vec_nested_instance().await.methods(); + + methods.nested_vec_access().call().await.unwrap(); +} diff --git a/test/src/sdk-harness/test_projects/storage_vec_nested/src/main.sw b/test/src/sdk-harness/test_projects/storage_vec_nested/src/main.sw new file mode 100644 index 00000000000..662177e1067 --- /dev/null +++ b/test/src/sdk-harness/test_projects/storage_vec_nested/src/main.sw @@ -0,0 +1,68 @@ +contract; + +use std::storage::storage_vec::*; + +storage { + nested_vec: StorageVec> = StorageVec {}, +} + +abi ExperimentalStorageTest { + #[storage(read, write)] + fn nested_vec_access(); +} + +impl ExperimentalStorageTest for Contract { + #[storage(read, write)] + fn nested_vec_access() { + storage.nested_vec.push(StorageVec {}); + storage.nested_vec.push(StorageVec {}); + storage.nested_vec.push(StorageVec {}); + let mut inner_vec0 = storage.nested_vec.get(0).unwrap(); + let mut inner_vec1 = storage.nested_vec.get(1).unwrap(); + let mut inner_vec2 = storage.nested_vec.get(2).unwrap(); + assert(storage.nested_vec.len() == 3); + assert(storage.nested_vec.get(3).is_none()); + + inner_vec0.push(0); + inner_vec0.push(1); + + inner_vec1.push(2); + inner_vec1.push(3); + inner_vec1.push(4); + + inner_vec2.push(5); + inner_vec2.push(6); + inner_vec2.push(7); + inner_vec2.push(8); + + inner_vec0.set(0, 0); + inner_vec0.set(1, 11); + + inner_vec1.set(0, 22); + inner_vec1.set(1, 33); + inner_vec1.set(2, 44); + + inner_vec2.set(0, 55); + inner_vec2.set(1, 66); + inner_vec2.set(2, 77); + inner_vec2.set(3, 88); + + assert(inner_vec0.len() == 2); + assert(inner_vec0.get(0).unwrap().read() == 0); + assert(inner_vec0.get(1).unwrap().read() == 11); + assert(inner_vec0.get(2).is_none()); + + assert(inner_vec1.len() == 3); + assert(inner_vec1.get(0).unwrap().read() == 22); + assert(inner_vec1.get(1).unwrap().read() == 33); + assert(inner_vec1.get(2).unwrap().read() == 44); + assert(inner_vec1.get(3).is_none()); + + assert(inner_vec2.len() == 4); + assert(inner_vec2.get(0).unwrap().read() == 55); + assert(inner_vec2.get(1).unwrap().read() == 66); + assert(inner_vec2.get(2).unwrap().read() == 77); + assert(inner_vec2.get(3).unwrap().read() == 88); + assert(inner_vec2.get(4).is_none()); + } +}