[Ethereum] Unable to add new struct item into mapping or array

arraysmappingsolidity

trying to do a sample based on struct, storing a list of struct as a mapping.
but when i add an item and trying to retrieve i cannot find that item in the mapping

below is my contract

contract ItemListContract {
    struct  item 
    {
      bytes iname;
      uint16 itemid;
      bytes icode;
      uint ivalue;
    }
    uint itemcount;
    mapping(bytes => item) itemlist;
    item[] itemarray;
    function ItemListContract()
    {
       log0('hi');
    }
    function AddItem(bytes name, uint16 iid, bytes code, uint val)
    {        
       var itemnew = item(name, iid ,code, val);
       log0(itemnew);
       itemlist[code] = itemnew;
       itemarray.push(itemnew);
       itemcount++;
    }
    function countitemlist() returns (uint count)
    {     
      return itemcount;
    }

    function removeitem(bytes code)
    {
    delete itemlist[code];
    itemcount--;
    }
    function getitem(bytes code) returns (bytes iname, uint val)
    {   
      return (itemlist[code].iname,itemlist[code].ivalue);
    }
}

I tried to add item by using the below statements

var listarrayinterface =[{"constant":false,"inputs":[{"name":"name","type":"bytes"},{"name":"iid","type":"uint16"},{"name":"code","type":"bytes"},{"name":"val","type":"uint256"}],"name":"AddItem","outputs":[],"payable":false,"type":"function"},{"constant":false,"inputs":[{"name":"code","type":"bytes"}],"name":"getitem","outputs":[{"name":"iname","type":"bytes"},{"name":"val","type":"uint256"}],"payable":false,"type":"function"},{"constant":false,"inputs":[],"name":"countitemlist","outputs":[{"name":"count","type":"uint256"}],"payable":false,"type":"function"},{"constant":false,"inputs":[{"name":"code","type":"bytes"}],"name":"removeitem","outputs":[],"payable":false,"type":"function"},{"constant":false,"inputs":[],"name":"countitemarray","outputs":[{"name":"count","type":"uint256"}],"payable":false,"type":"function"},{"constant":false,"inputs":[{"name":"code","type":"bytes"}],"name":"getitemfromarray","outputs":[{"name":"iname","type":"bytes"},{"name":"val","type":"uint256"}],"payable":false,"type":"function"},{"inputs":[],"payable":false,"type":"constructor"}];
var listarratcontract = eth.contract(listarrayinterface).at("0x62fxxx")
listarratcontract.AddItem.call({data:{name:"item2",iid:2,code:"i2",val:2}})

after calling the contract with the above data i got [] as resoponse

Now I tried to query the saved data by

listarratcontract.countitemlist.call()
0

got response as 0.

when i called using

listarratcontract.getitem.call("i2")
["0xo",0]

I cant get the saved data or dont even know if the data is saved or not?

can any one point out what the issue might be?

Best Answer

Summary

The issues are:

  1. The default gas for a transaction executing a contract is 90,000 . Your statement to execute addItem() does not specify the gas amount so 90,000 is assumed. The execution of this addItem() method took 226,554 gas.
  2. The getItem(...) method should be marked constant to return the values correctly.
  3. The countItemList() method should also be marked constant to return the value correctly.
  4. And as @Tjaden Hess commented below, your statement listarratcontract.AddItem.call({data:{name:"item2",iid:2,code:"i2",val:2}}) does not execute the method as a transaction modifying the blockchain data. See below for the statement to execute this method as a transaction. See What is the difference between a transaction and a call? for further information.



Details

I've made some minor changes to your source code:

  • Formatting.
  • Marking countItemList() and getItem(...) as constant.
  • Commenting out log0(itemnew) as this statement causes an error in my Browser Solidity / geth.

Here is the source code:

pragma solidity ^0.4.0;

