Solidity Error Handling Assignment

You could also check so that the name is an empty string. But it would accomplish the same thing.

This is my function:

function addDog(string memory _name, uint _age) public{
    require(ownerToDog[msg.sender].age == 0, "Owner already has a dog");
    require(_age > 0, "Dog's age should be higher than 0");
    Dog memory currentDog = Dog(_name, _age);
    ownerToDog[msg.sender] = currentDog;
}

Is there a way to simplify it?

Looks good. You could simplify it a little bit by doing this.

require(_age > 0 && ownerToDog[msg.sender].age==0)

But then you wouldn’t be able to have 2 different error messages.

1 Like

Thanks Filip, I though so

1 Like

pragma solidity 0.5.1;

contract DogContract{
struct Dog {
string name;
uint age;

}

mapping(address => Dog) ownerToDog;

function addDog(string memory _name, uint _age) public {

   require(ownerToDog[msg.sender].age == 0); 
   Dog memory currentDog = Dog(_name, _age);
   ownerToDog[msg.sender] = currentDog;
   assert(currentDog.age == _age);

}
function getDog() public view returns (string memory) {
address owner = msg.sender;
return ownerToDog[owner].name;

}

}

1 Like

Hello Fillip,
I have to admit I had to rerun the “Mapping Assignment” detecting the flaw and “Solution + Control Flow” several time in order to figure out where do I begin finding what this error (flaw) may be. LOL, now I “think” I understand that it’s the correct method of writing the contract.
I understand the logic correcting the flaw is to prevent adding more than one dog which will cause the mapping will be overwritten, as you stated, and clearly demonstrated that “one key can only have one value”.
So here are my questions:

  1. This is not an instance of code errors but to ensure nothing is overwritten on a current contract?
  2. Can you please describe a scenario, aside from the “Dog” example that this would occur in a real scenario? This would help me confirm what I am learning in this exercise.

Sorry, forgot to add the “Error Handling Assignment Solution”…
pragma solidity 0.5.1;

contract DogContract{
struct Dog {
string name;
uint age;
}

mapping(address => Dog) ownerToDog;

function addDog(string memory _name, uint _age) public{
   require(ownerToDog[msg.sender].age ==0);/*The dog has already been registered*/
   
   Dog memory currentDog = Dog(_name, _age);
   ownerToDog[msg.sender] = currentDog;
 
}
function getDog() public view returns(string memory){
    address owner= msg.sender;
    return ownerToDog[owner].name;
    
}

}

1 Like
  1. Exactly, not code errors. But quite stupid code. So even though there is nothing wrong in the code per say, it might not behave like people would think.

  2. It’s hard to come up with a real world example. But let’s say instead of dogs you saved users of your dapp. And you forgot to make a check to see if a user already exists with that same address. Then you might overwrite the data of the already registered user.

Hi @filip
Here is my answer, i tried a different example to test assert and require after testing the basic one and
i struggle to find a simple way to compare string.

pragma solidity 0.5.1;

contract DogContract{
    struct Dog {
        string name;
        uint age;
    }
    
    mapping(address => Dog) ownerToDog;
    
    function compare(string memory _a, string memory _b) private pure returns (int){
        bytes memory a = bytes(_a);
        bytes memory b = bytes(_b);
        uint minLength = a.length;
        if (b.length < minLength) minLength = b.length;
        for (uint i = 0; i < minLength; i ++)
            if (a[i] != b[i])
                return 1;
        if (a.length != b.length)
            return 1;
        else
            return 0;
    }
    
    function addDog(string memory _name, uint _age) public{
        require(bytes(_name).length != 0
                && _age != 0,
                "name or age couldn't be null");
        require(compare(ownerToDog[msg.sender].name, _name) == 1
                ,"Owner already have a dog with the same name, try an other one !");
        
        Dog memory currentDog = Dog(_name,_age);
        ownerToDog[msg.sender] = currentDog;
        assert(compare(ownerToDog[msg.sender].name, _name) == 0);
    }

    function getDogName() public view returns (string  memory){
        return ownerToDog[msg.sender].name;
    }
    
    function getDogAge() public view returns (uint){
        return ownerToDog[msg.sender].age;
    }
}

I found the StringUtils library but i just implement a light version of it as it cost me less gas.
I found an example on Stackoverflow where a guy is using keccak256() to compare two string but in my example an error occur:

    keccak256(ownerToDog[msg.sender].name);
              ^-------------------------^

TypeError: Invalid type for argument in function call. Invalid implicit conversion from string storage ref to bytes memory requested. This function requires a single bytes argument. Use abi.encodePacked(…) to obtain the pre-0.5.0 behaviour or abi.encode(…) to use ABI encoding.

Is keccak256 only works for static variable ? Is this function hash a string before saving it on the blockchain ? Can we consider it as post processing operation ? Because it works fine when comparing two string.
require(keccak256(“foo”) != keccak256(“bar”))

hashing a string use less gas than comparing 2 strings byte by byte, do you have an other solution to compare string with an efficient way ?
Sorry if my Question is a bit out of the scope :slight_smile:

thx @Capaburro for the notification on require :wink: it helps to debug

1 Like

Hey @tjourneyinge
I tried a sample with a name comparison, but i am not sure it s the most efficient way, let me know what do you think about it :wink:

1 Like

