7

Since reading on the Blockchain does not need performance of other nodes, I wonder how I can get values from a Smart Contract without any transactions. I have created a little example contract:

contract Test {
    uint x;

    function Test() { //to init the contract I definitely need a transaction
        x = 0;
    }

    function inc() returns (uint) { //here I need a transaction too since I change the value
        x = x + 1;
        return x;
    }

    function get() returns (uint) { //I am not sure what is about this function
        return x;
    }
}

I want to check my understanding and have some questions:

  • Which functions need a transaction to trigger?
  • Do I even need a function to get a value from a smart Contract when I am a full node? Couldn't I just read it?
  • What happens when inc() is called with a transaction but not inserted in a Block and I read an old value? Is this an important point or can it be ignored?
  • When do I get a/the return value? Instantly or when the transaction in placed in a block?

I appreciate any answers :)

6

In which functions do I need a transaction?

Only in that that changes values. The other you can call from a single ethereum node. This does not require spending any any ETH.

From the web3 documentation:

web3.eth.call(callObject [, defaultBlock] [, callback])

Executes a message call transaction, which is directly executed in the VM of the node, but never mined into the blockchain.

Use constant functions

To make sure that the function can be called without transactions use constant.
That would be:

   function get() constant returns (uint) { 
        return x;
    }

From Solidity doc:

constant functions can perform some action and return a value, but cannot change state (this is not yet enforced by the compiler). In other words, a constant function cannot save or update any variables within the contract or wider blockchain. These functions are called using c.someFunction(...) from geth or any other web3.js environment.

“non-constant” functions (those lacking the constant specifier) must be called with c.someMethod.sendTransaction({from:eth.accounts[x], gas: 1000000}); That is, because they can change state, they have to have a gas payment sent along to get the work done.

Do I need a function to get a value from a smart Contract when I am a full node?

It depends, public state variables have automatically a getter setter, but I prefer to do it explicitly

What happens when inc() is called with a transaction but not inserted in a Block and I read an old value? Is this an important point or can it be ignored?

Ultimately the mined block decides what ist the true history of your contract calls. So yes it does matter. Each block is like a discrete time step. Note that you can call multiple inc() in one block but the order and if they are included is not deterministic.

When do I get a/the return value? Instantly or when the transaction in placed in a block?

In the same line of argument: only if the block was mined, and to confuse you further... only if the block has been confirmed enough often to be sure this is the correct blockchain fork ;-)

  • Thank you very much for your answers! Reagarding the last answer: Let's say I would try to do something explicitly (web3) when the transaction is send, included and confirmed. Do I need an event in the contract for this or can I use a callback function? – Ba5t14n Jul 13 '16 at 9:13
  • I would go for an event, because then you can steer exactly when the event happened. A callback function would also work. Currently, I think either a function should return and be constant or it should change the state, no mixes. I have the feeling this asynchronicity is very helpful, but still open to debate. The alternative would be to use a constant function to read a state later eventually. – Roland Kofler Jul 13 '16 at 9:45
4

With the title "Reading values from a contract: When do I need transactions?" the answer is transactions are never needed for reading contract values.

A transaction is needed when you want to change state: in the example, when you want to change and save the value of x.

Which functions need a transaction to trigger?

Since you probably want to save the value of x, inc() should be invoked with a transaction.

As you've noted, to deploy the contract and invoke the Test() constructor, you do need a transaction.

Do I even need a function to get a value from a smart Contract when I am a full node? Couldn't I just ... read it?

From outside the blockchain you don't need a function, but you will need a function if you want a contract to get the value.

What happens when inc() is called with a transaction but not inserted in a Block and I read an old value? Is this an important point or can it be ignored?

If your transaction is not inserted in a block, your application should disregard the transaction: for example if someone says they paid you in a particular transaction and you don't find it in the blockchain, you would still require they pay you. It's important you disregard the transaction: for example you still want to be paid!

When do I get a/the return value? Instantly or when the transaction in placed in a block?

You only get a return value when you invoke a function with a call, as in contract.get.call(), and you get it immediately. If you use contract.get.sendTransaction() you will get an immediate transactionHash: you will not be able to get the return value without rewriting the contract code, for example to use an Event. More details: What is the difference between a transaction and a call?

Notes:

  • inc() should be probably be invoked with contract.inc.sendTransaction() (so that x is saved), but it is possible to use contract.inc.call() and it would be a preview of what the "next" value of x is.

  • get() should probably have constant, but even with constant, it's still possible to use contract.get.sendTransaction(): it would not make much sense though.

  • Thank you for your answer! Sadly, I can not acceppt 2 answers at the same time. Is this "preview" call possible with all functions in the contract? Why is there such a functionality implemented? I imagine this could make a lot of confusion, what is your opinion to this? – Ba5t14n Jul 13 '16 at 10:23
  • No problem about accepting :) Yes, all functions can be invoked with call(). Yes it is a confusing part when starting to program with a blockchain: both are needed and maybe the analogy of HTTP POST and a pure HTTP GET can help. – eth Jul 13 '16 at 10:31
  • interesting thing though, let's see if I will ever come over this again, but interesting functionality :) – Ba5t14n Jul 13 '16 at 11:13
2

As you imply if the function you're calling doesn't need to modify anything you can get the return value instantly without sending a transaction to the rest of the network. However you need to mark the function you're calling as constant.

function get() constant returns (uint) {
   return x;
}

Since your inc() function alters state, it needs to be called in a transaction. Although it has a return value that could have been returned if you'd called it in another function, it won't be returned to you when you send the transaction to the network, since the transaction isn't executed until it's included in a block.

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.