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.aquaimport "@fluencelabs/aqua-lib/builtin.aqua"func ts_getter(node: string, num_peers: u32) -> []u64:res: *u64on 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.aquaimport "@fluencelabs/aqua-lib/builtin.aqua"func ts_getter(node: string, num_peers: u32) -> []u64:res: *u64on 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:
- Run
- Result
sh
# use `fluence run` as your client with some peer idfluence 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 idfluence run \--relay /dns4/kras-02.fluence.dev/tcp/19001/wss/p2p/12D3KooWHLxVhUQyAuZe6AHMB29P7wkvTNMn7eDMcsqimJYLKREf \-i aqua-scripts/timestamp_getter.aqua \-f 'ts_getter("12D3KooWHLxVhUQyAuZe6AHMB29P7wkvTNMn7eDMcsqimJYLKREf", 10)'
Here we go. Ten timestamps in micro seconds obtained in parallel:
json
[[1624928596292,1624928596291,1624928596291,1624928596299,1624928596295,1624928596286,1624928596295,1624928596284,1624928596293,1624928596289]]
json
[[1624928596292,1624928596291,1624928596291,1624928596299,1624928596295,1624928596286,1624928596295,1624928596284,1624928596293,1624928596289]]
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.