pragma solidity 0.5.1;

contract DogContract{

struct Dog { 

    string name;

    uint age;

}

mapping(address => Dog) ownerToDog;

function addDog(string memory _name, uint _age) public {
/* checking that dog not yet assigned*/
require(ownerToDog[msg.sender].age == 0;

Dog memory currentDog = Dog(_name, _age);

OwnerToDog[msg.sender] = currentDog;

}

function getDog() public view returns ( string memory ) {

address owner = msg.sender;

return  ownerToDog[owner].name;

}

1 Like

mapping(address => dog) ownerdog;
function addperson(string memory _name, uint _age) public {
require(ownerdog[msg.sender].age == 0);
dog memory currentperson = dog(_name, _age);
ownerdog[msg.sender] = currentperson;
}

function getperson() public view returns(string memory){
    address owner = msg.sender;
    return ownerdog[owner].name;
}
1 Like
pragma solidity 0.5.1;
contract DogContract{
    struct Dog {
        string name;
        uint age;
    }

    mapping(address => Dog) ownerToDog;
    
    function addDog(string memory _name, uint _age) public {
        require(ownerToDog[msg.sender].age == 0); //check if address has a dog assigned already
        Dog memory currentDog = Dog(_name, _age); //create the dog
        ownerToDog[msg.sender] = currentDog;//assign it to the address

        assert(ownerToDog[msg.sender].age == _age);//last safeguard, if something went VERY wrong, fall back
    }

    function getDog() public view returns (string memory) {
        address owner = msg.sender;
        return ownerToDog[owner].name;
    }
}

I then tried to add two dogs to the same address and got an error back as expected.

1 Like

pragma solidity 0.5.1;

contract DogContract{

struct Dog {
    string name;
    uint age;
}

mapping(address => Dog) ownerToDog;

function addDog(string memory _name, uint _age) public {
 require(ownerToDog[msg.sender].age == 0, "No dog age specified, so sender not authourised.");

    Dog memory currentDog = Dog(_name, _age);
    ownerToDog[msg.sender] = currentDog;
}

function getDog() public view returns (string memory) {
    address owner = msg.sender;
    return ownerToDog[owner].name;
}

}

1 Like
pragma solidity 0.5.1;

contract DogContract{
   struct Dog{
       string name;
       uint age;
   }
   
   mapping(address => Dog) ownerToDog;
   
   function addDog(string memory _name, uint _age) public{
        require(ownerToDog[msg.sender].age == 0, "There is already a Dog here");
        Dog memory currentDog = Dog(_name, _age);
        ownerToDog[msg.sender] = currentDog;
        
   }
   
   function getDog() public view returns(string memory){
       address owner = msg.sender;
       return ownerToDog[owner].name;
   }
}
1 Like

pragma solidity 0.5.1;

contract DogContract{
struct Dog {
string name;
uint age;
}

mapping(address => Dog) ownerToDog;

function addDog(string memory _name, uint _age) public returns (uint) {

/* only ‘require’ that there is not a dog already assigned /
require(ownerToDog[msg.sender].age == 0);
if(ownerToDog[msg.sender].age == 0){
Dog memory currentDog = Dog(_name, _age);
/
no need for the assert statement as this gives the user a chance to create the dog for a different address without penalization */
ownerToDog[msg.sender] = currentDog;
}
}

function getDog() public view returns (string memory) {
    address owner = msg.sender;
    return ownerToDog[owner].name;
}

}

1 Like

My solution is this:

    function addDog(string memory _name, uint _age) public {
        require(ownerToDog[msg.sender].age == 0);
    
        Dog memory currentDog = Dog(_name, _age);
        ownerToDog[msg.sender] = currentDog;
    }

I used require, because errors should always be caught as soon as possible. And if necessary conditions for a successful function execution are not given, it doesn’t make sense to continue and waste gas.

1 Like
    modifier noDog() {
        require(ownerToDog[msg.sender].age == 0);
        _;
    }
    
    function addDog(string memory _name, uint _age) public noDog {
        dog memory currentDog = dog(_name, _age);
        ownerToDog[msg.sender] = currentDog;
    }
1 Like

pragma solidity 0.5.1;

contract DogContract{

struct Dog {
    string name;
    uint age;
}

mapping(address => Dog) ownerToDog;

function addDog(string memory _name, uint _age) public {
    
    require (ownerToDog[msg.sender].age == 0);
        Dog memory currentDog = Dog(_name, _age);
        ownerToDog[msg.sender] = currentDog;
    

}

function getDog() public view returns (string memory) {
    address owner = msg.sender;
    return ownerToDog[owner].name;
}

}

1 Like

pragma solidity 0.5.1;

contract dogContract12{

struct Dog {

  string name;
  uint age;
    }

mapping (address=>Dog) ownerOfDog;

function addDog (string memory _name, uint _age ) public {
require(ownerOfDog[msg.sender].age==0) ; /*compliance with the input's threshhold conditions */
Dog memory currentDog= Dog( _name, _age);
ownerOfDog[msg.sender]=currentDog;
assert( ownerOfDog[msg.sender].age==_age); /*checking the conditions (compare the parameter and argument (_age) values. */
}

function getDog () public view returns (string memory _name) {
address owner= msg.sender;
return ownerOfDog[owner].name;
}
}

1 Like