Solidity Guide – How to Manipulate Data in a Smart Contract

contract-developmentgastransactionsweb3js

I have a smart contract with some members which should get modified on certain events. For simplicity, let's imagine we have a greeter contract.

If I call greeter.greet() in the JavaScript console, it responds with something like Hello World. But what if I want to count the number of greetings and store them inside the contract?

My first try was the following:

contract greeter
{
  string greeting;
  uint calls;

  function greeter ( string _greeting ) public
  {
    greeting = _greeting;
    calls = 0;
  }

  function greet ( ) constant returns ( string )
  {
    calls = calls + 1; // does not work
    return greeting;
  }
}

The calls variable was not updated. My first guess is that I need to somehow create a transaction to pay for the gas. I used web3.js to deploy the contract. Should I use web3 also for calling greet() with a transaction?

Or could I fund the contract account with some Ether to enable the contract to pay its own gas? How to manipulate data in a Solidity smart contract?

Best Answer

Because your greet() function is marked constant, web3 by default simulates the call and returns the value, but no transaction is sent, and thus no state changes are retained. This behavior can be forced in non-constant methods using contract.method.call().

To call the function in a way that does send a transaction and update the chain, use greeter.greet.sendTransaction({from:eth.coinbase, gas:100000}).

Unfortunately, while other contracts will recieve the proper return value, web3 will return a transaction hash, as opposed to a return value. In this case, it makes sense to use Events.

For example, the solidity would look something like:

contract greeter { 
    string greeting; 
    uint calls; 
    event Greet (string greeting);
    function greeter ( string _greeting ) public { 
        greeting = _greeting; 
        calls = 0; 
     }
     function greet ( ) public returns ( string ) { 
         calls = calls + 1; 
         Greet(greeting);
          return greeting; 
     } 
 }

And to get a return value:

 greeter.greet.sendTransaction(
    {from:eth.coinbase, gas:100000},

    function (error, result){ 
    var event = greeter.Greet()
    event.watch(
        function(error, result){ 
             if (!error) console.log(result.args.greeting); 
         }
    );
)
Related Topic