Skip to content

Commit

Permalink
feat!: autoload storage slots (#1120)
Browse files Browse the repository at this point in the history
Storage slots will now be automatically loaded when doing `Contract::load_from`. If the autodiscovery process fails or if autoloading is undesirable, an opt-out exists in `StorageConfiguration`.
  • Loading branch information
segfault-magnet authored Sep 1, 2023
1 parent 2915eb7 commit 34f9216
Show file tree
Hide file tree
Showing 16 changed files with 349 additions and 88 deletions.
1 change: 1 addition & 0 deletions docs/src/SUMMARY.md
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@
- [The `abigen!` macro](abigen/the-abigen-macro.md)
- [Deploying contracts](./deploying/index.md)
- [Configurable constants](./deploying/configurable-constants.md)
- [Storage slots](./deploying/storage-slots.md)
- [Interacting with contracts](./deploying/interacting-with-contracts.md)
- [The FuelVM Binary file](./deploying/the-fuelvm-binary-file.md)
- [Calling contracts](./calling-contracts/index.md)
Expand Down
13 changes: 13 additions & 0 deletions docs/src/deploying/storage-slots.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
# Overriding storage slots

If you use storage in your contract, the default storage values will be generated in a JSON file (e.g. `my_contract-storage_slots.json`) by the Sway compiler. These are loaded automatically for you when you load a contract binary. If you wish to override some of the defaults, you need to provide the corresponding storage slots manually:

```rust,ignore
{{#include ../../../examples/contracts/src/lib.rs:storage_slots_override}}
```

If you don't have the slot storage file (`my_contract-storage_slots.json` example from above) for some reason, or you don't wish to load any of the default values, you can disable the auto-loading of storage slots:

```rust,ignore
{{#include ../../../examples/contracts/src/lib.rs:storage_slots_disable_autoload}}
```
41 changes: 38 additions & 3 deletions examples/contracts/src/lib.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,12 @@
#[cfg(test)]
mod tests {
use fuels::types::errors::{error, Error, Result};
use fuels::types::Bits256;
use fuels::{
prelude::{LoadConfiguration, StorageConfiguration},
types::{
errors::{error, Error, Result},
Bits256,
},
};

#[tokio::test]
async fn instantiate_client() -> Result<()> {
Expand Down Expand Up @@ -138,7 +143,8 @@ mod tests {
let key = Bytes32::from([1u8; 32]);
let value = Bytes32::from([2u8; 32]);
let storage_slot = StorageSlot::new(key, value);
let storage_configuration = StorageConfiguration::from(vec![storage_slot]);
let storage_configuration =
StorageConfiguration::default().add_slot_overrides([storage_slot]);
let configuration = LoadConfiguration::default()
.with_storage_configuration(storage_configuration)
.with_salt(salt);
Expand Down Expand Up @@ -791,4 +797,33 @@ mod tests {

Ok(())
}

#[tokio::test]
async fn storage_slots_override() -> Result<()> {
{
// ANCHOR: storage_slots_override
use fuels::{programs::contract::Contract, tx::StorageSlot};
let slot_override = StorageSlot::new([1; 32].into(), [2; 32].into());
let storage_config =
StorageConfiguration::default().add_slot_overrides([slot_override]);

let load_config =
LoadConfiguration::default().with_storage_configuration(storage_config);
let _: Result<Contract> = Contract::load_from("...", load_config);
// ANCHOR_END: storage_slots_override
}

{
// ANCHOR: storage_slots_disable_autoload
use fuels::programs::contract::Contract;
let storage_config = StorageConfiguration::default().with_autoload(false);

let load_config =
LoadConfiguration::default().with_storage_configuration(storage_config);
let _: Result<Contract> = Contract::load_from("...", load_config);
// ANCHOR_END: storage_slots_disable_autoload
}

Ok(())
}
}
6 changes: 4 additions & 2 deletions examples/cookbook/src/lib.rs
Original file line number Diff line number Diff line change
@@ -1,9 +1,11 @@
#[cfg(test)]
mod tests {
use fuels::types::Bits256;
use fuels::{
prelude::Result,
types::transaction_builders::{ScriptTransactionBuilder, TransactionBuilder},
types::{
transaction_builders::{ScriptTransactionBuilder, TransactionBuilder},
Bits256,
},
};

#[tokio::test]
Expand Down
8 changes: 4 additions & 4 deletions packages/fuels-code-gen/src/program_bindings/abigen.rs
Original file line number Diff line number Diff line change
Expand Up @@ -54,10 +54,10 @@ impl Abigen {
}
fn wasm_paths_hotfix(code: &TokenStream) -> TokenStream {
[
(r#"::\s*std\s*::\s*string"#, "::alloc::string"),
(r#"::\s*std\s*::\s*format"#, "::alloc::format"),
(r#"::\s*std\s*::\s*vec"#, "::alloc::vec"),
(r#"::\s*std\s*::\s*boxed"#, "::alloc::boxed"),
(r"::\s*std\s*::\s*string", "::alloc::string"),
(r"::\s*std\s*::\s*format", "::alloc::format"),
(r"::\s*std\s*::\s*vec", "::alloc::vec"),
(r"::\s*std\s*::\s*boxed", "::alloc::boxed"),
]
.map(|(reg_expr_str, substitute)| (Regex::new(reg_expr_str).unwrap(), substitute))
.into_iter()
Expand Down
6 changes: 4 additions & 2 deletions packages/fuels-core/src/types/bech32.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,12 +3,14 @@ use std::{
str::FromStr,
};

use crate::types::Bits256;
use bech32::{FromBase32, ToBase32, Variant::Bech32m};
use fuel_tx::{Address, Bytes32, ContractId, ContractIdExt};
use fuel_types::AssetId;

use crate::types::errors::{Error, Result};
use crate::types::{
errors::{Error, Result},
Bits256,
};

// Fuel Network human-readable part for bech32 encoding
pub const FUEL_BECH32_HRP: &str = "fuel";
Expand Down
3 changes: 2 additions & 1 deletion packages/fuels-core/src/types/core/sized_ascii_string.rs
Original file line number Diff line number Diff line change
@@ -1,8 +1,9 @@
use std::fmt::{Debug, Display, Formatter};

use crate::types::errors::{error, Error, Result};
use serde::{Deserialize, Serialize};

use crate::types::errors::{error, Error, Result};

// To be used when interacting with contracts which have string slices in their ABI.
// The FuelVM strings only support ascii characters.
#[derive(Debug, PartialEq, Clone, Eq)]
Expand Down
2 changes: 0 additions & 2 deletions packages/fuels-core/src/types/param_types.rs
Original file line number Diff line number Diff line change
Expand Up @@ -469,8 +469,6 @@ fn try_str_slice(the_type: &Type) -> Result<Option<ParamType>> {

fn try_array(the_type: &Type) -> Result<Option<ParamType>> {
if let Some(len) = extract_array_len(&the_type.type_field) {
if the_type.components.len() != 1 {}

return match the_type.components.as_slice() {
[single_type] => {
let array_type = single_type.try_into()?;
Expand Down
8 changes: 4 additions & 4 deletions packages/fuels-core/src/types/transaction_builders.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9,9 +9,10 @@ use fuel_tx::{
StorageSlot, Transaction as FuelTransaction, TransactionFee, TxPointer, UniqueIdentifier,
Witness,
};
use fuel_types::{bytes::padded_len_usize, Bytes32, Salt};
use fuel_types::{bytes::padded_len_usize, Bytes32, MemLayout, Salt};
use fuel_vm::{checked_transaction::EstimatePredicates, gas::GasCosts};

use super::unresolved_bytes::UnresolvedBytes;
use crate::{
constants::{BASE_ASSET_ID, WORD_SIZE},
offsets,
Expand All @@ -27,8 +28,6 @@ use crate::{
},
};

use super::unresolved_bytes::UnresolvedBytes;

#[derive(Debug, Clone, Default)]
struct UnresolvedSignatures {
addr_idx_offset_map: HashMap<Bech32Address, u8>,
Expand Down Expand Up @@ -373,6 +372,7 @@ impl CreateTransactionBuilder {
num_witnesses: u8,
consensus_parameters: &ConsensusParameters,
) -> Result<Create> {
let num_of_storage_slots = self.storage_slots.len();
let mut tx = FuelTransaction::create(
self.gas_price,
self.gas_limit,
Expand All @@ -382,7 +382,7 @@ impl CreateTransactionBuilder {
self.storage_slots,
resolve_fuel_inputs(
self.inputs,
base_offset,
base_offset + num_of_storage_slots * StorageSlot::LEN,
num_witnesses,
&self.unresolved_signatures,
)?,
Expand Down
12 changes: 1 addition & 11 deletions packages/fuels-macros/src/setup_program_test/code_gen.rs
Original file line number Diff line number Diff line change
Expand Up @@ -120,16 +120,10 @@ fn contract_deploying_code(
.get(&command.contract.value())
.expect("Project should be in lookup");
let bin_path = project.bin_path();
let storage_path = project.storage_path();

quote! {
let #contract_instance_name = {
let storage_config = StorageConfiguration::load_from(#storage_path)
.expect("Failed to load storage slots from path");
let load_config =
LoadConfiguration::default()
.with_storage_configuration(storage_config)
.with_salt([#(#salt),*]);
let load_config = LoadConfiguration::default().with_salt([#(#salt),*]);

let loaded_contract = Contract::load_from(#bin_path, load_config).expect("Failed to load the contract");

Expand Down Expand Up @@ -212,8 +206,4 @@ impl Project {
fn bin_path(&self) -> String {
self.compile_file_path(".bin", "the binary file")
}

fn storage_path(&self) -> String {
self.compile_file_path("-storage_slots.json", "the storage slots file")
}
}
8 changes: 4 additions & 4 deletions packages/fuels-programs/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -31,9 +31,9 @@ strum_macros = { workspace = true }
thiserror = { workspace = true, default-features = false }
tokio = { workspace = true }

[dev-dependencies]
tempfile = "3.8"

[features]
default = ["std"]
std = [
"fuels-core/std",
"fuels-accounts/std",
]
std = ["fuels-core/std", "fuels-accounts/std"]
6 changes: 3 additions & 3 deletions packages/fuels-programs/src/call_utils.rs
Original file line number Diff line number Diff line change
Expand Up @@ -220,7 +220,7 @@ pub(crate) fn get_instructions(
.iter()
.zip(&offsets)
.flat_map(|(call, offset)| get_single_call_instructions(offset, &call.output_param))
.chain(op::ret(RegId::ONE).to_bytes().into_iter())
.chain(op::ret(RegId::ONE).to_bytes())
.collect()
}

Expand Down Expand Up @@ -558,13 +558,13 @@ mod test {
Bech32ContractId::new("test", Bytes32::new([1u8; 32])),
];

let asset_ids = vec![
let asset_ids = [
AssetId::from([4u8; 32]),
AssetId::from([5u8; 32]),
AssetId::from([6u8; 32]),
];

let selectors = vec![[7u8; 8], [8u8; 8], [9u8; 8]];
let selectors = [[7u8; 8], [8u8; 8], [9u8; 8]];

// Call 2 has multiple inputs, compute_custom_input_offset will be true

Expand Down
Loading

0 comments on commit 34f9216

Please sign in to comment.