Data Location Assignment

pragma solidity 0.5.1;

contract MemoryAndStorage {

    mapping(uint => User) users;

    struct User{
        uint id;
        uint balance;
    }

    function addUser(uint id, uint balance) public {
        users[id] = User(id, balance);
    }

    function updateBalance(uint id, uint balance) public {
         User storage user = users[id];//memory is a temporary storage, to get a persistent one, switch to storage. like here. I could update the balance with this.
         user.balance = balance;
    }

    function getBalance(uint id) view public returns (uint) {
        return users[id].balance;
    }

Thanks Capa

pragma solidity 0.5.1;
contract MemoryAndStorage {

mapping(uint => User) users;

struct User{
    uint id;
    uint balance;
}

function addUser(uint id, uint balance) public {
    users[id] = User(id, balance);
}

function updateBalance(uint id, uint balance) public {

// User memory user = users[id];
User storage user = users[id];
user.balance = balance;
// uint balance = balance; doesn’t work
}

function getBalance(uint id) view public returns (uint) {
    return users[id].balance;
}

}

pragma solidity 0.5.1;
contract MemoryAndStorage {

    mapping(uint => User) users;

    struct User{
        uint id;
        uint balance;
    }

    function addUser(uint id, uint balance) public {
        users[id] = User(id, balance);
    }

    function updateBalance(uint id, uint balance) public {
         //User memory user = users[id]; - Removed 
         //user.balance = balance; - Removed 
         users[id].balance = balance;
    }

    function getBalance(uint id) view public returns (uint) {
        return users[id].balance;
    }

}

Update the balance of the user stored in the users mapping which is part of storage. That way it will persist between function calls:

function updateBalance(uint id, uint balance) public {
     users[id].balance = balance;
}

The problem here is that there is a mismatch in terms of how the state variable ‘users’ is persisting users to the storage but the ‘user’ variable within the updateBalance function is only temporarily saving the value to memory (not persisting to storage). There are a few ways to fix this by either changing the user local variable in the updateBalance function from memory to storage OR by directly updating the users state variable. The second approach is more efficient:

function updateBalance(uint id, uint balance) public {
         users[id].balance = balance;
    }

Problem: A temporary variable was introduced to hold the user. Then, the balance was updated. But the temporary user variable was held in memory, so after function execution, the temporary user was deleted. Thus, the balance was updated on the user in memory, not the one in permanent storage.

My solution is to update the balance of the user from storage without even introducing a variable, which is completely unnecessary here.

    function updateBalance(uint id, uint balance) public {
         users[id].balance = balance;
    }

pragma solidity 0.5.1;
contract MemoryAndStorage {

mapping(uint => User) users;

struct User{
    uint id;
    uint balance;
}

function addUser(uint id, uint balance) public {
    users[id] = User(id, balance);
}

function updateBalance(uint id, uint balance) public {
     //User memory user = users[id]; //This only update the balance of the local user, not the user in the state mapper
     users[id].balance = balance;
}

function getBalance(uint id) view public returns (uint) {
    return users[id].balance;
}

}

Need to change memory into storage in this part of the code

{
function updateBalance(uint id, uint balance) public {
User storage user = users[id];
user.balance = balance;
}

pragma solidity 0.5.1;
contract MemoryAndStorage {

    mapping(uint => User) users;

    struct User{
        uint id;
        uint balance;
    }

    function addUser(uint id, uint balance) public {
        users[id] = User(id, balance);
    }

    function updateBalance(uint id, uint balance) public {
         User memory user = users[id];
         user.balance = balance;
         users[id] = user;
    }

    function getBalance(uint id) view public returns (uint) {
        return users[id].balance;
    }

}

It seems like the updateBalance function is modifying a local struct variable created with the name “user”, which initially gets the same value as users[id]. Trying to change the value of this variable won’t affect the real user with the id (users[id]).

So, my suggestion is changing the function from this:

function updateBalance(uint id, uint balance) public {
User memory user = users[id];
user.balance = balance;
}

to this:

function updateBalance(uint id, uint balance) public {
users[id].balance = balance;
}

  1. The first solution:
function updateBalance (uint _id , uint _balance) public {

users [_id].balance=_balance;
}

2.There is another solution that works (changing the updateBalance function from memory to storage):
:

function updateBalance(uint id, uint balance) public {
         User storage user = users[id];
         user.balance = balance;
    }

**However, it is not clear to me how the second solution works because the following function in the code (get balance function), refers to the users[id].balance and not to the user.balance

your advice …

The problem was in line “15” of the code. Changing line “16” from “memory” to “storage” work for me.

pragma solidity 0.5.1;
contract MemoryAndStorage {

    mapping(uint => User) users;

    struct User{
        uint id;
        uint balance;
    }

    function addUser(uint _id, uint _balance) public {
        users[_id] = User(_id, _balance);
    }

    function updateBalance(uint _id, uint _balance) public {
        // User memory _user = users[_id];
         users[_id].balance = _balance;
    }

    function getBalance(uint _id) view public returns (uint) {
        return users[_id].balance;
    }

}

I have came up with three solutions:

  1. By changing the data location to storage, because after updating the temporary variable, which was memory, we didn’t do anything with it and that 's why after function finished executing nothing has changed.
function updateBalance(uint id, uint balance) public {
         User storage user = users[id];
         user.balance = balance;
    }
  1. Now we still have memory storage, but this time we are assigning updated value to the array of users (so in the end it is in the storage).
function updateBalance(uint id, uint balance) public {
         User memory user = users[id];
         user.balance = balance;
         users[id] = user;
    }
  1. We are updating the user balance directly.
function updateBalance(uint id, uint balance) public {
         users[id].balance = balance;
    }

Fix to bug in updating :

function updateBalance(uint _id, uint _balance) public {
        users[_id].balance = _balance;
    }
1 Like

pragma solidity 0.5.1;
contract MemoryAndStorage {

mapping(uint => User) users;

struct User{
    uint id;
    uint balance;
}


function updateBalance(uint id, uint balance) public {
     //here the fix
     users[id].balance = balance;
}

}

Hi Filip,

There are two solutions, but I am not sure how to explain the correct version although both will end with similar outcome:

  1. users[id].balance = balance; (consume gas 5360)
  2. change the “memory” to “storage” (consume gas 5373)

Of course option 1 should be the right one since this is your answer, which meant “to look for the current balance.” As for option 2, can I assume it is not appropriate as it “permanently change” the the intended balance, which means the previous record was deleted?

Hope to hear from you soon. Thanks.

1 Like

pragma solidity 0.5.1;
contract MemoryAndStorage {

mapping(uint => User) users;

struct User{
    uint id;
    uint balance;
}

function addUser(uint id, uint balance) public {
    users[id] = User(id, balance);
}

function updateBalance(uint id, uint balance) public {
     User storage user = users[id];
     user.balance = balance;
}

function getBalance(uint id) view public returns (uint) {
    return users[id].balance;
}

}

1 Like

Both are correct, and they will give the same result :slight_smile: Good job!

Changed memory to storage so that the data updated is stored in a persistent location, which allows it to persist and remain after the function call, whereas storing it in memory would only store it while the function is being called but not after.

pragma solidity >=0.5.0 <0.7.0;

contract MemoryAndStorage{
    
    mapping(uint => User) users;
    
    struct User{
        uint id;
        uint balance;
    }
    
    function addUser(uint id, uint balance) public {
        users[id] = User(id, balance);
    }
    
    function updateBalance(uint id, uint balance) public {
        User storage user = users[id];
        user.balance = balance;
    }
    
    function getBalance(uint id) view public returns (uint) {
        return users[id].balance;
    }
}