The Actors

Index

  1. Toc
  2. Contributing
    1. Understanding Any Module
    2. Style Guide
    3. Writing Documents
    4. Examples Over Testing
    5. Git
    6. Iex
    7. Mnesia Vs Actor State
    8. Observer
    9. Testing
      1. Running Tests
      2. Writing Tests
  3. Visualization
    1. Actors
  4. Hoon
    1. Calling
    2. Dumping
    3. Setting Up
  5. Analysis

An overview of Anoma

A good overview of Actors can be seen by looking at the supervision tree of Anoma itself.

Kino.Process.render_app_tree(:anoma_node, direction: :left_right)
graph LR;
application_master(#PID<0.875.0>):::supervisor ---> supervisor_ancestor;
supervisor_ancestor(#PID<0.876.0>):::supervisor ---> 0;
0(Anoma.Node.Supervisor):::root ---> 1(Anoma.Node.Transport.Supervisor):::supervisor
0(Anoma.Node.Supervisor):::root ---> 6(Anoma.Node.Transaction.Supervisor):::supervisor
1(Anoma.Node.Transport.Supervisor):::supervisor ---> 2(ProxySupervisor):::supervisor
1(Anoma.Node.Transport.Supervisor):::supervisor ---> 3(Anoma.Node.Transport.TCPSupervisor):::supervisor
1(Anoma.Node.Transport.Supervisor):::supervisor ---> 4(ProxyRegister):::supervisor
4(ProxyRegister):::supervisor ---> 5(ProxyRegister.PIDPartition0):::worker
classDef root fill:#c4b5fd, stroke:#374151, stroke-width:4px;
classDef supervisor fill:#c4b5fd, stroke:#374151, stroke-width:1px;
classDef worker fill:#93c5fd, stroke:#374151, stroke-width:1px;
classDef notstarted color:#777, fill:#d9d9d9, stroke:#777, stroke-width:1px;

Mempool

A good view of visualizing Anoma can be seen through running the mempool, as it orchastrates the other actors in Anoma to act

First we will create a transaction and see how that changes the base supervision tree before executing

alias Anoma.Node.Ordering
alias Anoma.Node.Mempool
alias Anoma.Node.Router
import TestHelper.Nock

name = :anoma
node = Anoma.Node.state(name)
key = 555
zero = zero_counter(key)
pid_zero = Mempool.tx(node.mempool, {:kv, zero}).pid
#PID<0.438.0>

The previous evaluations PID can be seen in the diagram below!

{_, [pid1, pid2]} = Process.info(Process.whereis(:anoma), :links)
Kino.Process.render_sup_tree(pid2, direction: :left_right)
graph LR;
0(supervisor hWXJ+NujE76g6g4X5Bu+KH1YtSKrur7yDUfeu0JguKY=):::root ---> 1(Anoma.Node.Router hWXJ+NujE76g6g4X5Bu+KH1YtSKrur7yDUfeu0JguKY=):::worker
0(supervisor hWXJ+NujE76g6g4X5Bu+KH1YtSKrur7yDUfeu0JguKY=):::root ---> 2(Anoma.Node.Clock plaqCqOIQ4LLCT9MAmEMV+qkqZq4+qZV2KSpqSxRZu0=):::worker
0(supervisor hWXJ+NujE76g6g4X5Bu+KH1YtSKrur7yDUfeu0JguKY=):::root ---> 3(Anoma.Node.Logger BDTPKlJ5ubxM9NMrbgMzxE5jfKKn+qwnxISeroCw3xc=):::worker
0(supervisor hWXJ+NujE76g6g4X5Bu+KH1YtSKrur7yDUfeu0JguKY=):::root ---> 4(Anoma.Node.Ordering rVQnNBPLju9VBsHOQzAdKaEXRK2u03vF8huvKzVPyT8=):::worker
0(supervisor hWXJ+NujE76g6g4X5Bu+KH1YtSKrur7yDUfeu0JguKY=):::root ---> 5(Anoma.Node.Executor po4ivXyVtjQ9jvTtra0D2DbKIpM8YOClCmfk8JLp31k=):::worker
0(supervisor hWXJ+NujE76g6g4X5Bu+KH1YtSKrur7yDUfeu0JguKY=):::root ---> 6(Anoma.Node.Mempool yg3U9BqClfT+jJkwbtuYm2WCmIgR+f6ELjodD5P4eko=):::worker
0(supervisor hWXJ+NujE76g6g4X5Bu+KH1YtSKrur7yDUfeu0JguKY=):::root ---> 7(Anoma.Node.Pinger Oc96nqV6/0FFT/JULG5Ep+Z1c62/8f1Bi0gY9CVmJhs=):::worker
classDef root fill:#c4b5fd, stroke:#374151, stroke-width:4px;
classDef supervisor fill:#c4b5fd, stroke:#374151, stroke-width:1px;
classDef worker fill:#93c5fd, stroke:#374151, stroke-width:1px;
classDef notstarted color:#777, fill:#d9d9d9, stroke:#777, stroke-width:1px;

Now let us see what happens between the actors when we run the mempool

Kino.Process.render_seq_trace(
  [Process.whereis(node.mempool.server)],
  fn ->
    Mempool.execute(node.mempool)
  end,
  message_label: &Anoma.Utility.message_label/1
)
sequenceDiagram
participant 3 AS code_server;
participant 7 AS mnesia_locker;
participant 6 AS mnesia_tm;
participant 8 AS Anoma.Node.Router hWXJ+NujE76g6g4X5Bu+KH1YtSKrur7yDUfeu0JguKY=;
participant 2 AS Anoma.Node.Logger BDTPKlJ5ubxM9NMrbgMzxE5jfKKn+qwnxISeroCw3xc=;
participant 4 AS Anoma.Node.Ordering rVQnNBPLju9VBsHOQzAdKaEXRK2u03vF8huvKzVPyT8=;
participant 1 AS Anoma.Node.Mempool yg3U9BqClfT+jJkwbtuYm2WCmIgR+f6ELjodD5P4eko=;
participant 0 AS self();
participant 5 AS #35;PID<0.438.0>;
0->>1: CALL: execute
1->>2: ADD LEVEL: info
1->>3: INFO: code_call
3->>1: INFO: code_server
1->>3: INFO: code_call
3->>1: INFO: code_server
1->>3: INFO: code_call
3->>1: INFO: code_server
1->>3: INFO: code_call
3->>1: INFO: code_server
1->>4: CALL: next_order
4->>1: INFO: tuple
1->>3: INFO: code_call
3->>1: INFO: code_server
1->>3: INFO: code_call
3->>1: INFO: code_server
1->>2: ADD LEVEL: info
1->>4: CALL: new_order
4->>1: INFO: tuple
1->>2: ADD LEVEL: info
1->>5: INFO: write_ready
1->>2: ADD LEVEL: info
1->>6: INFO: tuple
6->>1: INFO: mnesia_tm
1->>7: INFO: tuple
7->>1: INFO: mnesia_locker
1->>7: INFO: release_tid
1->>6: INFO: delete_transaction
1->>2: ADD LEVEL: info
1->>2: ADD LEVEL: info
1->>8: CAST: cast
1->>0: INFO: tuple
{:ok, 1}

As we can see, we get a fairly solid overview of what actors sent what messages

We can also see what processes startup when we start an execution

Kino.Process.render_seq_trace(
  [Process.whereis(node.mempool.server)],
  fn -> Mempool.tx(node.mempool, {:kv, increment_counter_val(555)}).pid() end,
  message_label: &Anoma.Utility.message_label/1
)
#PID<0.1147.0>
Kino.Process.render_seq_trace(
  :all,
  fn -> Anoma.Node.Logger.add(node.logger, :info, "help") end,
  message_label: &Anoma.Utility.message_label/1
)
:ok