Go to file
Mike Voronov 87f7e2f361
feat(execution-engine)!: make fold convergent wrt errors (#351)
fold over a stream was not convergent when errors are produced inside a fold body. After iteration, it produces if there were several errors, only the last one is bubbled up. But on the same peer, there could different last (and first) errors, and it'll become non-convergent and moreover non-deterministic.

After this PR fold won't bubble any errors to make execution convergent and deterministic. To obtain errors from a fold body one should wrap this body into xor and push errors into some stream. Then fold over this stream and handle errors.
2023-02-09 17:09:24 +03:00
.cargo ci: Update e2e (#378) 2022-11-16 14:49:51 +02:00
.github chore(ci): Release workflow fixes [fixes FLU-273] (#460) 2023-02-08 15:07:33 +02:00
air feat(execution-engine)!: make fold convergent wrt errors (#351) 2023-02-09 17:09:24 +03:00
air-interpreter chore: release master (#454) 2023-02-08 15:28:17 +03:00
avm chore(ci): Release workflow fixes [fixes FLU-273] (#460) 2023-02-08 15:07:33 +02:00
benches feat(tools): VM-194 performance metering (#440) 2023-02-03 23:26:06 +07:00
crates chore: release master (#454) 2023-02-08 15:28:17 +03:00
docs Document import scheme and doc comment style (#268) 2022-06-29 22:23:33 +03:00
images Update readme (#260) 2022-05-14 17:12:48 +03:00
junk/cidify chore(deps): update rust crate serde_json to 1.0.92 (#448) 2023-02-06 16:44:20 +03:00
tools chore: release master (#454) 2023-02-08 15:28:17 +03:00
.gitignore Rename Aqua to AIR, move AVM from FCE (#99) 2021-05-10 14:25:34 +03:00
Cargo.lock feat(execution-engine)!: make fold convergent wrt errors (#351) 2023-02-09 17:09:24 +03:00
Cargo.toml feat(tools): VM-194 performance metering (#440) 2023-02-03 23:26:06 +07:00
CHANGELOG.md feature(execution-engine): Canon data with CID (#419) 2023-01-09 13:22:57 +07:00
Config.toml Rename Aqua to AIR, move AVM from FCE (#99) 2021-05-10 14:25:34 +03:00
LICENSE Initial commit 2020-09-18 14:05:43 +03:00
next-hardfork-changes.md chore(docs): add more upcoming data changes (#450) 2023-02-07 21:09:22 +03:00
README.md update links (#370) 2022-10-26 12:49:31 +03:00
rust-toolchain.toml change pinned rust toolchain version (#418) 2022-12-27 11:03:12 +03:00

crates.io version npm version

AquaVM

AquaVM executes compiled Aqua, i.e., Aqua Intermediate Representation (AIR) scripts, and plays an integral part in the implementation of the Fluence peer-to-peer compute protocol. Specifically, AquaVM allows expressing network choreography in scripts and composing distributed, peer-to-peer hosted services. Moreover, AquaVM plays a significant role in facilitating function addressability in the Fluence network. Figure 1.

Figure 1: Stylized AquaVM And AIR Model

AquaVM & AIR model

Since AquaVM compiles to Wasm, it can run in both client, such as browsers and nodejs apps, and server environments.

AquaVM: Interpreter Execution Model

AquaVM's execution model facilitates Fluence protocol's data push model implemented as a particle, i.e., a smart packet comprised of data, AIR, and some metadata. In this context, AquaVM can be viewed as a pure state transition function that facilitates particle updates, which includes state management of particle data by taking previous and current state to produce a new state and an updated list of peers and call requests in the remaining AIR workflow. In addition to local service call execution, AquaVM handles requests from remote peers, e.g. as part of a parallel execution block, to call local services and handle the future response. See Figure 2.

Figure 2: AquaVM Interpreter Execution Model

interpreter execution model

In summary, the AquaVM execution model handles the topological hops for simple and advanced composition patters, such as (async) parallel service execution on one or multiple peers.

Aquamarine Intermediate Representation (AIR): IR For P2P Systems

AIR scripts control the Fluence peer-to-peer network, its peers and, through Marine adapter services, even resources on other (p2p) networks, such as IPFS and Filecoin, e.g., Fluence IPFS library.

What is AIR?

AIR: Instructions

call

(call <peer_id> (<service name> <service function>) [<arguments list>] <output name>)
  • moves execution to the peer_id specified
  • the peer is expected to host Wasm service with the specified service name
  • the service function is expected to contain the specified function
  • the arguments list is given to the function and may be empty
  • the result of the function execution is saved and returned by it's output name

Example:

(call "peer_id" ("dht" "put") [key value] result)

seq

(seq <left_instruction> <right_instruction>)
  • executes instructions sequentially: right_instruction will be executed iff left_instruction finished successfully

par

(par <left_instruction> <right_instruction>)
  • executes instructions in parallel: right_instruction will be executed independently of the completion of left_instruction

ap

(ap <literal> <dst_variable>)
(ap <src_variable>.$.<lambda> <dst_variable>)
  • puts literal into dst_variable
  • or applies lambda to src_variable and saves the result in dst_variable

Example:

(seq
    (call "peer_id" ("user-list" "get_users") [] users)
    (ap users.$.[0].peer_id user_0)
)

canon

(canon "peer_id" <$stream> <#canon_stream>)
  • executes on peer_id, takes $stream as it is on the moment of first canonicalization
  • every next execution #canon_stream will be the same — as first seen by peer_id

Example:

(seq
    (ap user $users)
    (canon "peer_id" $stream #canon_stream)
)

match/mismath

(match <variable> <variable> <instruction>)
(mismatch <variable> <variable> <instruction>)
  • executes the instruction iff variables are equal/notequal

Example:

(seq
    (call "peer_id" ("user-list" "get_users") [] users)
    (mismatch users.$.length 0
        (ap users.$.[0].peer_id user_0)
    )
)

fold/next

(fold <iterable> <iterator> <instruction>)
  • is a form of a fixed-point combinator
  • iterates through the iterable, assigning each element to the iterator
  • on each iteration instruction is executed
  • next triggers next iteration

Example:

(fold users user
    (seq
        (call user.$.peer_id ("chat" "display") [msg])
        (next user)
    )
)

xor

(xor <left_instruction> <right_instruction>)
  • right_instruction is executed iff left_instruction failed

new

(new <variable>)
  • creates a new scoped variable with the provided name (it's similar to \mu operator from pi-calculus that creates an anonymous channel)

fail

(fail <variable>)
(fail <error code> <error message>)
  • throws an exception with provided error code and error message or construct it from a provided variable]

Example

(fail 1337 "error message")

never

(never)
  • marks a subgraph as incomplete, useful for code generation

null

(null)
  • does nothing, useful for code generation

AIR: values

Scalars

  • scalars are fully consistent - have the same value on each peer during a script execution
  • could be an argument of any instruction
  • JSON-based (fold could iterate only over array-based value)

Streams

  • streams are CRDT-like (locally-consistent) - have deterministic execution wrt one peer
  • versioned
  • could be used only by call and fold instructions (more instructions for streams to come)
  • could be turned to scalar (canonicalized)

Canonicalized streams

  • contains an array of elements that was in a stream at the moment of canonicalization
  • canonicalized streams are imutable and fully consistent as scalars
  • has the same algebra as a stream for match/mismatch and call argument
  • has the same algebra as a scalar for new
  • has mixed behaviour for with other instructions