Skip to content

Commit

Permalink
fix: proxy deployments for contracts with storage (#6591)
Browse files Browse the repository at this point in the history
## Description

Fixes an issue where storage access wasn't working for proxied
contracts. The fix is passing the combined storage slots to the proxy
contract.

## Checklist

- [ ] I have linked to any relevant issues.
- [ ] I have commented my code, particularly in hard-to-understand
areas.
- [ ] I have updated the documentation where relevant (API docs, the
reference, and the Sway book).
- [ ] If my change requires substantial documentation changes, I have
[requested support from the DevRel
team](https://github.com/FuelLabs/devrel-requests/issues/new/choose)
- [ ] I have added tests that prove my fix is effective or that my
feature works.
- [ ] I have added (or requested a maintainer to add) the necessary
`Breaking*` or `New Feature` labels where relevant.
- [ ] I have done my best to ensure that my PR adheres to [the Fuel Labs
Code Review
Standards](https://github.com/FuelLabs/rfcs/blob/master/text/code-standards/external-contributors.md).
- [ ] I have requested a review from the relevant team or maintainers.
  • Loading branch information
sdankel authored Sep 26, 2024
1 parent 6fe4223 commit 344f1c5
Show file tree
Hide file tree
Showing 7 changed files with 108 additions and 29 deletions.
11 changes: 8 additions & 3 deletions forc-plugins/forc-client/src/op/deploy.rs
Original file line number Diff line number Diff line change
Expand Up @@ -200,6 +200,7 @@ async fn deploy_chunked(
async fn deploy_new_proxy(
command: &cmd::Deploy,
pkg_name: &str,
pkg_storage_slots: &[StorageSlot],
impl_contract: &fuel_tx::ContractId,
provider: &Provider,
account: &ForcClientAccount,
Expand All @@ -208,9 +209,11 @@ async fn deploy_new_proxy(
let proxy_dir_output = create_proxy_contract(pkg_name)?;
let address = account.address();

let storage_path = proxy_dir_output.join("proxy-storage_slots.json");
let storage_configuration =
StorageConfiguration::default().add_slot_overrides_from_file(storage_path)?;
// Add the combined storage slots from the original contract and the proxy contract.
let proxy_storage_path = proxy_dir_output.join("proxy-storage_slots.json");
let storage_configuration = StorageConfiguration::default()
.add_slot_overrides(pkg_storage_slots.iter().cloned())
.add_slot_overrides_from_file(proxy_storage_path)?;

let configurables = ProxyContractConfigurables::default()
.with_INITIAL_TARGET(Some(*impl_contract))?
Expand Down Expand Up @@ -391,10 +394,12 @@ pub async fn deploy(command: cmd::Deploy) -> Result<Vec<DeployedContract>> {
address: None,
}) => {
let pkg_name = &pkg.descriptor.name;
let pkg_storage_slots = &pkg.storage_slots;
// Deploy a new proxy contract.
let deployed_proxy_contract = deploy_new_proxy(
&command,
pkg_name,
pkg_storage_slots,
&deployed_contract_id,
&provider,
&account,
Expand Down
21 changes: 21 additions & 0 deletions forc-plugins/forc-client/test/data/standalone_contract/src/main.sw
Original file line number Diff line number Diff line change
@@ -1,11 +1,32 @@
contract;

storage {
value: u8 = 5,
}

abi MyContract {
fn test_function() -> bool;

#[storage(read)]
fn test_function_read() -> u8;

#[storage(read, write)]
fn test_function_write(value: u8) -> u8;
}

impl MyContract for Contract {
fn test_function() -> bool {
true
}

#[storage(read)]
fn test_function_read() -> u8 {
storage.value.read()
}

#[storage(read, write)]
fn test_function_write(value: u8) -> u8 {
storage.value.write(value);
storage.value.read()
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,10 @@
{
"type": "bool",
"concreteTypeId": "b760f44fa5965c2474a3b471467a22c43185152129295af588b022ae50b50903"
},
{
"type": "u8",
"concreteTypeId": "c89951a24c6ca28c13fd1cfdc646b2b656d69e61a92b91023be7eb58eb914b6b"
}
],
"metadataTypes": [],
Expand All @@ -15,6 +19,38 @@
"name": "test_function",
"output": "b760f44fa5965c2474a3b471467a22c43185152129295af588b022ae50b50903",
"attributes": null
},
{
"inputs": [],
"name": "test_function_read",
"output": "c89951a24c6ca28c13fd1cfdc646b2b656d69e61a92b91023be7eb58eb914b6b",
"attributes": [
{
"name": "storage",
"arguments": [
"read"
]
}
]
},
{
"inputs": [
{
"name": "value",
"concreteTypeId": "c89951a24c6ca28c13fd1cfdc646b2b656d69e61a92b91023be7eb58eb914b6b"
}
],
"name": "test_function_write",
"output": "c89951a24c6ca28c13fd1cfdc646b2b656d69e61a92b91023be7eb58eb914b6b",
"attributes": [
{
"name": "storage",
"arguments": [
"read",
"write"
]
}
]
}
],
"loggedTypes": [],
Expand Down

This file was deleted.

This file was deleted.

This file was deleted.

47 changes: 43 additions & 4 deletions forc-plugins/forc-client/tests/deploy.rs
Original file line number Diff line number Diff line change
Expand Up @@ -341,7 +341,7 @@ async fn test_simple_deploy() {
node.kill().unwrap();
let expected = vec![DeployedContract {
id: ContractId::from_str(
"50fe882cbef5f3da6da82509a66b7e5e0a64a40d70164861c01c908a332198ae",
"4ea5fa100cd7c8972bc8925ed6f8ccfb6bf1e16f79c3642c3a503c73b7d18de2",
)
.unwrap(),
proxy: None,
Expand Down Expand Up @@ -383,7 +383,7 @@ async fn test_deploy_submit_only() {
node.kill().unwrap();
let expected = vec![DeployedContract {
id: ContractId::from_str(
"50fe882cbef5f3da6da82509a66b7e5e0a64a40d70164861c01c908a332198ae",
"4ea5fa100cd7c8972bc8925ed6f8ccfb6bf1e16f79c3642c3a503c73b7d18de2",
)
.unwrap(),
proxy: None,
Expand Down Expand Up @@ -428,12 +428,12 @@ async fn test_deploy_fresh_proxy() {
node.kill().unwrap();
let impl_contract = DeployedContract {
id: ContractId::from_str(
"50fe882cbef5f3da6da82509a66b7e5e0a64a40d70164861c01c908a332198ae",
"4ea5fa100cd7c8972bc8925ed6f8ccfb6bf1e16f79c3642c3a503c73b7d18de2",
)
.unwrap(),
proxy: Some(
ContractId::from_str(
"8eae70214f55d25a65608bd288a5863e7187fcf65705143ee1a45fd228dacc19",
"deb633128bceadcd4eb4fe546089f6653727348b60228638a7f9d55d0b6da1ae",
)
.unwrap(),
),
Expand Down Expand Up @@ -491,6 +491,25 @@ async fn test_proxy_contract_re_routes_call() {
));

let impl_contract_a = ImplementationContract::new(proxy_contract_id, wallet_unlocked.clone());

// Test storage functions
let res = impl_contract_a
.methods()
.test_function_read()
.with_contract_ids(&[impl_contract_id.into()])
.call()
.await
.unwrap();
assert_eq!(res.value, 5);
let res = impl_contract_a
.methods()
.test_function_write(8)
.with_contract_ids(&[impl_contract_id.into()])
.call()
.await
.unwrap();
assert_eq!(res.value, 8);

let res = impl_contract_a
.methods()
.test_function()
Expand Down Expand Up @@ -525,6 +544,26 @@ async fn test_proxy_contract_re_routes_call() {
let impl_contract_id_after_update = contract_ids[0].id;
assert!(impl_contract_id != impl_contract_id_after_update);
let impl_contract_a = ImplementationContract::new(proxy_contract_after_update, wallet_unlocked);

// Test storage functions
let res = impl_contract_a
.methods()
.test_function_read()
.with_contract_ids(&[impl_contract_id_after_update.into()])
.call()
.await
.unwrap();
// Storage should be preserved from the previous target contract.
assert_eq!(res.value, 8);
let res = impl_contract_a
.methods()
.test_function_write(9)
.with_contract_ids(&[impl_contract_id_after_update.into()])
.call()
.await
.unwrap();
assert_eq!(res.value, 9);

let res = impl_contract_a
.methods()
.test_function()
Expand Down

0 comments on commit 344f1c5

Please sign in to comment.