Solidity Error Handling

Hey @alegarap

You can initialise it outside the constructor although the best practice is to initialise your variables inside the constructor.
The only things that have to be initialised during the declaration are constant.

Cheers,
Dani

2 Likes

Thanks for the response!

1 Like

Hi everyone, could someone please be so kind and and in simple terms explain what the abi.encodePacked is I am assuming it has to do with the keccak256 encryption or am I wrong?, Please advise. I really enjoyed the mapping and error chapters but when you get curved balls in the mix like abi it just get very frustrating. :angry:

Thx,

1 Like

@filip

Hi Filip, could you please be so kind and and in simple terms explain what the abi.encodePacked is, I am assuming it has to do with the keccak256 encryption or am I wrong?, Please advise. I really enjoyed the mapping and error chapters but when you get curved balls in the mix like abi it just get very frustrating. :angry: Otherwise I’m really enjoing this course. Good work filip :clap: :+1:

Thx,

1 Like

Hi @NLUGNER,

In Solidity we cannot use the == equality operator, on its own, to compare 2 string values (like we can with integers and Booleans). However, one way we can perform this operation is to first use the keccak256 and abi.encodePacked functions together. Firstly, abi.encodePacked converts the string into a hexidecimal number. Then, keccak256 creates a hash of that number. We can then compare these 2 hashes with the == operator. abi.encodePacked will also convert multiple values into a single hexidecimal number, making this method also suitable for comparing multiple properties of 2 struct instances. At first, I wasn’t sure why we can’t just compare the 2 hexidecimal numbers generated by abi.encodePacked. My understanding is that we also hash these hex numbers with keccak256, because this will always generate 2 fixed length hash values and so prevents excessive gas costs. I think that by hashing the values we are comparing, we also ensure that the same set of values (or the same sequence of characters in a string) will always evaluate as being equal to each other, because the same values will always produce the same hash.
This is the way I have come to understand this. I’m also tagging @dan-i and @Alko89 as they may be able to add more detail as to the reason why we can’t compare string values in Solidity using only the == operator. Hopefully, they can also confirm and/or clarify the reasons I’ve given for using keccak256 as well as abi.encodePacked.

4 Likes

@jon_m

Thank you very much for the clarification. Much appreciated and fully understood.

Best Regards and have a great day in the academy.

Nils

1 Like

I’ve noticed that it’s easy to loose brackets of any kind when ide in Remix isset to dark instead of a light background. It’s much easier to follow the code when using a light backgroun. You can change the theme in settings by clicking the cog wheel bottom right column. This is only my opinion. We are all different,

1 Like

what does it mean when we say assert consumes all the gas remaining in the function?

1 Like

Hello,
when we delete a person using function deleteperson, the address remains in the creators array, but it shouldn’t. I mean person 1 for example is deleted from people mapping, but his address is stored at the creators array as the creator 1. when we create a new person it should replace the deleted one but creators array doesn’t refresh.we need to delete the element in the deleteperson function but i don’t know how to address the corresponding index. is it okay to search the creators for the given address?
image

1 Like

Hi @sajede.k,

Take a look at this post. It should answer your question. Let us know if anything about this is still unclear.

1 Like

But we set cost in the code,how is it possible? Does it get back money to sender?

hello @filip
could you please help me with it?

Hi @sajede.k,

I think you are confusing the following two different ā€œcostsā€:

  1. Gas costs (transaction + execution costs) which are the computational costs charged for running the smart contract on the Ethereum network (the EVM), and which will go to the miners as block rewards. These costs are charged by the network.

  2. Cost of payments coded into the smart contract, and required to be paid by the msg.sender in order to be able to invoke certain functions and execute specific transactions. This is the cost assigned to msg.value and, when required, is paid by the msg.sender in addition to gas costs. These costs are charged by the smart contract.

When we are talking about the effects on cost of either require or assert failing, then we are talking about gas costs charged by the network, and not the cost of any additional payments charged by the smart contract.

I hope that clarifies things. Let us know if you have any further questions.

1 Like

Thanks for explanation.

1 Like

Hi again, @sajede.k :slight_smile:

Apologies for the delay in replying to your question about deleting the address from the creators array.

Your question is a very good one, but there isn’t a straightforward solution. In fact it’s quite involved. You need to iterate through the array and find the address of the person you’re deleting. The complication is that if you then just delete it, you will be left with an empty element at that index. All of the other addresses won’t automatically shift down one index to compensate. If you want to do this (i.e. shorten the array by one for each address deleted) then you need to save the index to a local variable. Then, you need to iterate through the array again from the index of the deleted address, shifting each element down one index. Then finally, you need to reduce the length of the array by one, as, again, this isn’t done automatically. The following code is my solution to this, and following that I’ve linked to a discussion thread and a video which contain helpful background information about the methods used. I hope this answers your question and you find it helpful and interesting :slightly_smiling_face: Let us know if anything is still unclear. I think this is a good example of why mappings are generally easier than arrays to work with in Solidity!

