5

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?

2

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.

  • 1
    I think the most important thin OP was missing is that .call in web3 simulates a transaction. They wanted to use an actual transaction – Tjaden Hess Dec 12 '16 at 14:12
  • 1
    I observed that gas consumed changing every time i execute the same function, I executed removeItem for 3 times and see different transaction cost and execution cost every time ? Result: "0x" Transaction cost: 24023 gas. Execution cost: 26070 gas. Result: "0x" Transaction cost: 63046 gas. Execution cost: 41070 gas. Result: "0x" Transaction cost: 48046 gas. Execution cost: 26070 gas. – mahesh gupta Dec 13 '16 at 5:59
  • I've added a new section to show you the source of the difference in the gas cost for the addItem(...) function called the first and second time. You can use the same type of analysis to find the difference in the gas cost for the removeItem(...) function called the second-last and the last time. Please ask a new question referencing this Q&A if you have further queries about the gas cost. – The Officious BokkyPooBah Dec 13 '16 at 7:53

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.