Error Handling in Ethereum

Welcome to the thread about Error handling in Ethereum. Here you can discuss everything about this chapter.

1 Like

Using DogContract.sol

We write the Kettle Code with the Breed included, and the internal settings and error handling.

pragma solidity^0.4.0;

import './DogContract.sol';

contract Kennel is DogContract {
    
    function transferDog(address _newOwner) private{
        address owner = msg.sender;
        
        //Soft. Throws error if sender is new owner. Soft. 
        require(owner != _newOwner);
        
        uint dogId = ownerToDog[owner];
        delete(ownerToDog[owner]);
        ownerToDog[_newOwner] = dogId;
        
        //Strict. Will not happen.
        assert(ownerToDog[owner] == 0);
    }
    
    function addKennelDog(string _name, uint _age, string _breed) {
        addDog(_name, _age, _breed);
    }
    
}
1 Like

If an assert is false, what happens to the instructions already executed? Eg. if both sender and receiver now own the same dog and assert causes the contract to exit - will the owner revert back to sender only or are we stuck with the ‘double spend’ problem??

2 Likes

If you use assert, the changes to state variables will be reverted. So all data within the contract would be in the same state as it was before the execution.

3 Likes

Got it, thanks!!! :slight_smile:

1 Like

Hi, where are the exercises, exactly ? You only show the solutions. ^^

2 Likes

How to customize the error message?

2 Likes

By mistake I thought the quizzes were called exercises. So when I say exercises in the video and mean the quizzes most of the time.

1 Like

There is no way to customize an error message with the require or assert functions. The best option is to use an event.

1 Like

So! for handle the error what is it a better practice to use “requier” or “assert”?

It depends on the situation. Here is a good explanation about the difference between the two.

2 Likes

What is revert() ? Could you elaborate more?

@filip Are there ways of exiting gracefully using assert and require? Or is it desirable for them to throw what looks like fatal errors?

I rewrote the code in the getDog() function to take into account owners who do not have dog IDs mapped to them using a simple if statement so not to throw an error and return a string:

function getDog() view public returns (string) {
    address owner = msg.sender;
    uint id = ownerOfDog[owner];
    if (id == 0) {
        return "No dog found";
    }
    return dogs[id-1].name;
}

I originally rewrote the addDog() function to store the actual index of the array in the mapping, thinking it would make things simpler later on as we are only really interested in index, not the return value:

ownerOfDog[msg.sender] = dogs.push(Dog(_name, _age)) - 1;

I later realised this is not a good idea, as I discovered all keys in a mapping will hold a value of zero if they are not assigned to anything. This means the first dog owner will have the same value as any other owner who does not yet have a dog!

My question at this point is, is it possible (and if so, is it desirable) to use assert() or require() to check if an owner has a dog, and if not exit gracefully by returning a string rather than throwing an error?

1 Like

You can also test the assert this way:

pragma solidity ^0.4.0;

import ‘./Arrays.sol’;

contract Kennel is dogContract {

function transferDog (address _newOwner){
address owner = msg.sender;
//require (owner != _newOwner);
uint dogID = ownerToDog[owner];

// delete ownerToDog[owner];
ownerToDog[_newOwner] = dogID;
assert(ownerToDog[owner] == 0);
}

function addKennelDog (string _name, uint _age){
    addDog(_name,_age);
}

}

If you do not carry out the DELETE, then both new and old owners will have the dog, and therefore the assertion will fail. This is probably the thing we would be most likely to forget.

of course you don’t have to comment out the requirement as well to test this.

This is a good improvement to the contract! I think you will learn a lot by doing it.

I think the best way to do it would be to change to mapping so it stores the Struct instead of the uint id. Since all values in a mapping will be initialized to its “zero value”, it’s a bit trickier to check whether the owner has a dog when we are using a custom Struct as the value.

The best thing to do to simplify and clarify the if statement would be to add an “exists” property to the dog struct, and set it to true every time you add a dog to the mapping. Then in the if statement instead of checking if (id == 0) you would check if (dog.exists == false).

Let me know if my explanation was clear. Otherwise I can explain further. Good job dude!

Hi Filip,

Are there any libraries for Solidity that already include typical functions or code pieces so we don’t need to reinvent the wheel and do everything from scratch? – Thanks!

1 Like

Yes, openzeppelin is a great one. I cover it in this video on my youtube channel: https://www.youtube.com/watch?v=TAbcztHglT8

When I update the Programming Course early next year it will include openzeppelin as well.

1 Like

Thank you so much, Filip!

Quiz, second question.
I chose only the first option, that assert is needed to validate inputs since my thought is that the second option would be too restrictive and thus not valid. Seems that both are true ?
I thought this was not very clear. I also was not aware that more options could be selected. (maybe to mention that somewhere at the beginning of the course? Or did I miss it somewhere?)