(image)

Programming Hotmoka
A tutorial on Hotmoka and smart contracts in Takamaka

4.4 The @View annotation

(See the io-hotmoka-tutorial-examples-ponzi_view project in https://github.com/Hotmoka/hotmoka)

Our SimplePonzi.java code can still be improved. As it is now, an investor must call invest() and be ready to pay a sufficiently large amount of coins to pay back and replace the previous investor. How much is large actually large enough? Well, it depends on the current investment. But that information is kept inside the contract and there is no easy way to access it from outside. An investor can only try with something that looks large enough, running a transaction that might end up in two scenarios, both undesirable:

  • 1. The amount invested was actually large enough, but larger than needed: the investor invested more than required in the Ponzi scheme, taking the risk that no one will ever invest more and pay him back.

  • 2. The amount invested might not be enough: the require() function will throw an exception that makes the transaction running invest() fail. The investment will not be transferred to the SimplePonzi contract, but the investor will be penalized by charging him all the gas provided for the transaction. This is unfair since, after all, the investor had no way to know that the proposed investment was not large enough.

Hence, it would be nice and fair to provide investors with a way to access the value in the currentInvestment field. This is actually very easy: just add this method to SimplePonzi.java:

public BigInteger getCurrentInvestment() {
    return currentInvestment;
}

This solution is perfectly fine but can be improved. Written this way, an investor that wants to call the method getCurrentInvestment() must run a Hotmoka transaction, by invoking the method addInstanceMethodCallTransaction() of the node, creating a new transaction that ends up in the store of the node. That transaction will cost gas, hence its side-effect will be to reduce the balance of the calling investor. But the goal of the caller was just to access information in the store of the node, not to modify the store through side-effects. The balance reduction for the caller is, indeed, the only side-effect of that call! In cases like this, Takamaka allows one to specify that a method is expected to have no side-effects on the visible state of the node, but for the change of the balance of the caller. This is possible through the @View annotation. Import that class in the Java source and edit the declaration of getCurrentInvestment(), as follows:

import io.takamaka.code.lang.View;
...
public @View BigInteger getCurrentInvestment() {
    return currentInvestment;
}

An investor can now call that method through another API method of the Hotmoka nodes, called runInstanceMethodCallTransaction(), that does not expand the store of the node, but yields the response of the transaction, including the returned value of the call. If method getCurrentInvestment() had side-effects beyond that on the balance of the caller, then the execution will fail with a run-time exception. Note that the execution of a @View method still requires gas, but that gas is given back at the end of the call. The advantage of @View is hence that of allowing the execution of getCurrentInvestment() for free and without expanding the store of the node with useless transactions, that do not modify its state. Moreover, transactions run through runInstanceMethodCallTransaction() do not need a correct nonce, chain identifier or signature, hence any constant value can be used for them. This simplifies the call. For the same reason, transactions run through runInstanceMethodCallTransaction() do not count for the computation of the nonce of the caller.

The annotation @View is checked, at run time, when a transaction calls the @View method from outside the blockchain, directly. It is not checked if, instead, the method is called indirectly, from other Takamaka code. The check occurs at run time, since the presence of side-effects in computer code is undecidable. Future versions of Takamaka might check @View at the time of installing a jar in a node, as part of bytecode verification. That check can only be an approximation of the run-time check.

If a @View method is called through the moka objects call command, the moka tool will automatically perform a runInstanceMethodCallTransaction(), internally, to spare gas, and the call will occur for free.