contract ItemListContract {
    struct item {
        bytes iname;
        uint16 itemid;
        bytes icode;
        uint ivalue;
    }

    uint itemCount;
    mapping(bytes => item) itemList;
    item[] itemArray;

    function ItemListContract() {
        log0('hi');
    }

    function addItem(bytes name, uint16 iid, bytes code, uint val) {        
        var itemnew = item(name, iid ,code, val);
        // log0(itemnew);
        itemList[code] = itemnew;
        itemArray.push(itemnew);
        itemCount++;
    }

    function countItemList() constant returns (uint count) {     
        return itemCount;
    }

    function removeItem(bytes code) {
        delete itemList[code];
        itemCount--;
    }

    function getItem(bytes code) constant returns (bytes iname, uint val) {   
        return (itemList[code].iname, itemList[code].ivalue);
    }
}

The following screenshot of your code being deployed and executed using Browser Solidity shows that the addItem(...) method took 226,554 gas.

enter image description here

Calling getItem(...) returned the value added in the call to addItem(...). And calling countItemList() returned 1.

The following section shows the execution of your contract methods using the geth command line and the increased gas amount:

> var itemListABI = [{"constant":false,"inputs":[{"name":"code","type":"bytes"}],"name":"removeItem","outputs":[],"payable":false,"type":"function"},{"constant":true,"inputs":[],"name":"countItemList","outputs":[{"name":"count","type":"uint256"}],"payable":false,"type":"function"},{"constant":true,"inputs":[{"name":"code","type":"bytes"}],"name":"getItem","outputs":[{"name":"iname","type":"bytes"},{"name":"val","type":"uint256"}],"payable":false,"type":"function"},{"constant":false,"inputs":[{"name":"name","type":"bytes"},{"name":"iid","type":"uint16"},{"name":"code","type":"bytes"},{"name":"val","type":"uint256"}],"name":"addItem","outputs":[],"payable":false,"type":"function"},{"inputs":[],"type":"constructor"}];
undefined
> var itemList = eth.contract(itemListABI).at("0xee7b790b638553cc95a4355d422536bad1566fd7");
undefined
> itemList.addItem("item3", 3, "i3", 3, {from: eth.accounts[0], gas: 500000});
"0xc70469c662c759627c217827845a6567ff1ac1dd2ebd5e0d52fe817aeeb7867a"
> itemList.countItemList()
3
> itemList.getItem("i3")
["0x6974656d33", 3]



Gas Cost Differences - Responding To Question In Comments

addItem(...) Gas Cost Differences

I called addItem(...) 4 times with the following parameters and the associated gas cost:

  • "item1", 1, "i1", 1 - 226,554
  • "item2", 2, "i2", 2 - 196,554
  • "item3", 3, "i3", 3 - 196,554
  • "item4", 4, "i4", 4 - 196,554

Following is the Browser Solidity screenshot: enter image description here

I ran a debug.traceTransaction(...) for the first and second operation to find the differences in the gas cost.

Here is a screenshot showing the first difference in gas cost: enter image description here

And here is a screenshot showing the second difference in gas cost: enter image description here

Here is the code for addItem(...):

function addItem(bytes name, uint16 iid, bytes code, uint val) {        
    var itemnew = item(name, iid ,code, val);
    // log0(itemnew);
    itemList[code] = itemnew;
    itemArray.push(itemnew);
    itemCount++;
}

The difference in gas cost between the first and second operation is (20,000 x 2) - (5,000 x 2) = 30,000 for the SSTORE operation when assigning itemnew to itemList[code] and itemArray.push(...).

From the fee schedule in the Ethereum Yellow Paper, you can see that the first SSTORE operation to store the new data in itemList and itemArray sets the storage value from zero to non-zero and costs 20,000 gas (highlighted in green below).

The second SSTORE operation to store the new data in itemList and itemArray sets the storage value from non-zero to non-zero and costs 5,000 gas (highlighted in pink below).

enter image description here


removeItem(...) Gas Cost Differences

I then called removeItem(...) 4 times with the following parameters and the associated gas cost:

  • "item1" - 48,181
  • "item2" - 48,181
  • "item3" - 48,181
  • "item4" - 33,181

Following is the Browser Solidity screenshot: enter image description here

You can run a debug.traceTransaction(...) for the third and fourth operations to find the differences in the gas cost.