Node architecture: machines, engine groups, engines

In the previous version of the specs (v1), we have described and organized the node architecture in terms of machines, engine groups, and engines.

In the current version (v2) we have an updated and more precise notion of engines and their types, however it’s not clear how this connects with the node architecture.

Before, we had machines that were further subdivided into engine groups, which had a number of engines where we described the relevant types, messages and behaviour.

In the new specs these are described under engine families, in the node_architecture/engines/ directory in a flat structure, and not listed in the ToC.

Questions:

Does this way of talking about machines and engine groups fit the new engine model, or do we also need to revise these?

How do we connect the engine families to the machines and engine groups in the node architecture? We need updated machine and engine group templates to clarify.

Shall we add the engine families to the ToC under engine groups like before?
Or list them in the ToC under Engine Families? Or both (not sure if possible)?
Listing them under engine groups like before would result in a clearer structure I think.

Also, describing how engine instances are spawned for each engine family, (e.g. whether an engine has a single instance launched at node start, or many instances spawed during runtime, and if so how).
Where shall we talk about these? In the engine family description or under machines / engine groups?

@jonathan @graphomath @degregat

1 Like

How the new model on engines connects to the node arquitecture?

How? I’d say in the same way as before. I mean, the new model only provides a
better conceptualisation of what the specs had before. Say a better definition
of what an engine is.

As it is now in the Specs, Node Architecture describes how a node is internally composed of various engines and how precisely each engine works. (Agreed)

The above means that in the Specs, we should be able to find the following:

  1. the engine instances,
  2. their formal definition (description of how they work), and
  3. how they (internally) interact. That is, how the composition actually works.

If we don’t have the above, then we are not doing a good job at formalising the
model.

We have addressed 1. What’s an engine instance, and 2. its formal definition.
But, as you pointed out, we haven’t formally established:

  • how engines interact, and
  • how to group them.

Does this way of talking about machines and engine groups fit the new engine
model, or do we also need to revise these?

Yes, we need to revise all related to grouping engine instances and how they
interact, as said earlier.

I propose to get rid of the concept of “machine” in favor of “engine system
components” (or something like that).

How do we connect the engine families to the machines and engine groups in the
node architecture? We need updated machine and engine group templates to
clarify.

Let me revise and connect some dots in what follows of what I understand the
current state of the specifications regarding engines is/should be.

I’ll work with four levels of conceptualisation of engines:

  1. engine instance,
  2. engine family,
  3. engine system components, and
  4. engine system.

It is very similar to Talcott’s actor model but for engines.

At the lowest level, we must specify engine instances, “engines” for short.
An engine instance would be analogous to an individual actor in the actor
model. That is, defining their behaviour in terms of how they respond to
messages and interact with other engines.

An engine family represents a collection of engine instances that share the same
specification, that is, engines with identical behaviour, not state. Now,
because we have a type system in our court, we expect a type to be associated
with each engine family. An engine instances are terms of the corresponding
engine family type. That also means, we can find the type of what an engine
family really is.

type EngineFamily (S I M H A L X : Type) := mkEngineFamily {
  guards : List (Guard S I M H A L X);
  action : ActionFunction S I M H A L X;
  conflictSolver : Set A -> List (Set A);
};

The snippet above was taken from Engine Family - Anoma Specification

On the other hand, the concept of an engine system component is not present in the specs atm. An engine system component is/would be defined analogously to an actor system component. That is, an engine system component is a collection
of engine instances that work together to perform a specific (complex) task. How
to specify this? not yet clear to me. But if we follow Talcott’s actor model,
then, it should include a well-defined interface containing:

    1. Receptionists: a subset of visible names of engine instances (or all of
      them) to the “environment” (this relates to items n.3 and 4., the “big.”
      system(s)).
    1. Externals: a set of names of other engine instances outside the component
      to which any engine instance in the system component is allowed to send
      messages.

What I’m not sure of is how to guarantee/enforce that the knowledge/names provided
by the interface are effective (i.e. how to update the acquaintances list in each
involved engine instance).

Finally, what is an engine system? An engine system englobes all, the overall
system composed of engine system components.

We may later would like to talk about an open-world distributed system.
This construct could be an engine system interacting with other engine systems, where these other systems form together what I’d call the “outside”/“world”.

In Talcott’s Composable Semantics Models for Actor-theories, these systems are, for example, equipped with structure for (parallel) composition of their system components and other operations, not to be discussed here.

Shall we add the engine families to the ToC under engine groups like before?
Or list them in the ToC under Engine Families? Or both (not sure if possible)?
Listing them under engine groups like before would result in a clearer structure
I think.

