Additional Solidity Concepts - Discussion

Do I understand correctly that all emitted events are logged to the blockchain? If so, is that a relatively expensive operation?

1 Like

Hi @letscrypto,

The emitted events are logged in the transaction data. You can see the log created in the transaction detail, by clicking on the arrow next to the transaction confirmation in the panel below the code editor in Remix. My understanding is that all of this transaction data (including the event logs) are hashed and then included in one of the mined blocks. However, event data is not stored in smart contract state variables and so this reduces their cost in terms of gas. As well as being part of the transaction hash, which becomes an immutable part of the Ethereum blockchain, the actual raw (unhashed) event log data is also stored in the nodes as part of the transaction receipt. This is the event log data which can then be accessed by the dapp for end-user display, data analytics, and data management purposes.

Again, Iā€™m tagging @gabba so that he can add any further clarification, or correct any inaccuracies in my explanation.

2 Likes

These contracts are on the EVM which is blockchain correct? This section dealt with ā€˜deletingā€™ a person or address. How is that possible due to immutability? Or is it just how it is named? Is it actually ā€˜inactivatingā€™ this person as they are not really deleted?

The reason I bring this up is an accounting program I used over the years called Simply Accounting you could not delete anything, you reverted transactionsā€¦but there was always a record which I think is a concept of true accounting.

Then came along Quickbooks which was easier to learn. In this program you could actually delete accounting events altogetherā€¦as though they never happened at all.

This is the life experiece comparison I make to EVM and the ā€˜deleteā€™ person.

@filip first and foremost, thank you for the great lessons!

I tried googling for the precise explanation on why we donā€™t need to tell the location when defining a parameter in a event, but couldnā€™t find anything, so I just wanted to give a slight contribution on why I think this is the case, since you mentioned youā€™re not sure :slight_smile:

It makes sense that we donā€™t have to specify the location for the event parameters because the definition of the event is pretty much just an abstraction (you can see it doesnā€™t even have a method body for example). When you emit the event, itā€™s just going to send whatever information you provided to any subscribers, so it doesnā€™t really matter if this information is coming from memory, storage, or anything else for that matter, because this information is directly available during the execution of the method in which youā€™re emitting the event. Also, I think if somehow we could specify ā€œstorageā€ as a location in a event for example, this could lead to some problems, because then this would mean that any subscriber of that event would be able to modify information that is internal to the contract without calling any of the contract methods, and I also donā€™t think itā€™s possible to do something like that, technically speaking :sweat_smile:

1 Like

@armadillo-tank Welcome to the Forum!
Amazing explanation and thanks for the contribution :slight_smile:

1 Like

question from quiz
" When is the function modifiers code executed?"
why the answer ā€œwhen called by the functionā€ is wrong?
isnā€™t it like a function called at beginning of the main function?

1 Like

Hi @sajede.k,

Apologies for the delay in replying to your question.

I must admit this question is a bit confusing, and maybe isnā€™t worded as well as it could be. Have a look at Filipā€™s reply to the same question already asked by another student (always check the discussion thread to see if someone has already asked the same question and had it answered :wink:
So, I think you are correct thatā€¦

ā€¦ itā€™s just that the correct answer is emphasising the fact that the modifierā€™s code is executed from the function header, which is actually before the functionā€™s code block is executed.
I hope that clarifies things, and confirms that both answers could in fact be considered correct, depending on how you interpreted them.

2 Likes

thanks for advise and explanation.

1 Like

My solution, which appears to work in testing:
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].balance = balance;
}

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

}

1 Like

Nice solution @chrisdbarnett :ok_hand:
ā€¦ and welcome to the Academy forum! Great to see you here :slightly_smiling_face:

2 Likes

Hey Filip,
There is a discrepancy between the video and the code on github.
I expect you did this deliberately to keep us awake!
In the code its:

emit personDeleted(name, senior, owner);

In the video itā€™s:

emit personDeleted(name, senior, msg.sender);

This is the version that works.
Donā€™t ask me why, Iā€™m just a student.

When do I get to build my crypto!

DOODESVILLE :nerd_face:

Hello Community!

Iā€™m sorry if the topic was already covered above or if itā€™s for another section, but couldnā€™t find it so:

If I understood correctly, Filip mentioned in one of the videos that itā€™s not a good idea to use references like this

Person person = people[something];
person.property1 = newValue;
ā€¦some other modifications on person
people[something] = person;

Could you please confirm if thatā€™s correct and elaborate me why is that so? @jon_m

1 Like

Hi Rusko,

This may refer to the Data Location Assignment, and the following possible solution (one of several alternatives):

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

This is a very long-winded way of achieving the desired result. There is redundant code, and it is more costly on gas.

On the 3rd line of the function body, the value held temporarily in the local variable (user) is assigned to the mapping (users[id]). There is therefore no reason to also assign the data initially held in the mapping (referenced using users[id]) to the local variable (user) in the 1st line when defining it. If we are going to use a local variable stored in memory, we can simply define it initially, on the 1st line, as:

User memory user;

However, creating a separate local variable in memory still uses more gas than just changing memory to storageā€¦

User storage user = users[id];
user.balance = balance;

ā€¦ because this code doesnā€™t actually create a separate variable, but instead establishes a reference (a ā€œpointerā€) to the User instance stored in the mapping, and then uses this pointer to assign the new balance to this User instance in the 2nd line. In fact, this solution can also be made more concise as follows:

users[id].balance = balance;

This performs exactly the same operation, achieves the same result, and consumes the same amount of gas as the two-line solution using storage above. You can read more about
the reasoning and logic behind this here.

I hope this helps to clarify the issues, concepts and considerations with this code.

Just let us know if you have any further questions about this. :slight_smile:

3 Likes

:grinning: Hello all. Thanks for being here.

2 Likes

Accidentally posted my solution here instead of the correct place. My badā€¦ :frowning:

1 Like

Thanks for correcting @Jethrodog :slight_smile:

pragma solidity 0.7.5;
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;
    }


}
1 Like

Changed to storage.

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

pragma solidity 0.7.5;

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

}

1 Like

pragma solidity 0.7.5;
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; 
     // you could also just directly write users[id].balance = balance;
}

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

}

1 Like