Error `No method named "push" found for type "StorageVec<u64>".` during usage of nested StorageVec inside a StorageMap

Error No method named "push" found for type "StorageVec<u64>". during usage of nested StorageVec inside a StorageMap

Hello friends :sparkles:
We are in the process of building our perps and have been faced with a strange problem: I’m trying to store a storage list of opened orders for each user (to make cancel_all func)

We are having the next storage item orders_by_owner: StorageMap<Address, StorageVec<u64>> = StorageMap {}, but during the build, I got the next error in editing of the orders list place

let mut orders_by_owner = storage.orders_by_owner.get(owner).read();
orders_by_owner.push(id);
//^^^^ No method named "push" found for type "StorageVec<u64>".
storage.orders_by_owner.insert(owner, orders_by_owner);

Here I created a simple contract to show that error in the simplest way:

contract;
use std::hash::*;
use std::storage::storage_vec::*;

storage{
    v: StorageMap<Address, StorageVec<u64>> = StorageMap {},
}

abi MyContract {
    #[storage(read, write)]
    fn test_function(n: u64);
}

impl MyContract for Contract {
    #[storage(read, write)]
    fn test_function(n: u64) {
        let address = msg_sender_address();

        let mut v = storage.v.get(address).read();
        v.push(n); //error No method named "push" found for type "StorageVec<u64>".
        storage.v.insert(address, v);
    }
}


pub fn msg_sender_address() -> Address {
    match std::auth::msg_sender().unwrap() {
        Identity::Address(identity) => identity,
        _ => revert(0),
    }
}

How to reproduce?

git clone https://github.com/chlenc/nested-storage-vec-example.git
cd nested-storage-vec-example
forc build

toolchain

Default host: aarch64-apple-darwin
fuelup home: /Users/alexey/.fuelup

installed toolchains
--------------------
beta-3-aarch64-apple-darwin
beta-4-rc.2-aarch64-apple-darwin
latest-aarch64-apple-darwin (default)
beta-4-aarch64-apple-darwin
hotfix
my-custom-toolchain

active toolchain
-----------------
latest-aarch64-apple-darwin (default)
  forc : 0.46.0
    - forc-client
      - forc-deploy : 0.46.0
      - forc-run : 0.46.0
    - forc-doc : 0.46.0
    - forc-explore : 0.28.1
    - forc-fmt : 0.46.0
    - forc-index : 0.21.0
    - forc-lsp : 0.46.0
    - forc-tx : 0.46.0
    - forc-wallet : 0.3.0
  fuel-core : 0.20.5
  fuel-core-keygen : Error getting version string
  fuel-indexer : 0.21.0

fuels versions
---------------
forc : 0.45
forc-wallet : 0.45
3 Likes

Hey @fuel thanks for using the forum! Your problem is on this line:

let mut v = storage.v.get(address).read();

  1. Your .get() returns type StorageKey
  2. So when you do a .read()after it is loading in an empty struct because you’ve defined it as StorageMap {} previously
  3. Since the StorageMap keeps the storage in place there is no need to insert again either

the updated example would look like this

impl MyContract for Contract {
    #[storage(read, write)]
    fn test_function(n: u64) {
        let address = msg_sender_address();

        let mut v = storage.v.get(address);
        v.push(n);
    }
}

@bitzoic wrote a more comprehensive example here

contract;

use std::{storage::storage_vec::*, auth::msg_sender, hash::Hash};

storage {
    my_map: StorageMap<Identity, StorageVec<u64>> = StorageMap {},
}

abi MyContract {
    #[storage(read, write)]
    fn test_function() -> bool;
}

impl MyContract for Contract {
    #[storage(read, write)]
    fn test_function() -> bool {
        // Setup and initalize storage
        let sender = msg_sender().unwrap();
        storage.my_map.insert(sender, StorageVec{});

        // Method 1
        let key_of_vec: StorageKey<StorageVec<u64>> = storage.my_map.get(sender);
        key_of_vec.push(4);

        // Method 2
        storage.my_map.get(sender).push(7);

        // Make sure that 4 is at index 0 and 7 at index 1
        assert(key_of_vec.get(0).unwrap().read() == 4);
        assert(storage.my_map.get(sender).get(1).unwrap().read() == 7);

        true
    }
}

#[test]
fn test_example() {
    let contract_abi = abi(MyContract, CONTRACT_ID);
    let _ = contract_abi.test_function();
}

Hope this helps!

2 Likes

Oh, Nice!!!
I can do that even better using

  // Method 2
        storage.my_map.get(sender).push(7);

@calldelegation @bitzoic Thank you guys :heart:

2 Likes

This topic was automatically closed 20 days after the last reply. New replies are no longer allowed.