In short, I’d say we should.

So, we have an entry point for engine families in the node architecture. Under
this section, we have an intro, the type of engine families, and the components
like definition of what an engine environment is, and the behaviour must be
defined (engine dynamics). But, yes, we have no engine family listed. So, we
could have:

- Node Architecture:
...
- Engine Family Background:
    - ./node_architecture/engines/index.md
    - Definitions:
        - Engine Environment: ./node_architecture/types/engine_environment.juvix.md
        - Engine Dynamics: ./node_architecture/types/engine_dynamics.juvix.md
        - Engine Family: ./node_architecture/types/engine_family.juvix.md
        - Anoma Message: ./node_architecture/types/anoma_message.juvix.md
        - Anoma Environment: ./node_architecture/types/anoma_environment.juvix.md
- Anoma Engine Families:
    - Timestamper Engine Family: ./node_architecture/engines/timestamp/index.md
    - Ticker Engine Family: ./node_architecture/engines/ticker/index.md (example)
- System Components:
    - ./node_architecture/components/index.md
    - Networking Component: 
        - ./node_architecture/components/networking/index.md
        - Networking engine instances:
            - ...

Also, describing how engine instances are spawned for each engine family,
(e.g. whether an engine has a single instance launched at node start, or many
instances spawed during runtime, and if so how).

Sorry, we missed this matter in the Ticker example. I’d should open a PR to fix
this. Engine Spawing, technically speaking, only requires you to know the type of environment for your engine. Where do you specify which engines spawn? That goes in the behaviour description of your engine instance, their dynamics. When defining the “action” instances of your engine family, you have a field for spawning engines.

See Engine Dynamics - Anoma Specification

type ActionEffect (S I M H A L X : Type) :=
  mkActionEffect {
    newEnv : EngineEnvironment S I M H;
    producedMessages : List (EnvelopedMessage Anoma.Msg);
    timers : List (Timer H);
    spawnedEngines : List Anoma.Env
  };

Also, once you have defined an engine family, the type of engine instances follows. We want to instantiate the Engine type (cf. the definition in the
specs).

type Engine (S I M H A L X : Type) := mkEngine {
  name : Name;
  family : EngineFamily S I M H A L X;
  initEnv : EngineEnvironment S I M H;
};

Snippet from: Engine Family - Anoma Specification

For example, say we have a Ticker engine family. Then, we have a type of engine
instances, TickerEngine. That is, TickerEngine is the type for terms of the
Ticker engine family. (I am not sure if the following typechecks, but you get the
point)

zeroTickerEngine : TickerEngine :=
mkEngine {
  name := "zero";
  family := TickerEngineFamily;
  initEnv := mkEngineEnvironment {
    state := 0;
    mailbox := emptyMailbox;
    acquaintances := [];
    timers := [];
  };
};

Then, feel free to use this zeroTickerEngine to describe how the system
component uses this engine instance.

… Where shall we talk about these? In the engine family description or under
machines / engine groups?

Engine instances should be described when introducing a new engine system
component, say, Networking. Again, it’s my opinion.

Pending, while writing this to me, and to @graphomath,

  • how to organise engine system components into engine systems.
  • what semantics model to use for describing these engine systems,
    interaction paths?
  • Not exactly related, but worth bringing it up: as suggested by @tg-x once, perhaps a better folder structure is architecture/(node|system).

I extended my self, sorry: In short, I propose:

  • Engine Families go in node_architecture/engines: These define the behaviors that
    engine instances can exhibit.
  • System Components go in node_architecture/components: These compose engine instances into larger “units”.
  • Engine Systems go in node_architecture/systems: These compose system components into complete distributed systems.
2 Likes

I agree with this, I think using the word “machine” as we did is confusing, as it doesn’t refer to a distinct concept (just a group of engines with related functionality). I like “system component”.

I think, however, that we do need to differentiate somehow between system component families and system component instances, similar to differentiating between engine families and engine instances. To wit: a system component family should be a collection of engine families and instructions for how to instantiate them and connect them together (ideally, this itself is well-typed), while a system component instance should be an actual collection of engines, with actual connections and state.

Finally, what is an engine system? An engine system englobes all, the overall system composed of engine system components.

I am fine with this term, but I think before dedicating an entire subsection to engine systems, we should check that we actually have multiple ones. I’m not sure if we do. One way to structure a node is a single engine system which can be configured to run different engines at different times depending on available resources. Another way would be to have different engine systems for “full nodes”, “light nodes”, “validators”, etc. Did you have something specific in mind here?