function deletePerson(address creator) public {
    require(msg.sender == owner, "Caller must be owner");
    
    delete people[creator];

    uint index;  /* Defines local variable to store temporarily the index
                    of the address to be deleted */
    
    for(uint i = 0; i < creators.length; i++) {   // Iterates through array
        if(creators[i] == creator) {              // to find address
            index = i;             // Assigns index to local variable
            delete creators[i];    // Deletes address from array
            break;                 // Exits loop when address found and deleted
        }
    }   
    // Iterates through the array from the index of deleted address
    for(uint i = index; i < creators.length - 1; i++) {
        creators[i] = creators[i + 1];  // Each element shifted down one index
    }
    creators.length--;  // Length of array shortened by one index number
        
    assert(people[creator].age == 0 && people[creator].height == 0 && people[creator].senior == false);
}
2 Likes

Hello,
I really appreciate your help. Thank you.
it was really complete and helpful.
is it a real case? because I suppose it will end up really expensive with all these lines of code and iterating :grimacing:

1 Like

Hi @sajede.k,

Glad you found it helpful :slightly_smiling_face:

You are right that the gas costs may be high, but it all depends on how important the operation is, and whether the contract owner is prepared to pay those costs i.e. you’d need to think about cost v benefit. If there isn’t a cheaper way to perform the same operation, and the operation is a necessary one, then there would be no alternative other than to pay whatever the gas costs are.

The reason why the array of addresses was included in the first place, was just to keep a record for the contract owner of all of the addresses of users who have created a new person instance. The idea is that the owner only needs to know the index number where that person’s address is stored in the array, in order to be able to retrieve the much longer address from the getCreator function. The address can then just be copied and pasted into the deletePerson function call as the argument. That particular person can then be deleted from the people mapping when the function is invoked. So, I would suggest that the addresses of deleted records don’t actually need to be removed from the array, because we want each person to have a different index number anyway, as this is acting as a unique reference number.

Without testing it, I’m not sure what the gas costs are, to be honest. If you are interested you can find this out for yourself by clicking on Debug next to the transaction report (bottom right), after calling the deletePerson function. This will open the Debugger . You can click forward through the different operations contained within the deletePerson function until you get to the first one associated with the code you are testing and want to know the gas cost for (you will know when you get there because the associated code is highlighted). As you then click through all the operations associated with that particular piece of code, you will notice the different amounts of gas used for each operation. I add up all these amounts to get the total gas cost of executing a partiular piece of code.

3 Likes

Thanks for the explanation. I’m so grateful.

1 Like

Hey, you’re welcome @sajede.k,

I’ve just had a look at the gas costs as I was curious :wink:

To be honest with you, Remix seems to generate some odd results for gas, and in the past I’ve also been told by one of my colleagues @gabba, that the gas costs shown in the transaction reports in Remix aren’t accurate. These seem to be stated in wei and I’ve noticed that the transaction gas cost is the amount of wei deducted from the function caller’s address in the dropdown account section in Deploy & Run Transactions.

I think you’ll get a more meaningful comparison of gas costs by looking at the Debugger, as I mentioned earlier. What I’ve done is deployed the same contract in Remix both with and without the additional code in the deletePerson function (the code I came up with to iterate through the array, find the address and delete it). Then I created a person, got the owner to find the address by calling the getCreator function with index 0 as the argument, and then finally got the owner to call deletePerson both with and without the additional code. In the Debugger, instead of adding up all of the individual gas amounts for each operation associated with the additional code, as I suggested before, I’ve found that you can just jump to the end of the transaction and find the figure for gas remaining after all that transaction’s op codes have been performed. If we always leave the Gas Limit in Deploy & Run Transactions as the default of 3,000,000 wei then:

Gas Limit - gas remaining = gas used

Also, by using this method, we account for all of the differences in gas caused by including the additional functionality, which isn’t actually the case when using the method I mentioned before.

Results:

WITHOUT additional code to find and delete the address from the array
Gas used to deploy contract: 312,020
Gas used to run deletePerson: 44,292

WITH additional code to find and delete the address from the array
Gas used to deploy contract: 341,771
Gas used to run deletePerson: 62,199

ADDITIONAL gas used…
… to deploy contract:   29,751
… to run deletePerson: 17,907

Make of that what you will. As I said before it all comes down to a cost v benefit analysis really.

I would encourage you try to recreate the test I’ve explained above, not for the purposes of obtaining accurate results, but more for finding your way around and experimenting with the different information/data available in Remix in terms of the transaction reports and Debugger.

3 Likes

so we added an array to track creator addresses but if we delete some one should we not remove the address from the array?

not sure how you remove an item (you have to shift everything after the deleted location down one?

why can you iterate of a map (it can be done in Java, and JavaScript) is there a ā€œblockchainā€ reason why we cant do this?

1 Like