Mismatched types - StorageKey<u64>

Using the Quickstart guide, this is my current toolchain configuration:

installed toolchains
--------------------
beta-3-aarch64-apple-darwin (default)
latest-aarch64-apple-darwin

active toolchain
-----------------
beta-3-aarch64-apple-darwin (default)
  forc : 0.37.3
    - forc-client
      - forc-deploy : 0.37.3
      - forc-run : 0.37.3
    - forc-doc : 0.37.3
    - forc-explore : 0.28.1
    - forc-fmt : 0.37.3
    - forc-index : 0.11.2
    - forc-lsp : 0.37.3
    - forc-tx : 0.37.3
    - forc-wallet : 0.2.2
  fuel-core : 0.17.11
  fuel-indexer : 0.11.2

fuels versions
---------------
forc : 0.39

Compiling my contract (from the quickstart guide):

contract;

storage {
    counter: u64 = 0,
}

abi Counter {
    #[storage(read, write)]
    fn increment();

    #[storage(read)]
    fn count() -> u64;
}

impl Counter for Contract {
    #[storage(read)]
    fn count() -> u64 {
        storage.counter
    }

    #[storage(read, write)]
    fn increment() {
        storage.counter = storage.counter + 1;
    }
}

works fine, but my IDE using Sway VS Code plugin is giving me this error message:

Mismatched types.
expected: u64
found:    StorageKey<u64>.
help: Implicit return must match up with block's type.
Mismatched types.
expected: u64
found:    StorageKey<u64>.
help: Function body's return type does not match up with its return type annotation.

I have a couple of questions:

  1. How to make this error message go away? or maybe the sway VS Code plugin is out of date?
  2. If I’m creating a video tutorial, will the syntax change in the next few days or weeks? If so, should I wait until the new updates are made so the tutorial is not out of date?
2 Likes

Tried adding .read:

impl Counter for Contract {
    #[storage(read)]
    fn count() -> u64 {
        storage.counter.read()
    }

    #[storage(read, write)]
    fn increment() {
        storage.counter = storage.counter.read() + 1;
    }
}

but got

No method named "read" found for type "StorageKey<u64>".
1 Like

For me, the following code builds successfully.

contract;

storage {
    counter: u64 = 0,
}

abi Counter {
    #[storage(read, write)]
    fn increment();

    #[storage(read)]
    fn count() -> u64;
}

impl Counter for Contract {
    #[storage(read)]
    fn count() -> u64 {
        storage.counter.read()
    }

    #[storage(read, write)]
    fn increment() {
        storage.counter.write(storage.counter.read() + 1)
    }
}

The following is my fuelup show output:

active toolchain
-----------------
latest-aarch64-apple-darwin (default)
  forc : 0.38.0
    - forc-client
      - forc-deploy : 0.38.0
      - forc-run : 0.38.0
    - forc-doc : 0.38.0
    - forc-explore : 0.28.1
    - forc-fmt : 0.38.0
    - forc-index : 0.11.2
    - forc-lsp : 0.38.0
    - forc-tx : 0.38.0
    - forc-wallet : 0.2.2
  fuel-core : 0.17.11
  fuel-indexer : 0.11.2

fuels versions
---------------
forc : 0.39

Please run fuelup toolchain install latest in case you haven’t in a longer while.
You can also always run fuelup check to see if there are updates available :).

1 Like

ah ok I see that my forc fuels version is 39 but my forc toolchain is only 37.3

1 Like

I believe the upgrade to 0.38 should do the trick

1 Like

uninstalling and re-installing beta-3 still gives me version 37.3, are you on latest or beta-3?

I am on latest :slight_smile: blablabla at least 20 chars blabla

got it, so when I default to latest, your code compiles, but in both instances I’m getting syntax errors in my IDE:

So, still curious:

  1. Will this soon be rolled into beta 3
  2. If so, should I wait to record my tutorial to use the new API?
  3. If this works / compiles, why is the IDE still throwing errors?

The Fuel team will be better suited to answer 1 and 2.
I seldom trust the IDE errors when I write Sway. They sometimes do interesting things.

