Anoma.Node.Transaction.Ordering (Anoma v0.29.0)

I am the Ordering Engine.

I act as a mediator between Workers and Storage. In particular, Workers working on a transaction may ask to read and write information. However, they do not know when to do it, they only know the ID of the transaction they work on.

I process such requests, keeping them waiting until consensus provides some ordering to a transaction in question. Once they do, I pair a transaction ID with its timestamp and forward queries to Storage.

Public API

I provide the following public functonality:

Summary

Types

t()

I am the type of the Ordering Enigine.

Functions

I am the Ordering write function.

I am the Ordering append function.

Returns a specification to start this module under a supervisor.

I am the initialization function for the Ordering Engine.

I am the Ordering order function.

I am the Ordering read function.

I am the start_link function for the Ordering Engine.

I am a filter spec which filters for any event with a tx_id field and matches iff the ID stored is the one supplied.

I am the Ordering write function.

Types

@type t() :: %Anoma.Node.Transaction.Ordering{
  next_height: integer(),
  node_id: String.t(),
  tx_id_to_height: %{required(binary()) => integer()}
}

I am the type of the Ordering Enigine.

I contain the Node for which the Ordering is launched, the upcoming hight as well as a map from transaction IDs to their global order.

Fields

  • :node_id - The ID of the Node to which an Ordering instantiation is
             bound.
  • :next_height - The height that the next ordered transaction
                 candidate will get.
                 Default: 1
  • :tx_id_to_height - A map from an ID of a transaction candidate to
                     its order.

Functions

Link to this function

add(node_id, arg)

@spec add(
  String.t(),
  {binary(), %{write: list(), append: list()}}
) :: any()

I am the Ordering write function.

I receive a Node ID and an {id, map} tuple. There are two states possible when Ordering processes my request. Either:

  • The id has been assigned an order.
  • The id has not been assigned an order.

If the former is true, I send the request to appropriately add the map to the Storage at the specified height. See Storage.add/2

If the latter is true, I leave the caller blocked until the id has been assigned a value, i.e. until a corresponding event gets received.

Link to this function

append(node_id, arg)

@spec append(
  String.t(),
  {binary(), [{any(), MapSet.t()}]}
) :: :ok

I am the Ordering append function.

I receive a Node ID and an {id, kvlist} tuple. There are two states possible when Ordering processes my request. Either:

  • The id has been assigned an order.
  • The id has not been assigned an order.

If the former is true, I send the request to append the key-value list at the specified height to the Storage. See Storage.append/2

If the latter is true, I leave the caller blocked until the id has been assigned a value, i.e. until a corresponding event gets received.

Link to this function

child_spec(init_arg)

Returns a specification to start this module under a supervisor.

See Supervisor.

I am the initialization function for the Ordering Engine.

From the specified arguments, I get the Node ID as well as the info regarding the next height Ordering should be started with.

Link to this function

order(node_id, txs)

@spec order(String.t(), [binary()]) :: :ok

I am the Ordering order function.

Given a Node ID and a list of transaction IDs, I percieve the latter as a partial ordering of transactions. Afterwards, I assign them a global ordering by adding the next height stored in the Ordering Engine to the respective ordering inside a list.

Afterwards, I send an event specifying that a particular ID has indeed received an order.

Link to this function

read(node_id, arg)

@spec read(
  String.t(),
  {binary(), any()}
) :: any()

I am the Ordering read function.

I receive a Node ID and an {id, key} tuple. There are two states possible when Ordering processes my request. Either:

  • The id has been assigned an order.
  • The id has not been assigned an order.

If the former is true, I send the request to read the key at the specified height minus one to the Storage. That is, we ask the storage to read the most recent value assigned to the key from the point of view of the transaction candidate. See Storage.read/2.

If the latter is true, I leave the caller blocked until the id has been assigned a value, i.e. until a corresponding event gets received.

Link to this function

start_link(args \\ [])

@spec start_link([startup_options()]) :: GenServer.on_start()

I am the start_link function for the Ordering Engine.

I register the engine with supplied node ID provided by the arguments.

Link to this function

tx_id_filter(tx_id)

I am a filter spec which filters for any event with a tx_id field and matches iff the ID stored is the one supplied.

Link to this function

write(node_id, arg)

@spec write(
  String.t(),
  {binary(), [{any(), any()}]}
) :: :ok

I am the Ordering write function.

I receive a Node ID and an {id, kvlist} tuple. There are two states possible when Ordering processes my request. Either:

  • The id has been assigned an order.
  • The id has not been assigned an order.

If the former is true, I send the request to write the key-value list at the specified height to the Storage. See Storage.write/2

If the latter is true, I leave the caller blocked until the id has been assigned a value, i.e. until a corresponding event gets received.