I’m going to be honest I got confused by this…remix was throwing up strange errors and wouldn’t let me compile the broken script before I could even try to fix it
The problem is that the updateBalance
function does not consolidate the new balance in to the users
mapping (which has a storage
type data allocation). The User memory user = users[id];
has a memory
type data allocation, and it will only be valid during the updateBalance
function execution.
We could just update the balance directly changing the mapping value:
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;
}
}
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;
}
}
It took me forever to come up with the solution. I tried several different solutions while keeping the “memory” location in the code. Once I realized I should change the location to “storage”, the answer came easily!
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;
}
}
Hi @ponchooo,
Are you still having problems? If so, what code are you trying to compile as your solution, and what errors exactly is the compiler throwing? We need to know that in order to help you.
Have you compared your code to other students’ solutions posted here? Maybe that will help you come unstuck…
Anyway, let us know how you’re getting on.
I was able to fix it in a couple of different ways. I like the second solution better because it’s just working directly with the mapping data.
Question: Does putting the user into memory and modifying it there cost more gas? If it does then I definitely like option 2 better.
I see others are using storage instead of memory. Interesting… It seems to me that the users mapping is already in storage and thus that specific user. Isn’t that just creating a copy that you don’t really need and might that cost more gas?
OK - Filip just explained that it’s a pointer to the same object.
First thing that came to my mind is to change data location type in updateBalance function from memory to storage. Since the memory type data allocation stores the variable value only during function execution, all variables outside function scope remain unchanged once the function is executed. Other logical and little bit more elegant solution is to lose intermediary step and directly use mapping in updateBalance function instead, which uses storage data allocation by default users[id].balance = balance;
but this was not mine solution…
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;
}
}
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;
}
}
Hi @chadrickm,
That’s good that you’re experimenting with different alternative solutions, and even better that you’re also considering potential gas implications
Yes it does:
Option 1 is more expensive: total gas = 1985 (1045 with optimization turned on)
function updateBalance(uint id, uint balance) public {
User memory user = users[id]; // 1824 gas
user.balance = balance; // 25 gas
users[id] = user; // 136 gas
}
Option 2 is cheaper: total gas = 99 (78 with optimization turned on)
function updateBalance(uint id, uint balance) public {
users[id].balance = balance; // 99 gas
}
Setting the data location to storge
instead of memory
…
function updateBalance(uint id, uint balance) public {
User storage user = users[id]; // 74 gas
user.balance = balance; // 41 gas
}
// costs ever so slighty more gas than Option 2 (with optimization turned off)
// but costs exactly the same with optimization turned on, which makes sense
// total gas = 115 (78 with optimization turned on)
Just needed this change…
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 storage user = users[id];
user.balance = balance;
}
function getBalance(uint id) view public returns (uint) {
return users[id].balance;
}
}
function updateBalance(uint id, uint balance) public {
User storage user = users[id];
user.balance = balance;
}
or simply
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 { // update balance when deploying contract doesn't work
User storage user = users[id]; // simple solution was change the "memory" to "storage". It didn't work before because memory is temporary where storage is permanent same as mapping. "Memory" was executed once and deleted that's why there was no value to change via updateBalance function.
user.balance = balance;
}
function getBalance(uint id) view public returns (uint) {
return users[id].balance;
}
}
function updateBalance(uint id, uint balance) public {
User storage user = users[id];
user.balance = balance;
}
changing memory to storage works but is very confusing.
Changing it directly seems better.
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 {
users[id].balance = balance
}
function getBalance(uint id) view public returns (uint) {
return users[id].balance;
}
}
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].balance = balance;
}
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];
user.balance = balance;
users[id] = user;
}
function getBalance(uint id) view public returns (uint) {
return users[id].balance;
}
}
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 memory user = users[id];
user.balance = balance;
users[id].balance = user.balance;
}
function getBalace(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;
boolean state = false; // added #1
}
function addUser(uint id, uint balance) public {
users[id] = User(id, balance, true); // added #2
}
function updateBalance(uint id, uint balance) public {
if( users[id].state == true ){ // added #3
users[id].balance = balance;
}
}
function getBalance(uint id) view public returns (uint) {
return users[id].balance;
}
}
This is wat I did:
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;
}
}