Interface Application

All Superinterfaces:
AutoCloseable, io.hotmoka.closeables.api.OnCloseHandlersContainer

public interface Application extends AutoCloseable, io.hotmoka.closeables.api.OnCloseHandlersContainer
An application for the Mokamint blockchain. It specifies the application layer of a blockchain. Mokamint applications are the run-time support to filter the transactions reaching a node and to execute sequential groups of transactions, those inside a block of the blockchain. In particular, a node executes the transactions inside a block at a given height, having a given deadline, starting from the state whose identifier is initialStateId (which is typically that at the end of the previous block), at a moment when, by calling the API of its application as follows:
  • groupId = beginBlock(height, initialStateId, when);
  • for each transaction tx in the block, do:
    • checkTransaction(tx);
    • deliverTransaction(tx, groupId);
  • finalStateId = endBlock(groupId, deadline);
  • commitBlock(groupId);
This commits the final state at the end of the execution of all transactions, whose identifier is finalStateId. That is, that state will be recoverable in the future, from finalStateId, if required by the node. If, instead, the final state needn't be committed, because if won't be needed in the future (for instance, because finalStateId does not match its expected value and hence block verification fails), then abortBlock(int) is called at the end, instead of commitBlock(int).
The execution of a group of transactions is identified by a numerical groupId, that should be unique among all currently ongoing executions. This is because the application might be required to run more groups of transactions, concurrently, and each of those executions must be identified by a different groupId. After the execution of commitBlock(groupId) or abortBlock(groupId), that groupId may be recycled for a subsequent execution.
The implementation of all these methods must be deterministic. The execution of a group of transactions can depend only on height, deadline, initialStateId and when.
The method checkTransaction(Transaction) does not receive the identifier of the group execution, since it performs a context-independent (and typically, consequently, superficial) check, that is applied also as a filter before adding transactions to the mempool of a node. Method deliverTransaction(int, Transaction) subsequently performs a more thorough consistency check later, that considers the context of its execution (for instance, the state where the check is performed). This is why both these methods can throw a TransactionRejectedException.
  • Method Summary

    Modifier and Type
    Method
    Description
    void
    abortBlock(int groupId)
    The node calls this method to abort the execution of the group of transactions identified by id.
    int
    beginBlock(long height, LocalDateTime when, byte[] stateId)
    The node calls this method at the start of the execution of the transactions inside a block.
    boolean
    checkPrologExtra(byte[] extra)
    Checks if the given extra data from the prolog of a deadline is considered valid by this application.
    void
    Checks if the given transaction is valid according to this application.
    void
    Closes this application.
    void
    commitBlock(int groupId)
    The node calls this method to commit the state resulting at the end of the execution of the group of transactions identified by id.
    void
    deliverTransaction(int groupId, Transaction transaction)
    Delivers another transaction inside the group execution identified by id.
    byte[]
    endBlock(int groupId, Deadline deadline)
    The node calls this method when a group execution of transactions ends.
    byte[]
    Yields the identifier of the state of this application when it starts, before any transaction has been executed.
    long
    getPriority(Transaction transaction)
    Computes the priority of the given transaction.
    Yields a string representation of the transaction, that can be used to print or process its structure.
    void
    Informs the application that states of blocks created with a beginBlock(long, LocalDateTime, byte[]) whose when parameter is before start are allowed to be garbage-collected, if the application has some notion of garbage-collection.
    void
    publish(Block block)
    Publishes the given block, that has just been added to the blockchain.

    Methods inherited from interface io.hotmoka.closeables.api.OnCloseHandlersContainer

    addOnCloseHandler, removeOnCloseHandler
  • Method Details

    • checkPrologExtra

      boolean checkPrologExtra(byte[] extra) throws ClosedApplicationException, TimeoutException, InterruptedException
      Checks if the given extra data from the prolog of a deadline is considered valid by this application. This method is called whenever a node receives a new deadline from one of its miners. The application can decide to accept or reject the deadline, on the basis of its prolog's extra bytes. This allows applications to require a specific structure for the prologs of the valid deadlines. If this is not relevant for an application, it can just require this array to be any array or force it to be empty.
      Parameters:
      extra - the extra, application-specific bytes of the prolog
      Returns:
      true if and only if extra is valid according to this application
      Throws:
      ClosedApplicationException - if the application is already closed
      TimeoutException - if no answer arrives before a time window
      InterruptedException - if the current thread is interrupted while waiting for an answer to arrive
    • checkTransaction

      Checks if the given transaction is valid according to this application. Invalid transactions are just rejected when added to a node and they will never be added to the mempool and consequently never to the blockchain. This check is called as soon as a transaction reaches a node. It is typically a simply syntactical, context-independent check. An application can safely implement this method as a no-operation, since it is only meant for a quick optimization: to discard transactions that are clearly invalid, avoiding pollution of the mempool and without even trying to deliver them.
      Parameters:
      transaction - the transaction to check
      Throws:
      TransactionRejectedException - if the check failed and the transaction should not be added to the mempool
      ClosedApplicationException - if the application is already closed
      TimeoutException - if no answer arrives before a time window
      InterruptedException - if the current thread is interrupted while waiting for an answer to arrive
    • getPriority

      Computes the priority of the given transaction. Nodes may (but are not required to) implement a policy of transaction inclusion in blocks that favors transactions with higher priority.
      Parameters:
      transaction - the transaction
      Returns:
      the priority of transaction
      Throws:
      TransactionRejectedException - if the priority of the transaction cannot be computed
      ClosedApplicationException - if the application is already closed
      TimeoutException - if no answer arrives before a time window
      InterruptedException - if the current thread is interrupted while waiting for an answer to arrive
    • getRepresentation

      Yields a string representation of the transaction, that can be used to print or process its structure. This can be everything, possibly, but not necessarily, JSON. It is expected (but not required) that if a transaction passes the checkTransaction(Transaction) test without throwing a TransactionRejectedException, then getRepresentation(Transaction) will not throw that exception either.
      Parameters:
      transaction - the transaction
      Returns:
      the representation of transaction
      Throws:
      TransactionRejectedException - if the representation of the transaction cannot be computed
      ClosedApplicationException - if the application is already closed
      TimeoutException - if no answer arrives before a time window
      InterruptedException - if the current thread is interrupted while waiting for an answer to arrive
    • getInitialStateId

      Yields the identifier of the state of this application when it starts, before any transaction has been executed. This is typically the hash of the empty state of the application.
      Returns:
      the identifier of the state of this application when it starts
      Throws:
      ClosedApplicationException - if the application is already closed
      TimeoutException - if no answer arrives before a time window
      InterruptedException - if the current thread is interrupted while waiting for an answer to arrive
    • beginBlock

      int beginBlock(long height, LocalDateTime when, byte[] stateId) throws UnknownStateException, ClosedApplicationException, TimeoutException, InterruptedException
      The node calls this method at the start of the execution of the transactions inside a block. The application must be able to support the concurrent execution of more groups of transactions. Consequently, each execution is identified by a unique number.
      Parameters:
      height - the height of the block whose transactions are being executed
      when - the time at the beginning of the execution of the transactions in the block
      stateId - the identifier of the state of the application at the beginning of the execution of the transactions in the block
      Returns:
      the identifier of the group execution that is being started; this must be different from the identifier of other executions that are currently being performed
      Throws:
      UnknownStateException - if the application cannot find the state with identifier stateId
      ClosedApplicationException - if the application is already closed
      TimeoutException - if no answer arrives before a time window
      InterruptedException - if the current thread is interrupted while waiting for an answer to arrive
    • deliverTransaction

      Delivers another transaction inside the group execution identified by id. This means that the transaction will be fully checked and then executed. If the full check fails, an exception is thrown instead. Fully checked means that the transaction could be completed verified in the context of the block. This is then a thorough, context-dependent check, must stronger, in general, than the check performed by checkTransaction(Transaction).
      Parameters:
      groupId - the identifier of the group execution
      transaction - the transaction to deliver
      Throws:
      TransactionRejectedException - if the check or execution of the transaction failed
      UnknownGroupIdException - if the groupId is not valid
      ClosedApplicationException - if the application is already closed
      TimeoutException - if no answer arrives before a time window
      InterruptedException - if the current thread is interrupted while waiting for an answer to arrive
    • endBlock

      The node calls this method when a group execution of transactions ends. This gives the application the opportunity of adding the effects of coinbase transactions that it should execute at the end of the execution of the transactions in the group. Such coinbase transactions are typically related to a deadline, that inside the block whose transactions have been executed, which is why the latter is provided to this method.
      Parameters:
      groupId - the identifier of the group execution of transactions that is being ended
      deadline - the deadline that has been computed for the block containing the transactions
      Returns:
      the identifier of the state resulting at the end of the group execution of the transactions, including eventual coinbase transactions added at its end
      Throws:
      ClosedApplicationException - if the application is already closed
      UnknownGroupIdException - if the groupId is not valid
      TimeoutException - if no answer arrives before a time window
      InterruptedException - if the current thread is interrupted while waiting for an answer to arrive
    • commitBlock

      The node calls this method to commit the state resulting at the end of the execution of the group of transactions identified by id. This means that the application, in the future, must be able to recover the state at the end of that execution, from the identifier of that state. This typically requires to commit the resulting state into a database.
      Parameters:
      groupId - the identifier of the execution of a group of transactions that is being committed
      Throws:
      UnknownGroupIdException - if the groupId is not valid
      ClosedApplicationException - if the application is already closed
      TimeoutException - if no answer arrives before a time window
      InterruptedException - if the current thread is interrupted while waiting for an answer to arrive
    • abortBlock

      The node calls this method to abort the execution of the group of transactions identified by id. This means that the application, in the future, will not be required to recover the state at the end of that execution, from the identifier of that state. This typically requires to abort a database transaction and clear some resources.
      Parameters:
      groupId - the identifier of the execution of a group of transactions that is being aborted
      Throws:
      UnknownGroupIdException - if the groupId is not valid
      ClosedApplicationException - if the application is already closed
      TimeoutException - if no answer arrives before a time window
      InterruptedException - if the current thread is interrupted while waiting for an answer to arrive
    • keepFrom

      Informs the application that states of blocks created with a beginBlock(long, LocalDateTime, byte[]) whose when parameter is before start are allowed to be garbage-collected, if the application has some notion of garbage-collection.
      Parameters:
      start - the limit time, before which states can be garbage-collected
      Throws:
      ClosedApplicationException - if the application is already closed
      TimeoutException - if no answer arrives before a time window
      InterruptedException - if the current thread is interrupted while waiting for an answer to arrive
    • publish

      Publishes the given block, that has just been added to the blockchain. The application might exploit this hook, for instance, in order to trigger events on the basis of the content of the block. Or it might just do nothing.
      Parameters:
      block - the block to publish
      Throws:
      ClosedApplicationException - if the application is already closed
      TimeoutException - if no answer arrives before a time window
      InterruptedException - if the current thread is interrupted while waiting for an answer to arrive
    • close

      void close()
      Closes this application. After this closure, the methods of this application will throw a ClosedApplicationException. An application cannot be reopened after being closed.
      Specified by:
      close in interface AutoCloseable