3

I've set up a Truffle sample project, which contains the following contract with the last method added for demonstration purposes (see logs below):

pragma solidity ^0.4.4;

import "./ConvertLib.sol";

// This is just a simple example of a coin-like contract.
// It is not standards compatible and cannot be expected to talk to other
// coin/token contracts. If you want to create a standards-compliant
// token, see: https://github.com/ConsenSys/Tokens. Cheers!

contract MetaCoin {
  mapping (address => uint) balances;

  event Transfer(address indexed _from, address indexed _to, uint256 _value);

  function MetaCoin() {
    balances[tx.origin] = 10000;
  }

  function sendCoin(address receiver, uint amount) returns(bool sufficient) {
    if (balances[msg.sender] < amount) return false;
    balances[msg.sender] -= amount;
    balances[receiver] += amount;
    Transfer(msg.sender, receiver, amount);
    return true;
  }

  function getBalanceInEth(address addr) returns(uint){
    return ConvertLib.convert(getBalance(addr),2);
  }

  function getBalance(address addr) returns(uint) {
    return balances[addr];
  }

  function getBalanceWithConstant(address addr) constant returns(uint) {
    return balances[addr];
  }
}

The getBalance() function only return a value and doesn't alter the state of the network. Why was there no constant used for this function in the Truffle sample code? From what I can tell looking at the logs, in its current form, it needs mining and costs gas when being called.

Update

Here's the log.

First I call the function with the constant, which just returns the value:

Home:truffle migu$ truffle console
truffle(development)> var meta;
undefined
truffle(development)> MetaCoin.deployed().then(function(instance) { meta = instance;})
undefined
truffle(development)> address = '0xf27c14a83851210c6e26502433fd8193733ace90'
'0xf27c14a83851210c6e26502433fd8193733ace90'
truffle(development)> var tx = meta.getBalanceWithConstant(address);
undefined
truffle(development)> tx
{ [String: '10000'] s: 1, e: 4, c: [ 10000 ] }

Also, the testrpc logs don't show any mining:

eth_call

Then I call the function without a constant:

truffle(development)> var tx1 = meta.getBalance(address);
undefined
truffle(development)> tx1
{ tx: '0xc671857f5fdfb1e7f487cebd32d74a1dfd99a3d54d8201f4435e4595753400be',
  receipt: 
   { transactionHash: '0xc671857f5fdfb1e7f487cebd32d74a1dfd99a3d54d8201f4435e4595753400be',
     transactionIndex: 0,
     blockHash: '0xe12fce4f8e2b3dd8fc0ca840ab5a63e60a8c94e22ab6c5b157fc654ddf4c2f48',
     blockNumber: 6,
     gasUsed: 23146,
     cumulativeGasUsed: 23146,
     contractAddress: null,
     logs: [] },
  logs: [] }

And the testrpc logs show mining activities:

eth_sendTransaction

  Transaction: 0xc671857f5fdfb1e7f487cebd32d74a1dfd99a3d54d8201f4435e4595753400be
  Gas usage: 0x5a6a
  Block Number: 0x06
  Block Time: Sun Mar 12 2017 08:07:27 GMT+1100 (AEDT)

eth_getTransactionReceipt
3

There's a lot to untangle here, so I will try to be precise and hopefully not add to confusion.

First, let's assume that the Truffle example is aimed at illuminating how to use Truffle and not at illustrating how to make the most efficient coin contract.

@migu, you're right. It looks like the last two getter functions could be constant and that would be both faster and cheaper to run.

Designating the function constant is a decision the developer makes about how the function should be run. It specifies the use of the local resources and the immediate result. Similar execution can be specified with web3 for any using .call(). That means the client doesn't want network verification. That's what the Truffle example test is doing (metacoin.js).

It's not the EVM determines that the function makes no changes. Using constant (contract) or .call() (in the client) indicates that the developer doesn't want any changes. That makes it (constant) suitable for read-only and dry-run (what would happen if ...) operations.

Hope it helps.

  • Thanks, that makes sense. Is it correct to assume that if a function is read only and the developer doesn't know how this function will be consumed, there is no reason to not use constant? – migu Mar 11 '17 at 21:24
1

"in their current form, both functions need mining and cost gas when being called"

This statement doesn't make sense.

The constantness of the function is defined whether it changes the state. constant keyword is optional (others please correct me if I am wrong here).

Because the functions do not change any state, they are executed locally in your Ethereum node and no transaction needs mined, no value transfer happens to any direction.

  • I've added logs and another method with a constant to better illustrate my point. – migu Mar 11 '17 at 21:12
  • The constant keyword is indeed optional. But it does not mean that the compiler will determine for you if states are changed by the function. In reality, it is simple: the developper uses constant, then the execution on the function is done on the local evm with the local data of the blockchain (up to date or not) and returned value is available locally. If the developer did not use the keyword then the function is treated as a transaction and is required to be mined. Return value is not available to the caller (unless using the debug.traceTransaction!) – Guenole de Cadoudal Mar 12 '17 at 13:09
  • @GuenoledeCadoudal I am pretty sure you are wrong - currently constant keyword does nothing: Please see the notes here solidity.readthedocs.io/en/develop/… – Mikko Ohtamaa Mar 12 '17 at 23:18
  • Hi, please try having both a constant and non constant function on a contract, modifying a state variable of a simple contract and test it. You will see how it behaves. Good luck – Guenole de Cadoudal Mar 12 '17 at 23:21
  • Hi @MikkoOhtamaa have you been able to test ? – Guenole de Cadoudal Mar 14 '17 at 15:23

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.