Skip to main content

Quick Start

Every Fluence reference node comes with a set of builtin services that are accessible to Aqua programs. Let's use those readily available services to get the timestamp of a few of our peer-to-peer neighborhood nodes with Aqua.

aqua
-- timestamp_getter.aqua
import "@fluencelabs/aqua-lib/builtin.aqua"
func ts_getter(node: string, num_peers: u32) -> []u64:
res: *u64
on node:
key <- Op.string_to_b58(node)
nodes <- Kademlia.neighborhood(key, nil, [num_peers])
for n <- nodes par:
on n:
try:
res <- Peer.timestamp_ms()
join res[num_peers - 1]
<- res
aqua
-- timestamp_getter.aqua
import "@fluencelabs/aqua-lib/builtin.aqua"
func ts_getter(node: string, num_peers: u32) -> []u64:
res: *u64
on node:
key <- Op.string_to_b58(node)
nodes <- Kademlia.neighborhood(key, nil, [num_peers])
for n <- nodes par:
on n:
try:
res <- Peer.timestamp_ms()
join res[num_peers - 1]
<- res

Let's explain this script line by line. First of all, it brings builtin services (see aqua-lib) in scope by import:

aqua
import "@fluencelabs/aqua-lib/builtin.aqua"
aqua
import "@fluencelabs/aqua-lib/builtin.aqua"

Next it defines a function named ts_getter with two parameters: node which is peer id and num_peers which is how many neighbors to check. That function returns array of obtained timestamps.

aqua
func ts_getter(node: string, num_peers: u32) -> []u64:
aqua
func ts_getter(node: string, num_peers: u32) -> []u64:

On the first line it creates stream variable (see CRDT Streams) res:

aqua
res: *u64
aqua
res: *u64

Then execution is transfered on peer with id that was passed in node (see on expression):

aqua
on node:
aqua
on node:

On node it obtains no more than num_peers neighbour nodes using builtin services:

aqua
key <- Op.string_to_b58(node)
nodes <- Kademlia.neighborhood(key, nil, [num_peers])
aqua
key <- Op.string_to_b58(node)
nodes <- Kademlia.neighborhood(key, nil, [num_peers])

After that for each of the obtained nodes in parallel (see Parallel for) it tries (see try) to push local timestamp to res:

aqua
for n <- nodes par:
on n:
try:
res <- Peer.timestamp_ms()
aqua
for n <- nodes par:
on n:
try:
res <- Peer.timestamp_ms()

Back on node element res[num_peers - 1] is joined (see join expression) thus making all results available:

aqua
join res[num_peers - 1]
aqua
join res[num_peers - 1]

Finally, stream is converted to scalar (see Streams Lifecycle) and returned:

aqua
<- res
aqua
<- res

See the ts-oracle example for the corresponding Aqua files in the aqua-script directory.

Now that we have our script, let's use Fluence CLI to run it:

sh
# use `fluence run` as your client with some peer id
fluence run \
--relay /dns4/kras-02.fluence.dev/tcp/19001/wss/p2p/12D3KooWHLxVhUQyAuZe6AHMB29P7wkvTNMn7eDMcsqimJYLKREf \
-i aqua-scripts/timestamp_getter.aqua \
-f 'ts_getter("12D3KooWHLxVhUQyAuZe6AHMB29P7wkvTNMn7eDMcsqimJYLKREf", 10)'
sh
# use `fluence run` as your client with some peer id
fluence run \
--relay /dns4/kras-02.fluence.dev/tcp/19001/wss/p2p/12D3KooWHLxVhUQyAuZe6AHMB29P7wkvTNMn7eDMcsqimJYLKREf \
-i aqua-scripts/timestamp_getter.aqua \
-f 'ts_getter("12D3KooWHLxVhUQyAuZe6AHMB29P7wkvTNMn7eDMcsqimJYLKREf", 10)'

And that's it. We now have ten timestamps right from our selected peer's neighbors.

Note that if you try to request too many peers, execution could halt.