(image)

Programming Hotmoka
A tutorial on Hotmoka and smart contracts in Takamaka

4.5 The hierarchy of contracts

Fig. 4.1 shows the hierarchy of the Takamaka classes used for contracts. The topmost abstract class io.takamaka.code.lang.Contract extends io.takamaka.code.lang.Storage since contracts are meant to be stored in a node (as are other classes that are not contracts, such as our first Person example class). Programmers typically extend Contract to define their own contracts. This is the case, for instance, of our SimplePonzi class. Class Storage provides a caller() final protected method that can be called inside @FromContract methods and constructors, to access the calling contract. Class Contract provides a final @View method balance() that can be used to access the private balance field of the contract. Note that class Contract is annotated with the inherited annotation @Exported, hence contracts, such as instances of SimplePonzi, can be receivers of calls from outside the node and can be passed as arguments to calls from outside the node. Instances of Storage are not normally @Exported, unless their class is explicitly annotated as @Exported, as we did for Person.

(-tikz- diagram)

Figure 4.1: The hierarchy of contract classes.

The abstract subclass PayableContract is meant to implement contracts that can receive coins from other contracts, by calling their final method receive(). Its concrete subclass named ExternallyOwnedAccount is a payable contract that can be used to pay for a transaction. Such accounts are typically controlled by humans, through a wallet keeping its private key, but can be subclassed and instantiated freely in Takamaka code. Their constructors allow one to build an externally owned account and fund it with an initial amount of coins. As we have seen in Sec. 3.23.3 and 3.4, the methods of Hotmoka nodes that start a transaction require to specify a payer for that transaction. Such a payer is required to be an instance of ExternallyOwnedAccount, or an exception will be thrown. In our previous examples, we have used, as payer, an account created by the moka accounts create command, that is an instance of ExternallyOwnedAccount. ExternallyOwnedAccounts have a private field nonce that can be accessed through the public @View method nonce(): it yields a BigInteger that specifies the next nonce to use for the next transaction having that account as caller. This nonce gets automatically increased after each such transaction.

Instances of ExternallyOwnedAccount hold their public key in their private publicKey field, as a Base64-encoded string, that can be accessed through the publicKey() method. That key is used to verify the signature of the transactions having that account as caller. As we will see later, there is a default signature algorithm for transactions and that is what ExternallyOwnedAccounts use. However, it is possible to require a specific signature algorithm, that overrides the default used for the node. For that, it is enough to instantiate classes ExternallyOwnedAccountSHA256DSA, or ExternallyOwnedAccountED25519, or ExternallyOwnedAccountQTESLA1 or, finally, the class ExternallyOwnedAccountQTESLA3. The latter two use a quantum-resistant signature algorithm (see ?? later). This means that it is possible to mix many signature algorithms for signing transactions inside the same Hotmoka node, as we will show later.