16

I have a sorted linked list that contains around 1000 items. When I receive a new item my goal is to push the item to the list keeping the sorted order. So if I receive very small value, I am required to iterate all the list to find the tail of the list.

Constant function's goal is to return the index location for transaction function to push into.

Iteration(iterateListToFindPushIndex()) might look like this:

struct Interval { 
  uint32 num;  //contained value.
  uint32 next; //points to next node on the linkedlist.
}

prevNode     = self.list[self.head]; //head of the list, largest value.
currentNode  = self.list[prevNode.next];
while( true ) {
  if( s > currentNode.num ){ 
    //self.list.push(Interval( { num: s, next: prevNode.next }) );
    //prevNode.next = uint32(self.list.length - 1);
    return prevNode.next; 
//returned indexed would be use in transaction function to insert intem into the correct location.
  }
  prevNode         = currentNode;
  currentNode      = self.list[currentNode.next];
}

As we know when we call a constant function, it does not cost any gas and its free to use. So when I find the index location via a constant function, it won't cost me any gas.

function iterateListToFindPushIndex() constant returns(uint index){}
function func(intervalNode storage self) { 
  index = iterateListToFindPushIndex();
  self.list.push(Interval( { num: s, next: index }) )
}

Inside a transaction function, when I iterate through my list even though I don't change any memory storage, it cost me additional gas.

So is it possible to call a constant function without spending any gas inside a transaction function.

Thank you for your valuable time and help.

17

Calling a constant function inside a transaction costs just as much as calling a non-constant function inside a transaction. What constant means is that since it doesn't alter the state, your local node can run it and tell you the result without needing a transaction. This doesn't cost gas because only your node has to run the calculation.

You may be able to use this to save gas in a transaction by first running the constant function from your JavaScript code to get a result, then passing that result as a parameter to the transaction. However, unless your contract trusts the person sending it, you still need to verify it inside the transaction. This may still be useful: If you have a sorted list and you want to know where to put an item, it may be useful to check it on the client side and find the index x, pass in the index x as a transaction parameter, then let the smart contract code in the transaction verify that the item at x-1 comes before what you're adding, and the item at x+1 comes after it.

One pitfall is that the data may change between reading a result and sending a call containing it to the blockchain in a transaction, in which case your transaction will fail and you will have to send it again.

  • Related to your suggestion: for example blockchain's best block is 100. But my node is in currently at blockNumber 90 (basically behind of the blockchain). So when I do your suggestion client's node may get the index of the list up to first 90 blocks and miss items generated on the remaining 10 blocks. Is it possible to check that does my node's block number matches with the blockchain's best and latest block number? If that possible your solution will work. Otherwise client will unaware of the does his node sync with the chain and may find index of list base on missing items. @Edmund Edgar – alper Apr 3 '17 at 13:36
  • Please note, it seems like a different question, I asked on a different thread.: ethereum.stackexchange.com/q/13863/4575 – alper Apr 3 '17 at 13:58
  • If you ask for 'latest' you'll get the most recent block your node can see. Your node shouldn't usually be more than a few seconds behind the rest of the network once it's finished syncing. If it's consistently behind then as you say, you might want to ask another question. – Edmund Edgar Apr 3 '17 at 14:01
  • I am working on a private chain. As you can see on the image(ethereum.stackexchange.com/q/13863/4575), sometimes my node get behind 10 or maybe more blocks behind. But some time all on the latest block. So it is hard to trust to node's behaviour on my case. @Edmund Edgar – alper Apr 3 '17 at 14:03
7

As we know when we call a constant function, it does not cost any gas and its free to use.

This statement is false. I'd like to know what is the source of this statement is as it should be corrected.

A transaction, by definition, changes Ethereum blockchain state, moves ETH or bits around.

When transactions perform computations they use CPU time of miners. Not just miners, but also CPU time of all Ethereum full nodes, as currently every transaction is played on every node. Miners are not non-profit and they naturally charge you for their service of using their CPU. It does not matter if the subcalls or computations mutate the state (non-constant) or do not have side effects (constant) if the transaction total result is the change of even one bit in Ethereum blockchain.

Calling constant function is free only if you query the state from your local node, as then you are not doing a transaction, you are just doing a RPC query call to your local blockchain database.

4

Calling constant function might increase your gas consumption. The EVM now need to fetch another function and add it to the stack to calculate the right value. Take a look at the following code for example:

contract Child{

    uint8 public age = 1;


    function birthDay() { <-- gas used: 26933 
        age = age + 1;
    }

    function nextYearIllBe() constant returns (uint8){
        return age + 1;
    }


    function newBirthDay() { <-- gas used 26991
        age = nextYearIllBe();
    }
}

Both birthday functions perform the same addition and storage operation, but the newBirthDay function also adds an extra call to your flow.

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.