diff --git a/aqua-examples/echo-greeter/aqua/echo_greeter.aqua b/aqua-examples/echo-greeter/aqua/echo_greeter.aqua index d86c2ca..0b8c4c2 100644 --- a/aqua-examples/echo-greeter/aqua/echo_greeter.aqua +++ b/aqua-examples/echo-greeter/aqua/echo_greeter.aqua @@ -73,7 +73,6 @@ func echo_greeting_par(greet: bool, echo_service: EchoServiceInput, greeting_ser on greeting_service.node: res <- GreetingService.greeting(result.echo, greet) Op.noop() - -- OpString.identity(res!5) join res[5] <- res diff --git a/aqua-examples/price-oracle/README.md b/aqua-examples/price-oracle/README.md deleted file mode 100644 index a142329..0000000 --- a/aqua-examples/price-oracle/README.md +++ /dev/null @@ -1,253 +0,0 @@ -# Price Oracle With Fluence And Aqua - - -## About Fluence - -Fluence provides an open Web3 protocol, framework and associated tooling to develop and host applications, interfaces and backends on permissionless peer-to-peer networks. An integral part of the Fluence solution is the Aquamarine stack comprised of Aqua and Marine. Aqua is a new programming language and paradigm purpose-built to program distributed networks and compose applications from distributed services. Marine is a general purpose Wasm runtime and toolkit, allows developers to build distributed services that can be composed into distributed applications by Aqua. - -Fluence Developer Resources: - -* [Developer Documentation](https://doc.fluence.dev/docs/) - -Aqua Developer Resources: - -* [Aqua Book](https://app.gitbook.com/@fluence/s/aqua-book/) -* [Aqua Playground](https://github.com/fluencelabs/aqua-playground) -* [Aqua repo](https://github.com/fluencelabs/aqua) - - Marine Developer Resources: - -* [Marine repo](https://github.com/fluencelabs/marine) -* [Marine SDK](https://github.com/fluencelabs/marine-rs-sdk) - - -## Overview - -Price (feed) oracles are probably the most used and in-demand oracle type and tend to have a significant impact on the success and profitability of DeFi and related on- and off-chain operations. In this example, we demonstrate how to create a decentralized, off-chain price (feed) oracle on the Fluence peer-to-peer network from a set of distributed, re-usable Marine services composed by Aqua. - -Figure 1: Stylized Price Oracle Network And Service Process -

- -

- -As outlined in Figure 1, we use one or more services distributed across the Fluence peer-to-peer network to obtain price quotes from sources. For example, we could have one service capable of querying one or more sources such as DEX contracts deployed on multiple network peers allowing us to poll price sources in parallel. We then join these results and submit them to a processing service also deployed on the peer-to-peer network to establish, for example, an oracle point-estimate. Once we've obtained our oracle, we return it to the peer-client, e.g., a browser. - -## Quick Start - -Let's get right to it: - -```bash -% cd web -% npm install -% npm start -``` - -opens a browser tab allowing you to enter the coin name and currency to price it in. In return, you get the oracle from the processed individual price quotes. See Figure 2. - -Figure 2: Browser Peer Client For Price Oracle Application - - - -Please note that the coin name must the full name, e.g., ethereum or bitcoin instead of eth or btc, whereas currency is specified in the traditional ISO 4217 Alpha-3 codes. - -If you like things a little closer to metal, see the [client-peer](./client-peer) directory for a peer-client based on the Fluence JS-SDK. To run the headless client: - -```bash -% cd client-peer -% npm instal -% npm start run -``` - -which gives us: - -```text -# -hello crypto investors -created a fluence client 12D3KooWEKui98wfChxaPou6qcNcH5zY3LzfXRwJbTViKUdY7aWi with relay 12D3KooWFEwNWcHqi9rtsmDhsYcDbRUCDXH84RC4FW6UfsFWaoHi -seq result: { error_msg: '', result: 3989.19, success: true } -par result: { error_msg: '', result: 3674.25, success: true } -``` - -As evident from our results, we are executing two different workflows to get our price oracle: the first approach uses one price getter service twice in sequence and the second approach uses two price getter services deployed on different hosts in parallel. See the code example below. - -```typescript -// client-peer/index.ts -import { Fluence } from "@fluencelabs/fluence"; -import { krasnodar, Node } from "@fluencelabs/fluence-network-environment"; -import { get_price, get_price_par } from "./_aqua/get_crypto_prices"; - -interface NodeServicePair { - node: string; - service_id: string; -} - -// (node, service) tuples, json-style, for price getter services -let getter_topo: Array; -let mean_topo: NodeServicePair; - -// description of the services' locations, copypaste from data/deployed_services.json -getter_topo = [ - { - node: "12D3KooWCMr9mU894i8JXAFqpgoFtx6qnV1LFPSfVc3Y34N4h4LS", - service_id: "b67586f7-e96f-49ee-914e-9eabe1a0b83d", - }, - { - node: "12D3KooWFEwNWcHqi9rtsmDhsYcDbRUCDXH84RC4FW6UfsFWaoHi", - service_id: "f5b456fa-ee18-4df1-b18b-84fe7ebc7ad0", - } -]; -mean_topo = [ - { - node: "12D3KooWCMr9mU894i8JXAFqpgoFtx6qnV1LFPSfVc3Y34N4h4LS", - service_id: "79b8ddb9-e2e6-4924-9293-c5d55c94af6b", - }, - { - node: "12D3KooWFEwNWcHqi9rtsmDhsYcDbRUCDXH84RC4FW6UfsFWaoHi", - service_id: "debecd02-ba7d-40a2-92ab-08a9321da2cf" - } -]; - -async function main() { - // create the Fluence client for the Krasnodar testnet - await Fluence.start({ connectTo: krasnodar[5] }); - - // call the get_price function -- sequential processing - const network_result = await get_price( - "ethereum", "usd", - getter_topo[1].node, getter_topo[1].service_id, mean_topo[1].service_id - ); - console.log("seq result: ", network_result); - - // call the get_price_par function -- parallel processing - const network_result_par = await get_price_par("ethereum", "usd", getter_topo, mean_topo[0]); - console.log("par result: ", network_result_par); - - await Fluence.stop(); -} -``` - -where the Aqua script can be found in the `aqua-scripts` dirctory and the compiled Aqua code is found in the `get_crypto_prices.ts` file. For more on the Aqua script, see below. - -## Service Development And Deployment - -**Prerequisites:** If you want to follow along, compile Wasm modules, create services and deploy service, you need Rust, Node and a few Fluence tools installed. Please see follow the [Setup](https://doc.fluence.dev/docs/tutorials_tutorials/recipes_setting_up) instructions. - -Applications are composed from one or more services available on one or more Fluence peer-to-peer nodes. Services are comprised of one or more Wasm modules providing a wide range of compute functionality and access to persistance, e.g. IPFS and SQLite. For the purpose of our objective, we need a service that can call on some API to source price quotes. In an ideal, production world, this would be calling on a large set of DEX contacts to obtain price pairs and, say, lquidity, over a particular window of time. For our purposes, we simplify the process and call on the [Coingecko API](https://www.coingecko.com/api/documentations/v3) and add a random jitter to each quote retrieved to give us some variance. - -For implementation details, see [price_getter_service]("./../price_getter_service/src/main.rs), which compiles to our desired wasm32-wasi target. Since Wasm modules don't have sockets but we need to use cUrl, which is provided by the host node. In order to do that, we fist need to write an adapter that allows us to access the cUrl service from a Wasm module and then link that service to our price_getter service. See [cUrl adapter example](./marine-scripts/curl_adapter) for more details on the implementation of our [curl adapter service](./curl_adapter/src/main.rs). - -Figure 3: Stylized Service Creation By Marine Module Linking - - - -As seen in Figure 3, we link the price_getter module and curl adapter module into a price_getter service ready for deployment to the Fluence peer-to-peer network. Before we proceed, we have one more service to consider: the price quote processing service which yields the oracle. Again, we simplified what could be an extensive processing algorithm into a simple mean calculation, see [mean_service]("./../mean_service/src/main.rs") for implementation details. Unlike the price getter service, mean service is a simple, FaaS compute module that deploys on any number of network peers. - -We now have our code in place and area ready to compile and our compilation instructions are contain in the `scripts/build.sh` script, which basically instructs the the code is compiled with `marine` and that the resulting Wasm modules are copied to the `artifacts` directory. In the project directory: - -```bash -./scripts/build.sh -``` - -which gives you the updated Wasm modules in the `artifacts` directory. - -The next step is to deploy the two services to one or more peers and we use the `fldist` tool to get this done. First, we need to now what peers are available and we can get an enumeration from: - -```bash -fldist env -``` - -*Please note that multiple service instances have been already deployed and the (peer id, service id) tuples can be found in [data]("./data/deployed_services.json) json file. While your more than welcome to deploy your services, you don't have to in order to use them.* - -Pick any of the peer ids from the listed peers to deploy your services. Let's say we use peer id `12D3KooWFEwNWcHqi9rtsmDhsYcDbRUCDXH84RC4FW6UfsFWaoHi`: - -```bash -$ fldist --node-id 12D3KooWFEwNWcHqi9rtsmDhsYcDbRUCDXH84RC4FW6UfsFWaoHi new_service --ms artifacts/curl_adapter.wasm:configs/curl_adapter_cfg.json artifacts/price_getter_service.wasm:configs/price_getter_service_cfg.json --name price-getter-service-0 -service id: f5b456fa-ee18-4df1-b18b-84fe7ebc7ad0 # <--- REMEMBER service id !! -service created successfully -``` - -to deploy a price-getter service and - -```bash -$ fldist --node-id 12D3KooWFEwNWcHqi9rtsmDhsYcDbRUCDXH84RC4FW6UfsFWaoHi new_service --ms artifacts/mean_service.wasm:configs/mean_service_cfg.json --name mean-service-0 -service id: debecd02-ba7d-40a2-92ab-08a9321da2cf # <--- REMEMBER service id !! -service created successfully -``` - -to deploy a mean service. Please take note of the service-id you get back for each fo the deployments, which are needed to locate the service in the future. - -That's it for service development and deployment! - -## Application Composition with Aqua - -Aqua allows us to compose distributed services into decentralized applications such as our price oracle app. However, Aqua permits a great degree of freedom of *how* to compose services. As Aqua combines [Layer 3 and Layer 7](https://en.wikipedia.org/wiki/OSI_model) programming, i.e., network and application programming, respectively, Aqua allows us to specify parallel or sequential workflows in response to service availability and deployment. - -For example, the `get_price` function in `aqua-scripts/get_crypto_prices.aqua` makes two sequential calls to the price_getter service on one node before calling the mean service and finally, return the result to the peer client. - -```aqua --- aqua-scripts/get_crypto_prices.aqua -func get_price(coin: string, currency: string, node: string, pg_sid: string, mean_sid: string) -> Result: - prices: *f64 - on node: --< On this peer - k <- Op.string_to_b58(node) - - PriceGetterService pg_sid --< Init service binding with service_id - MeanService mean_sid --< Init service binding with mean service_id - - ts_ms0 <- Peer.timestamp_ms() - res0 <- PriceGetterService.price_getter(coin, currency, ts_ms0) --< First call to service - prices <- F64Op.identity(res0.result) - - ts_ms1 <- Peer.timestamp_ms() - res1 <- PriceGetterService.price_getter(coin, currency, ts_ms1) --< Second call to service, in sequence - prices <- F64Op.identity(res1.result) - - result <- MeanService.mean(prices) --< Process price quotes with mean service - - <- result --< Return result to client peer -``` - -With just a few lines of code, we can program the network and application layers to compose hose peer-topeer services into powerful decentralized applications. However, with a little more preparation, i.e., more deployed services, we can vastly improve and scale our solution. How? By parallelizing our workflow. In the file, `aqua-scripts/get_crypto_prices.aqua`, look at the `get_price_par` function: - -```aqua --- aqua-scripts/get_crypto_prices.aqua - -data NodeServicePair: - node: string - service_id: string - -func get_price_par(coin: string, currency: string, getter_topo: []NodeServicePair, mean_topo: NodeServicePair) -> Result: - prices: *f64 - for topo <- getter_topo par: --< For each instance of the getter topology in parallel - on topo.node: --< On each specified node - k <- Op.string_to_b58(topo.node) - - PriceGetterService topo.service_id --< And service id - ts_ms <- Peer.timestamp_ms() - res <- PriceGetterService.price_getter(coin, currency, ts_ms) --< Run the price getter service to obtain a quote - prices <- F64Op.identity(res.result) - - on mean_topo.node: --< After the parallel loop, create the Mean service binding on the specified node - MeanService mean_topo.service_id - result <- MeanService.mean(prices) --< Process the price quote array - <- result --< Return the result to the client peer - -``` - -In this invocation of our application workflow, we process price quote acquisition in parallel over price_getter services deployed to many nodes. This allows us to scale our workflow and take sull advantage of the network size and service deployment commitments. - -To compile our Aqua script, we use the `aqua` tool and either compile our code to raw Air: - -```text -% aqua -i aqua-scripts -o air-scripts -a -``` - -or to a ready-made typescript stub: - -```text -% aqua -i aqua-scripts -o air-scripts -``` - -## Summary - -We illustrated different ways to create decentralized price oracle applications with Aqua and the Fluence stack by reusing existing services hosted on network peers. While the implementations for both price getter and oracle, i.e., mean, services are stylized, it should be quite apparent that the Fluence stack is well suited for a broad range of Web3 off-chain applications including price (feed) oracles. diff --git a/aqua-examples/price-oracle/client-peer/package.json b/aqua-examples/price-oracle/client-peer/package.json index b6cc9cd..46904f3 100644 --- a/aqua-examples/price-oracle/client-peer/package.json +++ b/aqua-examples/price-oracle/client-peer/package.json @@ -18,7 +18,7 @@ "it-all": "^1.0.5" }, "scripts": { - "compile-aqua": "aqua -i ../aqua-scripts -o src/_aqua", + "compile-aqua": "aqua -i ../aqua -o src/_aqua", "prebuild": "npm run compile-aqua", "build": "tsc", "prestart:local": "npm run build", diff --git a/aqua-examples/price-oracle/web/src/_aqua/builtin.ts b/aqua-examples/price-oracle/web/src/_aqua/builtin.ts deleted file mode 100644 index f7c722d..0000000 --- a/aqua-examples/price-oracle/web/src/_aqua/builtin.ts +++ /dev/null @@ -1,770 +0,0 @@ -/** - * - * This file is auto-generated. Do not edit manually: changes may be erased. - * Generated by Aqua compiler: https://github.com/fluencelabs/aqua/. - * If you find any bugs, please write an issue on GitHub: https://github.com/fluencelabs/aqua/issues - * Aqua version: 0.3.2-233 - * - */ -import { Fluence, FluencePeer } from '@fluencelabs/fluence'; -import { - ResultCodes, - RequestFlow, - RequestFlowBuilder, - CallParams -} from '@fluencelabs/fluence/dist/internal/compilerSupport/v1'; - - -function missingFields(obj: any, fields: string[]): string[] { - return fields.filter(f => !(f in obj)) -} - -// Services - -export interface SrvDef { - add_alias: (alias: string, service_id: string, callParams: CallParams<'alias' | 'service_id'>) => void; -create: (blueprint_id: string, callParams: CallParams<'blueprint_id'>) => string; -get_interface: (service_id: string, callParams: CallParams<'service_id'>) => { function_signatures: { arguments: string[][]; name: string; output_types: string[]; }[]; record_types: { fields: string[][]; id: number; name: string; }[]; }; -list: (callParams: CallParams) => { blueprint_id: string; id: string; owner_id: string; }[]; -remove: (service_id: string, callParams: CallParams<'service_id'>) => void; -resolve_alias: (alias: string, callParams: CallParams<'alias'>) => string; -} -export function registerSrv(service: SrvDef): void; -export function registerSrv(serviceId: string, service: SrvDef): void; -export function registerSrv(peer: FluencePeer, service: SrvDef): void; -export function registerSrv(peer: FluencePeer, serviceId: string, service: SrvDef): void; - - -export function registerSrv(...args: any) { - let peer: FluencePeer; - let serviceId: any; - let service: any; - if (FluencePeer.isInstance(args[0])) { - peer = args[0]; - } else { - peer = Fluence.getPeer(); - } - - if (typeof args[0] === 'string') { - serviceId = args[0]; - } else if (typeof args[1] === 'string') { - serviceId = args[1]; - } else { - serviceId = "srv" - } - - // Figuring out which overload is the service. - // If the first argument is not Fluence Peer and it is an object, then it can only be the service def - // If the first argument is peer, we are checking further. The second argument might either be - // an object, that it must be the service object - // or a string, which is the service id. In that case the service is the third argument - if (!(FluencePeer.isInstance(args[0])) && typeof args[0] === 'object') { - service = args[0]; - } else if (typeof args[1] === 'object') { - service = args[1]; - } else { - service = args[2]; - } - - const incorrectServiceDefinitions = missingFields(service, ['add_alias', 'create', 'get_interface', 'list', 'remove', 'resolve_alias']); - if (!!incorrectServiceDefinitions.length) { - throw new Error("Error registering service Srv: missing functions: " + incorrectServiceDefinitions.map((d) => "'" + d + "'").join(", ")) - } - - peer.internals.callServiceHandler.use((req, resp, next) => { - if (req.serviceId !== serviceId) { - next(); - return; - } - - if (req.fnName === 'add_alias') { - const callParams = { - ...req.particleContext, - tetraplets: { - alias: req.tetraplets[0],service_id: req.tetraplets[1] - }, - }; - resp.retCode = ResultCodes.success; - service.add_alias(req.args[0], req.args[1], callParams); resp.result = {} - } - -if (req.fnName === 'create') { - const callParams = { - ...req.particleContext, - tetraplets: { - blueprint_id: req.tetraplets[0] - }, - }; - resp.retCode = ResultCodes.success; - resp.result = service.create(req.args[0], callParams) - } - -if (req.fnName === 'get_interface') { - const callParams = { - ...req.particleContext, - tetraplets: { - service_id: req.tetraplets[0] - }, - }; - resp.retCode = ResultCodes.success; - resp.result = service.get_interface(req.args[0], callParams) - } - -if (req.fnName === 'list') { - const callParams = { - ...req.particleContext, - tetraplets: { - - }, - }; - resp.retCode = ResultCodes.success; - resp.result = service.list(callParams) - } - -if (req.fnName === 'remove') { - const callParams = { - ...req.particleContext, - tetraplets: { - service_id: req.tetraplets[0] - }, - }; - resp.retCode = ResultCodes.success; - service.remove(req.args[0], callParams); resp.result = {} - } - -if (req.fnName === 'resolve_alias') { - const callParams = { - ...req.particleContext, - tetraplets: { - alias: req.tetraplets[0] - }, - }; - resp.retCode = ResultCodes.success; - resp.result = service.resolve_alias(req.args[0], callParams) - } - - next(); - }); -} - - - -export interface PeerDef { - connect: (id: string, multiaddrs: string[] | null, callParams: CallParams<'id' | 'multiaddrs'>) => boolean; -get_contact: (peer: string, callParams: CallParams<'peer'>) => { addresses: string[]; peer_id: string; }; -identify: (callParams: CallParams) => { external_addresses: string[]; }; -is_connected: (peer: string, callParams: CallParams<'peer'>) => boolean; -timestamp_ms: (callParams: CallParams) => number; -timestamp_sec: (callParams: CallParams) => number; -} -export function registerPeer(service: PeerDef): void; -export function registerPeer(serviceId: string, service: PeerDef): void; -export function registerPeer(peer: FluencePeer, service: PeerDef): void; -export function registerPeer(peer: FluencePeer, serviceId: string, service: PeerDef): void; - - -export function registerPeer(...args: any) { - let peer: FluencePeer; - let serviceId: any; - let service: any; - if (FluencePeer.isInstance(args[0])) { - peer = args[0]; - } else { - peer = Fluence.getPeer(); - } - - if (typeof args[0] === 'string') { - serviceId = args[0]; - } else if (typeof args[1] === 'string') { - serviceId = args[1]; - } else { - serviceId = "peer" - } - - // Figuring out which overload is the service. - // If the first argument is not Fluence Peer and it is an object, then it can only be the service def - // If the first argument is peer, we are checking further. The second argument might either be - // an object, that it must be the service object - // or a string, which is the service id. In that case the service is the third argument - if (!(FluencePeer.isInstance(args[0])) && typeof args[0] === 'object') { - service = args[0]; - } else if (typeof args[1] === 'object') { - service = args[1]; - } else { - service = args[2]; - } - - const incorrectServiceDefinitions = missingFields(service, ['connect', 'get_contact', 'identify', 'is_connected', 'timestamp_ms', 'timestamp_sec']); - if (!!incorrectServiceDefinitions.length) { - throw new Error("Error registering service Peer: missing functions: " + incorrectServiceDefinitions.map((d) => "'" + d + "'").join(", ")) - } - - peer.internals.callServiceHandler.use((req, resp, next) => { - if (req.serviceId !== serviceId) { - next(); - return; - } - - if (req.fnName === 'connect') { - const callParams = { - ...req.particleContext, - tetraplets: { - id: req.tetraplets[0],multiaddrs: req.tetraplets[1] - }, - }; - resp.retCode = ResultCodes.success; - resp.result = service.connect(req.args[0], req.args[1].length === 0 ? null : req.args[1][0], callParams) - } - -if (req.fnName === 'get_contact') { - const callParams = { - ...req.particleContext, - tetraplets: { - peer: req.tetraplets[0] - }, - }; - resp.retCode = ResultCodes.success; - resp.result = service.get_contact(req.args[0], callParams) - } - -if (req.fnName === 'identify') { - const callParams = { - ...req.particleContext, - tetraplets: { - - }, - }; - resp.retCode = ResultCodes.success; - resp.result = service.identify(callParams) - } - -if (req.fnName === 'is_connected') { - const callParams = { - ...req.particleContext, - tetraplets: { - peer: req.tetraplets[0] - }, - }; - resp.retCode = ResultCodes.success; - resp.result = service.is_connected(req.args[0], callParams) - } - -if (req.fnName === 'timestamp_ms') { - const callParams = { - ...req.particleContext, - tetraplets: { - - }, - }; - resp.retCode = ResultCodes.success; - resp.result = service.timestamp_ms(callParams) - } - -if (req.fnName === 'timestamp_sec') { - const callParams = { - ...req.particleContext, - tetraplets: { - - }, - }; - resp.retCode = ResultCodes.success; - resp.result = service.timestamp_sec(callParams) - } - - next(); - }); -} - - - -export interface OpDef { - array: (a: string, b: string | null, c: string | null, d: string | null, callParams: CallParams<'a' | 'b' | 'c' | 'd'>) => string[]; -array_length: (array: string[], callParams: CallParams<'array'>) => number; -bytes_from_b58: (b: string, callParams: CallParams<'b'>) => number[]; -bytes_to_b58: (bs: number[], callParams: CallParams<'bs'>) => string; -concat: (a: string[], b: string[] | null, c: string[] | null, d: string[] | null, callParams: CallParams<'a' | 'b' | 'c' | 'd'>) => string[]; -identity: (s: string | null, callParams: CallParams<'s'>) => string | null; -noop: (callParams: CallParams) => void; -sha256_string: (s: string, callParams: CallParams<'s'>) => string; -string_from_b58: (b: string, callParams: CallParams<'b'>) => string; -string_to_b58: (s: string, callParams: CallParams<'s'>) => string; -} -export function registerOp(service: OpDef): void; -export function registerOp(serviceId: string, service: OpDef): void; -export function registerOp(peer: FluencePeer, service: OpDef): void; -export function registerOp(peer: FluencePeer, serviceId: string, service: OpDef): void; - - -export function registerOp(...args: any) { - let peer: FluencePeer; - let serviceId: any; - let service: any; - if (FluencePeer.isInstance(args[0])) { - peer = args[0]; - } else { - peer = Fluence.getPeer(); - } - - if (typeof args[0] === 'string') { - serviceId = args[0]; - } else if (typeof args[1] === 'string') { - serviceId = args[1]; - } else { - serviceId = "op" - } - - // Figuring out which overload is the service. - // If the first argument is not Fluence Peer and it is an object, then it can only be the service def - // If the first argument is peer, we are checking further. The second argument might either be - // an object, that it must be the service object - // or a string, which is the service id. In that case the service is the third argument - if (!(FluencePeer.isInstance(args[0])) && typeof args[0] === 'object') { - service = args[0]; - } else if (typeof args[1] === 'object') { - service = args[1]; - } else { - service = args[2]; - } - - const incorrectServiceDefinitions = missingFields(service, ['array', 'array_length', 'bytes_from_b58', 'bytes_to_b58', 'concat', 'identity', 'noop', 'sha256_string', 'string_from_b58', 'string_to_b58']); - if (!!incorrectServiceDefinitions.length) { - throw new Error("Error registering service Op: missing functions: " + incorrectServiceDefinitions.map((d) => "'" + d + "'").join(", ")) - } - - peer.internals.callServiceHandler.use((req, resp, next) => { - if (req.serviceId !== serviceId) { - next(); - return; - } - - if (req.fnName === 'array') { - const callParams = { - ...req.particleContext, - tetraplets: { - a: req.tetraplets[0],b: req.tetraplets[1],c: req.tetraplets[2],d: req.tetraplets[3] - }, - }; - resp.retCode = ResultCodes.success; - resp.result = service.array(req.args[0], req.args[1].length === 0 ? null : req.args[1][0], req.args[2].length === 0 ? null : req.args[2][0], req.args[3].length === 0 ? null : req.args[3][0], callParams) - } - -if (req.fnName === 'array_length') { - const callParams = { - ...req.particleContext, - tetraplets: { - array: req.tetraplets[0] - }, - }; - resp.retCode = ResultCodes.success; - resp.result = service.array_length(req.args[0], callParams) - } - -if (req.fnName === 'bytes_from_b58') { - const callParams = { - ...req.particleContext, - tetraplets: { - b: req.tetraplets[0] - }, - }; - resp.retCode = ResultCodes.success; - resp.result = service.bytes_from_b58(req.args[0], callParams) - } - -if (req.fnName === 'bytes_to_b58') { - const callParams = { - ...req.particleContext, - tetraplets: { - bs: req.tetraplets[0] - }, - }; - resp.retCode = ResultCodes.success; - resp.result = service.bytes_to_b58(req.args[0], callParams) - } - -if (req.fnName === 'concat') { - const callParams = { - ...req.particleContext, - tetraplets: { - a: req.tetraplets[0],b: req.tetraplets[1],c: req.tetraplets[2],d: req.tetraplets[3] - }, - }; - resp.retCode = ResultCodes.success; - resp.result = service.concat(req.args[0], req.args[1].length === 0 ? null : req.args[1][0], req.args[2].length === 0 ? null : req.args[2][0], req.args[3].length === 0 ? null : req.args[3][0], callParams) - } - -if (req.fnName === 'identity') { - const callParams = { - ...req.particleContext, - tetraplets: { - s: req.tetraplets[0] - }, - }; - resp.retCode = ResultCodes.success; - - var respResult = service.identity(req.args[0].length === 0 ? null : req.args[0][0], callParams); - resp.result = respResult === null ? [] : [respResult] - - } - -if (req.fnName === 'noop') { - const callParams = { - ...req.particleContext, - tetraplets: { - - }, - }; - resp.retCode = ResultCodes.success; - service.noop(callParams); resp.result = {} - } - -if (req.fnName === 'sha256_string') { - const callParams = { - ...req.particleContext, - tetraplets: { - s: req.tetraplets[0] - }, - }; - resp.retCode = ResultCodes.success; - resp.result = service.sha256_string(req.args[0], callParams) - } - -if (req.fnName === 'string_from_b58') { - const callParams = { - ...req.particleContext, - tetraplets: { - b: req.tetraplets[0] - }, - }; - resp.retCode = ResultCodes.success; - resp.result = service.string_from_b58(req.args[0], callParams) - } - -if (req.fnName === 'string_to_b58') { - const callParams = { - ...req.particleContext, - tetraplets: { - s: req.tetraplets[0] - }, - }; - resp.retCode = ResultCodes.success; - resp.result = service.string_to_b58(req.args[0], callParams) - } - - next(); - }); -} - - - -export interface KademliaDef { - merge: (target: string, left: string[], right: string[], count: number | null, callParams: CallParams<'target' | 'left' | 'right' | 'count'>) => string[]; -neighborhood: (key: string, already_hashed: boolean | null, count: number | null, callParams: CallParams<'key' | 'already_hashed' | 'count'>) => string[]; -} -export function registerKademlia(service: KademliaDef): void; -export function registerKademlia(serviceId: string, service: KademliaDef): void; -export function registerKademlia(peer: FluencePeer, service: KademliaDef): void; -export function registerKademlia(peer: FluencePeer, serviceId: string, service: KademliaDef): void; - - -export function registerKademlia(...args: any) { - let peer: FluencePeer; - let serviceId: any; - let service: any; - if (FluencePeer.isInstance(args[0])) { - peer = args[0]; - } else { - peer = Fluence.getPeer(); - } - - if (typeof args[0] === 'string') { - serviceId = args[0]; - } else if (typeof args[1] === 'string') { - serviceId = args[1]; - } else { - serviceId = "kad" - } - - // Figuring out which overload is the service. - // If the first argument is not Fluence Peer and it is an object, then it can only be the service def - // If the first argument is peer, we are checking further. The second argument might either be - // an object, that it must be the service object - // or a string, which is the service id. In that case the service is the third argument - if (!(FluencePeer.isInstance(args[0])) && typeof args[0] === 'object') { - service = args[0]; - } else if (typeof args[1] === 'object') { - service = args[1]; - } else { - service = args[2]; - } - - const incorrectServiceDefinitions = missingFields(service, ['merge', 'neighborhood']); - if (!!incorrectServiceDefinitions.length) { - throw new Error("Error registering service Kademlia: missing functions: " + incorrectServiceDefinitions.map((d) => "'" + d + "'").join(", ")) - } - - peer.internals.callServiceHandler.use((req, resp, next) => { - if (req.serviceId !== serviceId) { - next(); - return; - } - - if (req.fnName === 'merge') { - const callParams = { - ...req.particleContext, - tetraplets: { - target: req.tetraplets[0],left: req.tetraplets[1],right: req.tetraplets[2],count: req.tetraplets[3] - }, - }; - resp.retCode = ResultCodes.success; - resp.result = service.merge(req.args[0], req.args[1], req.args[2], req.args[3].length === 0 ? null : req.args[3][0], callParams) - } - -if (req.fnName === 'neighborhood') { - const callParams = { - ...req.particleContext, - tetraplets: { - key: req.tetraplets[0],already_hashed: req.tetraplets[1],count: req.tetraplets[2] - }, - }; - resp.retCode = ResultCodes.success; - resp.result = service.neighborhood(req.args[0], req.args[1].length === 0 ? null : req.args[1][0], req.args[2].length === 0 ? null : req.args[2][0], callParams) - } - - next(); - }); -} - - - -export interface ScriptDef { - add: (air_script: string, interval: string | null, callParams: CallParams<'air_script' | 'interval'>) => string; -list: (callParams: CallParams) => { failures: number; id: string; interval: string; owner: string; src: string; }; -remove: (script_id: string, callParams: CallParams<'script_id'>) => boolean; -} -export function registerScript(service: ScriptDef): void; -export function registerScript(serviceId: string, service: ScriptDef): void; -export function registerScript(peer: FluencePeer, service: ScriptDef): void; -export function registerScript(peer: FluencePeer, serviceId: string, service: ScriptDef): void; - - -export function registerScript(...args: any) { - let peer: FluencePeer; - let serviceId: any; - let service: any; - if (FluencePeer.isInstance(args[0])) { - peer = args[0]; - } else { - peer = Fluence.getPeer(); - } - - if (typeof args[0] === 'string') { - serviceId = args[0]; - } else if (typeof args[1] === 'string') { - serviceId = args[1]; - } else { - serviceId = "script" - } - - // Figuring out which overload is the service. - // If the first argument is not Fluence Peer and it is an object, then it can only be the service def - // If the first argument is peer, we are checking further. The second argument might either be - // an object, that it must be the service object - // or a string, which is the service id. In that case the service is the third argument - if (!(FluencePeer.isInstance(args[0])) && typeof args[0] === 'object') { - service = args[0]; - } else if (typeof args[1] === 'object') { - service = args[1]; - } else { - service = args[2]; - } - - const incorrectServiceDefinitions = missingFields(service, ['add', 'list', 'remove']); - if (!!incorrectServiceDefinitions.length) { - throw new Error("Error registering service Script: missing functions: " + incorrectServiceDefinitions.map((d) => "'" + d + "'").join(", ")) - } - - peer.internals.callServiceHandler.use((req, resp, next) => { - if (req.serviceId !== serviceId) { - next(); - return; - } - - if (req.fnName === 'add') { - const callParams = { - ...req.particleContext, - tetraplets: { - air_script: req.tetraplets[0],interval: req.tetraplets[1] - }, - }; - resp.retCode = ResultCodes.success; - resp.result = service.add(req.args[0], req.args[1].length === 0 ? null : req.args[1][0], callParams) - } - -if (req.fnName === 'list') { - const callParams = { - ...req.particleContext, - tetraplets: { - - }, - }; - resp.retCode = ResultCodes.success; - resp.result = service.list(callParams) - } - -if (req.fnName === 'remove') { - const callParams = { - ...req.particleContext, - tetraplets: { - script_id: req.tetraplets[0] - }, - }; - resp.retCode = ResultCodes.success; - resp.result = service.remove(req.args[0], callParams) - } - - next(); - }); -} - - - -export interface DistDef { - add_blueprint: (blueprint: { dependencies: string[]; name: string; }, callParams: CallParams<'blueprint'>) => string; -add_module: (wasm_b56_content: number[], conf: { name: string; }, callParams: CallParams<'wasm_b56_content' | 'conf'>) => string; -get_interface: (module_id: string, callParams: CallParams<'module_id'>) => { function_signatures: { arguments: string[][]; name: string; output_types: string[]; }[]; record_types: { fields: string[][]; id: number; name: string; }[]; }; -list_blueprints: (callParams: CallParams) => { dependencies: string[]; id: string; name: string; }[]; -list_modules: (callParams: CallParams) => { config: { name: string; }; hash: string; name: string; }[]; -make_blueprint: (name: string, dependencies: string[], callParams: CallParams<'name' | 'dependencies'>) => { dependencies: string[]; name: string; }; -make_module_config: (name: string, mem_pages_count: number | null, logger_enabled: boolean | null, preopened_files: string[] | null, envs: string[][] | null, mapped_dirs: string[][] | null, mounted_binaries: string[][] | null, logging_mask: number | null, callParams: CallParams<'name' | 'mem_pages_count' | 'logger_enabled' | 'preopened_files' | 'envs' | 'mapped_dirs' | 'mounted_binaries' | 'logging_mask'>) => { name: string; }; -} -export function registerDist(service: DistDef): void; -export function registerDist(serviceId: string, service: DistDef): void; -export function registerDist(peer: FluencePeer, service: DistDef): void; -export function registerDist(peer: FluencePeer, serviceId: string, service: DistDef): void; - - -export function registerDist(...args: any) { - let peer: FluencePeer; - let serviceId: any; - let service: any; - if (FluencePeer.isInstance(args[0])) { - peer = args[0]; - } else { - peer = Fluence.getPeer(); - } - - if (typeof args[0] === 'string') { - serviceId = args[0]; - } else if (typeof args[1] === 'string') { - serviceId = args[1]; - } else { - serviceId = "dist" - } - - // Figuring out which overload is the service. - // If the first argument is not Fluence Peer and it is an object, then it can only be the service def - // If the first argument is peer, we are checking further. The second argument might either be - // an object, that it must be the service object - // or a string, which is the service id. In that case the service is the third argument - if (!(FluencePeer.isInstance(args[0])) && typeof args[0] === 'object') { - service = args[0]; - } else if (typeof args[1] === 'object') { - service = args[1]; - } else { - service = args[2]; - } - - const incorrectServiceDefinitions = missingFields(service, ['add_blueprint', 'add_module', 'get_interface', 'list_blueprints', 'list_modules', 'make_blueprint', 'make_module_config']); - if (!!incorrectServiceDefinitions.length) { - throw new Error("Error registering service Dist: missing functions: " + incorrectServiceDefinitions.map((d) => "'" + d + "'").join(", ")) - } - - peer.internals.callServiceHandler.use((req, resp, next) => { - if (req.serviceId !== serviceId) { - next(); - return; - } - - if (req.fnName === 'add_blueprint') { - const callParams = { - ...req.particleContext, - tetraplets: { - blueprint: req.tetraplets[0] - }, - }; - resp.retCode = ResultCodes.success; - resp.result = service.add_blueprint(req.args[0], callParams) - } - -if (req.fnName === 'add_module') { - const callParams = { - ...req.particleContext, - tetraplets: { - wasm_b56_content: req.tetraplets[0],conf: req.tetraplets[1] - }, - }; - resp.retCode = ResultCodes.success; - resp.result = service.add_module(req.args[0], req.args[1], callParams) - } - -if (req.fnName === 'get_interface') { - const callParams = { - ...req.particleContext, - tetraplets: { - module_id: req.tetraplets[0] - }, - }; - resp.retCode = ResultCodes.success; - resp.result = service.get_interface(req.args[0], callParams) - } - -if (req.fnName === 'list_blueprints') { - const callParams = { - ...req.particleContext, - tetraplets: { - - }, - }; - resp.retCode = ResultCodes.success; - resp.result = service.list_blueprints(callParams) - } - -if (req.fnName === 'list_modules') { - const callParams = { - ...req.particleContext, - tetraplets: { - - }, - }; - resp.retCode = ResultCodes.success; - resp.result = service.list_modules(callParams) - } - -if (req.fnName === 'make_blueprint') { - const callParams = { - ...req.particleContext, - tetraplets: { - name: req.tetraplets[0],dependencies: req.tetraplets[1] - }, - }; - resp.retCode = ResultCodes.success; - resp.result = service.make_blueprint(req.args[0], req.args[1], callParams) - } - -if (req.fnName === 'make_module_config') { - const callParams = { - ...req.particleContext, - tetraplets: { - name: req.tetraplets[0],mem_pages_count: req.tetraplets[1],logger_enabled: req.tetraplets[2],preopened_files: req.tetraplets[3],envs: req.tetraplets[4],mapped_dirs: req.tetraplets[5],mounted_binaries: req.tetraplets[6],logging_mask: req.tetraplets[7] - }, - }; - resp.retCode = ResultCodes.success; - resp.result = service.make_module_config(req.args[0], req.args[1].length === 0 ? null : req.args[1][0], req.args[2].length === 0 ? null : req.args[2][0], req.args[3].length === 0 ? null : req.args[3][0], req.args[4].length === 0 ? null : req.args[4][0], req.args[5].length === 0 ? null : req.args[5][0], req.args[6].length === 0 ? null : req.args[6][0], req.args[7].length === 0 ? null : req.args[7][0], callParams) - } - - next(); - }); -} - -// Functions - diff --git a/aqua-examples/price-oracle/web/src/_aqua/get_crypto_prices.ts b/aqua-examples/price-oracle/web/src/_aqua/get_crypto_prices.ts deleted file mode 100644 index be71c8b..0000000 --- a/aqua-examples/price-oracle/web/src/_aqua/get_crypto_prices.ts +++ /dev/null @@ -1,415 +0,0 @@ -/** - * - * This file is auto-generated. Do not edit manually: changes may be erased. - * Generated by Aqua compiler: https://github.com/fluencelabs/aqua/. - * If you find any bugs, please write an issue on GitHub: https://github.com/fluencelabs/aqua/issues - * Aqua version: 0.6.0-273 - * - */ -import { Fluence, FluencePeer } from '@fluencelabs/fluence'; -import { - CallParams, - callFunction, - registerService, -} from '@fluencelabs/fluence/dist/internal/compilerSupport/v2'; - - -// Services - -export interface MeanServiceDef { - mean: (data: number[], callParams: CallParams<'data'>) => { error_msg: string; result: number; success: boolean; } | Promise<{ error_msg: string; result: number; success: boolean; }>; -} -export function registerMeanService(serviceId: string, service: MeanServiceDef): void; -export function registerMeanService(peer: FluencePeer, serviceId: string, service: MeanServiceDef): void; - - -export function registerMeanService(...args: any) { - registerService( - args, - { - "functions" : [ - { - "functionName" : "mean", - "argDefs" : [ - { - "name" : "data", - "argType" : { - "tag" : "primitive" - } - } - ], - "returnType" : { - "tag" : "primitive" - } - } - ] -} - ); -} - - - -export interface F64OpDef { - identity: (x: number, callParams: CallParams<'x'>) => number | Promise; -} -export function registerF64Op(service: F64OpDef): void; -export function registerF64Op(serviceId: string, service: F64OpDef): void; -export function registerF64Op(peer: FluencePeer, service: F64OpDef): void; -export function registerF64Op(peer: FluencePeer, serviceId: string, service: F64OpDef): void; - - -export function registerF64Op(...args: any) { - registerService( - args, - { - "defaultServiceId" : "op", - "functions" : [ - { - "functionName" : "identity", - "argDefs" : [ - { - "name" : "x", - "argType" : { - "tag" : "primitive" - } - } - ], - "returnType" : { - "tag" : "primitive" - } - } - ] -} - ); -} - - - -export interface PriceGetterServiceDef { - price_getter: (coin: string, currency: string, timestamp_ms: number, callParams: CallParams<'coin' | 'currency' | 'timestamp_ms'>) => { error_msg: string; result: number; success: boolean; } | Promise<{ error_msg: string; result: number; success: boolean; }>; -} -export function registerPriceGetterService(serviceId: string, service: PriceGetterServiceDef): void; -export function registerPriceGetterService(peer: FluencePeer, serviceId: string, service: PriceGetterServiceDef): void; - - -export function registerPriceGetterService(...args: any) { - registerService( - args, - { - "functions" : [ - { - "functionName" : "price_getter", - "argDefs" : [ - { - "name" : "coin", - "argType" : { - "tag" : "primitive" - } - }, - { - "name" : "currency", - "argType" : { - "tag" : "primitive" - } - }, - { - "name" : "timestamp_ms", - "argType" : { - "tag" : "primitive" - } - } - ], - "returnType" : { - "tag" : "primitive" - } - } - ] -} - ); -} - -// Functions -export type Get_price_parArgMean_topo = { node: string; service_id: string; } -export type Get_price_parResult = { error_msg: string; result: number; success: boolean; } -export function get_price_par( - coin: string, - currency: string, - getter_topo: { node: string; service_id: string; }[], - mean_topo: Get_price_parArgMean_topo, - config?: {ttl?: number} -): Promise; - -export function get_price_par( - peer: FluencePeer, - coin: string, - currency: string, - getter_topo: { node: string; service_id: string; }[], - mean_topo: Get_price_parArgMean_topo, - config?: {ttl?: number} -): Promise; - -export function get_price_par(...args: any) { - - let script = ` - (xor - (seq - (seq - (seq - (seq - (seq - (seq - (call %init_peer_id% ("getDataSrv" "-relay-") [] -relay-) - (call %init_peer_id% ("getDataSrv" "coin") [] coin) - ) - (call %init_peer_id% ("getDataSrv" "currency") [] currency) - ) - (call %init_peer_id% ("getDataSrv" "getter_topo") [] getter_topo) - ) - (call %init_peer_id% ("getDataSrv" "mean_topo") [] mean_topo) - ) - (new $prices - (seq - (par - (fold getter_topo topo - (par - (seq - (seq - (seq - (call -relay- ("op" "noop") []) - (xor - (seq - (seq - (seq - (call topo.$.node! ("peer" "timestamp_ms") [] ts_ms) - (call topo.$.node! (topo.$.service_id! "price_getter") [coin currency ts_ms] res) - ) - (call topo.$.node! ("op" "identity") [res.$.result!] $prices) - ) - (call topo.$.node! ("op" "noop") []) - ) - (seq - (call -relay- ("op" "noop") []) - (call %init_peer_id% ("errorHandlingSrv" "error") [%last_error% 1]) - ) - ) - ) - (call -relay- ("op" "noop") []) - ) - (call mean_topo.$.node! ("op" "noop") []) - ) - (next topo) - ) - ) - (null) - ) - (xor - (seq - (seq - (call mean_topo.$.node! ("op" "identity") [$prices.$.[1]!]) - (call mean_topo.$.node! (mean_topo.$.service_id! "mean") [$prices] result) - ) - (call -relay- ("op" "noop") []) - ) - (seq - (call -relay- ("op" "noop") []) - (call %init_peer_id% ("errorHandlingSrv" "error") [%last_error% 2]) - ) - ) - ) - ) - ) - (xor - (call %init_peer_id% ("callbackSrv" "response") [result]) - (call %init_peer_id% ("errorHandlingSrv" "error") [%last_error% 3]) - ) - ) - (call %init_peer_id% ("errorHandlingSrv" "error") [%last_error% 4]) - ) - ` - return callFunction( - args, - { - "functionName" : "get_price_par", - "returnType" : { - "tag" : "primitive" - }, - "argDefs" : [ - { - "name" : "coin", - "argType" : { - "tag" : "primitive" - } - }, - { - "name" : "currency", - "argType" : { - "tag" : "primitive" - } - }, - { - "name" : "getter_topo", - "argType" : { - "tag" : "primitive" - } - }, - { - "name" : "mean_topo", - "argType" : { - "tag" : "primitive" - } - } - ], - "names" : { - "relay" : "-relay-", - "getDataSrv" : "getDataSrv", - "callbackSrv" : "callbackSrv", - "responseSrv" : "callbackSrv", - "responseFnName" : "response", - "errorHandlingSrv" : "errorHandlingSrv", - "errorFnName" : "error" - } -}, - script - ) -} - - -export type Get_priceResult = { error_msg: string; result: number; success: boolean; } -export function get_price( - coin: string, - currency: string, - node: string, - pg_sid: string, - mean_sid: string, - config?: {ttl?: number} -): Promise; - -export function get_price( - peer: FluencePeer, - coin: string, - currency: string, - node: string, - pg_sid: string, - mean_sid: string, - config?: {ttl?: number} -): Promise; - -export function get_price(...args: any) { - - let script = ` - (xor - (seq - (seq - (seq - (seq - (seq - (seq - (seq - (call %init_peer_id% ("getDataSrv" "-relay-") [] -relay-) - (call %init_peer_id% ("getDataSrv" "coin") [] coin) - ) - (call %init_peer_id% ("getDataSrv" "currency") [] currency) - ) - (call %init_peer_id% ("getDataSrv" "node") [] node) - ) - (call %init_peer_id% ("getDataSrv" "pg_sid") [] pg_sid) - ) - (call %init_peer_id% ("getDataSrv" "mean_sid") [] mean_sid) - ) - (new $prices - (seq - (call -relay- ("op" "noop") []) - (xor - (seq - (seq - (seq - (seq - (seq - (seq - (seq - (seq - (call node ("op" "string_to_b58") [node] k) - (call node ("peer" "timestamp_ms") [] ts_ms0) - ) - (call node (pg_sid "price_getter") [coin currency ts_ms0] res0) - ) - (call node ("op" "identity") [res0.$.result!] $prices) - ) - (call node ("peer" "timestamp_ms") [] ts_ms1) - ) - (call node (pg_sid "price_getter") [coin currency ts_ms1] res1) - ) - (call node ("op" "identity") [res1.$.result!] $prices) - ) - (call node (mean_sid "mean") [$prices] result) - ) - (call -relay- ("op" "noop") []) - ) - (seq - (call -relay- ("op" "noop") []) - (call %init_peer_id% ("errorHandlingSrv" "error") [%last_error% 1]) - ) - ) - ) - ) - ) - (xor - (call %init_peer_id% ("callbackSrv" "response") [result]) - (call %init_peer_id% ("errorHandlingSrv" "error") [%last_error% 2]) - ) - ) - (call %init_peer_id% ("errorHandlingSrv" "error") [%last_error% 3]) - ) - ` - return callFunction( - args, - { - "functionName" : "get_price", - "returnType" : { - "tag" : "primitive" - }, - "argDefs" : [ - { - "name" : "coin", - "argType" : { - "tag" : "primitive" - } - }, - { - "name" : "currency", - "argType" : { - "tag" : "primitive" - } - }, - { - "name" : "node", - "argType" : { - "tag" : "primitive" - } - }, - { - "name" : "pg_sid", - "argType" : { - "tag" : "primitive" - } - }, - { - "name" : "mean_sid", - "argType" : { - "tag" : "primitive" - } - } - ], - "names" : { - "relay" : "-relay-", - "getDataSrv" : "getDataSrv", - "callbackSrv" : "callbackSrv", - "responseSrv" : "callbackSrv", - "responseFnName" : "response", - "errorHandlingSrv" : "errorHandlingSrv", - "errorFnName" : "error" - } -}, - script - ) -}