Hey @dabit3 - I messaged you privately but posting here too. Given that Sway is so new and new features are constantly being released, I wouldn’t encourage you to wait. There will always be something “new” around the corner that breaks code.

I would focus your video less on specific syntax, and focus more on high level things about the language, like how storage works, compile time safety, exhaustive pattern matching, generics, etc.

Its unfortunate but its just the reality of the state of the tech- it’s evolving extremely quickly and its far from being at a point where you can expect stability over a long period of time.

got it.

imo the main challenge here is that these updates seem to be breaking many of the existing guides and codebases including the quickstart and making it confusing if someone is using them, so that if someone wants to try it out right even following along in the docs, they will be unable to

I guess the main callout (which I’m sure your team is already aware of) is to consider prioritizing rolling out these new updates across the entire toolchain including the VS Code plugin

thanks for your help, I think I have enough to work with now

@maurice any chance you know how the test for this might differ from what’s in the quickstart?

https://fuelbook.fuel.network/master/quickstart/smart-contract.html#testing-your-contract

So far what I’m trying is not working

Here is the test:


#[tokio::test]
async fn can_get_contract_id() {
    let (instance, _id) = get_contract_instance().await;

    // Increment the counter
    instance.methods().increment().call().await;

    // // Get the current value of the counter
    let result = instance.methods().count().call().await.unwrap();

    // // Check that the current value of the counter is 1.
    // // Recall that the initial value of the counter was 0.
    assert_eq!(result.value, 1);
}

Here is the error I’m getting:

failures:

---- can_get_contract_id stdout ----
thread 'can_get_contract_id' panicked at 'called `Result::unwrap()` on an `Err` value: RevertTransactionError { reason: "Revert(0)", revert_id: 0, receipts: [Call { id: 0000000000000000000000000000000000000000000000000000000000000000, to: 1b16bef0e1a5e4c32309a84e1a98fdbfd13a1ae7269e4e9d2b1d4f3b380f96be, amount: 0, asset_id: 0000000000000000000000000000000000000000000000000000000000000000, gas: 1000000, param1: 1012642802, param2: 1, pc: 11624, is: 11624 }, Revert { id: 1b16bef0e1a5e4c32309a84e1a98fdbfd13a1ae7269e4e9d2b1d4f3b380f96be, ra: 0, pc: 11900, is: 11624 }, ScriptResult { result: Revert, gas_used: 343 }] }', tests/harness.rs:44:58
note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace


failures:
    can_get_contract_i

Hi @dabit3, before trying to reproduce your Rust SDK test, let me just put my quick-and-dirty in-lang test here. Currently, I always code a quick in-lang (if there are no substantial storage initializations / TxParams / CallParams needed) before going over to the Rust SDK.

That should at least give you a working test for now:

contract;

////
// All the other contract code
////

#[test]
fn test_count() {
    let caller = abi(Counter, CONTRACT_ID);

    let res = caller.count();

    assert(res == 0);
}

#[test]
fn test_increment() {
    let caller = abi(Counter, CONTRACT_ID);

    let res = caller.count();
    assert(res == 0);

    caller.increment();

    let res = caller.count();
    assert(res == 1);
}

Alright, so here is the Rust SDK fix, it’s a bit tricky.

First of all, what caused the revert(0)?
The increment() method first reads the current storage value, then increases it by 1, then writes it to storage with write(). Despite initializing the storage variable with 0, it seems that it is not actually initialized when we call read() on it since the read() internally just unwraps the value (in our case probably a None) and throws the revert(0).

How to fix that?
I might post the reproducer on the Discord because it seems the error shouldn’t happen in the first place (since we initialized count with 0 in storage decl). However, we can mitigate this problem by slightly changing our increment function to:

#[storage(read, write)]
fn increment() {
    storage.counter.write(storage.counter.try_read().unwrap_or(0) + 1)
}

As you can see, we use try_read() instead of read() which gives us back an Option. We then unwrap with unwrap_or() so that we can define the behavior in case of an error and set it to 0.

I hope that explanation helps. Let me know in case it doesn’t work on your end :slight_smile:

1 Like

@maurice please let me buy you a beer or something more, you’ve been extremely helpful, this is great and worked like a charm, THANK YOU!

1 Like