Data Location Assignment [OLD]

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 {
     users[id].balance = balance;
}

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

}

2 Likes

user is destroyed after function is called so balance being updated is not persistent. Update balance in mapping instead.

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

I’m just posting my amended updateBalance function, as the rest of my contract remains unchanged.

Solution 1
The original version stops at line 2 of the function body, and saves the updated balance to user (the newly created instance of the User struct). However, as user is only saved locally to memory , it and all its properties (including the updated balance) are lost when the function is exited. This is resolved by adding line 3 to the function body, which assigns this locally created instance (together with all its properties, including the updated balance) to the mapping (users) before it is lost. The updated balance is now saved permanently (until it is updated again) because the mapping is saved in storage.

function updateBalance(uint id, uint balance) public {
    User memory user = users[id];
    user.balance = balance;        // original version stopped here
    users[id] = user;              // adding this line solves the problem
}

Solution 2 (my preferred solution)
This is a more concise version of solution 1. By combining lines 1 and 2 of the function body, it avoids the unnecessary step of creating the temporary instance (user), and instead directly assigns the updated balance to the mapping. The additional line 3 in solution 1 is also therefore no longer needed.

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

i had to change some variable names to not get stupid with small u big U, singular and plural, solved, took me an ungodly amount of time to find the correct syntax but the error was clear pretty soon actually.

pragma solidity 0.5.1;
contract MemoryAndStorage {

mapping(uint => person)private users;

struct person{
    uint id;
    uint balance;
}


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

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

}

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

}

1 Like

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

1 Like

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

1 Like

pragma solidity 0.5.12;
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

so the correction that I have made is this:

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

or simpler:

......
function updateBalance(uint id, uint balance) public {
         users[id].balance = balance;
.....
1 Like
function updateBalance(uint id, uint balance) public {
    // User memory user = users[id];
    // user.balance = balance;
   //CORRECTION :
    users[id].balance = balance;
}
  1. in the first code, we used ‘memory’ for user so the balance can’t be stored more than the life time of the function.
  2. even if we don’t use ‘memory’, balance is stored in the user Struct but we didn’t affect this user to the mapping
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

The new balance value should be stored as storage value, not in memory.

swapped out memory for storage in the updateBalance function. memory variables don’t hold values outside of a function.

What happened to your code?
Ivo

Don’t you want to post it here?

Ivo

I changed the memory to storage as storage is saved permanently therefore fixing the bug.

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

I changed the compiler version from 0.5.1 to 0.5.12 to be consistent with the course.
Testing the contract it is clear that the updateBalance function has an issue with permanent storage of the new balance. The function parameter ‘uint balance’ can not be modified in terms of data location. Uint will always remain in stack.
As a solution I modified the function so that both id and new balance are stored permanently in the mapping. It seemed the most simplistic answer to me. I tested my solution and it worked.
Another (less elegant) way would have been to assign ‘storage’ data location to the User struct inside the updateBalance function.

pragma solidity 0.5.12;
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 {
        users[id] = User(id, balance);
    }

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

}
1 Like

`I changed memory for storage and seemed to work, will move on to the solution and see the explanation :slight_smile:

++++++++++++++++++++++++++++++++++

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

In updateBalance function, the variable user is just executed inside the function and it will not save outside it, because of memory statement.

The fastest solution to solve this problem is to change the data location from memory to storage, to save it permanently.

pragma solidity 0.5.12;

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;
    }
}

The cheapest solution will be to rewrite the function whit the same body as addUser function. In this way there isn’t any extra data stored permanently (eg. into variable user).

pragma solidity 0.5.12;

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 {
        users[id] = User(id, balance);
    }
    
    function getBalance(uint id) view public returns (uint) {
        return users[id].balance;
    }
}
1 Like

I changed memory to storage so that the update data will be available outside the update function too.

And this works, however the update and the add user functions now do the exact same thing. If I re-add a user with the same ID but with a new balance, the data is updated as well. So do we actually need an update function at all?

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;
}

}

1 Like