├── .github ├── CODEOWNERS └── workflows │ └── codeowners.yml ├── .gitignore ├── .vscode ├── extensions.json ├── markdown.code-snippets └── settings.json ├── README.md ├── babel.config.js ├── blog ├── 2021-09-03-marine-rs-sdk-test-update.md ├── 2021-09-08-aqua-compiler-0.3.md └── authors.yml ├── docs.iml ├── docs ├── aqua-book │ ├── aqua-js-api.md │ ├── changelog.md │ ├── getting-started │ │ ├── getting-started.md │ │ ├── installation │ │ │ ├── Aqua-Extension-for-VSCode.png │ │ │ └── installation.md │ │ └── quick-start.md │ ├── introduction.md │ ├── language │ │ ├── abilities.md │ │ ├── closures.md │ │ ├── crdt-streams.md │ │ ├── expressions │ │ │ ├── expressions.md │ │ │ ├── functions.md │ │ │ ├── header.md │ │ │ ├── overridable-constants.md │ │ │ └── services.md │ │ ├── flow │ │ │ ├── conditional.md │ │ │ ├── flow.md │ │ │ ├── iterative.md │ │ │ ├── parallel.md │ │ │ └── sequential.md │ │ ├── header │ │ │ ├── control-scope-and-visibility.md │ │ │ └── header.md │ │ ├── language.md │ │ ├── services.md │ │ ├── topology.md │ │ ├── types.md │ │ └── values.md │ └── libraries │ │ ├── aqua-ipfs.md │ │ ├── aqua-lib.md │ │ ├── libraries.md │ │ └── registry.md ├── build │ ├── concepts │ │ ├── best_practices.md │ │ ├── fluence_functions_revisited.md │ │ ├── http_gateways.md │ │ ├── marketplace.md │ │ ├── scheduling_functions.md │ │ └── security.md │ ├── examples │ │ └── frpc.md │ ├── glossary.md │ ├── how-to │ │ ├── configure.md │ │ ├── deploy.md │ │ ├── develop.md │ │ ├── migrate.md │ │ ├── monitor.md │ │ ├── schedule_functions.md │ │ ├── securing_functions.md │ │ ├── setting_up.md │ │ ├── setup_payments.md │ │ └── test.md │ ├── introducing_fluence.md │ ├── overview │ │ ├── fluence_functions.md │ │ ├── getting_started.md │ │ └── roadmap.md │ ├── quickstarts │ │ ├── connecting_to_local_storage.md │ │ ├── connecting_to_the_world.md │ │ └── your_first_function.md │ ├── references.md │ ├── security.md │ ├── setting-up │ │ ├── installing_cli.md │ │ ├── setting_up.md │ │ └── working_with_local_networks.md │ └── tutorials │ │ ├── event_handling_in_js.md │ │ ├── testing_serverless.md │ │ └── workflow_fundamentals.md ├── learn │ ├── fluence-comparison.md │ ├── governance │ │ └── overview.md │ ├── how-it-works.md │ ├── overview.md │ ├── use-cases.md │ └── why-fluence.md └── marine-book │ ├── basic-concepts │ ├── an-example-of-Fluence-service.png │ └── basic-concepts.md │ ├── changelog.md │ ├── introduction.md │ ├── marine-runtime │ ├── api │ │ ├── api.md │ │ ├── core-api.md │ │ ├── marine-api.md │ │ └── marine-js-api.md │ ├── architecture │ │ ├── architecture │ │ │ ├── Marine-Layered-Architecture.png │ │ │ └── architecture.md │ │ ├── core │ │ │ ├── core.md │ │ │ ├── marine-performance.png │ │ │ ├── marine-using-interface-types-V1.png │ │ │ ├── multi-module-call-step-1.png │ │ │ ├── multi-module-call-step-2.png │ │ │ ├── multi-module-call-step-3.png │ │ │ ├── multi-module-call-step-4.png │ │ │ ├── multi-module-call-step-5.png │ │ │ ├── passing-scheme-between-three-modules.png │ │ │ └── scheme-with-Wasmer-instances.png │ │ ├── interface-types-instructions.md │ │ └── marine-js │ │ │ ├── marine-js.md │ │ │ ├── marine-web-scheme.png │ │ │ └── marine-web-value-passing.png │ ├── configuration-file.md │ ├── host-exports.md │ ├── i-value-and-i-type.md │ ├── marine-runtime.md │ ├── module-types │ │ ├── marine-as-ecosystem.png │ │ └── module-types.md │ └── mounted-binaries.md │ ├── marine-rust-sdk │ ├── developing │ │ ├── call-parameters.md │ │ ├── developing.md │ │ ├── environment-variables.md │ │ ├── export-functions.md │ │ ├── import-functions.md │ │ ├── logging.md │ │ ├── module-manifest.md │ │ ├── mounted-binaries.md │ │ └── structures.md │ ├── marine-rust-sdk.md │ ├── module-abi.md │ └── testing-and-debugging │ │ ├── internal-debugging-api.md │ │ ├── testing-a-module.md │ │ ├── testing-a-service.md │ │ ├── testing-and-debugging.md │ │ └── using-cargo-build-scripts.md │ ├── marine-tooling-reference │ ├── marine-cli.md │ ├── marine-repl.md │ └── marine-tooling-reference.md │ └── quick-start │ ├── develop-a-multi-modules-service.md │ ├── develop-a-single-module-service.md │ ├── quick-start.md │ └── setting-up-the-development-environment.md ├── docusaurus.config.ts ├── package-lock.json ├── package.json ├── sidebars.js ├── src ├── css │ └── custom.scss ├── pages │ ├── index.module.scss │ └── index.tsx └── types.d.ts ├── static ├── .nojekyll ├── img │ ├── aurora-connect-faucet.png │ ├── aurora-explorer-inspect-transfers.png │ ├── aurora-faucet-connect-metamask.png │ ├── aurora-request-eth.png │ ├── aurora-request-success.png │ ├── aurora-testnet-success-metamask.png │ ├── favicon.ico │ ├── fluence-chain-diagram.png │ ├── fluence-faucet-add-tUSDC-metamask.png │ ├── fluence-faucet-add-tUSDC.png │ ├── fluence-faucet-confirm-fluence-transfer.png │ ├── fluence-faucet-confirm-tUSDC-added.png │ ├── fluence-faucet-login.png │ ├── fluence-faucet-request-tUSDC.png │ ├── fluence-faucet-sign-up.png │ ├── fluence-faucet-tUSDC-transfer-update.png │ ├── fluence-functions.png │ ├── logo.svg │ ├── marine.jpg │ ├── marketplace-capacity.png │ ├── marketplace-matching.png │ ├── marketplace-provider-resources.png │ ├── marketplace-providers.png │ ├── metamask-add-manually.png │ ├── metamask-add-network.png │ ├── metamask-aurora-chain-info.png │ ├── metamask-mumbai-chain-info.png │ ├── metamask-request-mumbai-tokens.png │ ├── metamask-updated-MATIC-balance.png │ ├── metamask-updated-aeth-balance.png │ ├── metamask_tx_prompt.png │ ├── mvm │ │ └── dar_faucet.png │ └── polygon-explorer-inspect-transfers.png └── mermaid.js ├── tsconfig.json └── vercel.json /.github/CODEOWNERS: -------------------------------------------------------------------------------- 1 | # about codeowners 2 | # https://docs.github.com/en/repositories/managing-your-repositorys-settings-and-features/customizing-your-repository/about-code-owners 3 | 4 | # default owner is Artem since he setup up docusaurus 5 | * @shamsartem 6 | 7 | .github/** @nahsi 8 | 9 | blog/** @evgenyponomarev 10 | docs/learn/** @evgenyponomarev 11 | docs/build/** @boneyard93501 12 | docs/aqua-book/** @alari 13 | docs/marine-book/** @mikevoronov 14 | -------------------------------------------------------------------------------- /.github/workflows/codeowners.yml: -------------------------------------------------------------------------------- 1 | name: codeowners 2 | 3 | on: 4 | pull_request: 5 | paths: 6 | - ".github/workflows/codeowners.yml" 7 | - ".github/CODEOWNERS" 8 | 9 | concurrency: 10 | group: "${{ github.workflow }}-${{ github.ref }}" 11 | cancel-in-progress: true 12 | 13 | jobs: 14 | validate: 15 | name: Validate CODEOWNERS 16 | runs-on: ubuntu-latest 17 | steps: 18 | - name: Checkout 19 | uses: actions/checkout@v4 20 | 21 | - name: Validate CODEOWNERS file 22 | uses: mszostok/codeowners-validator@v0.7.4 23 | with: 24 | checks: "files,owners,duppatterns,syntax" 25 | github_access_token: ${{ secrets.FLUENCEBOT_RELEASE_PLEASE_PAT }} 26 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Dependencies 2 | /node_modules 3 | 4 | # Production 5 | /build 6 | # Generated files 7 | .docusaurus 8 | .cache-loader 9 | .idea 10 | 11 | # Misc 12 | .DS_Store 13 | .env.local 14 | .env.development.local 15 | .env.test.local 16 | .env.production.local 17 | 18 | npm-debug.log* 19 | yarn-debug.log* 20 | yarn-error.log* 21 | -------------------------------------------------------------------------------- /.vscode/extensions.json: -------------------------------------------------------------------------------- 1 | { 2 | "recommendations": [ 3 | "streetsidesoftware.code-spell-checker", 4 | "blackmist.LinkCheckMD" 5 | ] 6 | } 7 | -------------------------------------------------------------------------------- /.vscode/markdown.code-snippets: -------------------------------------------------------------------------------- 1 | { 2 | "Tabs imports": { 3 | "prefix": "import-tabs", 4 | "body": [ 5 | "import Tabs from \"@theme/Tabs\";", 6 | "import TabItem from \"@theme/TabItem\";" 7 | ], 8 | "description": "Import tabs" 9 | }, 10 | "Tabs": { 11 | "prefix": "tabs", 12 | "body": [ 13 | "", 14 | "", 15 | "", 16 | "", 17 | "", 18 | "", 19 | "", 20 | "", 21 | "", 22 | "", 23 | "", 24 | "", 25 | ] 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /.vscode/settings.json: -------------------------------------------------------------------------------- 1 | { 2 | "cSpell.words": [ 3 | "acks", 4 | "appendable", 5 | "builtins", 6 | "bytearray", 7 | "canonicalization", 8 | "canonicalized", 9 | "codomain", 10 | "commoditized", 11 | "composability", 12 | "concat", 13 | "contravariance", 14 | "CRDT", 15 | "ctypes", 16 | "deallocate", 17 | "dockerized", 18 | "EVM", 19 | "featureful", 20 | "fldist", 21 | "fluence", 22 | "fluencelabs", 23 | "ftype", 24 | "gibibyte", 25 | "hostless", 26 | "incentivized", 27 | "instanceof", 28 | "ipfs", 29 | "kademlia", 30 | "kibibyte", 31 | "kibibytes", 32 | "koderhq", 33 | "kras", 34 | "libp2p", 35 | "mebibyte", 36 | "microservices", 37 | "MITM", 38 | "mrepl", 39 | "mtype", 40 | "multiaddr", 41 | "multiaddress", 42 | "multiaddresses", 43 | "overridable", 44 | "pebibyte", 45 | "permisisonless", 46 | "permissioned", 47 | "permissioning", 48 | "permissionless", 49 | "PITM", 50 | "pluggable", 51 | "preopened", 52 | "println", 53 | "pseudocode", 54 | "quickstart", 55 | "roundtrips", 56 | "runtimes", 57 | "rustup", 58 | "sandboxed", 59 | "specificator", 60 | "specificators", 61 | "struct", 62 | "structs", 63 | "subnetworks", 64 | "tebibyte", 65 | "Tendermint", 66 | "tetraplet", 67 | "tetraplets", 68 | "toolchains", 69 | "usize", 70 | "wasi", 71 | "wasmer" 72 | ], 73 | "cSpell.ignoreRegExpList": ["/dns4/[a-zA-Z0-9/\\-\\.]*", "12d[a-zA-Z0-9]*"], 74 | "markdown.updateLinksOnFileMove.enabled": "always", 75 | "markdown.validate.enabled": true, 76 | "markdown.validate.fileLinks.enabled": "error", 77 | "markdown.validate.fileLinks.markdownFragmentLinks": "error", 78 | "markdown.validate.fragmentLinks.enabled": "error", 79 | "markdown.validate.referenceLinks.enabled": "error", 80 | "cSpell.language": "en,en-US" 81 | } 82 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Fluence Docs 2 | 3 | Fluence Docs are built using [Docusaurus 2](https://docusaurus.io/), a modern static website generator. 4 | 5 | ## Contributing 6 | 7 | - Generally docs hierarchy should be reflected in the file hierarchy, but ultimately the docs tree must be set up inside `sidebars.js` file. If you put a markdown file inside a directory - don't ever name it `index.md` - use the same name as the directory itself instead (e.g. [basic-concepts.md](./docs/marine-book/basic-concepts/basic-concepts.md)) 8 | - Currently the index page is redirected to `/docs/learn/overview`. This is because we don't have a design of what's best to place on the index page. The redirect is configured in the `vercel.json` file 9 | - Avoid adding a lot of images. Images are added using `![short description of an image](./path-to-an-image.png)` syntax. If you have to add an image - please put it inside the directory near the doc where it is used. Check out [basic-concepts.md](./docs/marine-book/basic-concepts/basic-concepts.md). Please use .png or even better - svg for diagrams and .jpg for photos, resize the image as small as you are comfortable and compress it using [tinypng.com](https://tinypng.com/) (or [svgomg](https://jakearchibald.github.io/svgomg/) for .svg). 10 | - When adding ANY github links please use [permalinks](https://docs.github.com/en/get-started/writing-on-github/working-with-advanced-formatting/creating-a-permanent-link-to-a-code-snippet) - otherwise links will point to the wrong place eventually. I also added new experimental markdown related settings to .vscode/settings.json which help a lot with writing valid markdown. Also [this vscode extension](https://marketplace.visualstudio.com/items?itemName=blackmist.LinkCheckMD) can help you find broken external links as well 11 | - Please at least use spell checker inside your editor or maybe Grammarly and be attentive when writing docs - they are the face of the company in a sense 12 | - [Here](https://github.com/fluencelabs/docs/blob/9c6e5a257f453b6dbffb856fc236917908e80602/docusaurus.config.js#L61) is where you can add syntax highlight for other programming languages. Use \`\`\`aqua and \`\`\`air for codeblocks in these languages. Use \`\`\`sh for something that you intend to type in a shell. Maybe don't put \$ signs and execution results right inside \`\`\`sh code-blocks for the following reasons: \$ signs and commands output mixed with all of it make it harder to copy and use the code from the docs and also some of the commands output will be changed by us and will have to be maintained in the docs as well which is very inconvenient. 13 | - Headings are not just a stylistic tool but also semantic one. Headings are used to give document a structure which is especially important for page navigation for certain people and also for generating valid quick navigation tree that is displayed on the right side of the docs. So basically the main rule is to not skip heading levels (e.g. don't do #Heading followed immediately by ###Heading - use ##Heading instead) 14 | - For the lack of maintainer, Blog is currently removed from `sidebars.js` but we can add it back. It's still available and working 15 | - For `mermaid` code to work you would currently need to do the following: 16 | ````markdown 17 | Some text that you have in your md 18 | 19 | mermaid 20 | ```mermaid 21 | graph YourDiagram; 22 | A-->B; 23 | A-->C; 24 | B-->D; 25 | C-->D; 26 | ``` 27 | 28 | rest of the text on your page 29 | ```` 30 | Notice the blank line before and after the mermaid section 31 | - TODO: would be cool to have docs near the code (e.g. put Marine docs to Marine repo) - I think it can be done with CI build process but I think there unfortunately is no out-of-the-box solution. If it would be possible - changelogs from github and fluence-js docs, etc. could be included in these docs 32 | 33 | ## Installation 34 | 35 | ```sh 36 | npm i 37 | ``` 38 | 39 | ## Local Development 40 | 41 | ```sh 42 | npm run dev 43 | ``` 44 | 45 | This command starts a local development server and opens up a browser window. Most changes are reflected live without having to restart the server. 46 | 47 | ## Build 48 | 49 | ```sh 50 | npm run build 51 | ``` 52 | 53 | This command generates static content into the `build` directory and can be served using any static contents hosting service. 54 | -------------------------------------------------------------------------------- /babel.config.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | presets: [require.resolve('@docusaurus/core/lib/babel/preset')], 3 | }; 4 | -------------------------------------------------------------------------------- /blog/2021-09-03-marine-rs-sdk-test-update.md: -------------------------------------------------------------------------------- 1 | --- 2 | slug: marine-rs-sdk-test-v0.2.0 3 | title: marine-rs-sdk-test v0.2.0 4 | authors: mikevoronov 5 | tags: [marine] 6 | --- 7 | 8 | Updated the marine-rs-sdk-test to the 0.2.0 version with the following changes: 9 | 10 | - `#[marine_test]` defines `marine_test_env` namespace with module interfaces 11 | 12 | - module interface type can be accessed by `marine_test_env::::ModuleInterface` 13 | 14 | - structs exported by a module can be accessed by `marine_test_env::::` 15 | 16 | - functions under `#[marine_test]` must specify in the arguments modules they use 17 | 18 | Chosen naming and passing modules interfaces in arguments should make tests more readable. 19 | Here is an example of a test written in old and new ways: 20 | 21 | old: 22 | ```rust 23 | #[marine_test(config_path = "../Config.toml", modules_dir = "../artifacts")] 24 | fn empty_string() { 25 | let actual = greeting.greeting(String::new()); 26 | assert_eq!(actual, "Hi, "); 27 | } 28 | ``` 29 | 30 | new: 31 | ```rust 32 | #[marine_test(config_path = "../Config.toml", modules_dir = "../artifacts")] 33 | fn empty_string(greeting: marine_test_env::greeting::ModuleInterface { 34 | let actual = greeting.greeting(String::new()); 35 | assert_eq!(actual, "Hi, "); 36 | } 37 | ``` 38 | 39 | Also the update the solves problem with the same structures from different modules: they are now linked and have the same type. 40 | 41 | If you need more examples, please look at tests in [call_parameters](https://github.com/fluencelabs/marine/blob/master/examples/call_parameters/src/main.rs#L43) and [greeting](https://github.com/fluencelabs/marine/blob/master/examples/greeting/src/main.rs#L30), they are already using new interface. 42 | -------------------------------------------------------------------------------- /blog/2021-09-08-aqua-compiler-0.3.md: -------------------------------------------------------------------------------- 1 | --- 2 | slug: aqua-v0.3 3 | title: Aqua v0.3 4 | authors: alari 5 | tags: [aqua] 6 | --- 7 | 8 | We have released the Aqua compiler 0.3. 9 | 10 | Now Aqua compiler runs natively in the javascript environment and distributed as [@fluencelabs/aqua](https://www.npmjs.com/package/@fluencelabs/aqua) NPM package. 11 | 12 | The next milestone is to call Aqua functions from the Aqua itself: we're building Aqua REPL. 13 | See the [changelog](https://fluence.dev/docs/aqua-book/changelog#030--september-8-2021). 14 | -------------------------------------------------------------------------------- /blog/authors.yml: -------------------------------------------------------------------------------- 1 | shamsartem: 2 | name: Artsiom Shamsutdzinau 3 | title: Web Developer 4 | url: https://github.com/shamsartem 5 | image_url: https://github.com/shamsartem.png 6 | 7 | mikevoronov: 8 | name: Mike Voronov 9 | title: R&D Engineer 10 | url: https://github.com/mikevoronov 11 | image_url: https://github.com/mikevoronov.png 12 | 13 | alari: 14 | name: Dmitry Kurinskiy 15 | title: Co-founder & CTO at Fluence Labs 16 | url: https://github.com/alari 17 | image_url: https://github.com/alari.png 18 | -------------------------------------------------------------------------------- /docs.iml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /docs/aqua-book/aqua-js-api.md: -------------------------------------------------------------------------------- 1 | # Aqua JS API 2 | 3 | Aqua JS API allows you to manage all aspects of [Aqua](introduction.md) development from your JS projects. 4 | 5 | To install the Aqua API package: 6 | 7 | ```sh 8 | npm install --save @fluencelabs/aqua-api 9 | ``` 10 | 11 | # API 12 | API compiles high-level Aqua code into low-level AIR instructions that can be used with Fluence JS client to make peer-to-peer calls. 13 | 14 | API has only one function: 15 | 16 | ```typescript 17 | export class Compiler { 18 | compile(input: Input | Path | Call, imports: string[], config?: AquaConfig): Promise; 19 | } 20 | ``` 21 | 22 | where input can be: 23 | 24 | - Aqua code as a string 25 | 26 | ```typescript 27 | export class Input { 28 | input: string 29 | } 30 | ``` 31 | 32 | - Path to `.aqua` file or directory with `.aqua` files. 33 | - Note: paths must be absolute 34 | 35 | ```typescript 36 | export class Path { 37 | path: string 38 | } 39 | ``` 40 | 41 | - Information about a function that you want to call. It wraps aqua code to gather and print call result. Also, it 42 | checks correctness of arguments. 43 | 44 | ```typescript 45 | export class Call { 46 | functionCall: string 47 | arguments: any 48 | input: Input | Path 49 | } 50 | ``` 51 | 52 | - `imports` is a path to files that is necessary for compilation but not needed to be compiled into AIR functions. More information [here](language/header/header.md). 53 | - `config` is the following `AquaConfig` data structure 54 | 55 | ```typescript 56 | export class AquaConfig { 57 | // compiler log level. Default: info 58 | logLevel?: string 59 | // constants can be defined or overrided by this option 60 | constants?: string[] 61 | // switches off error bubbling to initiator. Default: false 62 | noXor?: boolean 63 | // switches off first hop to relay peer. Default: false 64 | noRelay?: boolean 65 | } 66 | ``` 67 | More info about overridable constants [here](language/expressions/overridable-constants.md). 68 | 69 | Compilation result: 70 | ```typescript 71 | export class CompilationResult { 72 | // list of compiled services. Can be useful to create handlers for this services 73 | services: Record 74 | // list of Aqua functions 75 | functions: Record 76 | // information about function that is compiled with `Call` input 77 | functionCall?: AquaFunction 78 | // list of compilation errors in Aqua code. If not empty, then compilation failed and other fields will be empty 79 | errors: string[] 80 | } 81 | ``` 82 | 83 | # Usage example 84 | https://github.com/fluencelabs/aqua/tree/main/api/aqua-api-example/ -------------------------------------------------------------------------------- /docs/aqua-book/getting-started/getting-started.md: -------------------------------------------------------------------------------- 1 | # Getting Started 2 | 3 | [Aqua](https://github.com/fluencelabs/aqua), part of Fluence Lab's Aquamarine Web3 stack, is a purpose-built language to program peer-to-peer networks and compose distributed services hosted on peer-to-peer nodes into applications and backends. 4 | 5 | In addition to the language specification, Aqua provides a compiler, which produces Aqua Intermediary Representation (AIR) and an execution stack, Aqua VM, that is part of every Fluence node implementation to execute AIR. 6 | -------------------------------------------------------------------------------- /docs/aqua-book/getting-started/installation/Aqua-Extension-for-VSCode.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aliezzahn/docs/7af66c0600393eaadff7ffb28ba49a0febfc021a/docs/aqua-book/getting-started/installation/Aqua-Extension-for-VSCode.png -------------------------------------------------------------------------------- /docs/aqua-book/getting-started/installation/installation.md: -------------------------------------------------------------------------------- 1 | # Installation 2 | 3 | To work with Aqua code from command line, install [Fluence CLI](https://github.com/fluencelabs/cli) and use [`fluence aqua`](https://github.com/fluencelabs/cli/blob/main/docs/commands/README.md#fluence-aqua) subcommand. 4 | 5 | Also, the compiler API is exposed as an npm package, see [Aqua JS API](../../aqua-js-api.md). 6 | 7 | Moreover, a VSCode syntax-highlighting extension is available. In VSCode, click on the Extensions button, search for `aqua` and install the extension. 8 | 9 | ![Aqua Extension for VSCode](./Aqua-Extension-for-VSCode.png) 10 | -------------------------------------------------------------------------------- /docs/aqua-book/getting-started/quick-start.md: -------------------------------------------------------------------------------- 1 | import Tabs from "@theme/Tabs"; 2 | import TabItem from "@theme/TabItem"; 3 | 4 | # Quick Start 5 | 6 | Every Fluence reference node comes with a set of builtin services that are accessible to Aqua programs. 7 | Let's use those readily available services to get the timestamp of a few of our peer-to-peer neighborhood nodes with Aqua. 8 | 9 | ```aqua 10 | -- timestamp_getter.aqua 11 | import "@fluencelabs/aqua-lib/builtin.aqua" 12 | 13 | func ts_getter(node: string, num_peers: u32) -> []u64: 14 | res: *u64 15 | 16 | on node: 17 | key <- Op.string_to_b58(node) 18 | nodes <- Kademlia.neighborhood(key, nil, [num_peers]) 19 | for n <- nodes par: 20 | on n: 21 | try: 22 | res <- Peer.timestamp_ms() 23 | 24 | join res[num_peers - 1] 25 | 26 | <- res 27 | ``` 28 | 29 | Let's explain this script line by line. First of all, it brings builtin services (see [aqua-lib](../libraries/aqua-lib.md)) in scope by import: 30 | 31 | ```aqua 32 | import "@fluencelabs/aqua-lib/builtin.aqua" 33 | ``` 34 | 35 | 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. 36 | That function returns array of obtained timestamps. 37 | 38 | ```aqua 39 | func ts_getter(node: string, num_peers: u32) -> []u64: 40 | ``` 41 | 42 | On the first line it creates stream variable (see [CRDT Streams](../language/crdt-streams.md)) `res`: 43 | 44 | ```aqua 45 | res: *u64 46 | ``` 47 | 48 | Then execution is transfered on peer with id that was passed in `node` (see [`on` expression](../language/topology.md#on-expression)): 49 | 50 | ```aqua 51 | on node: 52 | ``` 53 | 54 | On `node` it obtains no more than `num_peers` neighbour nodes using builtin services: 55 | 56 | ```aqua 57 | key <- Op.string_to_b58(node) 58 | nodes <- Kademlia.neighborhood(key, nil, [num_peers]) 59 | ``` 60 | 61 | After that for each of the obtained nodes in parallel (see [Parallel `for`](../language/flow/iterative.md#parallel-for)) it tries (see [try](../language/flow/conditional#try)) to push local timestamp to `res`: 62 | 63 | ```aqua 64 | for n <- nodes par: 65 | on n: 66 | try: 67 | res <- Peer.timestamp_ms() 68 | ``` 69 | 70 | Back on `node` element `res[num_peers - 1]` is joined (see [`join` expression](../language/flow/parallel.md#explicit-join-expression)) thus making all results available: 71 | 72 | ```aqua 73 | join res[num_peers - 1] 74 | ``` 75 | 76 | Finally, stream is converted to scalar (see [Streams Lifecycle](../language/crdt-streams.md#streams-lifecycle-and-guarantees)) and returned: 77 | 78 | ```aqua 79 | <- res 80 | ``` 81 | 82 | See the [ts-oracle example](https://github.com/fluencelabs/examples/tree/d52f06dfc3d30799fe6bd8e3e602c8ea1d1b8e8a/aqua-examples/ts-oracle) for the corresponding Aqua files in the `aqua-script` directory. 83 | 84 | Now that we have our script, let's use [Fluence CLI](https://github.com/fluencelabs/cli) to run it: 85 | 86 | 87 | 88 | 89 | ```sh 90 | # use `fluence run` as your client with some peer id 91 | fluence run \ 92 | --relay /dns4/kras-02.fluence.dev/tcp/19001/wss/p2p/12D3KooWHLxVhUQyAuZe6AHMB29P7wkvTNMn7eDMcsqimJYLKREf \ 93 | -i aqua-scripts/timestamp_getter.aqua \ 94 | -f 'ts_getter("12D3KooWHLxVhUQyAuZe6AHMB29P7wkvTNMn7eDMcsqimJYLKREf", 10)' 95 | ``` 96 | 97 | 98 | 99 | 100 | Here we go. Ten timestamps in micro seconds obtained in parallel: 101 | ```json 102 | [ 103 | [ 104 | 1624928596292, 105 | 1624928596291, 106 | 1624928596291, 107 | 1624928596299, 108 | 1624928596295, 109 | 1624928596286, 110 | 1624928596295, 111 | 1624928596284, 112 | 1624928596293, 113 | 1624928596289 114 | ] 115 | ] 116 | ``` 117 | 118 | 119 | 120 | 121 | And that's it. We now have ten timestamps right from our selected peer's neighbors. 122 | 123 | Note that if you try to request too many peers, execution could halt. 124 | -------------------------------------------------------------------------------- /docs/aqua-book/introduction.md: -------------------------------------------------------------------------------- 1 | import ReactPlayer from "react-player"; 2 | 3 | # Introduction 4 | 5 | Fluence is an open protocol and a framework for internet or private cloud applications. Fluence provides a peer-to-peer development stack so that you can create applications free of proprietary cloud platforms, centralized APIs, and untrustworthy third-parties. The Fluence stack is open source and is maintained and governed by a community of developers. 6 | 7 | At the core of Fluence is the open-source language **Aqua** that allows for the programming of peer-to-peer scenarios separately from the computations on peers. Applications are turned into hostless workflows over distributed function calls, which enables various levels of decentralization: from handling by a limited set of servers to complete peer-to-peer architecture by connecting user devices directly. 8 | 9 | 10 |
11 | 12 |
13 | 14 | This book, currently in its alpha version, is dedicated to Aqua, with plans to significantly broaden its scope in the future. 15 | -------------------------------------------------------------------------------- /docs/aqua-book/language/abilities.md: -------------------------------------------------------------------------------- 1 | # Abilities 2 | 3 | Abilities are a way to organize code in modules and implement inversion of control pattern in Aqua. 4 | 5 | 6 | Ability is a product of [scalars](types.md#scalars), [structures](types.md#structures), [arrows](types.md#arrow-types) and other abilities. 7 | 8 | ```aqua 9 | data Struct: 10 | int: i8 11 | 12 | ability Simple: 13 | st: Struct 14 | arrow(x: i8) -> bool 15 | 16 | ability Complex: 17 | simple: Simple 18 | field: string 19 | ``` 20 | 21 | ## Creating abilities 22 | 23 | Abilities could be created inside functions just like [structures](types.md#structures). 24 | 25 | 26 | ```aqua 27 | func main(): 28 | closure = (x: i8) -> bool: 29 | <- x > 0 30 | 31 | field = "complex" 32 | 33 | MyComplex = Complex( 34 | simple = Simple( 35 | st = Struct(int = 0), 36 | arrow = closure 37 | ), 38 | field -- short for `field = field` 39 | ) 40 | ``` 41 | 42 | ## Passing abilities 43 | 44 | Abilities could be passed to and returned from functions, althrough they require special syntax: 45 | - Abilities required by function are listed before arguments without names 46 | - Abilities returned by function are listed in return types just as any other types 47 | 48 | ```aqua 49 | ability Additional: 50 | value: string 51 | 52 | func createComplex{Simple, Additional}(int: i8) -> Complex, string: 53 | MyComplex = Complex( 54 | simple = Simple( 55 | st = Struct(int = int), 56 | arrow = Simple.arrow 57 | ), 58 | field = Additional.value 59 | ) 60 | 61 | <- MyComplex, Additional.value 62 | 63 | func main() -> string, string: 64 | closure = (x: i8) -> bool: 65 | <- x > 0 66 | 67 | MySimple = Simple( 68 | st = Struct(int = 0), 69 | arrow = closure 70 | ) 71 | 72 | MyAdditional = Additional(value = "additional") 73 | 74 | MyComplex, value = createComplex{MySimple, MyAdditional}(42) 75 | 76 | <- MyComples.field, value 77 | ``` 78 | 79 | 80 | 81 | ## Why abilities are special 82 | 83 | Abilities are fully resolved in compile time and do not affect runtime by any means. 84 | In this sense they are more like a context or trait implementation in other languages. 85 | For this reason special syntax is used. 86 | 87 | ## Limitations 88 | 89 | As abilities do not exist in runtime, they could not be put into a [collection](types.md#collection-types). -------------------------------------------------------------------------------- /docs/aqua-book/language/closures.md: -------------------------------------------------------------------------------- 1 | # Closures 2 | 3 | In Aqua, you can create an arrow within the function, enclosing its context. 4 | 5 | ```aqua 6 | service Hello: 7 | say_hello(to_name: string, peer: string) 8 | 9 | func bar(callback: string -> ()): 10 | callback("Fish") 11 | 12 | func foo(peer: string): 13 | on peer: 14 | -- Capture service resolution 15 | Hello "world" 16 | -- Create a closure named "closure" 17 | closure = (name: string) -> string: 18 | -- Use a value that's available on the definition site 19 | -- To call a service that's resolved on the definition site 20 | Hello.say_hello(name, peer) 21 | -- Return a value from the closure; syntax is the same as in functions 22 | <- name 23 | -- Pass this closure to another function 24 | bar(closure) 25 | ``` 26 | 27 | Closures can be created anywhere in the function, starting with Aqua 0.4.1, and then used just like any other arrow (argument of arrow type, function, or service method): passed to another function as an argument, or called right there. 28 | 29 | Closures enclose over three domains: 30 | 31 | * Values in scope, 32 | * Service resolutions, 33 | * Topology: place where the closure is defined should be the place where it's executed. 34 | 35 | Comparing with functions, closures have one important difference: functions are detached from topology by default. `func` keyword can be used to bring this behavior to closures, if needed. 36 | 37 | ```aqua 38 | service Hello: 39 | say_hello() 40 | 41 | func foo(): 42 | on HOST_PEER_ID: 43 | Hello "hello" 44 | 45 | -- This closure will execute on HOST_PEER_ID 46 | closure = (): 47 | Hello.say_hello() 48 | 49 | fn = func (): 50 | Hello.say_hello() 51 | 52 | -- Will go to HOST_PEER_ID, where Hello service is resolved, and call say_hello 53 | closure() 54 | 55 | -- Will be called on current peer, probably INIT_PEER_ID, and may fail 56 | -- in case Hello service is not defined or has another ID 57 | fn() 58 | ``` 59 | 60 | It is not yet possible to return an arrow from an arrow. 61 | -------------------------------------------------------------------------------- /docs/aqua-book/language/crdt-streams.md: -------------------------------------------------------------------------------- 1 | # CRDT Streams 2 | 3 | In Aqua, an ordinary value is a name that points to a single result: 4 | 5 | ```aqua 6 | value <- foo() 7 | ``` 8 | 9 | A stream, on the other hand, is a name that points to zero or more results: 10 | 11 | ```aqua 12 | values: *string 13 | 14 | -- Write to a stream several times 15 | values <- foo() 16 | values <- foo() 17 | 18 | -- A value can be pushed to a stream 19 | -- without an explicit function call with <<- operator: 20 | values <<- "foo" 21 | x <- foo() 22 | values <<- x 23 | ``` 24 | 25 | Stream is a kind of [collection](types.md#collection-types) and can be used in place of other collections: 26 | 27 | ```aqua 28 | func foo(peer: string, relay: ?string): 29 | on peer via relay: 30 | Op.noop() 31 | 32 | func bar(peer: string, relay: string): 33 | relayMaybe: *string 34 | if peer != INIT_PEER_ID: 35 | -- Write into a stream 36 | relayMaybe <<- relay 37 | -- Pass a stream as an optional value 38 | foo(peer, relayMaybe) 39 | ``` 40 | 41 | But the most powerful use of streams pertains to their use with parallel execution, which incurs non-determinism. 42 | 43 | ## Streams: Lifecycle And Guarantees 44 | 45 | A stream's lifecycle can be separated into three stages: 46 | 47 | * Source: (Parallel) Writes to a stream 48 | * Map: Handles the stream values 49 | * Sink: Converts the resulting stream into a scalar 50 | 51 | Consider the following example: 52 | 53 | ```aqua 54 | alias PeerId: string 55 | 56 | func foo(peers: []PeerId) -> string: 57 | -- Store a list of peer IDs collected from somewhere 58 | -- This is a stream (denoted by *, which means "0 or more values") 59 | resp: *PeerId 60 | 61 | -- Will go to all peers in parallel 62 | for p <- peers par: 63 | -- Move execution flow to the peer p 64 | on p: 65 | -- Get a peer ID from a service call (called on p) 66 | resp <- Srv.call() 67 | 68 | -- You can think of resp2 as a locally consistent lazy list 69 | resp2: *PeerId 70 | 71 | -- What is the value of resp at this point? 72 | -- Keep an eye on the `par` there: actually, it's FORKing execution 73 | -- to several branches on different peers. 74 | for r <- resp par: 75 | -- Move execution to peer r 76 | on r: 77 | -- Call Srv locally 78 | resp2 <- Srv.call() 79 | 80 | -- Wait for 6 responses on resp2: it's JOIN 81 | Op.identity(resp2!5) 82 | -- Once we have 6 responses, merge them 83 | -- Function treats resp2 as an array of strings, and concatenates all 84 | -- of them into a single string. 85 | -- This function call "fixes" the content of resp2, making a single observation. 86 | -- This is a "stream canonicalization" event: values, order, and length 87 | -- is fixed at the moment of first function call, function will not be called 88 | -- again, with different data. 89 | r <- Srv.concat(resp2) 90 | -- You can keep writing to a stream after it's value is used 91 | 92 | <- r 93 | ``` 94 | 95 | In this case, for each peer `p` in `peers`, a new `PeerID` is going to be obtained from the `Srv.call` and written into the `resp` stream. 96 | 97 | Every peer `p` in peers does not know anything about how the other iterations proceed. 98 | 99 | Once `PeerId` is written to the `resp` stream, the second `for` is triggered. This is the mapping stage. 100 | 101 | And then the results are sent to the first peer, to call Op.identity there. This Op.identity waits until element number 5 is defined on `resp2` stream. 102 | 103 | When the join is complete, the stream is consumed by the concatenation service to produce a scalar value, which is returned. 104 | 105 | During execution, involved peers have different views on the state of execution: each of the `for` parallel branches has no view or access to the other branches' data and eventually, the execution flows to the initial peer. The initial peer then merges writes to the `resp` stream and to the `resp2` stream, respectively. These writes are done in a conflict-free fashion. Furthermore, the respective heads of the `resp`, `resp2` streams will not change from each peer's point of view as they are immutable and new values can only be appended. However, different peers may have a different order of the stream values depending on the order of receiving these values. 106 | 107 | ### Stream restrictions 108 | 109 | Restriction is a part of π calculus that bounds (restricts) a name to a scope. For Aqua streams it means that the stream is not accessible outside of definition scope, and the stream is always fresh when execution enters the scope. 110 | 111 | These behaviors are introduced in [Aqua 0.5](https://github.com/fluencelabs/aqua/releases/tag/0.5.0). 112 | 113 | ```aqua 114 | -- Note: returns []string (immutable, readonly collection), not *string 115 | func someFunc(xs: []string) -> []string: 116 | -- This stream is available within the function, and is empty 117 | outside: *string 118 | for x <- xs: 119 | -- This stream is empty at the beginning of each iteration 120 | inside: *string 121 | 122 | -- We can manipulate the inside stream within the scope 123 | if x == "ok" 124 | inside <<- "ok" 125 | else: 126 | inside <<- "not ok" 127 | 128 | -- Read the value 129 | if inside! == "ok": 130 | outside <<- "result" 131 | 132 | -- outside stream is not escaping this function scope: 133 | -- it is converted to an array (canonicalized) and cannot be appended after that 134 | <- outside 135 | ``` 136 | 137 | You still can keep streams as streams by using them as `*string` arguments, or by returning them as `*string`. 138 | 139 | ### Note 140 | `data` types must be immutable, therefore streams are not allowed in the type declarations. 141 | -------------------------------------------------------------------------------- /docs/aqua-book/language/expressions/expressions.md: -------------------------------------------------------------------------------- 1 | # Expressions 2 | 3 | Aqua file consists of a header and a body. 4 | 5 | ## Body expressions 6 | 7 | `func` 8 | 9 | Function definition is the most crucial part of the language, see [Functions](functions.md) for details. 10 | 11 | [Expressions source code](https://github.com/fluencelabs/aqua/tree/main/semantics/src/main/scala/aqua/semantics/expr) 12 | -------------------------------------------------------------------------------- /docs/aqua-book/language/expressions/functions.md: -------------------------------------------------------------------------------- 1 | # Functions 2 | 3 | A function in Aqua is a block of code expressing a workflow, i.e., a coordination scenario that works across one or more peers. 4 | 5 | A function may take arguments of any type and may return a value. 6 | 7 | A function can call other functions, take functions as arguments of [arrow type](../types.md#arrow-types) and be provided as an arrow argument. 8 | 9 | Essentially, a function is an arrow. The function call is an expression that connects named arguments to an arrow, and gives a name to the result. 10 | 11 | In essense, all a function does is call its arguments or service functions. 12 | 13 | ```aqua 14 | service MySrv: 15 | foo() 16 | 17 | func do_something(): -- arrow of type: -> () 18 | MySrv "srv id" 19 | MySrv.foo() 20 | ``` 21 | 22 | -------------------------------------------------------------------------------- /docs/aqua-book/language/expressions/header.md: -------------------------------------------------------------------------------- 1 | # Header 2 | 3 | ## Header expressions 4 | 5 | ### `import` 6 | 7 | The `import` expression brings everything defined within the imported file into the scope. 8 | 9 | ```aqua 10 | import "path/to/file.aqua" 11 | ``` 12 | 13 | The to be imported file path is first resolved relative to the source file path followed by checking for an `-imports` directories. 14 | 15 | See [Imports & Exports](../header/header.md) for details. 16 | -------------------------------------------------------------------------------- /docs/aqua-book/language/expressions/overridable-constants.md: -------------------------------------------------------------------------------- 1 | --- 2 | description: Static configuration pieces that affect compilation 3 | --- 4 | 5 | # Overridable constants 6 | 7 | ## `const` 8 | 9 | Constant definition. 10 | 11 | Constants can be used all across functions, exported and imported. If a constant is defined using `?=` , it can be overridden by value via compiler flags or imported values. 12 | 13 | ```aqua 14 | -- This can be overridden with --const 'TARGET_PEER_ID = "other peer id"' 15 | const TARGET_PEER_ID ?= "this is a target peer id" 16 | 17 | -- This constant cannot be overridden 18 | const SERVICE_ID = "service id" 19 | ``` 20 | 21 | You can assign only literals to constants. Constant type is the same as literal type. You can override only with a subtype of that literal type. 22 | -------------------------------------------------------------------------------- /docs/aqua-book/language/expressions/services.md: -------------------------------------------------------------------------------- 1 | # Services 2 | 3 | A service is a program running on a peer. Every service has an interface that consists of a list of functions. To call a service, the service must be identified: so, every service has an ID that must be resolved in the peer scope. 4 | 5 | In the service definition, you enumerate all the functions, their names, argument, and return types, and optionally provide the default Service ID. 6 | 7 | Services that are a part of the protocol, i.e. are available from the peer node, come along with IDs. Example of predefined service: 8 | 9 | ```aqua 10 | service Peer("peer"): 11 | foo() -- no arguments, no return 12 | bar(i: bool) -> bool 13 | 14 | func usePeer() -> bool: 15 | Peer.foo() -- results in a call of service "peer", function "foo", on current peer ID 16 | z <- Peer.bar(true) 17 | <- z 18 | ``` 19 | 20 | Example of a custom service: 21 | 22 | ```aqua 23 | service MyService: 24 | foo() 25 | bar(i: bool, z: i32) -> string 26 | 27 | func useMyService(k: i32) -> string: 28 | -- Need to tell the compiler what does "my service" mean in this scope 29 | MyService "my service id" 30 | MyService.foo() 31 | on "another peer id": 32 | -- Need to redefine MyService in scope of this peer as well 33 | MyService "another service id" 34 | z <- MyService.bar(false, k) 35 | <- z 36 | ``` 37 | 38 | Service definitions have types. Type of a service is a product type of arrows. See [Types](../types.md#type-of-a-service-and-a-file). 39 | -------------------------------------------------------------------------------- /docs/aqua-book/language/flow/conditional.md: -------------------------------------------------------------------------------- 1 | # Conditional 2 | 3 | Aqua supports branching, you can: 4 | - Check boolean expression with [`if`](#if) 5 | - Recover from error with [`try`](#try) or [`otherwise`](#otherwise) 6 | - Return different results with [conditional return](#conditional-return) 7 | 8 | ## Contract 9 | 10 | * The second branch of the conditional operator is executed if and only if the first block failed. 11 | * The second branch has no access to the first branch's data. 12 | * A conditional block is considered "executed" if and only if any branch was executed successfully. 13 | * A conditional block is considered "failed" if and only if the second (recovery) branch failed. 14 | 15 | ## Conditional operations 16 | 17 | ### `if` 18 | 19 | The first branch of the conditional operator, executed only if the condition holds. 20 | 21 | ```aqua 22 | x = true 23 | if x: 24 | -- always executed 25 | foo() 26 | 27 | if x == false: 28 | -- never executed 29 | bar() 30 | 31 | if x != false: 32 | -- always executed 33 | baz() 34 | ``` 35 | 36 | Any expression that produces `bool` is acceptable as a condition. 37 | 38 | `if` corresponds to `match`, `mismatch` extension of π-calculus. 39 | 40 | ### `else` 41 | 42 | The second branch of `if`, executed only in case the condition does not hold. 43 | 44 | ```aqua 45 | if false: 46 | foo() -- skipped 47 | else: 48 | bar() -- executed 49 | ``` 50 | 51 | If you want to set a variable based on condition, see [conditional return](#conditional-return). 52 | 53 | ### `try` 54 | 55 | Tries to perform operations, swallows produced error (if there's no `catch`, otherwise executes `catch`). 56 | 57 | ```aqua 58 | try: 59 | -- If foo fails with an error, execution will continue 60 | -- You should write your logic in a non-blocking fashion: 61 | -- If your code below depends on `x`, it may halt as `x` is not resolved. 62 | -- See conditional return below for workaround 63 | x <- foo() 64 | ``` 65 | 66 | ### `catch` 67 | 68 | Catches the standard error from the `try` block. 69 | 70 | ```aqua 71 | try: 72 | foo() 73 | catch e: 74 | logError(e) 75 | ``` 76 | 77 | Type of `e` is: 78 | 79 | ```aqua 80 | data LastError: 81 | instruction: string -- What AIR instruction failed 82 | msg: string -- Human-readable error message 83 | peer_id: string -- On what peer the error happened 84 | ``` 85 | 86 | ### `otherwise` 87 | 88 | You may add `otherwise` to provide recovery for any block or expression: 89 | 90 | ```aqua 91 | x <- foo() 92 | otherwise: 93 | -- if foo can't be executed, then do bar() 94 | y <- bar() 95 | ``` 96 | 97 | ## Conditional return 98 | 99 | In Aqua, functions may have only one return expression, which is the very last. 100 | 101 | So to get the value based on condition, we need to use a [writeable collection](../types.md#collection-types). 102 | 103 | ```aqua 104 | -- result may have 0 or more values of type string and is writeable 105 | resultBox: *string 106 | try: 107 | resultBox <- foo() 108 | otherwise: 109 | resultBox <- bar() 110 | 111 | -- now result contains only one value, let's extract it! 112 | result = resultBox! 113 | 114 | -- Type of result is string 115 | -- Please note that if there were no writes to resultBox, 116 | -- the first use of result will halt. 117 | -- So you need to be careful about it and ensure that there's always a value. 118 | ``` 119 | -------------------------------------------------------------------------------- /docs/aqua-book/language/flow/flow.md: -------------------------------------------------------------------------------- 1 | # Execution flow 2 | 3 | Aqua's main goal is to express how the execution flows: moves from peer to peer, forks to parallel flows and then joins back, uses data from one step in another. 4 | 5 | As the foundation of Aqua is based on π-calculus, finally flow is decomposed into [sequential](sequential.md) (`seq`, `.`), [conditional](conditional.md) (`xor`, `+`), [parallel](parallel.md) (`par`, `|`) computations and [iterations](iterative.md) based on data (`!P`). For each basic way to organize the flow, Aqua follows a set of rules to execute the operations: 6 | 7 | * What data is available for use? 8 | * What data is exported and can be used below? 9 | * How errors and failures are handled? 10 | 11 | These rules form a contract, as in [design-by-contract](https://en.wikipedia.org/wiki/Design_by_contract) programming. 12 | -------------------------------------------------------------------------------- /docs/aqua-book/language/flow/iterative.md: -------------------------------------------------------------------------------- 1 | # Iterative 2 | 3 | π-calculus has a notion of the repetitive process: `!P = P | !P`. That means, you can always fork a new `P` process if you need it. 4 | 5 | In Aqua, two operations correspond to it: you can call a service function (it's just available when it's needed), and you can use `for` loop to iterate on collections. 6 | 7 | ## `for` expression 8 | 9 | In short, `for` looks like the following: 10 | 11 | ```aqua 12 | xs: []string 13 | 14 | for x <- xs: 15 | y <- foo(x) 16 | 17 | -- x and y are not accessible there, you can even redefine them 18 | x <- bar() 19 | y <- baz() 20 | ``` 21 | 22 | ## Contract 23 | 24 | * Iterations of `for` loop are executed sequentially by default. 25 | * Variables defined inside `for` loop are not available outside. 26 | * `for` loop's code has access to all variables above. 27 | * `for` can be executed on a variable of any [Collection type](../types.md#collection-types). 28 | 29 | ### Conditional `for` 30 | 31 | For can be executed on a variable of any [Collection type](../types.md#collection-types). You can make several trials in a loop, and break once any trial succeeded. 32 | 33 | ```aqua 34 | xs: []string 35 | 36 | for x <- xs try: 37 | -- Will stop trying once foo succeeds 38 | foo(x) 39 | ``` 40 | 41 | The contract is changed as in [Parallel](parallel.md#contract) flow. 42 | 43 | ### Parallel `for` 44 | 45 | Running many operations in parallel is the most commonly used pattern for `for`. 46 | 47 | ```aqua 48 | xs: []string 49 | 50 | for x <- xs par: 51 | on x: 52 | foo() 53 | 54 | -- Once the fastest x succeeds, execution continues 55 | -- If you want to make the subsequent execution independent from for, 56 | -- mark it with par, e.g.: 57 | par continueWithBaz() 58 | ``` 59 | 60 | The contract is changed as in [Conditional](conditional.md#contract) flow. 61 | 62 | ### Export data from `for` 63 | 64 | The way to export data from `for` is the same as in [Conditional return](conditional.md#conditional-return) and [Race patterns](parallel.md#join-behavior). 65 | 66 | ```aqua 67 | xs: []string 68 | return: *string 69 | 70 | -- can be par, try, or nothing 71 | for x <- xs par: 72 | on x: 73 | return <- foo() 74 | 75 | -- Wait for 6 fastest results -- see Join behavior 76 | baz(return!5, return) 77 | ``` 78 | 79 | ### `for` on streams 80 | 81 | `for` on streams is one of the most advanced and powerful parts of Aqua. See [CRDT streams](../crdt-streams.md) for details. 82 | -------------------------------------------------------------------------------- /docs/aqua-book/language/flow/sequential.md: -------------------------------------------------------------------------------- 1 | # Sequential 2 | 3 | By default, Aqua code is executed line by line, sequentially. 4 | 5 | ## Contract 6 | 7 | * Data from the first line is available on the second line 8 | * A second line will be executed only if the first line succeeded 9 | * If any line failed, then the whole block is failed 10 | * If all lines succeeded, then the whole block is succeeded 11 | 12 | ```aqua 13 | f <- first() -- first line 14 | second(f) -- second line 15 | ``` 16 | 17 | _A block of code is any number of lines on the same indentation level or deeper._ 18 | 19 | ## Sequential operations 20 | 21 | ### call arrow 22 | 23 | Any runnable piece of code in Aqua is an arrow from its domain to the codomain. 24 | 25 | ```aqua 26 | -- Call a function 27 | foo() 28 | 29 | -- Call a function that returns something, assign results to a variable 30 | x <- foo() 31 | 32 | -- Call an ability function 33 | y <- Peer.identify() 34 | 35 | -- Pass an argument 36 | z <- Op.identity(y) 37 | ``` 38 | 39 | When you write `<-`, this means not just "assign results of the function on the right to variable on the left". It means that all the effects are executed: [service](../services.md) may change state, the [topology](../topology.md) may be shifted. But you end up being (semantically) on the same peer where you have called the arrow. 40 | 41 | ### on 42 | 43 | `on` denotes the peer where the code must be executed. `on` is handled sequentially, and the code inside is executed line by line by default. 44 | 45 | ```aqua 46 | func foo(): 47 | -- Will be executed where `foo` was executed 48 | bar() 49 | 50 | -- Move to another peer 51 | on another_peer: 52 | -- To call bar, we need to leave the peer where we were and get to another_peer 53 | -- It's done automatically 54 | bar() 55 | 56 | on third_peer via relay: 57 | -- This is executed on third_peer 58 | -- But we denote that to get to third_peer and to leave third_peer 59 | -- an additional hop is needed: get to relay, then to peer 60 | bar() 61 | 62 | -- Will be executed in the `foo` call site again 63 | -- To get from the previous `bar`, compiler will add a hop to relay 64 | bar() 65 | ``` 66 | 67 | See more in the [Topology](../topology.md) section. 68 | -------------------------------------------------------------------------------- /docs/aqua-book/language/header/header.md: -------------------------------------------------------------------------------- 1 | # Imports And Exports 2 | 3 | An Aqua source file has a header and a body. The body contains function definitions, services, types, constants. The header manages what is imported from other files and what is exported. 4 | 5 | ## Aqua source file header 6 | 7 | When header is omitted, `.aqua` file exports and declares everything it contains. With `aqua` header you can control what gets exported from the aqua file. 8 | 9 | ```aqua 10 | -- `aqua` expression may be only on the very first line of the file 11 | aqua AquaFile declares * 12 | ``` 13 | 14 | `Aqua.File` may contain dots. 15 | 16 | `AquaFile` can be used as the aqua's name when this file is `use`d. In this case, only what is enumerated in `declares` section will be available. `declares *` allows you to declare everything in the file as the module interface. 17 | 18 | ```aqua 19 | aqua AquaFile declares CONST_NAME, ServiceName, MyType, fn 20 | 21 | const CONST_NAME = "something" 22 | 23 | service ServiceName: 24 | do_something() 25 | 26 | data MyType: 27 | result: i32 28 | 29 | function fn() -> string: 30 | <- CONST_NAME 31 | ``` 32 | 33 | ## Import Expression 34 | 35 | The main way to import a file is via `import` expression: 36 | 37 | ```aqua 38 | import "@fluencelabs/aqua-lib/builtin.aqua" 39 | 40 | func foo(): 41 | Op.noop() 42 | ``` 43 | 44 | Aqua compiler takes a source directory and a list of import directories (usually with `node_modules` as a default). You can use relative paths to `.aqua` files, relatively to the current file's path, and to import folders. 45 | 46 | :::info 47 | `.aqua` extension in `import` and `use` expressions can be omitted. So, `import "builtin.aqua"` does exactly the same as `import "builtin"`. 48 | ::: 49 | 50 | Everything defined in the file is imported into the current namespace. 51 | 52 | You can cherry-pick and rename imports using `import ... from` expression: 53 | 54 | ```aqua 55 | import Op as Noop from "@fluencelabs/aqua-lib/builtin" 56 | 57 | func foo(): 58 | Noop.noop() 59 | ``` 60 | 61 | ## Use Expression 62 | 63 | The `use` expression makes it possible to import a file into a named scope. 64 | 65 | ```aqua 66 | use Op from "@fluencelabs/aqua-lib/builtin" as BuiltIn 67 | 68 | func foo(): 69 | BuiltIn.Op.noop() 70 | ``` 71 | 72 | If the imported file has a `aqua` header, `from` and `as` sections of `use` may be omitted. 73 | 74 | ```aqua 75 | use "@fluencelabs/aqua-lib/builtin.aqua" 76 | -- Assume that builtin.aqua's header is `aqua BuiltIn declares *` 77 | 78 | func foo(): 79 | BuiltIn.Op.noop() 80 | ``` 81 | 82 | ## Export 83 | 84 | While it's useful to split the code into several functions into different files, it's not always a good idea to compile everything into the host language. 85 | 86 | Another problem is libraries distribution. If a developer wants to deliver an `.aqua` library, he or she often needs to provide it in compiled form as well. 87 | 88 | `export` lets a developer decide what exactly is going to be exported, including imported functions. 89 | 90 | ```aqua 91 | import bar from "lib" 92 | 93 | -- Exported functions and services will be compiled for the host language 94 | -- You can use several `export` expressions 95 | export foo as my_foo 96 | export bar, MySrv 97 | 98 | service MySrv: 99 | call_something() 100 | 101 | func foo() -> bool: 102 | <- true 103 | ``` 104 | -------------------------------------------------------------------------------- /docs/aqua-book/language/language.md: -------------------------------------------------------------------------------- 1 | # Language 2 | 3 | Aqua is a language for distributed workflow coordination in p2p networks. 4 | 5 | It's structured with significant indentation: 6 | - Tabs and spaces are allowed simultaneously 7 | - Indentation of a parent block should be a strict prefix of indentation of a child block 8 | - First line in a block defines indentation and all consequent lines should have the same indentation 9 | 10 | ```aqua 11 | -- Comments begin with double-dash and end with the line (inline) 12 | func foo(): -- Comments are allowed almost everywhere 13 | -- Body of the block expression is indented 14 | bar(5) 15 | ``` 16 | 17 | Values in Aqua have types, which are designated by a colon, `:`, as seen in the function signature below. The type of a return, which is yielded when a function is executed, is denoted by an arrow pointing to the right `->` , whereas yielding is denoted by an arrow pointing to the left `<-`. 18 | 19 | ```aqua 20 | -- Define a function that yields a string 21 | func bar(arg: i16) -> string: 22 | -- Call a function 23 | someFunc(arg) 24 | 25 | -- Yield a value from a function 26 | x <- someFunc(arg) 27 | 28 | -- Return a yielded results from a function 29 | <- "return literal" 30 | ``` 31 | 32 | Subsequent sections explain the main parts of Aqua. 33 | 34 | Data: 35 | 36 | * [Types](types.md) 37 | * [Values of that types](values.md) 38 | 39 | Execution: 40 | 41 | * [Topology](topology.md) – how to express where the code should be executed 42 | * [Execution flow](flow/flow.md) – control structures 43 | 44 | Computations: 45 | 46 | * [Services](services.md) 47 | * [Abilities](abilities.md) 48 | 49 | Advanced parallelism: 50 | 51 | * [CRDT Streams](crdt-streams.md) 52 | 53 | Code management: 54 | 55 | * [Imports & exports](header/header.md) 56 | 57 | Reference: 58 | 59 | * [Expressions](expressions/expressions.md) 60 | -------------------------------------------------------------------------------- /docs/aqua-book/language/services.md: -------------------------------------------------------------------------------- 1 | # Services 2 | 3 | Services describe what can be called on peers, and how to call it. A service interfaces functions (often provided via WebAssembly interface) executable on a peer. Example of service definition: 4 | 5 | ```aqua 6 | service MyService: 7 | foo(arg: string) -> string 8 | bar() -> bool 9 | baz(arg: i32) 10 | ``` 11 | 12 | Service functions in Aqua have no function body. Computations, of any complexity, are implemented with any programming language that fits, and then brought to the Aqua execution context. Aqua calls these functions but does not peak into what's going on inside. 13 | 14 | ## Built-in Services 15 | 16 | Some services may be singletons available on all peers. Such services are called built-ins, and are always available in any scope. 17 | 18 | ```aqua 19 | -- Built-in service has a constant ID, so it's always resolved 20 | service Op("op"): 21 | noop() 22 | 23 | func foo(): 24 | -- Call the noop function of "op" service locally 25 | Op.noop() 26 | ``` 27 | 28 | ## Service Resolution 29 | 30 | A peer may host many services of the same type. To distinguish services from each other, Aqua requires Service resolution to be done: that means, the developer must provide an ID of the service to be used on the peer. 31 | 32 | ```aqua 33 | service MyService: 34 | noop() 35 | 36 | func foo(): 37 | -- Will fail 38 | MyService.noop() 39 | 40 | -- Resolve MyService: it has id "noop" 41 | MyService "noop" 42 | 43 | -- Can use it now 44 | MyService.noop() 45 | 46 | on "other peer": 47 | -- Should fail: we haven't resolved MyService ID on other peer 48 | MyService.noop() 49 | 50 | -- Resolve MyService on peer "other peer" 51 | MyService "other noop" 52 | MyService.noop() 53 | 54 | -- Moved back to initial peer, here MyService is resolved to "noop" 55 | MyService.noop() 56 | ``` 57 | 58 | There's no way to call an external function in Aqua without defining all the data types and the service type. One of the most convenient ways to do it is to generate Aqua types from Wasm code in Marine. 59 | -------------------------------------------------------------------------------- /docs/aqua-book/libraries/aqua-lib.md: -------------------------------------------------------------------------------- 1 | --- 2 | description: API of protocol-level service (a.k.a builtins) 3 | --- 4 | 5 | # @fluencelabs/aqua-lib 6 | 7 | ## Releases 8 | 9 | You can find the latest releases of `aqua-lib` [on NPM](https://www.npmjs.com/package/@fluencelabs/aqua-lib) and changelogs are [on GitHub](https://github.com/fluencelabs/aqua-lib/releases) 10 | 11 | ## API 12 | 13 | The most up-to-date documentation of the API is in the code, please [check it out on GitHub](https://github.com/fluencelabs/aqua-lib/blob/main/builtin.aqua) 14 | 15 | ### Services 16 | 17 | `aqua-lib` defines a number of services available on peers in the Fluence Network: 18 | 19 | * `Op` - short for "Operations". Functions for data transformation. 20 | * `Peer` - functions affecting peer's internal state 21 | * `Kademlia` - functions to manipulate libp2p Kademlia 22 | * `Srv` - short for "Service". Functions for service manipulation 23 | * `Dist` - short for "Distribution". Functions for module and blueprint distribution 24 | * `Script` - functions to run and remove scheduled (recurring) scripts 25 | 26 | ## How to use it 27 | 28 | ### In Aqua 29 | 30 | Add `@fluencelabs/aqua-lib` to your dependencies as described in [Libraries doc](./libraries.md), and then import it in your Aqua script: 31 | 32 | ```aqua 33 | import "@fluencelabs/aqua-lib/builtin.aqua" 34 | 35 | -- gather Peer.identify from all nodes in the neighborhood 36 | func getPeersInfo() -> []Info: 37 | infos: *Info 38 | nodes <- Kademlia.neighborhood(INIT_PEER_ID, nil, nil) 39 | for node <- nodes: 40 | on node: 41 | infos <- Peer.identify() 42 | <- infos 43 | ``` 44 | 45 | ### In TypeScript 46 | 47 | `aqua-lib` is meant to be used to write Aqua scripts, and since`aqua-lib` doesn't export any top-level functions, it's not callable directly in the TypeScript. 48 | 49 | ## Patterns 50 | 51 | ### Functions With A Variable Number Of Arguments 52 | 53 | Currently, Aqua doesn't allow to define functions with a variable number of arguments. And that limits `aqua-lib` API. But there's a way around that. 54 | 55 | Let's take `Op.concat_strings` as an example. You can use it to concatenate several strings. `aqua-lib` provides the following signature: 56 | 57 | ```aqua 58 | concat_strings(a: string, b: string) -> string 59 | ``` 60 | 61 | Sometimes that is enough, but sometimes you need to concatenate more than 2 strings at a time. Happily, under the hood `concat_strings` accepts any number of arguments, so you can redeclare it with the number of arguments that you want: 62 | 63 | ```aqua 64 | service MyOp("op"): 65 | concat_strings(a: string, b: string, c: string, d: string) -> string 66 | ``` 67 | 68 | #### List of operations with a variable number of arguments 69 | 70 | Here's a full list of other Op-s that you can apply this pattern to 71 | 72 | * `Op.concat` - can concatenate any number of arrays 73 | * `Op.array` - wraps any number of arguments into an array 74 | * `Op.concat_string` - concatenates any number of strings 75 | -------------------------------------------------------------------------------- /docs/aqua-book/libraries/libraries.md: -------------------------------------------------------------------------------- 1 | # Libraries 2 | 3 | `import` declaration allows to use functions, services and data types defined in another module on the file system. While it's a very simple mechanic, together with NPM flexibility it enables full-blown package management in Aqua. 4 | 5 | ## Available Aqua Libraries 6 | 7 | * Builtin services API: [@fluencelabs/aqua-lib](aqua-lib.md) (see on [NPM](https://www.npmjs.com/package/@fluencelabs/aqua-lib)) 8 | * Registry: [@fluencelabs/registry](registry.md) (see on [NPM](https://www.npmjs.com/package/@fluencelabs/registry)) 9 | * IPFS API: [@fluencelabs/aqua-ipfs](aqua-ipfs.md) (see on [NPM](https://www.npmjs.com/package/@fluencelabs/aqua-ipfs)) 10 | 11 | ## How To Use Aqua Libraries 12 | 13 | To use a library, you need to download it by adding the library to `dependencies` in `package.json` and then running `npm install`. 14 | 15 | :::info 16 | If you're not familiar with NPM, `package.json` is a project definition file. You can specify `dependencies` to be downloaded from [npm](https://npmjs.org) and define custom commands (`scripts`), which can be executed from the command line, e.g. `npm run compile-aqua.` 17 | 18 | To create an NPM project, run `npm init`in a directory of your choice and follow the instructions. 19 | ::: 20 | 21 | Here's an example of adding `aqua-lib` to `package.json` dependencies: 22 | 23 | ```json 24 | { 25 | "name": "my-awesome-project", 26 | "version": "0.0.1", 27 | "dependencies": { 28 | "@fluencelabs/aqua-lib": "0.1.10" 29 | } 30 | } 31 | ``` 32 | 33 | After running `npm i`, you will have `@fluencelabs/aqua-lib` in `node_modules` 34 | 35 | ### In Aqua 36 | 37 | After the library is downloaded, you can import it in your `.aqua` script as documented in [Imports And Exports](../language/header/header.md): 38 | 39 | ```typescript 40 | import "@fluencelabs/aqua-lib/builtin.aqua" 41 | ``` 42 | 43 | Check out corresponding pages for the API of available libraries. 44 | 45 | ### In TypeScript and JavaScript 46 | 47 | To execute Aqua functions, you need to be connected to the Fluence network. The easiest way is to add JS SDK to `dependencies`: 48 | 49 | ```json 50 | "dependencies": { 51 | "@fluencelabs/registry": "0.3.2", 52 | "@fluencelabs/fluence": "0.21.5", 53 | "@fluencelabs/fluence-network-environment": "1.0.13" 54 | } 55 | ``` 56 | 57 | After executing `npm install`, the Aqua API is ready to use. Now you need to export `registry` functions to TypeScript, that's easy. Create a file `export.aqua`: 58 | 59 | ```aqua 60 | import createRouteAndRegisterBlocking, resolveRoute from "@fluencelabs/registry/routing.aqua" 61 | 62 | export createRouteAndRegisterBlocking, resolveRoute 63 | ``` 64 | 65 | Now, install Aqua compiler and compile your Aqua code to TypeScript: 66 | 67 | ```sh 68 | npm install --save-dev @fluencelabs/aqua 69 | aqua -i . -o src/generated/ 70 | ``` 71 | 72 | That's it. Now let's call some functions on the Registry service: 73 | 74 | ```typescript 75 | import { Fluence } from "@fluencelabs/fluence"; 76 | import { krasnodar } from "@fluencelabs/fluence-network-environment"; 77 | import { createRouteAndRegisterBlocking, resolveRoute } from "./generated/export"; 78 | 79 | async function main() { 80 | // connect to the Fluence network 81 | await Fluence.start({ connectTo: krasnodar[1] }); 82 | 83 | let label = "myLabel"; 84 | let value = "put anything useful here"; 85 | let serviceId = "Foo"; 86 | let ack = 5; 87 | 88 | // create route and register for it 89 | let relay = Fluence.getStatus().relayPeerId; 90 | let route_id = await createRouteAndRegisterBlocking( 91 | label, value, relay, serviceId, 92 | (s) => console.log(`node ${s} saved the record`), 93 | ack 94 | ); 95 | 96 | // this will contain peer as route provider 97 | let providers = await resolveRoute(route_id, ack); 98 | } 99 | 100 | main().then(() => process.exit(0)) 101 | .catch(error => { 102 | console.error(error); 103 | process.exit(1); 104 | }); 105 | 106 | ``` 107 | -------------------------------------------------------------------------------- /docs/aqua-book/libraries/registry.md: -------------------------------------------------------------------------------- 1 | --- 2 | description: Aqua implementation of Fluence Registry and ResourcesAPI 3 | --- 4 | 5 | # @fluencelabs/registry 6 | 7 | Fluence Registry is an essential part of the Fluence network protocol. It provides a Resources API that can be used for service advertisement and discovery. For more details check out our [community call](https://www.youtube.com/watch?v=Md0_Ny_5_1o&t=770s). 8 | 9 | ## Releases 10 | 11 | You can find the latest `registry` release [on NPM](https://www.npmjs.com/package/@fluencelabs/registry) and the changelogs are in the [GitHub](https://github.com/fluencelabs/registry/releases) repo. 12 | 13 | ## API 14 | 15 | For the API implementation, take a look at [resources-api.aqua](https://github.com/fluencelabs/registry/blob/main/aqua/resources-api.aqua) in the `registry` repo. 16 | 17 | ## Learn 18 | 19 | You can checkout [README](https://github.com/fluencelabs/registry#readme) and follow the [example](https://github.com/fluencelabs/registry/tree/main/example#services-advertisement-and-discovery) -------------------------------------------------------------------------------- /docs/build/concepts/best_practices.md: -------------------------------------------------------------------------------- 1 | # Best Practices -------------------------------------------------------------------------------- /docs/build/concepts/fluence_functions_revisited.md: -------------------------------------------------------------------------------- 1 | # Fluence Functions Revisited -------------------------------------------------------------------------------- /docs/build/concepts/http_gateways.md: -------------------------------------------------------------------------------- 1 | # Handling HTTP Events -------------------------------------------------------------------------------- /docs/build/concepts/scheduling_functions.md: -------------------------------------------------------------------------------- 1 | # Scheduling Fluence Functions 2 | 3 | ## Introduction 4 | 5 | Like most serverless function, Fluence compute functions sit idle unless invoked. For the most part, event-based triggers will do the job, **link** to js-client. However, time-based triggers, such as cronjobs to poll some resource or simply wake up some other function at some pre-determined interval, are also a common source of function invocation. 6 | 7 | The Fluence Cloudless platform accommodates time-based triggers via Cloudless Scheduled Functions (aka spells). -------------------------------------------------------------------------------- /docs/build/concepts/security.md: -------------------------------------------------------------------------------- 1 | # Security -------------------------------------------------------------------------------- /docs/build/examples/frpc.md: -------------------------------------------------------------------------------- 1 | # Decentralized RPC With Fluence Functions 2 | 3 | Fluence's [fRPC Substrate](https://github.com/fluencelabs/frPC-Substrate) is a starter kit that includes all the components you need to quickly enable your dAPP with decentralized RPC using existing RPC as Service providers, e.g., Infura, Alchemy, QuickNode, etc., without having to modify your dApp's business logic or web3 libraries. -------------------------------------------------------------------------------- /docs/build/how-to/configure.md: -------------------------------------------------------------------------------- 1 | # Configure FLuence CLI -------------------------------------------------------------------------------- /docs/build/how-to/deploy.md: -------------------------------------------------------------------------------- 1 | # Deploy Your Fluence Functions -------------------------------------------------------------------------------- /docs/build/how-to/develop.md: -------------------------------------------------------------------------------- 1 | # Develop Your Fluence Functions 2 | 3 | -------------------------------------------------------------------------------- /docs/build/how-to/migrate.md: -------------------------------------------------------------------------------- 1 | # How To Migrate Your Deployed Fluence Functions -------------------------------------------------------------------------------- /docs/build/how-to/monitor.md: -------------------------------------------------------------------------------- 1 | # How To Monitor Your Fluence Functions 2 | -------------------------------------------------------------------------------- /docs/build/how-to/securing_functions.md: -------------------------------------------------------------------------------- 1 | # Secure your Fluence Functions -------------------------------------------------------------------------------- /docs/build/how-to/setting_up.md: -------------------------------------------------------------------------------- 1 | # Set Up Your Development Environment 2 | 3 | ## Overview 4 | 5 | Fluence provides an CLI that not only supports the scaffolding of development projects bu also manages a number of development dependencies including the Rust development tools necessary to code your business logic and compile to wasm-wasi. With respect to 6 | 7 | 8 | ## Fluence Tooling 9 | 10 | ### Preparing your system 11 | 12 | [node](https://nodejs.org/en/learn/getting-started/how-to-install-nodejs) 13 | 14 | ### FLuence CLI 15 | 16 | #### Install From Binary 17 | 18 | #### Install From Package Manager 19 | 20 | #### Install From Source 21 | 22 | 23 | ### VSCode Plug-In 24 | 25 | VSCode marketplace 26 | 27 | 28 | ## Crypto Wallet 29 | 30 | Note: Hopefully we won't need that 31 | 32 | ## Payment Account 33 | 34 | Fiat On Ramp: TBD 35 | 36 | -------------------------------------------------------------------------------- /docs/build/how-to/setup_payments.md: -------------------------------------------------------------------------------- 1 | # Manage Payments And Billing -------------------------------------------------------------------------------- /docs/build/how-to/test.md: -------------------------------------------------------------------------------- 1 | # Test Your Fluence Functions -------------------------------------------------------------------------------- /docs/build/overview/getting_started.md: -------------------------------------------------------------------------------- 1 | # Getting Started 2 | 3 | Let's explore the obligatory **Hello World** example as an end-to-end Fluence Cloudless App, which includes the following steps: 4 | 5 | * Scaffold a Fluence Cloud Function project with the [Fluence CLI](./../glossary#fluence-cli) 6 | * Create the Hello World example and compile it to Wasm 7 | * Distribute the Wasm module to capacity (hardware) providers 8 | * Execute your Fluence Functions Hello World application 9 | 10 | But first, let's get set up. 11 | 12 | ## Setting Up 13 | 14 | The recommended way to interact with the Fluence serverless network is to use the Fluence CLI. The CLI provides full lifecycle management for your Fluence Functions as well as your tooling and development dependencies. If you haven't installed the Fluence CLI already, use the install script provided below or check out the [Setting up](./../setting-up/setting_up.md) section. 15 | 16 | ```bash 17 | curl -qsL https://raw.githubusercontent.com/fluencelabs/cli/main/install.sh | bash 18 | ``` 19 | 20 | :::note 21 | Currently, Fluence CLI does not support Windows OS but supports Windows Linux Subsystem (WLS). 22 | ::: 23 | 24 | :::info 25 | During the installation process, you may be asked to provide *sudo* access to set the symlink for the binary. 26 | Alternative installation approaches can be found in the [Readme](https://github.com/fluencelabs/cli?tab=readme-ov-file#installation-and-usage). 27 | ::: 28 | 29 | After the installation process is complete, update the CLI with `fluence update stable` and check the version: 30 | 31 | ```bash 32 | fluence --version 33 | @fluencelabs/cli/0.15.10 darwin-arm64 node-v18.19.1 34 | ``` 35 | 36 | If you get the above CLI version, or higher, you are good to go. 37 | 38 | ## Hello World 39 | 40 | With the Fluence CLI installed, let's create our *hello world* project: 41 | 42 | ```bash 43 | fluence init hello-fluence 44 | ``` 45 | 46 | You will be asked to choose from different scaffolding templates: 47 | 48 | ```bash 49 | fluence init hello-fluence 50 | ? Select template (Use arrow keys) 51 | ❯ quickstart 52 | minimal 53 | ts 54 | js 55 | ``` 56 | 57 | Select the (default) *quickstart* template and in the subsequent network selection prompt continue to stay with the default (*kras*) network. Fluence CLI now scaffolds a project with the quickstart template and for the *kras* test network. Since this is your first use of the Fluence CLI, several dependencies may be downloaded and installed. Once the project has been successfully installed, you should see a message similar to: 58 | 59 | ```bash 60 | Successfully initialized Fluence CLI project template at /hello-fluence 61 | ``` 62 | 63 | Now *cd* into the *hello-fluence* directory and feel free to poke around the project. Our next step is to run *hello world* 64 | 65 | ```bash 66 | $ fluence run -f 'helloWorldRemote("Fluence")' --quiet 67 | ``` 68 | Which results in the following response: 69 | 70 | ```bash 71 | "Hi, Fluence" 72 | ``` 73 | 74 | Congratulations! You just scaffolded your first Fluence project and executed your first *Hello World* on a remote peer on the *dar* test network. We'll revisit our *Hello World* project in the [Quickstart](./../quickstarts/your_first_function.md) section. -------------------------------------------------------------------------------- /docs/build/overview/roadmap.md: -------------------------------------------------------------------------------- 1 | # Roadmap 2 | 3 | Coming soon. -------------------------------------------------------------------------------- /docs/build/references.md: -------------------------------------------------------------------------------- 1 | # References -------------------------------------------------------------------------------- /docs/build/security.md: -------------------------------------------------------------------------------- 1 | # Security 2 | 3 | revised edition -------------------------------------------------------------------------------- /docs/build/setting-up/setting_up.md: -------------------------------------------------------------------------------- 1 | # Setting Up 2 | 3 | ## Introduction 4 | 5 | In order to get your [Cloudless App](./../glossary#cloudless-app) developed and running, some housekeeping with respect to both development and payment environments are required. 6 | 7 | Fluence Cloudless offers you, the developer, a great degree of control over almost every aspect of your Cloudless App: 8 | 9 | * which data center(s) host you cloudless code, e.g., geo-location or carbon footprint requirements 10 | * what capacity capabilities execute your functions, e.g., CPU and RAM type 11 | * what level of resources you want to power your functions, e.g., number of CPUs 12 | * what level of availability you want for your Cloudless App. 13 | 14 | Moreover, in Fluence's *"verify, don't trust"* paradigm, providers have to submit [cryptographic proofs](./../glossary#proofs) attesting to the correct execution of your Cloudless Functions in order to be able to collect the pre-agreed price for their compute services rendered. Hence, the underlying billing and payment models also are different. 15 | 16 | Instead of a credit card on file that is (for the most part) charged at the end of the month for compute service charges incurred over the billing period, e.g., the last calendar month, as reported by the cloud provider, Fluence Cloudless operates on a pre-payment and token model putting you, the developer, fully into control of your payments. 17 | 18 | ### Fluence Networks 19 | 20 | In order to create and operate your Cloudless App, you need to interact with two different networks: the Fluence Compute Network and the Fluence Compute Marketplace. The Fluence Compute Network is a peer-to-peer network connecting peers, i.e., servers in various data centers, hosting and executing your Cloudless Deployments on demand. The Fluence Compute Marketplace is a blockchain hosting the necessary smart contracts to allow you to commit your [developer offer](./../glossary#developer-offer) for matching with [provider offers](./../glossary#provider-offer) and to manage the proof-based charges from each peer owner, i.e., provider, running your [Cloudless Deployments](./../glossary#cloudless-deployment). Each network is available in a production, i.e., mainnet, or testing, i.e., testnet, flavor. In addition, the remote testnets can be stood-up locally to further ease development. 21 | 22 | Table 1: Network Names 23 | 24 | | | Compute Network | Marketplace Network | 25 | |---|---|---| 26 | | testnet| `dar`| TBD| 27 | | mainnet| `kras` | TBD | 28 | | local | `dar` | TBD| 29 | 30 | Testnet deployments require the same token types than the mainnet except that those tokens have no trading value and are freely available in small quantities to cloudless developers from the testnet *faucet*, i.e., a web app that facilitates the distribution of free tokens. In the case of the Fluence testnet. Again, both **tFLT** and **tUSDC** carry no trading value and are freely available to developers in small but sufficient quantities to develop and test their Cloudless Apps. 31 | 32 | For details concerning the operation of a local network, see [Working With A Local Network](./working_with_local_networks.md). 33 | 34 | ## Setting Up For Payment 35 | 36 | In order to handle tokens, testnet or otherwise, you need a crypto wallet. If you are unfamiliar with crypto wallets, have a look at this [introduction](https://www.coindesk.com/learn/your-first-crypto-wallet-how-to-use-it-and-why-you-need-one/) but [DuckDuckGo](https://duckduckgo.com/?q=introduction+to+crypto+wallets&df=y&ia=web) is your friend. Note that you will be storing ERC 20 type tokens and interacting with an EVM-compatible blockchain. That is, select a [wallet that is compatible with the Ethereum Virtual Machine](https://shardeum.org/blog/what-is-evm-wallet/). For illustrative purposes, we'll be using [MetaMask](https://metamask.io/). Moreover, we will primarily focus on testnet deployments. A guide for migrating your Cloudless App to mainnet is coming soon. 37 | 38 | Assuming you have your wallet ready to go, you need to add the testnet and testnet tokens **tFLT** and **tUSDC**, respectively, request test tokens from the Fluence faucet. 39 | 40 | ### Creating And Funding Your Wallet 41 | 42 | It is recommended to use a dedicated development account for your testnet. That is, create a new account in your wallet and name it, say, *Fluence DAR Testnet* and use this account only to manage your testnet tokens and chain interactions. 43 | 44 | In your wallet, you need to create a network entry for the Fluence IPC `dar` testnet. Use the following parameters: 45 | 46 | ```json 47 | { 48 | "network name": "Fluence Dar Testnet" 49 | "rpc url": "https://ipc-dar.fluence.dev", 50 | "chain id": 3525067388221321, 51 | "currency symbol": "tFLT", 52 | "block explorer url": "https://blockscout.dar.fluence.dev/" 53 | } 54 | ``` 55 | 56 | Once you got the network set, it's time to visit the faucet and request our token allocation. You can find all relevant support urls for the `dar` testnet [here](https://dar.fluence.dev/). 57 | 58 | ### Requesting Test Tokens From The Faucet 59 | 60 | Now that your account and wallet are setup, select the Fluence network you just added and grab the account address you want to use to hold your testnet tokens. Go to the Fluence [dar testnet faucet](https://faucet-dar.fluence.dev/), which prompts you to sign in with an email address. Shortly after submitting your email address, you will receive an email from `Faucet`. Make sure to check your spam folder. Copy the code into the open field and submit. At this point, you should see a screen similar to this: 61 | 62 | 63 | 64 |
65 | Dar Faucet 70 |
71 | 72 | Enter the address of your wallet and, if you are using MetaMask, ask for the *tUSDC* token symbol to be imported. Then click the "Receive FLT & tUSDC" button. After a short delay, you should see a transaction id and the funds should be in your account. 73 | 74 | You are now equipped to pay for your Cloudless Deployment on the Fluence testnet! -------------------------------------------------------------------------------- /docs/build/tutorials/event_handling_in_js.md: -------------------------------------------------------------------------------- 1 | # Event Handling In The Browser (Event Handling With Clients ?) 2 | 3 | The ubiquitous browser is the origin of a large number of diverse events, many of which are triggers for subsequent compute. In order to invoke Fluence Functions from the browser, we need to be able to somehow invoke Aqua scripts from the browser. This can be accomplished with the Fluence [js-client](https://github.com/fluencelabs/js-client). The *js-client* allows you to connect from the browser to the Fluence network and invoke the execution of the desired Aqua. 4 | 5 | ## Setting Up For The Browser 6 | 7 | Just like in the quickstart sections, we use Fluence CLI to scaffold out project with the appropriate template. Initialize the new project with: 8 | 9 | ```bash 10 | $ fluence init browser-events 11 | ``` 12 | Choose the `ts` template and the default `kras` environment: 13 | 14 | ```bash 15 | ? Select template quickstart 16 | ? Select Fluence Environment to use by default with this project kras (default) 17 | <...> 18 | Successfully initialized Fluence CLI project template at /Users/bebo/localdev/fluence-code/mvm-docs-code/browser-events 19 | ``` 20 | 21 | Before you `cd` into the new directory, recall that you also can non-interactively initialize the project with `fluence init -t ts --env kras `. Iime to check out the new project scaffold: 22 | 23 | ```bash 24 | tree -L 3 -I target 25 | . 26 | ├── Cargo.lock 27 | ├── Cargo.toml 28 | ├── README.md 29 | ├── fluence.yaml 30 | └── src 31 | ├── aqua 32 | │   └── main.aqua 33 | ├── frontend 34 | │   ├── index.html 35 | │   ├── package.json 36 | │   ├── src 37 | │   ├── tsconfig.json 38 | │   └── vite.config.ts 39 | └── services 40 | └── myService 41 | ``` 42 | 43 | The major difference from the scaffolds based on the *quickstart* or *minimal* templates, is the `src/frontend` package for your `js` code. Feel free to poke around the project for a bit and give the default install a whirl. `cd` into the *src/frontend* directory, install the dependencies with `npm i` and run the default template install with `npm run dev`. If all went well, you should something like: 44 | 45 | ```bash 46 | VITE v4.4.5 ready in 102 ms 47 | 48 | ➜ Local: http://localhost:5173/ 49 | ➜ Network: use --host to expose 50 | ➜ press h to show help 51 | ``` 52 | 53 | Looks like your project was initialized and installed as desired and once you copy the provided url, i.e., `http://localhost:5173/`, into your browser, you see four buttons to click. Go head, click away and know, that some of the buttons work and others won't. More on that later. 54 | 55 | 56 | ** 57 | Note: 58 | why are the templated functions that do not use distributed services useful and of interest? 59 | What is an example of a serverless workflow that benefits from this approach? 60 | Any chance that web page can be spruced up a bit? Looks like crap. 61 | ** 62 | 63 | ## Event Triggers From The Browser 64 | 65 | How about: 66 | 67 | * deploy hello world Wasm 68 | * create browser button 69 | 70 | 71 | Let's move the IPFS example into a different section, example 72 | 73 | For more Browser event goodness, see the ??? and ??? example in the ?? section. 74 | 75 | 76 | ## Extending Fluence Functions [This needs to be moved to a separate section entirely] 77 | 78 | As mentioned at the outset and demonstrated in the previous sections, the *js-client* provides client peer capabilities to the Browser, which means that the client, given some constraints, can be called upon from Aqua just like any other distributed service. In fact, the js-client can "host" marine modules not unlike the Rust peer and make said modules available to Aqua workflows. 79 | 80 | ### Browser 81 | 82 | ### NodeJS 83 | 84 | 85 | 86 | 87 | 88 | 89 | 90 | 91 | -------------------------------------------------------------------------------- /docs/build/tutorials/testing_serverless.md: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aliezzahn/docs/7af66c0600393eaadff7ffb28ba49a0febfc021a/docs/build/tutorials/testing_serverless.md -------------------------------------------------------------------------------- /docs/build/tutorials/workflow_fundamentals.md: -------------------------------------------------------------------------------- 1 | # Aqua Worklfow Fundamentals -------------------------------------------------------------------------------- /docs/learn/fluence-comparison.md: -------------------------------------------------------------------------------- 1 | # Fluence Comparison 2 | 3 | ## Fluence vs Cloud platforms 4 | 5 | Proprietary cloud platforms have a clear economic incentive to create closed ecosystems of software services to make switching so hard that customers are effectively locked in within the platform. If a customer needs multiple cloud services, it is easier to buy from the same provider because the cost of integration between providers for typical tasks is usually quite high. Additionally, providers attempt to capture customers by setting up data pricing barriers: cheap inbound bandwidth but expensive outbound bandwidth to make the lock in even stronger. 6 | 7 | Once captured, a customer is vulnerable to platform risk as their business relies on a particular provider. When scaling a business and utilizing more resources from the cloud, sharp price movements might put a lot of pressure on business continuity. And as many companies have belatedly realized, switching a codebase to another cloud provider or to private infrastructure requires a significant investment of time and resources. 8 | 9 | The Fluence protocol frees developers from this proprietary tooling and allows applications to switch providers at will. Fluence enables developers to use any connected providers and easily switch between them. Additionally, the Fluence protocol enforces cryptographic proofs for any customer code execution, enabling better security and resilience. 10 | 11 | Unlike traditional clouds, Fluence provides infrastructure that is manageable via Web3 native organizations like DAOs. Digital organizations can pay using their multisig wallets, update their codebase via collective voting, and invite their community members to contribute into providing infrastructure for their project via the Fluence network. 12 | 13 | ## Fluence vs Blockchain app platforms 14 | 15 | Blockchain application platforms are based on replicated ledgers of transactions and require a consensus algorithm to update the ledger. This design, which prevents adversarial ledger updates and protects the information from tampering, is very useful for “digital value” use cases such as cryptocurrencies, decentralized finance, NFTs, or DAOs. However, the consensus model which requires verification of multiple network nodes is suited to relatively simple, deterministic computations on limited data. Additionally, blockchains add a new per transaction pricing model, where users have to pay gas for every on-chain operation. 16 | 17 | Fluence takes a different approach to decentralized computation where applications do not sit on top of distributed ledger. Applications are hosted off chain, similarly to centralized cloud platforms but because the protocol is open,applications can be hosted by multiple providers, and developers can switch between providers dynamically. This architecture dramatically reduces the importance of any particular provider and drives pricing down. Additionally, Fluence adds computation verifiability required for many applications by adding proofs of execution. Every provider in the Fluence network must submit cryptographic proofs that demonstrate they are serving applications correctly. Not submitting proofs results in losses as their stake is slashed and payments are stopped. 18 | 19 | Also Fluence accounts for the complexity of computations in a gas analogy as blockchains, but in Fluence by default a developer who deploys the application is responsible for covering the hosting cost, not the end user. And regarding the developer’s choice, there are built-in possibilities to transfer the requirement to pay for hosting to multisigs, DAOs, or end-users themselves if there is such a desire. 20 | 21 | Similarly to decentralized storage protocols (e.g. Filecoin) which store data off chain but use blockchain to track, validate and compensate the storage, the computation on Fluence happens off chain on the network nodes while proofs, and payments are submitted and validated on-chain. 22 | 23 | 24 | ## Fluence vs Rollups (optimistic and zk) 25 | 26 | Rollups provide a scaling mechanism for blockchains by creating additional blockspace and transaction processing capacity outside of L1s. To be compatible with wallets and L1 apps, rollups also use blocks and transactions and employ the same execution model (e.g. EVM). Rollups generate proofs of its chain state and these proofs (merkle or zero-knowledge) are validated on the relevant L1 to ensure roll-up validity at certain points in time. 27 | 28 | The Fluence execution and validation models are distinct as Fluence does not put execution into blocks and transactions, it runs applications as a traditional cloud but requires providers to submit proof of execution on-chain. This architecture allows it to be useful for distributed or non deterministic compute and be applicable where the “pay per transaction execution” model isn't natural. For example, backend API, data processing, indexing, message routing, multi-party computation, Internet-of-Things, etc. All of this doesn't really exist on chain or in rollups and isn’t suitable to be put on chain. 29 | 30 | 31 | ## Fluence Comparison 32 | 33 | | | Scalability | Censorship resistance | Verifiability | Payment model | Cost | 34 | |-----------------|:-----------:|:---------------------:|:-------------:|:---------------:|:----:| 35 | | Blockchains | Low | Yes | Yes | Per transaction | $$$$ | 36 | | Rollups | Medium | Yes* | Yes | Per transaction | $$$ | 37 | | Other d-compute | Medium | Yes** | No** | Per transaction | $$ | 38 | | Cloud | High | No | No | Per resource*** | $$ | 39 | | **Fluence** | **High** | **Yes** | **Yes** | **Per resource** | **$** | 40 | 41 | \* Rollups with a single node operator or low amount of operators are subject for potential censorship 42 | 43 | \** Decentralized computing implementations vary but usually do not provide strong cryptographic proofs of execution correctness 44 | 45 | \*** Clouds account for and charge for computations, memory and data bandwidth directly or using synthetic metrics 46 | -------------------------------------------------------------------------------- /docs/learn/overview.md: -------------------------------------------------------------------------------- 1 | import ReactPlayer from "react-player"; 2 | 3 | # Overview 4 | 5 | ## What is Fluence 6 | 7 | Fluence is a decentralized serverless platform & computing marketplace powered by blockchain economics. Fluence is a global, permissionless, scalable, and secure alternative to centralized cloud computing platforms. We say that Fluence is a **Cloudless Platform**, because it enables serverless without the cloud. 8 | 9 | Using Fluence, developers build and deploy applications to a network of compute providers, where providers can range from professional data centers to home computers. Providers compete on price and performance and, to be paid and earn rewards, they constantly prove that they are serving applications. 10 | 11 | Fluence is powered by a cryptographic token which is used by providers as collateral for participation and as a monetary incentive. Providers earn both the Fluence token and payment (usually stablecoin) for serving applications. 12 | 13 | 14 | 15 | ## For Developers 16 | 17 | Developers can use Fluence to build and deploy applications, backends, APIs, and other digital services. Fluence’s serverless platform provides a developer experience similar to the traditional serverless cloud but additionally allows developers to manage an application’s execution over the distributed network; choose providers and switch them at will. 18 | 19 | Unlike on cloud platforms, when using Fluence, developers may verify that their applications are served as intended and computations executed correctly by checking proofs posted by providers on-chain. 20 | 21 | Fluence integrates both Web2 and Web3 data storage and management platforms to plug data inputs and outputs for application execution. While Fluence isn’t designed for large scale data persistence, it perfectly fits for data caching, indexing, processing, and querying. 22 | 23 | | | Fluence Component | Web 2 Analogy | 24 | |-----------------------|:-----------------------------------------------------:|:------------------------------------:| 25 | | Cloud Functions | Compute Functions, Marine | AWS Lambda, Google Cloud Functions | 26 | | Distributed Workflows | Cloudless Functions, Aqua | AWS Step functions, Google Workflows | 27 | | Cloud services | Aqua libraries | Route53, ELB, Consul | 28 | | Data services | Subnets | S3, RDS, DynamoDB, MongoDB | 29 | 30 | ## For Compute Providers 31 | 32 | Compute providers earn rewards for offering their capacity for rent on the marketplace. 33 | 34 | Providers can offer for rent any device connected to a network including a professional rig or data center or even a personal computing device (even a laptop or raspberry pi). It is easy to become a provider: it is not required to establish complex setups for fault tolerance. Instead, reliability is provided by the protocol. Performance though depends on the provider's hardware and internet connection, so professional server hardware would most likely be favored by customers in most cases. 35 | 36 | Provider revenue comes from two main sources. Developers pay to providers for useful work: serving applications. The protocol additionally rewards providers with Fluence token for keeping compute capacity connected to the network and contributing to improving network performance and latency. 37 | 38 | Providers also don’t need to specifically advertise their services as the marketplace connects them to customers interested in their services. 39 | 40 | 41 | ## For Community 42 | 43 | Fluence's compute security model is powered by cryptoeconomic incentives. Fluence token holders may stake for compute hardware to support the attestation that the hardware is available on the network and performs compute jobs correctly. For this, the protocol rewards stakers with additional tokens. 44 | 45 | Fluence is managed by digital governance (DAO), so token holders may participate in governance process: create proposals, choose delegators and governance committee, and vote for proposals. 46 | -------------------------------------------------------------------------------- /docs/learn/use-cases.md: -------------------------------------------------------------------------------- 1 | # Use Cases 2 | 3 | Fluence is useful for all types of applications currently living in the cloud such as web applications, distributed backends, communication software, and IoT. Fluence facilitates building any decentralized application that prioritizes user data privacy, composability, and resilience. 4 | 5 | ## P2P Apps 6 | 7 | Fluence enables resilient and censorship-resistant applications, which may not rely on any intermediary servers and run completely on users' devices. The next generation of truly P2P applications is possible with the Fluence stack. 8 | 9 | - Messengers 10 | - Social networks 11 | - Audio and video calls 12 | - Streaming 13 | 14 | ## Decentralized Protocols 15 | 16 | Fluence makes it super easy to build and combine network protocols of any complexity, topology, and scale, using a common [Aqua language](../aqua-book/introduction.md), specifically designed for p2p programming. 17 | 18 | - Messaging protocols 19 | - Consensus engines 20 | - Decentralized governance 21 | - File sharing 22 | - Multi-party computation 23 | - Blockchain oracles 24 | 25 | ## Community-run Applications 26 | 27 | With Fluence, applications could be hosted and fully managed without central admin. Community members may run Fluence nodes with the application backends and coordinate via the incentive model they choose (governance token, DAO, etc). Redundancy and load balancing are programmed using the Aqua language and driven by incentives. 28 | 29 | - DAO-managed applications 30 | - Social media platforms 31 | - Creator economy 32 | 33 | ## Computations on Decentralized Data 34 | 35 | Apps can enable dynamic updates and computation for data they keep in decentralized content-addressable storage. Fluence [supports IPFS](../aqua-book/libraries/aqua-ipfs.md), and other projects are being constantly added. 36 | 37 | - Decentralized apps 38 | - Mutable/dynamic NFTs 39 | 40 | ## Cloud-native Computing 41 | 42 | Cloud-native applications may use Fluence to manage microservice backends without reliance on a central coordination server. The Fluence programming model allows upgrading applications and implementing new business logic without re-deploying microservices. Content addressable functions and services make backwards compatibility seamless, so things just do not break when a service is updated to a new version. 43 | 44 | - Distributed microservice orchestration 45 | - Distributed SaaS 46 | - Serverless 47 | 48 | ## Blockchain Infrastructure 49 | 50 | Cryptocurrency exchanges, multi-sig wallets, DAO management tools may use Fluence to optimize gas costs by moving signed transactions, order books off-chain while keeping on-chain trade settlement. 51 | 52 | - Cryptocurrency exchanges 53 | - Wallets 54 | - DAO tools 55 | - Cross-chain tools 56 | 57 | ## Unstoppable API and Composition 58 | 59 | As Fluence enables content-addressable code, services and functions can be permanently accessed over the network while hosted by at least a single node. This brings the new paradigm of composing APIs, which is much easier and faster than re-building and re-hosting similar micro-services in the cloud for every new app. 60 | -------------------------------------------------------------------------------- /docs/learn/why-fluence.md: -------------------------------------------------------------------------------- 1 | # Why Fluence? 2 | 3 | The internet is dominated by a handful of tech giants who control both user data and infrastructure. The position of "data totalitarians" allows them to use and misuse personal user data while also threatening businesses continuity with single points of failure and the ability to simply turn off entire software ecosystems. Such centralized data ownership presents a single point of failure and an easy target for censorship and government manipulation. 4 | 5 | Credible neutrality of internet infrastructure is crucial for changing the status quo. Decentralized models are neutral by design as they do not have centralized ownership or control and operate like truly democratic systems. Their design architecture makes it nearly impossible for a participant to take control of the system as the incentives of other participants prevent this from happening. 6 | 7 | Fluence is an open, distributed, peer-to-peer protocol, designed to be credibly neutral and enables the following features: 8 | 9 | ## Permissionless 10 | 11 | Similar to internet protocols such as HTTP, the Fluence protocol applies no limitations on who can join as providers and who can be a customer. There is no approval, KYC, or similar procedure to enter the compute marketplace or rent resources from the marketplace. There are no requirements for hardware performance, location, or ownership. 12 | 13 | ## Censorship resistance 14 | 15 | There is no way to censor who uses Fluence or what is being executed on Fluence. Customers and providers use the protocol to find each other and perform the work. Providers are free to filter what they are executing if they are restricted by local regulators, but as customers are not locked into a particular provider, there are always options to meet a customer’s criteria. 16 | 17 | ## Trust minimization 18 | 19 | The Fluence network runs on the Aqua protocol, which ensures cryptographic security, authentication of all application requests, and adds proofs and auditability for every execution. This dramatically decreases the reliance on provider good name, brand, or reputation. Customers now trust the protocol and not a particular provider. 20 | 21 | 22 | ## Collective ownership 23 | 24 | The Fluence network is governed by the Fluence DAO in which any Fluence token holder may participate. The DAO manages the protocol development, updates, and distributes funds from the treasury to enhance and grow the network. Fluence is managed collectively by its community and not by a traditional company structure. 25 | -------------------------------------------------------------------------------- /docs/marine-book/basic-concepts/an-example-of-Fluence-service.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aliezzahn/docs/7af66c0600393eaadff7ffb28ba49a0febfc021a/docs/marine-book/basic-concepts/an-example-of-Fluence-service.png -------------------------------------------------------------------------------- /docs/marine-book/basic-concepts/basic-concepts.md: -------------------------------------------------------------------------------- 1 | # 🧑🏫 Basic concepts 2 | 3 | This chapter describes some basic concepts that are crucial for understanding other parts. 4 | 5 | ### Wasm Modules 6 | 7 | [Wasm module](https://webassembly.github.io/spec/core/syntax/modules.html) is a way how Wasm programs are organized, it's an essential unit of deployment, loading, and compilation. 8 | 9 | **Marine Wasm module** (or just a Marine module) is a Wasm module compiled with the [Marine SDK](../marine-rust-sdk/marine-rust-sdk.md). These modules follow some internal conventions allows them to link with other modules (**module-module** scheme) and with a host (**module-host** scheme). You could find more information about the conventions in [this](../marine-rust-sdk/module-abi.md) section. 10 | 11 | **Host** is a part that runs a Wasm module, usually, it refers to a runtime or runtime and OS. In the case of Marine host could be either Rust-based or JavaScript-based Marine runtime component. 12 | 13 | Each Wasm module could have imports and exports. **Import** is a definition of some external for a module component, which this module could use during its execution. A module could import functions, memories, globals, and tables. An import function is the only possibility for a module way to call external API - Wasm modules are sandboxed by design from this perspective. **Export** is a definition of a module component accessible by a host or other module. Similarly to imports, a module could export functions, memories, globals, and tables. 14 | 15 | ### Fluence service 16 | 17 | Fluence service (or just service) is a group of Marine Wasm modules linked together with the shared-nothing linking scheme with help of interface-types. This scheme allows modules to encapsulate their inner state (such as memory, globals, and tables) and expose only export functions. So, modules are linked together by corresponding exports and imports functions: 18 | 19 | ![an example of Fluence service](./an-example-of-Fluence-service.png) 20 | 21 | In the picture above you could see an example of a Fluence service comprised of three different modules: `facade`, `SQLite`, and `authentication module`. The second and the third are linked to the `facade` module by linking each import to a corresponding export. 22 | 23 | Marine is one of a few Wasm runtimes that allows composing several Wasm modules in an easier manner. 24 | -------------------------------------------------------------------------------- /docs/marine-book/changelog.md: -------------------------------------------------------------------------------- 1 | # Changelog 2 | 3 | Marine development takes place in the [Marine repo](https://github.com/fluencelabs/marine) and the historic changelog can be found [here](https://github.com/fluencelabs/marine/blob/master/CHANGELOG.md). 4 | -------------------------------------------------------------------------------- /docs/marine-book/introduction.md: -------------------------------------------------------------------------------- 1 | import ReactPlayer from "react-player"; 2 | 3 | # Introduction 4 | 5 | Fluence is a peer-to-peer application platform which allows the creation of applications free of proprietary cloud providers or centralized APIs. Fluence provides a peer-to-peer development stack so that you can program p2p applications, workflows, and compose services, APIs without relying on centralized intermediaries. The Fluence stack is 100% open source and maintained and governed by a community of developers. 6 | 7 | The Fluence platform allows developers to create distributed services from Wasm Interface Type (IT) modules which can be deployed to one or more peers and composed into protocols and applications with Fluence's [Aqua](../aqua-book/introduction.md) language. 8 | 9 | We've chosen Wasm in the Fluence Labs as the main building mechanism for services because of: 10 | 11 | - flexible resources control 12 | - sandboxed modules by design 13 | - heterogeneous runtime with support of any language compiled to wasm 14 | - simple, but featureful composition between modules 15 | - life-cycles of modules are independent on each other 16 | 17 | The Marine ecosystem provides developers with the necessary Wasm development, testing, and runtime tools. 18 | 19 | Overview of using Wasm at Fluence: 20 | 21 | 22 |
23 | 24 | 25 |
26 | 27 | This book is dedicated to all things in Marine and currently in its **alpha** version, stay in touch or contact us via the following channels: 28 | 29 | - [Telegram](https://t.me/fluence_project) 30 | - [Marine github](https://github.com/fluencelabs/marine) 31 | - [Youtube](https://www.youtube.com/channel/UC3b5eFyKRFlEMwSJ1BTjpbw) 32 | -------------------------------------------------------------------------------- /docs/marine-book/marine-runtime/api/api.md: -------------------------------------------------------------------------------- 1 | # API 2 | 3 | This section describes API of three main components of Marine: [Marine](marine-api.md), [Marine-JS](marine-js-api.md) and [core](core-api.md). 4 | -------------------------------------------------------------------------------- /docs/marine-book/marine-runtime/api/core-api.md: -------------------------------------------------------------------------------- 1 | import Tabs from "@theme/Tabs"; 2 | import TabItem from "@theme/TabItem"; 3 | 4 | # Core API 5 | 6 | This chapter briefly describes the API of the lowest layer of `Marine`. This layer is intended to provide the most basic API for module handling. The most functionality could be tested with a help of the Marine [REPL](../../marine-tooling-reference/marine-repl.md). 7 | 8 | ## Calling a module 9 | 10 | ```rust 11 | fn call( 12 | &mut self, 13 | module_name: impl AsRef, 14 | func_name: impl AsRef, 15 | arguments: &[IValue], 16 | ) -> MResult> 17 | ``` 18 | 19 | Invokes a function of a module inside Marine by given function name with given arguments. For more info about `IValue` take a look to [this](./../i-value-and-i-type.md) chapter. 20 | 21 | ## Loading a module 22 | 23 | ```rust 24 | fn load_module( 25 | &mut self, 26 | name: impl Into, 27 | wasm_bytes: &[u8], 28 | config: MModuleConfig, 29 | ) -> MResult<()> 30 | ``` 31 | 32 | Loads a new module with the provided config inside Marine. All modules should have unique names. This config allows you to flexible adjusting of the behavior of the loaded module, it has the following structure: 33 | 34 | ```rust 35 | pub struct MarineModuleConfig { 36 | /// Maximum memory size accessible by a module in Wasm pages (64 Kb). 37 | pub mem_pages_count: Option, 38 | 39 | /// Maximum memory size for heap of Wasm module in bytes, if it set, mem_pages_count ignored. 40 | pub max_heap_size: Option, 41 | 42 | /// Defines whether Marine should provide a special host log_utf8_string function for this module. 43 | pub logger_enabled: bool, 44 | 45 | /// Export from host functions that will be accessible on the Wasm side by provided name. 46 | pub host_imports: HashMap>, 47 | 48 | /// A WASI config. 49 | pub wasi: Option, 50 | 51 | /// Mask used to filter logs, for details see `log_utf8_string` 52 | pub logging_mask: i32, 53 | } 54 | ``` 55 | 56 | ## Unloading a module 57 | 58 | ```rust 59 | fn unload_module(&mut self, name: impl AsRef) -> MResult<()> 60 | ``` 61 | 62 | Unloads a module from Marine by name. Use it carefully. It could crash service after the call if the module that linked with another will be unloaded. 63 | 64 | ## Getting a WASI state 65 | 66 | ```rust 67 | fn module_wasi_state<'s>( 68 | &'s mut self, 69 | module_name: impl AsRef, 70 | ) -> Option> 71 | ``` 72 | 73 | Returns a WASI state of a module. 74 | 75 | ## Getting a module interface 76 | 77 | 78 | 79 | 80 | ```rust 81 | fn interface(&self) 82 | -> impl Iterator)> 83 | 84 | fn module_interface(&self, module_name: impl AsRef) 85 | -> Option> 86 | 87 | fn module_record_types(&self, module_name: impl AsRef) 88 | -> Option<&MRecordTypes> 89 | 90 | fn module_record_type_by_id( 91 | &self, 92 | module_name: impl AsRef, 93 | record_id: u64, 94 | ) -> Option<&Rc> 95 | ``` 96 | 97 | 98 | 99 | 100 | ```rust 101 | struct MModuleInterface<'a> { 102 | pub record_types: &'a MRecordTypes, 103 | pub function_signatures: Vec, 104 | } 105 | 106 | type MRecordTypes = HashMap> 107 | 108 | struct MFunctionSignature { 109 | pub name: Rc, 110 | pub arguments: Rc>, 111 | pub outputs: Rc>, 112 | } 113 | ``` 114 | 115 | 116 | 117 | 118 | These methods returns a public interface of a module, i.e. a set of all public functions and records. 119 | 120 | ## Getting module memory stats 121 | 122 | 123 | 124 | 125 | ```rust 126 | fn module_memory_stats(&self) -> MemoryStats<'_> 127 | ``` 128 | 129 | 130 | 131 | 132 | ```rust 133 | struct MemoryStats<'module_name>(pub Vec>); 134 | 135 | /// Contains module name and a size of its linear memory in bytes. 136 | /// Please note that linear memory contains not only heap, but globals, shadow stack and so on. 137 | /// Although it doesn't contain operand stack, additional runtime (Wasmtime) structures, 138 | /// and some other stuff, that should be count separately. 139 | struct ModuleMemoryStat<'module_name> { 140 | pub name: &'module_name str, 141 | pub memory_size: usize, 142 | // None if memory maximum wasn't set 143 | pub max_memory_size: Option, 144 | } 145 | ``` 146 | 147 | 148 | 149 | 150 | Returns a statistics of memory usage for all loaded modules. 151 | -------------------------------------------------------------------------------- /docs/marine-book/marine-runtime/api/marine-api.md: -------------------------------------------------------------------------------- 1 | import Tabs from "@theme/Tabs"; 2 | import TabItem from "@theme/TabItem"; 3 | 4 | # Marine API 5 | 6 | FaaS layer is based on the runtime Marine component significantly expanding it by providing a few ways of its instantiation as well as calling with JSON values. 7 | 8 | ## Instantiation 9 | 10 | 11 | 12 | 13 | ```rust 14 | fn with_raw_config(config: C) -> FaaSResult 15 | where 16 | C: TryInto, 17 | FaaSError: From, 18 | ``` 19 | 20 | 21 | 22 | 23 | ```rust 24 | fn with_modules(mut modules: HashMap>, config: C) -> FaaSResult 25 | where 26 | C: TryInto, 27 | FaaSError: From, 28 | ``` 29 | 30 | 31 | 32 | 33 | ```rust 34 | fn with_module_names(names: &HashMap, config: C) -> FaaSResult 35 | where 36 | C: TryInto, 37 | FaaSError: From, 38 | ``` 39 | 40 | 41 | 42 | 43 | Creates a FaaS instance from the provided config and modules or just module names. 44 | 45 | ## Calling a module 46 | 47 | 48 | 49 | 50 | 51 | 52 | ```rust 53 | fn call_with_ivalues( 54 | &mut self, 55 | module_name: impl AsRef, 56 | func_name: impl AsRef, 57 | args: &[IValue], 58 | call_parameters: marine_rs_sdk::CallParameters, 59 | ) -> FaaSResult> 60 | ``` 61 | 62 | 63 | 64 | 65 | ```rust 66 | fn call_with_json( 67 | &mut self, 68 | module_name: impl AsRef, 69 | func_name: impl AsRef, 70 | json_args: JValue, 71 | call_parameters: marine_rs_sdk::CallParameters, 72 | ) -> FaaSResult 73 | ``` 74 | 75 | 76 | 77 | 78 | Invokes a function of a module inside Marine by given function name with given arguments. For more info about `IValue` take a look to [this](./../i-value-and-i-type.md) chapter. 79 | 80 | ## Getting a module interface 81 | 82 | 83 | 84 | 85 | ```rust 86 | fn get_interface(&self) -> FaaSInterface<'_> 87 | ``` 88 | 89 | 90 | 91 | 92 | ```rust 93 | struct FaaSInterface<'a> { 94 | pub modules: HashMap<&'a str, FaaSModuleInterface<'a>>, 95 | } 96 | 97 | struct FaaSInterface<'a> { 98 | pub modules: HashMap<&'a str, FaaSModuleInterface<'a>>, 99 | } 100 | 101 | struct MModuleInterface<'a> { 102 | pub record_types: &'a MRecordTypes, 103 | pub function_signatures: Vec, 104 | } 105 | 106 | type MRecordTypes = HashMap>; 107 | 108 | struct MFunctionSignature { 109 | pub name: Rc, 110 | pub arguments: Rc>, 111 | pub outputs: Rc>, 112 | } 113 | ``` 114 | 115 | 116 | 117 | 118 | This method returns a public interface of a module, i.e. a set of all public functions and records. 119 | 120 | ## Getting module memory stats 121 | 122 | 123 | 124 | 125 | ```rust 126 | fn module_memory_stats(&self) -> MemoryStats<'_> 127 | ``` 128 | 129 | 130 | 131 | 132 | ```rust 133 | struct MemoryStats<'module_name>(pub Vec>); 134 | 135 | /// Contains module name and a size of its linear memory in bytes. 136 | /// Please note that linear memory contains not only heap, but globals, shadow stack and so on. 137 | /// Although it doesn't contain operand stack, additional runtime (Wasmtime) structures, 138 | /// and some other stuff, that should be count separately. 139 | struct ModuleMemoryStat<'module_name> { 140 | pub name: &'module_name str, 141 | pub memory_size: usize, 142 | // None if memory maximum wasn't set 143 | pub max_memory_size: Option, 144 | } 145 | ``` 146 | 147 | 148 | 149 | 150 | Returns a statistics of memory usage for all loaded modules. 151 | -------------------------------------------------------------------------------- /docs/marine-book/marine-runtime/api/marine-js-api.md: -------------------------------------------------------------------------------- 1 | # Marine-JS API 2 | 3 | The web runtime is closely but not completely feature equivalent with the Rust Marine runtime. Specifically, Mounted Binaries are not supported, and the WASI filesystem API operates in an in-memory per-module sandboxed filesystem, which means that modules in a service do not share filesystem, and cannot make any network calls. [MarineService](https://github.com/fluencelabs/marine/blob/master/marine-js/npm-package/src/MarineService.ts#L25) is the central pillar of the web runtime and corresponds to [FluenceAppService](https://github.com/fluencelabs/marine/blob/master/crates/fluence-app-service/src/service.rs#L46) from the Rust runtime. but has a simplified interface. In the future `MarineService` will have a one-to-one correspondence with the Rust side. 4 | 5 | ## Loading Wasm 6 | 7 | Before registering the service corresponding Wasm files must be loaded, as well as the control module. Marine JS does not provide any API for doing this, but there is a quite simple implementations for node.js and web environments in js-client library. 8 | 9 | ## Playing with MarineService 10 | 11 | ### Constructing a service 12 | 13 | ```javascript 14 | constructor( 15 | private readonly controlModule: WebAssembly.Module, 16 | private readonly serviceId: string, 17 | private logFunction: LogFunction, 18 | private serviceConfig: MarineServiceConfig, 19 | private modules: { [x: string]: Uint8Array }, 20 | env?: Env, 21 | ) 22 | ``` 23 | Constructs a `MarineService` object that is ready to be started. This function corresponds to to `FluenceAppService::new`, and has the same meaning. 24 | 25 | The service configuration is passed as `MarineServiceConfig`, while module bytes are passed separately. `ModuleDescriptor.import_name` should match one of the keys in the `modules` argument. Actually used config values `import_names`, logger and WASI related ones. It is impossible to pass host imports to the modules, and WASI will only give access to a per-module sandboxed in-memory filesystem. 26 | ```javascript 27 | export interface MarineServiceConfig { 28 | /** 29 | * Settings for a module with particular name (not HashMap because the order is matter). 30 | */ 31 | modules_config: Array; 32 | 33 | /** 34 | * Settings for a module that name's not been found in modules_config. 35 | */ 36 | default_modules_config?: MarineModuleConfig; 37 | } 38 | 39 | export interface ModuleDescriptor { 40 | import_name: string; 41 | config: MarineModuleConfig; 42 | } 43 | 44 | export interface MarineModuleConfig { 45 | /** 46 | * Maximum memory size accessible by a module in Wasm pages (64 Kb). 47 | */ 48 | mem_pages_count?: number; 49 | 50 | /** 51 | * Maximum memory size for heap of Wasm module in bytes, if it set, mem_pages_count ignored. 52 | */ 53 | max_heap_size?: number; 54 | 55 | /** 56 | * Defines whether FaaS should provide a special host log_utf8_string function for this module. 57 | */ 58 | logger_enabled: boolean; 59 | 60 | /** 61 | * Export from host functions that will be accessible on the Wasm side by provided name. 62 | */ 63 | // host_imports: Map; 64 | 65 | /** 66 | * A WASI config. 67 | */ 68 | wasi: MarineWASIConfig; 69 | 70 | /** 71 | * Mask used to filter logs, for details see `log_utf8_string` 72 | */ 73 | logging_mask: number; 74 | } 75 | 76 | export type Env = WASIEnv; 77 | 78 | export type Args = WASIArgs; 79 | 80 | export interface MarineWASIConfig { 81 | /** 82 | * A list of environment variables available for this module. 83 | */ 84 | envs: Env; 85 | 86 | /** 87 | * A list of files available for this module. 88 | * A loaded module could have access only to files from this list. 89 | */ 90 | preopened_files: Set; 91 | 92 | /** 93 | * Mapping from a usually short to full file name. 94 | */ 95 | mapped_dirs: Map; 96 | } 97 | 98 | ``` 99 | Logs generated by a marine service are passed to the logFunction, which has the following type: 100 | ```javascript 101 | export type LogFunction = (message: LogMessage) => void; 102 | 103 | export interface LogMessage { 104 | service: string; 105 | message: string; 106 | level: LogLevel; 107 | } 108 | ``` 109 | 110 | The logging is enabled by setting `logger_enabled: true` in `MarineModuleConfig`, the log level is set via environment variable `WASM_LOG` that works just like `RUST_LOG` for [env_logger crate](https://docs.rs/env_logger/latest/env_logger/). It defaults to `off` (disabled logging), other useful values are `error`, `warn`, `info`, `debug`, `trace`. 111 | 112 | 113 | ### Starting as service 114 | ```javascript 115 | init: () => Promise 116 | ``` 117 | 118 | Starts this `MarineService` object. This includes instantiating the control module, as well as compiling, linking and instantiating the provides service modules. 119 | 120 | ### calling a service 121 | 122 | ```javascript 123 | call(functionName: string, args: JSONArray | JSONObject, callParams: CallParameters): unknown 124 | ``` 125 | 126 | Invokes a function of a module inside `MarineService` by given function name with given arguments in JSON string. The module to call is the last module listed in `modules_config` field of `MarineServiceConfig` -- the facade module. Call parameters is a fluence-related argument, a `defaultCallParameters` constant can be used when call parameters are not needed. This method will throw an exception in case of module execution error. The return value is the JS object returned by the facade module. 127 | 128 | -------------------------------------------------------------------------------- /docs/marine-book/marine-runtime/architecture/architecture/Marine-Layered-Architecture.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aliezzahn/docs/7af66c0600393eaadff7ffb28ba49a0febfc021a/docs/marine-book/marine-runtime/architecture/architecture/Marine-Layered-Architecture.png -------------------------------------------------------------------------------- /docs/marine-book/marine-runtime/architecture/architecture/architecture.md: -------------------------------------------------------------------------------- 1 | # Architecture 2 | 3 | `Marine` follows the layered architecture pattern allowing developers to use components with different abstraction layers to fit their purpose: 4 | 5 | ![Marine Layered Architecture](./Marine-Layered-Architecture.png) 6 | 7 | In this chapter, we briefly discuss these Marine components. 8 | 9 | ## [Core](https://github.com/fluencelabs/marine/tree/master/core) 10 | 11 | The core comprises the lower-level component of `Marine` to expose the [API](../../api/core-api.md) that allows developers to `load`, `unload`, and `call` modules as well as obtain information concerning their states such as WASI state, module interfaces (all export functions), and heap usage statistics. Internally, it interprets interface-types [instructions](../interface-types-instructions.md) providing module-module and module-host value passing scheme. 12 | 13 | The runtime component compiles to Wasm and is used in marine-js as a so-called [control module](../marine-js/marine-js.md) sharing the same code for marine and marine-js targets. 14 | 15 | This component is also used in the Rust and Javascript environments as well as Marine and Marine-JS. 16 | 17 | ## [Marine](https://github.com/fluencelabs/marine/tree/master/marine) 18 | 19 | Marine extends the core component with the following features: 20 | 21 | - can be called with json-based arguments (`call_with_json` [API](../../api/marine-api.md#calling-a-module)) 22 | - provides an internal mechanism for handling [host imports](../../host-exports.md) 23 | - defines three host imports for logging, call parameters, and mounted binary interface 24 | 25 | ## [Marine-js](https://github.com/fluencelabs/marine/tree/master/marine-js) 26 | 27 | Provides the basic Marine functionality for the browser and node.js targets. Marine-js is currently under active development and exposes only a basic core [API](../../api/marine-js-api.md) and supports only single-module service. 28 | -------------------------------------------------------------------------------- /docs/marine-book/marine-runtime/architecture/core/core.md: -------------------------------------------------------------------------------- 1 | # Core 2 | 3 | This section deep dives into the architecture of the Marine runtime component. 4 | 5 | ## Interface-types 6 | 7 | Marine uses a generic Wasm backend interface defined in this [crate](https://github.com/fluencelabs/marine/tree/master/crates/wasm-backend-traits) under the hood. There is only [implementation for Wasmtime](https://github.com/fluencelabs/marine/tree/master/crates/wasmtime-backend) at the moment. And uses this [crate](https://github.com/fluencelabs/interface-types) for interface types V1 implementation. By V1 we mean the interface-types proposal before November 2020: 8 | 9 | ![marine using interface types V1](./marine-using-interface-types-V1.png) 10 | 11 | Each export and import function in a Marine Wasm module is wrapped by a corresponding import or export adapter. The purpose of an **import adapter** is to lift Wasm types to corresponding IT types, while the purpose of an **export adapter** is to lower IT types to corresponding Wasm types. 12 | 13 | Adapters consist of IT instructions that are executed by a special interpreter. The full list of all supported instructions could be found [here](../interface-types-instructions.md). 14 | 15 | ## Module linking 16 | 17 | Let's consider a passing scheme between three modules in the [curl service](./../../../quick-start/develop-a-multi-modules-service.md): 18 | 19 | ![passing scheme between three modules](./passing-scheme-between-three-modules.png) 20 | 21 | Here the `gen_n_save` function from the `facade` module calls the `download` function from the `curl` module and `put` from the `local_storage` module (more info about how these modules are structured and used could be found [here](./../../../quick-start/develop-a-multi-modules-service.md)). 22 | 23 | For each module `Marine` creates corresponding Wasmtime instance and for each import and export function, it creates a special interface-types adapter with an interpreter. In the picture below you could see the scheme with Wasmtime instances for each module and adapters for each import and export linked together. 24 | 25 | ![scheme with Wasmer instances](./scheme-with-Wasmer-instances.png) 26 | 27 | ## How do multi-module calls work 28 | 29 | In this section, we're going to discuss what it costs to call a function from another module. Let's consider how it looks step-by-step when the `facade` module calls `download(url: String) -> String` exported from the `curl` module. 30 | 31 | ### Step 1 32 | 33 | This interop scheme starts with calling an adapter of the imported function `download`. 34 | 35 | ![multi-module call, step 1](./multi-module-call-step-1.png) 36 | 37 | This part aims to lift a string (remember that `download` function receives one `String` as an argument) meaning that it constructs it from a pointer and a size provided by the Wasm part. 38 | 39 | In the picture above the first two instructions push a pointer and a size to the operand stack, then `string.lift_memory` consumes them creating a resulted string. Then `call-core 1` calls `release_objects` that frees the memory occupied by the lifted string in a Wasm module. And, finally, the `curl.download` export adapter from the curl module is called. 40 | 41 | Also note that a list of instructions each adapter consists on could be obtained with the Marine CLI, you could find the guide [here](../../../marine-tooling-reference/marine-cli.md#it-shows-interface-types-of-the-wasm-binary). 42 | 43 | ### Step 2 44 | 45 | Then a prolog of the export adapter is being called. Its goal is vise-versa to the prolog of the import adapter - it should lower the passed string to make it possible to call the raw curl Wasm module with a pointer and a size. 46 | 47 | ![multi-module call, step 1](./multi-module-call-step-2.png) 48 | 49 | In this picture, the prolog starts with obtaining a string size by pushing it to the operand stack and calling `string.size`. Then it calls `allocate` exported from the `curl` module. Finally, it calls `string.lower_memory` that takes a string with a pointer to the allocated memory region and writes a string to this region. 50 | 51 | ### Step 3 52 | 53 | In the next step the "raw" `curl.download` is called with the pointer and the size produced on the previous step. 54 | 55 | ![multi-module call, step 1](./multi-module-call-step-3.png) 56 | 57 | ### Step 4 58 | 59 | The goal of 4th step is to lift the string produced by the `curl.download` function. 60 | 61 | ![multi-module call, step 1](./multi-module-call-step-4.png) 62 | 63 | The code snippet above starts with retrieving a pointer and a size of the `download` function. It's done via two functions: [get_result_ptr](../../../marine-rust-sdk/module-abi.md#get_result_ptr) and [get_result_size](../../../marine-rust-sdk/module-abi.md#get_result_size). They are used because at the moment our interface-type implementation doesn't support multi-value. The last instruction is used to clean up this string from the `curl` module memory. 64 | 65 | ### Step 5 66 | 67 | The last step aims to lower string back to the `facade` module. 68 | 69 | ![multi-module call, step 1](./multi-module-call-step-5.png) 70 | 71 | The lowering is done the similar to step 2 way: obtaining string size, calling `allocate`, and then `string.lower_memory`. The last two instructions call [set_result_size](../../../marine-rust-sdk/module-abi.md#set_result_size) and [set_result_ptr](../../../marine-rust-sdk/module-abi.md#set_result_ptr), which are needed for the current multi-value passing limitation. 72 | 73 | And, finally, the control flow returns back to the `facade` Wasm module with the resulted string from the `curl.download` function. 74 | 75 | The complete list of all IT instructions could be found in this [section](../interface-types-instructions.md). Also, you could find additional info about miscellaneous functions in module ABI in this [section](../../../marine-rust-sdk/module-abi.md). 76 | 77 | ## Performance 78 | 79 | Despite the complex passing scheme between modules, Marine is a fast runtime with a lot of optimizations on different levels. The Marine REPL measures each operation and playing with Redis [compiled](https://medium.com/fluence-network/porting-redis-to-webassembly-with-clang-wasi-af99b264ca8) to Wasm one could see the following values: 80 | 81 | ![marine performance](./marine-performance.png) 82 | -------------------------------------------------------------------------------- /docs/marine-book/marine-runtime/architecture/core/marine-performance.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aliezzahn/docs/7af66c0600393eaadff7ffb28ba49a0febfc021a/docs/marine-book/marine-runtime/architecture/core/marine-performance.png -------------------------------------------------------------------------------- /docs/marine-book/marine-runtime/architecture/core/marine-using-interface-types-V1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aliezzahn/docs/7af66c0600393eaadff7ffb28ba49a0febfc021a/docs/marine-book/marine-runtime/architecture/core/marine-using-interface-types-V1.png -------------------------------------------------------------------------------- /docs/marine-book/marine-runtime/architecture/core/multi-module-call-step-1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aliezzahn/docs/7af66c0600393eaadff7ffb28ba49a0febfc021a/docs/marine-book/marine-runtime/architecture/core/multi-module-call-step-1.png -------------------------------------------------------------------------------- /docs/marine-book/marine-runtime/architecture/core/multi-module-call-step-2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aliezzahn/docs/7af66c0600393eaadff7ffb28ba49a0febfc021a/docs/marine-book/marine-runtime/architecture/core/multi-module-call-step-2.png -------------------------------------------------------------------------------- /docs/marine-book/marine-runtime/architecture/core/multi-module-call-step-3.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aliezzahn/docs/7af66c0600393eaadff7ffb28ba49a0febfc021a/docs/marine-book/marine-runtime/architecture/core/multi-module-call-step-3.png -------------------------------------------------------------------------------- /docs/marine-book/marine-runtime/architecture/core/multi-module-call-step-4.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aliezzahn/docs/7af66c0600393eaadff7ffb28ba49a0febfc021a/docs/marine-book/marine-runtime/architecture/core/multi-module-call-step-4.png -------------------------------------------------------------------------------- /docs/marine-book/marine-runtime/architecture/core/multi-module-call-step-5.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aliezzahn/docs/7af66c0600393eaadff7ffb28ba49a0febfc021a/docs/marine-book/marine-runtime/architecture/core/multi-module-call-step-5.png -------------------------------------------------------------------------------- /docs/marine-book/marine-runtime/architecture/core/passing-scheme-between-three-modules.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aliezzahn/docs/7af66c0600393eaadff7ffb28ba49a0febfc021a/docs/marine-book/marine-runtime/architecture/core/passing-scheme-between-three-modules.png -------------------------------------------------------------------------------- /docs/marine-book/marine-runtime/architecture/core/scheme-with-Wasmer-instances.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aliezzahn/docs/7af66c0600393eaadff7ffb28ba49a0febfc021a/docs/marine-book/marine-runtime/architecture/core/scheme-with-Wasmer-instances.png -------------------------------------------------------------------------------- /docs/marine-book/marine-runtime/architecture/interface-types-instructions.md: -------------------------------------------------------------------------------- 1 | # Interface types instructions 2 | 3 | This section briefly describes full list of supported interface-types instructions: 4 | 5 | `arg.get` - pushes to the operand stack an argument by its id 6 | 7 | `array.lift_memory` - takes a pointer and a size from the operand stack, lifts an array from them, pushing it then back to the operand stack 8 | 9 | `array.lower_memory` - takes an array from the operand stack and lowers it to the provided pointer 10 | 11 | `bytearray.lift_memory` - takes a pointer and a size from the operand stack, lifts a bytearray from them, pushing it then back to the operand stack 12 | 13 | `bytearray.lower_memory` - takes a bytearray and a pointer from the operand stack and writes the given bytearray to the provided pointer 14 | 15 | `bytearray.size` - takes a bytearray from the operand stack, producing its size on the operand stack 16 | 17 | `call-core` - calls either an export adaptor or an export from a Wasm module function 18 | 19 | `dup` - duplicates the last value on the operand stack 20 | 21 | `record.lift` - takes a pointer and a size from the operand stack, lifts a record from them 22 | 23 | `record.lower` - takes a record from the operand stack and lowers it, producing a pointer to the result back to the operand stack 24 | 25 | `string.lift_memory` - takes a pointer and a size from the operand stack, lifts a string from them, pushing it then back to the operand stack 26 | 27 | `string.lower_memory` - takes a string and a pointer from the operand stack and writes the given string to the provided pointer 28 | 29 | `string.size` - takes a string from the operand stack, producing its size on the operand stack 30 | 31 | `swap` - swaps two top elements on the operand stack 32 | 33 | `.from_` - converts the source number\_type to the target number\_type 34 | 35 | `.push` - pushes a provided value of number\_type to the operand stack 36 | 37 | -------------------------------------------------------------------------------- /docs/marine-book/marine-runtime/architecture/marine-js/marine-js.md: -------------------------------------------------------------------------------- 1 | # Marine-JS 2 | 3 | Marine-js runs Marine modules in a browser or in a node.js environments. It's based on the `runtime` Marine component which handless interface-types and module linking, and wasm backend implementation for JS environment for executing Wasm. This is possible by compiling the [Core](./#core) part of Marine with JS-based wasm backend (we'll call it a `control module` then) to Wasm and handle all necessary calls through the JS wrapper. 4 | 5 | In the marine web environment, each service includes an instance of this control module. It handles all the requests made to any loaded module as well as requests to other modules of this service. 6 | 7 | Let's consider the following scheme: 8 | 9 | ![marine-web scheme](./marine-web-scheme.png) 10 | 11 | Here when a user calls a function from a Wasm module by [callService](../../api/marine-js-api.md#calling-a-service), the Marine JS Service first (`1`) calls the control module with the parsed interface-types section. The control module then executes the provided interface-types, which could potentially contain calls to other modules in networks, e.g., the further execution of interface-types would require calling `allocate` from the Marine module (consider the lowering string case in step 2 [here](../core/core.md#step-2)). To handle this call the control module calls (`2`) the Marine JS service by Wasm import functions and the service then calls `allocate` from the necessary Marine module returning back results (`3`). 12 | 13 | So, from the runtime (on which the control module is based) perspective the process looks as usual: it just executes interface-types instructions but each call and memory access requires passing the control flow to the Marine JS service and calling or accessing an appropriate Marine module. 14 | 15 | In the picture below you could see the sequence diagram of passing calls between JavaScript and Rust/Wasm parts: 16 | 17 | ![marine-web value passing](./marine-web-value-passing.png) 18 | 19 | Marine web is under active development and currently supports only single-module environments without WASI imports. In the near future, marine web will be as capable as the main runtime component. 20 | -------------------------------------------------------------------------------- /docs/marine-book/marine-runtime/architecture/marine-js/marine-web-scheme.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aliezzahn/docs/7af66c0600393eaadff7ffb28ba49a0febfc021a/docs/marine-book/marine-runtime/architecture/marine-js/marine-web-scheme.png -------------------------------------------------------------------------------- /docs/marine-book/marine-runtime/architecture/marine-js/marine-web-value-passing.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aliezzahn/docs/7af66c0600393eaadff7ffb28ba49a0febfc021a/docs/marine-book/marine-runtime/architecture/marine-js/marine-web-value-passing.png -------------------------------------------------------------------------------- /docs/marine-book/marine-runtime/configuration-file.md: -------------------------------------------------------------------------------- 1 | # Configuration file 2 | 3 | Service configuration files use TOML format. The most basic config for the `greeting` service might look like this: 4 | 5 | ```toml 6 | modules_dir = "artifacts/" 7 | total_memory_limit = "10 MiB" 8 | 9 | [[module]] 10 | name = "greeting" 11 | ``` 12 | 13 | This config contains the following information: 14 | 15 | * **modules\_dir** - default directory for searching modules 16 | * **\[\[module]]** - a list of modules that the service consists of 17 | * **total\_memory\_limit** - total maximum memory the entire service can allocate for modules in a service 18 | * **name** - the name of the Wasm file in the modules\_dir directory 19 | 20 | Tools will interpret all relative paths in the config as relative to the config file location. Absolute paths will be used unchanged. 21 | 22 | ### Config structure 23 | 24 | A more complex example of a service configuration file is shown below: 25 | 26 | ```toml 27 | modules_dir = "artifacts/" 28 | total_memory_limit = "10 MiB" 29 | 30 | [[module]] 31 | name = "effector" 32 | logger_enabled = true 33 | logging_mask = 0 34 | file_name = "effector-patched.wasm" 35 | load_from = "downloaded-artifacts/" 36 | 37 | [module.wasi] 38 | preopened_files = ["./dir"] 39 | mapped_dirs = { "alias" = "./dir" } 40 | envs = { "ENV1" = "arg1", "ENV2" = "arg2" } 41 | 42 | [module.mounted_binaries] 43 | curl = "/usr/bin/curl" 44 | 45 | [[module]] 46 | name = "pure" 47 | logger_enabled = true 48 | 49 | [[module]] 50 | name = "facade" 51 | logger_enabled = true 52 | ``` 53 | 54 | There are several additional fields here: 55 | 56 | #### **total\_memory\_limit** 57 | 58 | the maximum size of the Wasm heap that a service could allocate. This limit is a shared pool for all modules in the service. This setting should be specified as a string, that has the following format: 59 | 60 | `|Infinity|infinity` 61 | 62 | where `?` represents an optional field, `|` divides options and `specificator` is one from the following list: 63 | 64 | * `K`, `Kb` - kilobyte 65 | * `Ki`, `KiB` - kibibyte 66 | * `M`, `Mb` - megabyte 67 | * `Mi`, `MiB` - mebibyte 68 | * `G`, `Gb` - gigabyte 69 | * `Gi`, `GiB` - gibibyte 70 | * `T`, `Tb` - terabyte 71 | * `Ti`, `TiB` - tebibyte 72 | * `P`, `Pb` - petabyte 73 | * `Pi`, `PiB` - pebibyte 74 | 75 | Additionally, all specificators are case-insensitive. 76 | 77 | Allocating memory exceeding the limit triggers a (Rust) panic at runtime time. 78 | In this case the function call will be interrupted immediately, and the caller, i.e., the library using the marine-runtime, will be given an error detailing the out-of-memory (OOM) exception. 79 | 80 | Let's consider a few examples: 81 | 82 | total\_memory\_limit = "100" - 100 bytes 83 | 84 | total\_memory\_limit = "100K" - 100 kilobytes 85 | 86 | total\_memory\_limit = "100 Ki" - 100 kibibytes 87 | 88 | > **Note** 89 | > 90 | > Practically the Wasm memory is limited to `4 GiB` per module by the Wasm specification, so a service cannot consume more than `modules_number * 4 GiB`. 91 | 92 | > **Note** 93 | > 94 | > Each module allocates some memory on startup. Usually it is `>1 MiB`. In that case, on startup a service consumes at least `modules_number * 1 MiB` memory. To avoid startup fail, specify at `least modules_number * 2 MiB` total memory limit. 95 | 96 | #### **logger\_enabled** 97 | 98 | true, if it allows the corresponding Wasm module to use the Marine SDK logger. 99 | 100 | #### **logging\_mask** 101 | 102 | manages the logging targets, described in detail [here](../marine-rust-sdk/developing/logging.md#using-target-map). 103 | 104 | #### file\_name 105 | 106 | overrides the file name for loading, which by default is `$name.wasm` 107 | 108 | #### load\_from 109 | 110 | overrides `modules_dir` for this module. Path can contain file name, in this case it will be incompatible with `file_name` field. 111 | 112 | **module.wasi** 113 | 114 | a list of files available for reading/writing by the corresponding _effector_ module. 115 | 116 | #### **module.mounted\_binaries** 117 | 118 | a list of mounted binary executable files (more details in the previous [section](mounted-binaries.md)). 119 | 120 | #### **preopened\_files** 121 | 122 | describes a list of files and directories that this module could access with WASI. In the example above the `effector` module will have access only to a directory called `dir.` 123 | 124 | #### **mapped\_dirs** 125 | 126 | a map of accessible files and their aliases. Aliases should be normally used in Marine module development because it's hard to know the full path to a file. 127 | 128 | #### **envs** 129 | 130 | describes the environment variables accessible by a particular module with standard Rust [env](https://doc.rust-lang.org/std/env/index.html) API like this `std::env::var(IPFS_ADDR_ENV_NAME)`. Please note that Marine adds three additional environment variables. 131 | 132 | Module environment variables could be examined with mrepl, see the guide [here](https://fluence.dev/docs/marine-book/marine-tooling-reference/marine-repl#envs-show-environment-variables-of-a-module). 133 | 134 | ### Module types 135 | 136 | The service configuration defines the type of each module: the last one in the list becomes a **facade** module, the modules without `[module.wasi]` and `[module.mounted_binaries]` are **pure** modules, and the rest are **effectors**. 137 | 138 | More info about module types could be found [here](configuration-file.md#module-types). 139 | -------------------------------------------------------------------------------- /docs/marine-book/marine-runtime/host-exports.md: -------------------------------------------------------------------------------- 1 | # Host exports 2 | 3 | `Host export` is a function exported from a host and accessible by a Wasm module. Without interface-types it's not so easy to make a convenient API without the necessity for a developer to think about some low-level details (such as memory allocation for passing complex data types). 4 | 5 | `Marine` makes the development of such functions a trivial task. Each of such functions should be registered in the runtime config with `HostImportDescriptor`. 6 | 7 | ```rust 8 | pub type HostExportedFunc = Box) -> Option + 'static>; 9 | 10 | pub struct HostImportDescriptor { 11 | /// This closure will be invoked for corresponding import. 12 | pub host_exported_func: HostExportedFunc, 13 | 14 | /// Type of the closure arguments. 15 | pub argument_types: Vec, 16 | 17 | /// Types of output of the closure. 18 | pub output_type: Option, 19 | 20 | /// If Some, this closure is called with an error when errors are encountered while lifting. 21 | /// If None, panic will occur. 22 | pub error_handler: Option Option + 'static>>, 23 | } 24 | ``` 25 | 26 | And that is how a real-world [host exports](https://github.com/fluencelabs/marine/blob/1aeb9b70b573425c6d9f738b94cc35fbdf5aac58/marine/src/host_imports/mounted_binaries.rs#L25) looks like: 27 | 28 | ```rust 29 | pub(crate) fn create_mounted_binary_import(mounted_binary_path: PathBuf) -> HostImportDescriptor { 30 | let host_cmd_closure = move |_ctx: &mut Ctx, raw_args: Vec| { 31 | let result = 32 | mounted_binary_import_impl(&mounted_binary_path, raw_args).unwrap_or_else(Into::into); 33 | 34 | let raw_result = crate::to_interface_value(&result).unwrap(); 35 | 36 | Some(raw_result) 37 | }; 38 | 39 | HostImportDescriptor { 40 | host_exported_func: Box::new(host_cmd_closure), 41 | argument_types: vec![IType::Array(Box::new(IType::String))], 42 | output_type: Some(IType::Record(0)), 43 | error_handler: None, 44 | } 45 | } 46 | ``` 47 | 48 | Take a look at how `host_cmd_closure` is defined, it has two arguments: `Ctx` could be used for some low-level stuff, while `args` represents closure arguments and it's an array of [IValue](i-value-and-i-type.md), which could be handled in a handy way then. The result of the closure is `Option`, and resulted [IValue](i-value-and-i-type.md) could be easily constructed with a special function `to_interface_value`. 49 | 50 | And that's it! Just handle arguments, convert the result to IValue, and provide a descriptor! 51 | -------------------------------------------------------------------------------- /docs/marine-book/marine-runtime/i-value-and-i-type.md: -------------------------------------------------------------------------------- 1 | import Tabs from "@theme/Tabs"; 2 | import TabItem from "@theme/TabItem"; 3 | 4 | # IValue & IType 5 | 6 | `IValue` and `IType` are central pillars of passing values between modules and between a module and a host. Their main purpose is to allow developer not to think how this passing works internally and just use these handy enums. 7 | 8 | 9 | 10 | 11 | ```rust 12 | /// Represents values supported by interface-types. 13 | pub enum IValue { 14 | Boolean(bool), 15 | S8(i8), 16 | S16(i16), 17 | S32(i32), 18 | S64(i64), 19 | U8(u8), 20 | U16(u16), 21 | U32(u32), 22 | U64(u64), 23 | F32(f32), 24 | F64(f64), 25 | String(String), 26 | ByteArray(Vec), // specialization of Array for better performance 27 | Array(Vec), 28 | I32(i32), 29 | I64(i64), 30 | Record(NEVec), 31 | } 32 | ``` 33 | 34 | 35 | 36 | 37 | ```rust 38 | /// Represents types supported by IT. 39 | pub enum IType { 40 | Boolean, 41 | S8, 42 | S16, 43 | S32, 44 | S64, 45 | U8, 46 | U16, 47 | U32, 48 | U64, 49 | F32, 50 | F64, 51 | String, 52 | ByteArray, // specialization of Array for better performance 53 | Array(Box), 54 | I32, 55 | I64, 56 | Record(u64), 57 | } 58 | ``` 59 | 60 | 61 | 62 | -------------------------------------------------------------------------------- /docs/marine-book/marine-runtime/marine-runtime.md: -------------------------------------------------------------------------------- 1 | # Marine Runtime 2 | 3 | Marine is a modern general purpose Wasm runtime based on the [component model](https://github.com/WebAssembly/component-model) capable of running multi-module Wasm applications, aka services, with [interface-types](https://github.com/WebAssembly/interface-types) and a [shared-nothing linking](https://training.linuxfoundation.org/blog/how-and-why-to-link-webassembly-modules/) scheme. This execution model is well suited for a variety of scenarios and especially applicable to implementations following the [entity component system](https://en.wikipedia.org/wiki/Entity_component_system) (ECS) pattern or plugin-based architectures. 4 | 5 | Fluence peers, such as Fluence [Rust node](https://github.com/fluencelabs/fluence), include Marine to execute the hosted Wasm services composed with [Aqua](https://github.com/fluencelabs/aqua). 6 | 7 | This section is devoted to developers who want to understand the architecture of Marine or want to integrate it as a runtime to their projects. 8 | -------------------------------------------------------------------------------- /docs/marine-book/marine-runtime/module-types/marine-as-ecosystem.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aliezzahn/docs/7af66c0600393eaadff7ffb28ba49a0febfc021a/docs/marine-book/marine-runtime/module-types/marine-as-ecosystem.png -------------------------------------------------------------------------------- /docs/marine-book/marine-runtime/module-types/module-types.md: -------------------------------------------------------------------------------- 1 | # Module types 2 | 3 | There are three module types: 4 | 5 | - **facade** modules expose the API of an entire service that is callable from Aqua scripts 6 | - **pure** modules contain pure logic, and they can't access the filesystem or call external binaries 7 | - **effector** modules can access the filesystem through WASI and call external binaries 8 | 9 | This distinction between pure and effector modules aims to provide node owners with a better security mechanism. `Pure modules` could be considered harmless, because they can't access any external API, while `effector modules` could potentially do malicious action. And node owner could have a white list of allowed to run effector modules. 10 | 11 | Note that this differentiation is only partly implemented at the moment: `Marine` knows only about `facade` and `not facade` modules, but in the future, it'll differentiate modules into these three types and have an appropriate API. 12 | 13 | From this point of view, Marine could be considered as an ecosystem that could run several services comprised of different modules: 14 | 15 | ![marine as ecosystem](./marine-as-ecosystem.png) 16 | -------------------------------------------------------------------------------- /docs/marine-book/marine-runtime/mounted-binaries.md: -------------------------------------------------------------------------------- 1 | # Mounted binaries 2 | 3 | The `mounted binaries` section is for using external services inside a Wasm module. Each record of the form `cli_tool_name = cli-tool-path` within this section allows you to call a CLI tool located in the `cli-tool-path` directory. 4 | 5 | Consider the following example: 6 | 7 | ```toml 8 | [[module]] 9 | name = "curl_adapter" 10 | logger_enabled = true 11 | 12 | [module.mounted_binaries] 13 | curl = "/usr/bin/curl" 14 | ``` 15 | 16 | Using this config with adding the following lines in your source code: 17 | 18 | ```rust 19 | #[marine] 20 | #[link(wasm_import_module = "host")] 21 | extern "C" { 22 | fn curl(cmd: Vec) -> String; 23 | } 24 | ``` 25 | 26 | allows you to pass an argument as a string to the CLI tool and receive its output as a string. 27 | 28 | This import function is a host import function, meaning that wasm\_import\_module must be equal to `"host"`. Note that the signature of such functions must follow the pattern shown above: `cli_tool_name(Vec) -> MountedBinaryResult`. This pattern reflects the Rust process [API](https://doc.rust-lang.org/std/process/index.html). 29 | 30 | Then this function can be used as an ordinary Rust FFI function, but without `unsafe` block: 31 | 32 | ```rust 33 | #[marine] 34 | pub fn download(url: String) -> String { 35 | let result = curl(vec![url]); 36 | String::from_utf8(result.stdout).unwrap() 37 | } 38 | ``` 39 | -------------------------------------------------------------------------------- /docs/marine-book/marine-rust-sdk/developing/call-parameters.md: -------------------------------------------------------------------------------- 1 | # Call parameters 2 | 3 | There is a special API function `marine_rs_sdk::get_call_parameters()` that returns an instance of the `CallParameters` structure defined as follows: 4 | 5 | ```rust 6 | pub struct CallParameters { 7 | /// Peer id of the AIR script initiator. 8 | pub init_peer_id: String, 9 | 10 | /// Id of the current service. 11 | pub service_id: String, 12 | 13 | /// Id of the service creator. 14 | pub service_creator_peer_id: String, 15 | 16 | /// Id of the host which run this service. 17 | pub host_id: String, 18 | 19 | /// Id of the particle which execution resulted a call this service. 20 | pub particle_id: String, 21 | 22 | /// Security tetraplets which described origin of the arguments. 23 | pub tetraplets: Vec>, 24 | } 25 | ``` 26 | 27 | This structure contains vital for Fluence service fields, which allow to find out varied information about a source of a service call. 28 | 29 | One of the most common patterns of `CallParameters` usage is authentication services: 30 | 31 | ```rust 32 | use marine_rs_sdk::marine; 33 | 34 | pub fn is_owner() -> bool { 35 | let meta = marine_rs_sdk::get_call_parameters(); 36 | let caller = meta.init_peer_id; 37 | let owner = meta.service_creator_peer_id; 38 | 39 | caller == owner 40 | } 41 | 42 | #[marine] 43 | pub fn am_i_owner() -> bool { 44 | is_owner() 45 | } 46 | ``` 47 | -------------------------------------------------------------------------------- /docs/marine-book/marine-rust-sdk/developing/developing.md: -------------------------------------------------------------------------------- 1 | # Developing 2 | 3 | The Marine Rust SDK exports several main components: 4 | 5 | * `#[marine]` procedure macro - can be applied to a function, external block or structure. 6 | * call parameters interface - intended to extract a special structure called `CallParameters` that contains some module start parameters 7 | * mounted binaries interface - can be used to extract a result of CLI interface call 8 | * `module_manifest` macro - intended to embed some info into a compiled Wasm 9 | * logging stuff - allows adjusting a special Wasm logging mechanism 10 | -------------------------------------------------------------------------------- /docs/marine-book/marine-rust-sdk/developing/environment-variables.md: -------------------------------------------------------------------------------- 1 | # Environment variables 2 | 3 | The `Marine` runtime sets some environment variables for each loaded module: 4 | 5 | * `service_id` contains id of a current service 6 | * `local` - contains a full path to the `local` directory 7 | * `tmp` - contains a full path to the `tmp` directory 8 | 9 | Additionally, the runtime adds one variable for each mounted binary import specified in a configuration file, this variable contains a specified in the config file path to a mounted CLI binary. 10 | 11 | Environment variables could be seen with the Marine REPL, more details [here](../../marine-tooling-reference/marine-repl.md#envs-show-environment-variables-of-a-module). From the code perspective, such variables could be obtained with the standard Rust [std::env](https://doc.rust-lang.org/std/env/index.html) mechanism. 12 | -------------------------------------------------------------------------------- /docs/marine-book/marine-rust-sdk/developing/export-functions.md: -------------------------------------------------------------------------------- 1 | import Tabs from "@theme/Tabs"; 2 | import TabItem from "@theme/TabItem"; 3 | 4 | # Export functions 5 | 6 | Applying the `#[marine]` macro to a function results in its export, which means that it can be called from other modules or AIR scripts. 7 | 8 | ## mtype 9 | 10 | For the function to be compatible with this macro, its arguments must be of the `mtype`, which is defined as follows: 11 | 12 | `mtype` = `bool`, `u8`, `u16`, `u32`, `u64`, `i8`, `i16`, `i32`, `i64`, `f32`, `f64`, `String` 13 | 14 | `mtype` = `mtype` | `Vec` 15 | 16 | `mtype` = `mtype` | `Record` 17 | 18 | ## Function Export Requirements 19 | 20 | In other words, the arguments must be one of the types listed below: 21 | 22 | * one of the following Rust basic types: `bool`, `u8`, `u16`, `u32`, `u64`, `i8`, `i16`, `i32`, `i64`, `f32`, `f64`, `String` 23 | * a vector of elements of the above types 24 | * a vector composed of vectors of the above type, where recursion is acceptable, e.g. the type `Vec>>` is permissible 25 | * a record, where all fields are of the basic Rust types 26 | * a record, where all fields are of any above types or other records 27 | 28 | The return type of a function must follow the same rules, but currently, only one return type is possible. 29 | 30 | ## Examples 31 | 32 | See the example below of an exposed function with a complex type signature and return value: 33 | 34 | 35 | 36 | 37 | ```rust 38 | // export TestRecord as a public data structure bound by 39 | // the IT type constraints 40 | #[marine] 41 | pub struct TestRecord { 42 | pub field_0: i32, 43 | pub field_1: Vec>, 44 | } 45 | 46 | // export foo as a public function bound by the 47 | // the IT type constraints 48 | 49 | #[marine] 50 | pub fn foo(arg_1: Vec>>>, arg_2: String) -> Vec>>> { 51 | unimplemented!() 52 | } 53 | ``` 54 | 55 | 56 | 57 | 58 | ```rust 59 | // export Data and Input as a public data structures bound by 60 | // the IT type constraints 61 | #[marine] 62 | pub struct Data { 63 | pub name: String, 64 | } 65 | 66 | #[marine] 67 | pub struct Input { 68 | pub first_name: String, 69 | pub last_name: String, 70 | } 71 | 72 | // export produce as a public function bound by the 73 | // the IT type constraints 74 | #[marine] 75 | pub fn produce(data: Input) -> Data { 76 | unimplemented!() 77 | } 78 | ``` 79 | 80 | 81 | 82 | -------------------------------------------------------------------------------- /docs/marine-book/marine-rust-sdk/developing/import-functions.md: -------------------------------------------------------------------------------- 1 | import Tabs from "@theme/Tabs"; 2 | import TabItem from "@theme/TabItem"; 3 | 4 | # Import functions 5 | 6 | The `#[marine]` macro can also wrap a Rust [extern block](https://doc.rust-lang.org/std/keyword.extern.html). In this case, all functions declared in it are considered imported functions. If there are imported functions in some module, say, module A, then 7 | 8 | * There should be another module, module B, that exports the same functions. The name of module B is indicated in the `link` macro (see examples below) 9 | * Module B should be loaded into `Marine` by the moment the loading of module A starts. Module A cannot be loaded if at least one imported function is absent in `Marine`. 10 | 11 | ## **Function import requirements** 12 | 13 | * wrap an extern block with the function(s) to be imported with the `#[marine]` macro 14 | * all function(s) arguments must be of the mtype type 15 | * the return type of the function(s) must be mtype 16 | 17 | ## Examples 18 | 19 | See the examples below of wrapped `extern` block usage: 20 | 21 | 22 | 23 | 24 | ```rust 25 | #[marine] 26 | pub struct TestRecord { 27 | pub field_0: i32, 28 | pub field_1: Vec>, 29 | } 30 | 31 | // wrap the extern block with the marine macro to expose the function 32 | // as an import to the Marine VM 33 | #[marine] 34 | #[link(wasm_import_module = "some_module")] 35 | extern "C" { 36 | pub fn foo(arg: Vec>>>, arg_2: String) -> Vec>>>; 37 | } 38 | ``` 39 | 40 | 41 | 42 | 43 | ```rust 44 | #[marine] 45 | #[link(wasm_import_module = "some_module")] 46 | extern "C" { 47 | pub fn foo(arg: Vec>>>) -> Vec>>>; 48 | } 49 | ``` 50 | 51 | 52 | 53 | -------------------------------------------------------------------------------- /docs/marine-book/marine-rust-sdk/developing/logging.md: -------------------------------------------------------------------------------- 1 | # Logging 2 | 3 | Using logging is a simple way to assist in debugging without deploying the module(s) to a p2p node. 4 | 5 | ## Using logger 6 | 7 | The `logger` feature allows you to use a special logger that is based at the top of the [log](https://crates.io/crates/log) crate. To enable logging please specify the logger feature of the Marine SDK in `Config.toml` and add the [log](https://crates.io/crates/log) crate: 8 | 9 | ```toml 10 | [dependencies] 11 | log = "0.4.14" 12 | marine-rs-sdk = { version = "0.10.2", features = ["logger"] } 13 | ``` 14 | 15 | The logger should be initialized before its usage. This can be done in the `main` function as shown in the example below: 16 | 17 | ```rust 18 | use marine_rs_sdk::marine; 19 | use marine_rs_sdk::WasmLoggerBuilder; 20 | 21 | pub fn main() { 22 | WasmLoggerBuilder::new() 23 | // with_log_level can be skipped, 24 | // logger will be initialized with Info level in this case. 25 | .with_log_level(log::LevelFilter::Info) 26 | .build() 27 | .unwrap(); 28 | } 29 | 30 | #[marine] 31 | pub fn put(file_name: String, _file_content: Vec) -> String { 32 | log::info!("put called with file name {}", file_name); 33 | unimplemented!() 34 | } 35 | ``` 36 | 37 | To play with this logging stuff in REPL you need to 38 | 39 | * specify the `logger_enabled=true` for this module in the configuration file (more details in this [section](../../marine-runtime/configuration-file.md#logger_enabled)) 40 | * use environment variables for REPL to guide it about minimal log level (details [here](../../marine-tooling-reference/marine-repl.md#enabling-logger)) 41 | 42 | ## Using target map 43 | 44 | In addition to the standard log creation features, the Fluence logger allows the so-called target map to be configured during the initialization step. This allows you to filter out logs by `logging_mask`, which can be set for each module in the service configuration. Let's consider an example: 45 | 46 | ```rust 47 | use marine_rs_sdk::marine; 48 | 49 | const TARGET_MAP: [(&str, i32); 4] = [ 50 | ("instruction", 1 << 1), 51 | ("data_cache", 1 << 2), 52 | ("next_peer_pks", 1 << 3), 53 | ("subtree_complete", 1 << 4), 54 | ]; 55 | 56 | pub fn main() { 57 | use std::collections::HashMap; 58 | 59 | let target_map = HashMap::from_iter(TARGET_MAP.iter().cloned()); 60 | 61 | marine_rs_sdk::WasmLoggerBuilder::new() 62 | .with_target_map(target_map) 63 | .build() 64 | .unwrap(); 65 | } 66 | 67 | #[marine] 68 | pub fn foo() { 69 | log::info!(target: "instruction", "this will print if (logging_mask & 1) != 0"); 70 | log::info!(target: "data_cache", "this will print if (logging_mask & 2) != 0"); 71 | } 72 | ``` 73 | 74 | Here, an array called `TARGET_MAP` is defined and provided to a logger in the `main` function of a module. Each entry of this array contains a string (a target) and a number that represents the bit position in the 64-bit mask `logging_mask`. When you write a log message request `log::info!`, its target must coincide with one of the strings (the targets) defined in the `TARGET_MAP` array. The log will be printed if `logging_mask` for the module has the corresponding target bit set. 75 | 76 | A more complex example of this feature usage can be found in the Aqua [interpreter](https://github.com/fluencelabs/aquamarine/blob/e5244db6a12034022a6750f5352583d0b3885401/interpreter-lib/src/log_targets.rs). 77 | -------------------------------------------------------------------------------- /docs/marine-book/marine-rust-sdk/developing/module-manifest.md: -------------------------------------------------------------------------------- 1 | # Module manifest 2 | 3 | The `module_manifest!` macro embeds the Interface Type, SDK, and Rust project version as well as additional project and build information into a Wasm module. For the macro to be usable, it needs to be imported and initialized: 4 | 5 | ```rust 6 | use marine_rs_sdk::marine; 7 | use marine_rs_sdk::module_manifest; // import manifest macro 8 | 9 | module_manifest!( 10 | "Fluence Labs", // authors 11 | "0.1.0", // version 12 | "The greeting module for the Fluence network", // description 13 | ".../marine/examples/greeting", // repository 14 | ); 15 | 16 | fn main() {} 17 | 18 | #[marine] 19 | fn greeting(name: &str) {...} 20 | ``` 21 | 22 | Using the Marine CLI, we can inspect a module's manifest with `marine info`: 23 | 24 | ```sh 25 | marine info artifacts/greeting.wasm 26 | ``` 27 | ``` 28 | it version: 0.23.0 29 | sdk version: 0.6.0 30 | authors: Fluence Labs 31 | version: 0.1.0 32 | description: The greeting module for the Fluence network 33 | repository: https://github.com/fluencelabs/marine/tree/master/examples/greeting 34 | build time: 2022-04-12 18:16:34.487366668 +00:00 UTC 35 | ``` 36 | 37 | It's possible to omit arguments in the `module_manifest`, in this case it'll get them from `Cargo.toml`: 38 | 39 | ```rust 40 | use marine_rs_sdk::marine; 41 | use marine_rs_sdk::module_manifest; // import manifest macro 42 | 43 | module_manifest!(st); 44 | 45 | fn main() {} 46 | 47 | #[marine] 48 | fn greeting(name: &str) {...} 49 | ``` 50 | -------------------------------------------------------------------------------- /docs/marine-book/marine-rust-sdk/developing/mounted-binaries.md: -------------------------------------------------------------------------------- 1 | # Mounted binaries 2 | 3 | Due to the inherent limitations of Wasm modules, such as a lack of sockets, it may be necessary for a module to interact with its host to bridge such gaps, e.g. use a https transport provider like _curl_. In order for a Wasm module to use a host's _curl_ capabilities, we need to provide access to the binary, which at the code level is achieved through the Rust `extern` block: 4 | 5 | ```rust 6 | use marine_rs_sdk::marine; 7 | use marine_rs_sdk::MountedBinaryResult; 8 | 9 | pub fn main() {} 10 | 11 | #[marine] 12 | pub fn curl_request(curl_cmd: Vec) -> MountedBinaryResult { 13 | let response = curl(curl_cmd); 14 | response 15 | } 16 | 17 | #[marine] 18 | #[link(wasm_import_module = "host")] 19 | extern "C" { 20 | fn curl(cmd: Vec) -> MountedBinaryResult; 21 | } 22 | ``` 23 | 24 | Note that to import functions from a host, not from other Wasm modules, `wasm_import_module` must be equal to `"host"`. 25 | 26 | The code above creates a "curl adapter", i.e., a Wasm module that allows other Wasm modules to use the the `curl_request` function, which calls the imported _curl_ binary in this case, to make http calls. Please note that we are wrapping the `extern` block with the `#[marine]` macro and introduce a Marine-native data structure `MountedBinaryResult` as the linked-function return value. 27 | 28 | To play with it in the Marine REPL you need to specify a path to `curl` on your local system, it is described in more details [here](../../marine-runtime/mounted-binaries.md). 29 | -------------------------------------------------------------------------------- /docs/marine-book/marine-rust-sdk/developing/structures.md: -------------------------------------------------------------------------------- 1 | import Tabs from "@theme/Tabs"; 2 | import TabItem from "@theme/TabItem"; 3 | 4 | # Structures 5 | 6 | The `#[marine]` macro can also wrap a `struct` making it possible to use it as a function argument or return type. Note that 7 | 8 | * only macro-wrapped structures can be used as function arguments and return types 9 | * all fields of the wrapped structure must be public and of the `mtype` 10 | * it is possible to have inner records in the macro-wrapped structure and to import wrapped structs from other crates 11 | 12 | ## Structure passing requirements 13 | 14 | * wrap a structure with the `#[marine]` macro 15 | * all structures fields must be of the `mtype` 16 | * the structure must be pointed to without preceding package import in a function signature, i.e. `StructureName` but not `package_name::module_name::StructureName` 17 | * wrapped structures can be imported from crates 18 | 19 | ## Examples 20 | 21 | See the examples below for wrapping `struct`: 22 | 23 | 24 | 25 | 26 | ```rust 27 | #[marine] 28 | pub struct TestRecord0 { 29 | pub field_0: i32, 30 | } 31 | 32 | #[marine] 33 | pub struct TestRecord1 { 34 | pub field_0: i32, 35 | pub field_1: String, 36 | pub field_2: Vec, 37 | pub test_record_0: TestRecord0, 38 | } 39 | 40 | #[marine] 41 | pub struct TestRecord2 { 42 | pub test_record_0: TestRecord0, 43 | pub test_record_1: TestRecord1, 44 | } 45 | 46 | #[marine] 47 | fn foo(mut test_record: TestRecord2) -> TestRecord2 { unimplemented!(); } 48 | ``` 49 | 50 | 51 | 52 | 53 | ```rust 54 | #[marine] 55 | pub struct TestRecord0 { 56 | pub field_0: i32, 57 | } 58 | 59 | #[marine] 60 | pub struct TestRecord1 { 61 | pub field_0: i32, 62 | pub field_1: String, 63 | pub field_2: Vec, 64 | pub test_record_0: TestRecord0, 65 | } 66 | 67 | #[marine] 68 | pub struct TestRecord2 { 69 | pub test_record_0: TestRecord0, 70 | pub test_record_1: TestRecord1, 71 | } 72 | 73 | #[marine] 74 | #[link(wasm_import_module = "some_module")] 75 | extern "C" { 76 | fn foo(mut test_record: TestRecord2) -> TestRecord2; 77 | } 78 | ``` 79 | 80 | 81 | 82 | 83 | ```rust 84 | mod data_crate { 85 | use fluence::marine; 86 | #[marine] 87 | pub struct Data { 88 | pub name: String, 89 | pub data: f64, 90 | } 91 | } 92 | 93 | use data_crate::Data; 94 | use fluence::marine; 95 | 96 | fn main() {} 97 | 98 | #[marine] 99 | fn some_function() -> Data { 100 | Data { 101 | name: "example".into(), 102 | data: 1.0, 103 | } 104 | } 105 | ``` 106 | 107 | 108 | 109 | -------------------------------------------------------------------------------- /docs/marine-book/marine-rust-sdk/marine-rust-sdk.md: -------------------------------------------------------------------------------- 1 | # Marine Rust SDK 2 | 3 | The Marine SDK is comprised of two main crates: [marine-rs-sdk](https://github.com/fluencelabs/marine-rs-sdk/) and [marine-rs-sdk-test](https://github.com/fluencelabs/marine-rs-sdk-test). 4 | 5 | The `marine-rs-sdk` empowers developers to create suitable hosting on peers of the peer-to-peer network. Such services are constructed from one or more Wasm modules, where each is the result of Rust code compiled to `wasm32-wasi` compile target, executable by the Marine runtime. 6 | 7 | The `marine-rs-sdk-test` allows developers to write comprehensive tests for their modules and services. 8 | 9 | The main purpose of the SDK that influenced its design is to allow a developer to write modules on "vanilla" Rust wrapping necessary blocks with the provided macros. 10 | -------------------------------------------------------------------------------- /docs/marine-book/marine-rust-sdk/module-abi.md: -------------------------------------------------------------------------------- 1 | # Module ABI 2 | 3 | This section describes some low-level details of ABI used for module linking and passing values in module-module and module-host schemes. 4 | 5 | The best way to see ABI functions is to use the following command: 6 | 7 | ```sh 8 | marine info -i artifacts/greeting.wasm 9 | ... 10 | ;; Exports 11 | (@interface export "allocate" (func 0)) 12 | (@interface export "release_objects" (func 1)) 13 | (@interface export "get_result_size" (func 2)) 14 | (@interface export "get_result_ptr" (func 3)) 15 | (@interface export "set_result_size" (func 4)) 16 | (@interface export "set_result_ptr" (func 5)) 17 | ... 18 | ``` 19 | 20 | All these functions are generated by the SDK and normally a developer shouldn't care about them. 21 | 22 | Let's consider all these functions: 23 | 24 | ## allocate 25 | 26 | ```rust 27 | allocate(elem_count: usize, elem_ty: usize) -> usize 28 | ``` 29 | 30 | Allocate memory enough to place `elem_count` objects of type `elem_ty`, returns a pointer to allocated memory region 31 | 32 | ## release_objects 33 | 34 | ```rust 35 | release_objects() 36 | ``` 37 | 38 | Removes objects that were saved by generated by the `#[marine]` macro code to prevent their deletion before parameters passing ends. Usually called by the IT side at the end of passing a function result. 39 | 40 | Next four functions are intended to pass results from called functions. They are temporary solution and intended to overcome missing multi-value feature in IT, will be removed in the future with the multi-value passing scheme. 41 | 42 | ## get_result_size 43 | 44 | ```rust 45 | get_result_size() -> usize 46 | ``` 47 | 48 | Returns a size of a result to the IT operand stack. 49 | 50 | ## get_result_ptr 51 | 52 | ```rust 53 | get_result_ptr() -> usize 54 | ``` 55 | 56 | Returns a pointer to a result to the IT operand stack. 57 | 58 | ## set_result_size 59 | 60 | ```rust 61 | set_result_size(size: usize) 62 | ``` 63 | 64 | Set a size of a result to the given value. 65 | 66 | ## set_result_ptr 67 | 68 | ```rust 69 | set_result_ptr(ptr: usize) 70 | ``` 71 | 72 | Set a pointer of a result to the given value. 73 | -------------------------------------------------------------------------------- /docs/marine-book/marine-rust-sdk/testing-and-debugging/internal-debugging-api.md: -------------------------------------------------------------------------------- 1 | # Internal debugging API 2 | 3 | The `Marine SDK` has an internal feature called `debug`, it allows debugging some of the internal details of the IT execution. 4 | 5 | ## Enabling debug API 6 | 7 | To enable logging please specify the logger feature of the Marine SDK in `Config.toml`: 8 | 9 | ```toml 10 | [dependencies] 11 | marine-rs-sdk = { version = "0.7.1", features = ["debug"] } 12 | ``` 13 | 14 | ## Using debug API 15 | 16 | Normally, this feature should not be used by a backend developer. Below you can see examples of such details for the greeting service compiled with the `debug` feature. Please note, that it's [necessary](../../marine-tooling-reference/marine-repl.md#enabling-logger) to run REPL with `RUST_LOG`. 17 | 18 | ```sh 19 | # running the greeting service compiled with debug feature 20 | RUST_LOG="info" mrepl Config.toml 21 | 22 | Welcome to the Marine REPL (version 0.16.0) 23 | Minimal supported versions 24 | sdk: 0.6.0 25 | interface-types: 0.20.0 26 | 27 | app service was created with service id = 0ba05b05-4e92-48bf-ac30-2b8b59efe189 28 | elapsed time 746.509µs 29 | 30 | 1> call greeting greeting "user" 31 | [greeting] sdk.allocate: 4 32 | [greeting] sdk.set_result_ptr: 1114240 33 | [greeting] sdk.set_result_size: 8 34 | [greeting] sdk.get_result_ptr, returns 1114240 35 | [greeting] sdk.get_result_size, returns 8 36 | [greeting] sdk.get_result_ptr, returns 1114240 37 | [greeting] sdk.get_result_size, returns 8 38 | [greeting] sdk.deallocate: 0x110080 8 39 | 40 | result: String("Hi, user") 41 | elapsed time: 222.675µs 42 | ``` 43 | 44 | The most important information these logs relates to the `allocate`/`deallocate` function calls. The `sdk.allocate: 4` line corresponds to passing the 4-byte `user` string to the Wasm module, with the memory allocated inside the module, and the string is copied there. Whereas `sdk.deallocate: 0x110080 8` refers to passing the 8-byte resulting string `Hi, user` to the host side. Since all arguments and results are passed by value, `deallocate` is called to delete unnecessary memory inside the Wasm module. 45 | -------------------------------------------------------------------------------- /docs/marine-book/marine-rust-sdk/testing-and-debugging/testing-a-module.md: -------------------------------------------------------------------------------- 1 | # Testing a module 2 | 3 | To use the `#[marine-test]` macro add `marine-rs-sdk-test` crate to the `[dev-dependencies]` section of `Config.toml`: 4 | 5 | ```toml 6 | [dev-dependencies] 7 | marine-rs-sdk-test = "0.7.0" 8 | ``` 9 | 10 | Let's have a look at an implementation example: 11 | 12 | ```rust 13 | use marine_rs_sdk::marine; 14 | use marine_rs_sdk::module_manifest; 15 | 16 | module_manifest!(); 17 | 18 | pub fn main() {} 19 | 20 | #[marine] 21 | pub fn greeting(name: String) -> String { // 1 22 | format!("Hi, {}", name) 23 | } 24 | 25 | #[cfg(test)] 26 | mod tests { 27 | use marine_rs_sdk_test::marine_test; // 2 28 | 29 | #[marine_test(config_path = "../Config.toml", modules_dir = "../artifacts")] // 3 30 | fn empty_string(greeting: marine_test_env::greeting::ModuleInterface) { 31 | let actual = greeting.greeting(String::new()); // 4 32 | assert_eq!(actual, "Hi, "); 33 | } 34 | 35 | #[marine_test(config_path = "../Config.toml", modules_dir = "../artifacts")] 36 | fn non_empty_string(greeting: marine_test_env::greeting::ModuleInterface) { 37 | let actual = greeting.greeting("name".to_string()); 38 | assert_eq!(actual, "Hi, name"); 39 | } 40 | } 41 | ``` 42 | 43 | 1. We wrap a basic _greeting_ function with the `#[marine]` macro which results in the greeting.wasm module. 44 | 2. We wrap our tests as usual with `[cfg(test)]` and import the marine _test crate._ Do **not** import _super_ or the _local crate_. 45 | 3. Instead, we apply the `#[marine_test]` macro to each of the test functions by providing the path to the config file, e.g., Config.toml, and the directory containing the Wasm module we obtained after compiling our project with `marine build`. Moreover, we add the type of the test as an argument in the function signature. It is imperative that the project build precedes the test runner otherwise the required Wasm file will be missing. 46 | 4. The target of our tests is the `pub fn greeting` function. Since we are calling the function from the Wasm module we must prefix the function name with the module namespace -- `greeting` in this example case as specified in the function argument. 47 | 48 | Now that we have our Wasm module and tests in place, we can proceed with `cargo test --release.` Note that using the `release`flag vastly improves the import speed of the necessary Wasm modules. 49 | 50 | The full example could be found [here](https://github.com/fluencelabs/marine/tree/master/examples/greeting). 51 | -------------------------------------------------------------------------------- /docs/marine-book/marine-rust-sdk/testing-and-debugging/testing-a-service.md: -------------------------------------------------------------------------------- 1 | import Tabs from "@theme/Tabs"; 2 | import TabItem from "@theme/TabItem"; 3 | 4 | # Testing a service 5 | 6 | The `#[marine_test]` macro also allows testing data flow between multiple services, so you do not need to deploy anything to the network and write an Aqua app just for basic testing. Let's look at an example: 7 | 8 | 9 | 10 | 11 | ```rust 12 | fn main() {} 13 | 14 | #[cfg(test)] 15 | mod tests { 16 | use marine_rs_sdk_test::marine_test; 17 | #[marine_test( // 1 18 | producer( 19 | config_path = "../producer/Config.toml", 20 | modules_dir = "../producer/artifacts" 21 | ), 22 | consumer( 23 | config_path = "../consumer/Config.toml", 24 | modules_dir = "../consumer/artifacts" 25 | ) 26 | )] 27 | fn test() { 28 | let mut producer = marine_test_env::producer::ServiceInterface::new(); // 2 29 | let mut consumer = marine_test_env::consumer::ServiceInterface::new(); 30 | let input = marine_test_env::producer::Input { // 3 31 | first_name: String::from("John"), 32 | last_name: String::from("Doe"), 33 | }; 34 | let data = producer.produce(input); // 4 35 | let result = consumer.consume(data); 36 | assert_eq!(result, "John Doe") 37 | } 38 | } 39 | ``` 40 | 41 | 42 | 43 | 44 | ```rust 45 | use marine_rs_sdk::marine; 46 | use marine_rs_sdk::module_manifest; 47 | 48 | module_manifest!(); 49 | 50 | pub fn main() {} 51 | 52 | #[marine] 53 | pub struct Data { 54 | pub name: String, 55 | } 56 | 57 | #[marine] 58 | pub struct Input { 59 | pub first_name: String, 60 | pub last_name: String, 61 | } 62 | 63 | #[marine] 64 | pub fn produce(data: Input) -> Data { 65 | Data { 66 | name: format!("{} {}", data.first_name, data.last_name), 67 | } 68 | } 69 | ``` 70 | 71 | 72 | 73 | 74 | ```rust 75 | use marine_rs_sdk::marine; 76 | use marine_rs_sdk::module_manifest; 77 | 78 | module_manifest!(); 79 | 80 | pub fn main() {} 81 | 82 | #[marine] 83 | pub struct Data { 84 | pub name: String, 85 | } 86 | 87 | #[marine] 88 | pub fn consume(data: Data) -> String { 89 | data.name 90 | } 91 | ``` 92 | 93 | 94 | 95 | 96 | ```rust 97 | fn main() {} 98 | 99 | #[cfg(test)] 100 | #[marine_rs_sdk_test::marine_test( 101 | producer( 102 | config_path = "../producer/Config.toml", 103 | modules_dir = "../producer/artifacts" 104 | ), 105 | consumer( 106 | config_path = "../consumer/Config.toml", 107 | modules_dir = "../consumer/artifacts" 108 | ) 109 | )] 110 | mod tests_on_mod { 111 | #[test] 112 | fn test() { 113 | let mut producer = marine_test_env::producer::ServiceInterface::new(); 114 | let mut consumer = marine_test_env::consumer::ServiceInterface::new(); 115 | let input = marine_test_env::producer::Input { 116 | first_name: String::from("John"), 117 | last_name: String::from("Doe"), 118 | }; 119 | let data = producer.produce(input); 120 | let result = consumer.consume(data); 121 | assert_eq!(result, "John Doe") 122 | } 123 | } 124 | ``` 125 | 126 | 127 | 128 | 129 | 1. We wrap the `test` function with the `marine_test` macro by providing named service configurations with module locations. Based on its arguments the macro defines a `marine_test_env` module with an interface to the services. 130 | 2. We create new services. Each `ServiceInterface::new()` runs a new marine runtime with the service. 131 | 3. We prepare data to pass to a service using structure definition from `marine_test_env`. The macro finds all structures used in the service interface functions and defines them in the corresponding submodule of `marine_test_env`. 132 | 4. We call a service function through the `ServiceInterface` object. 133 | 5. It is possible to use the result of one service call as an argument for a different service call. The interface types with the same structure have the same rust type in `marine_test_env`. 134 | 135 | In the `test_on_mod.rs` tab we can see another option — applying `marine_test` to a `mod`. The macro just defines the `marine_test_env` at the beginning of the module and then it can be used as usual everywhere inside the module. 136 | 137 | The full example is [here](https://github.com/fluencelabs/marine/tree/master/examples/multiservice_marine_test). 138 | 139 | The `marine_test` macro also gives access to the interface of internal modules which may be useful for setting up a test environment. This feature is designed to be used in situations when it is simpler to set up a service for a test through internal functions than through the service interface. To illustrate this feature we have rewritten the previous example: 140 | 141 | ```rust 142 | fn main() {} 143 | 144 | #[cfg(test)] 145 | mod tests { 146 | use marine_rs_sdk_test::marine_test; 147 | #[marine_test( 148 | producer( 149 | config_path = "../producer/Config.toml", 150 | modules_dir = "../producer/artifacts" 151 | ), 152 | consumer( 153 | config_path = "../consumer/Config.toml", 154 | modules_dir = "../consumer/artifacts" 155 | ) 156 | )] 157 | fn test() { 158 | let mut producer = marine_test_env::producer::ServiceInterface::new(); 159 | let mut consumer = marine_test_env::consumer::ServiceInterface::new(); 160 | let input = marine_test_env::producer::modules::producer::Input { // 1 161 | first_name: String::from("John"), 162 | last_name: String::from("Doe"), 163 | }; 164 | let data = producer.modules.producer.produce(input); // 2 165 | let consumer_data = marine_test_env::consumer::modules::consumer::Data { name: data.name } // 3; 166 | let result = consumer.modules.consumer.consume(consumer_data); 167 | assert_eq!(result, "John Doe") 168 | } 169 | } 170 | ``` 171 | 172 | 1. We access the internal service interface to construct an interface structure. To do so, we use the following pattern: `marine_test_env::$service_name::modules::$module_name::$structure_name`. 173 | 2. We access the internal service interface and directly call a function from one of the modules of this service. To do so, we use the following pattern: `$service_object.modules.$module_name.$function_name` . 174 | 3. In the previous example, the same interface types had the same rust types. It is limited when using internal modules: the property is true only when structures are defined in internal modules of one service, or when structures are defined in service interfaces of different services. So, we need to construct the proper type to pass data to the internals of another module. 175 | 176 | -------------------------------------------------------------------------------- /docs/marine-book/marine-rust-sdk/testing-and-debugging/testing-and-debugging.md: -------------------------------------------------------------------------------- 1 | # Testing & Debugging 2 | 3 | Since we are compiling to a wasm32-wasi target with `mtype` constraints, the basic `cargo test` is not all that useful or even usable for our purposes. To alleviate that limitation, Fluence has introduced the `#[marine-test]` macro that does a lot of the heavy lifting to allow developers to use `cargo test` as intended. That is, the `#[marine-test]` macro generates the necessary code to call Marine, one instance per test function, based on the Wasm module and associated configuration file so that the actual test function is run against the Wasm module, not the native code. 4 | -------------------------------------------------------------------------------- /docs/marine-book/marine-rust-sdk/testing-and-debugging/using-cargo-build-scripts.md: -------------------------------------------------------------------------------- 1 | import Tabs from "@theme/Tabs"; 2 | import TabItem from "@theme/TabItem"; 3 | 4 | # Using cargo build scripts 5 | 6 | Testing sdk also has the interface for [cargo build scripts](https://doc.rust-lang.org/cargo/reference/build-scripts.html). Some IDEs can analyze files generated in build scripts, providing code completion and error highlighting for code generated in build scripts. But using it may be a little bit tricky because build scripts are not designed for such things. 7 | 8 | To set up IDE you need to do the following: 9 | 10 | #### CLion: 11 | 12 | * in the `Help -> Actions -> Experimental Futures` enable `org.rust.cargo.evaluate.build.scripts` 13 | * refresh cargo project in order to update generated code: change `Cargo.toml` and build from IDE or press `Refresh Cargo Project` in Cargo tab 14 | 15 | #### VS Code: 16 | 17 | * install the `rust-analyzer` plugin 18 | * change `Cargo.toml` to let plugin update code from generated files 19 | 20 | The update will not work instantly: you should build service to wasm, and then trigger `build.rs` run again, but for the native target. 21 | 22 | And here is the example of using this: 23 | 24 | 25 | 26 | 27 | ```rust 28 | use marine_rs_sdk_test::generate_marine_test_env; 29 | use marine_rs_sdk_test::ServiceDescription; 30 | 31 | fn main() { 32 | let services = vec![ // <- 1 33 | ("greeting".to_string(), ServiceDescription { 34 | config_path: "Config.toml".to_string(), 35 | modules_dir: Some("artifacts".to_string()), 36 | }) 37 | ]; 38 | 39 | let target = std::env::var("CARGO_CFG_TARGET_ARCH").unwrap(); 40 | if target != "wasm32" { // <- 2 41 | generate_marine_test_env(services, "marine_test_env.rs", file!()); // <- 3 42 | } 43 | 44 | println!("cargo:rerun-if-changed=src/main.rs"); // <- 4 45 | } 46 | ``` 47 | 48 | 49 | 50 | 51 | ```rust 52 | use marine_rs_sdk::marine; 53 | use marine_rs_sdk::module_manifest; 54 | 55 | module_manifest!(); 56 | 57 | pub fn main() {} 58 | 59 | #[marine] 60 | pub fn greeting(name: String) -> String { 61 | format!("Hi, {}", name) 62 | } 63 | 64 | #[cfg(test)] 65 | mod built_tests { 66 | marine_rs_sdk_test::include_test_env!("/marine_test_env.rs"); // <- 4 67 | #[test] 68 | fn non_empty_string() { 69 | let mut greeting = marine_test_env::greeting::ServiceInterface::new(); 70 | let actual = greeting.greeting("name".to_string()); 71 | assert_eq!(actual, "Hi, name"); 72 | } 73 | }t 74 | ``` 75 | 76 | 77 | 78 | 79 | ```toml 80 | [package] 81 | name = "wasm-build-rs" 82 | version = "0.1.0" 83 | authors = ["Fluence Labs"] 84 | description = "The greeting module for the Fluence network" 85 | repository = "https://github.com/fluencelabs/marine/tree/master/examples/build_rs" 86 | edition = "2018" 87 | publish = false 88 | 89 | [[bin]] 90 | name = "build_rs_test" 91 | path = "src/main.rs" 92 | 93 | [dependencies] 94 | marine-rs-sdk = "0.10.2" 95 | 96 | [dev-dependencies] 97 | marine-rs-sdk-test = "0.5.0" 98 | 99 | [build-dependencies] 100 | marine-rs-sdk-test = "0.5.0" 101 | ``` 102 | 103 | 104 | 105 | 106 | 1. We create a vector of pairs (service\_name, service\_description) to pass to the generator. The structure is the same with multi-service `marine_test`. 107 | 2. We check if we build for a non-wasm target. As we build this marine service only for `wasm32-wasi` and tests are built for native target, we can generate `marine_test_env` only for tests. This is needed because our generator depends on the artifacts from `wasm32-wasi` build. We suggest using a separate crate for using build scripts for testing purposes. It is here for simplicity. 108 | 3. We pass our services, the name of the file to generate, and a path to the build script file to the `marine_test_env` generator. Just always use `file!()` for the last argument. The generated file will be in the directory specified by the `OUT_DIR` variable, which is set by cargo. The build script must not change any files outside of this directory. 109 | 4. We set up conditions to re-run the build script. It must be customized, a good choice is to re-run the build script when .wasm files or `Config.toml` are changed. 110 | 5. We import the generated file with the `marine_test_env` definition to the project. 111 | 6. Do not forget to add `marine-rs-sdk-test` to the `build-dependencies` section of `Cargo.toml`. 112 | -------------------------------------------------------------------------------- /docs/marine-book/marine-tooling-reference/marine-cli.md: -------------------------------------------------------------------------------- 1 | # Marine CLI 2 | 3 | The [Marine CLI](https://github.com/fluencelabs/marine/tree/master/tools/cli) provides a convenience wrapper over several of the Marine tools and utilities. 4 | 5 | ## Installation 6 | 7 | Install `marine` with: 8 | 9 | ```sh 10 | cargo +nightly install marine 11 | ``` 12 | 13 | ## List of commands 14 | 15 | The CLI functionality is available with: 16 | 17 | ```sh 18 | marine --help 19 | 20 | Fluence Marine command line tool 0.12.7 21 | Fluence Labs 22 | 23 | USAGE: 24 | marine [SUBCOMMAND] 25 | 26 | FLAGS: 27 | -h, --help Prints help information 28 | -V, --version Prints version information 29 | 30 | SUBCOMMANDS: 31 | aqua Shows data types of provided module in a format suitable for Aqua 32 | build Builds provided Rust project to Wasm 33 | generate Generates a template project for a Marine Wasm module 34 | help Prints this message or the help of the given subcommand(s) 35 | info Shows manifest and sdk version of the provided Wasm file 36 | it Shows IT of the provided Wasm file 37 | repl Starts Fluence application service REPL 38 | set Sets interface types and version to the provided Wasm file 39 | ``` 40 | 41 | ### aqua: show types in an Aqua-compatible way 42 | 43 | Shows all data types defined in a Marine module in the Aqua-compatible way: 44 | 45 | ```sh 46 | marine help aqua 47 | 48 | USAGE: 49 | marine aqua [OPTIONS] 50 | 51 | OPTIONS: 52 | -i, --id optional service id 53 | -s, --service optional service name 54 | 55 | ARGS: 56 | a path to a Wasm file 57 | ``` 58 | ```sh 59 | marine aqua -i TestServiceId -s TestServiceName artifacts/records_effector.wasm 60 | 61 | module TestServiceName declares * 62 | 63 | data TestRecord: 64 | field_0: bool 65 | field_1: i8 66 | field_2: i16 67 | field_3: i32 68 | field_4: i64 69 | field_5: u8 70 | field_6: u16 71 | field_7: u32 72 | field_8: u64 73 | field_9: f32 74 | field_10: f64 75 | field_11: string 76 | field_12: []u8 77 | 78 | service TestServiceName("TestServiceId"): 79 | mutate_struct(test_record: TestRecord) -> TestRecord 80 | ``` 81 | 82 | ### build: compile Marine module 83 | 84 | Compiles Rust project to a Marine Wasm module. Under the hood, it calls `cargo build` providing all given arguments, then compiles and embeds interface-types to compiled Wasm binary. 85 | 86 | ```sh 87 | marine help build 88 | 89 | USAGE: 90 | marine build [optional]... 91 | 92 | ARGS: 93 | ... cargo build arguments 94 | ``` 95 | 96 | ### generate: generate Marine project templates 97 | 98 | Uses the power `cargo-generate` to generate a new project from [this](https://github.com/fluencelabs/marine-template) template. Note that `cargo-generate` should be installed (by `cargo install cargo-generate`) to use this subcommand. 99 | 100 | ```sh 101 | marine help generate 102 | 103 | USAGE: 104 | marine generate [FLAGS] [OPTIONS] 105 | 106 | FLAGS: 107 | -i, --init generate the template into the current dir without creating a new one 108 | 109 | OPTIONS: 110 | -n, --name a project name; if the name isn't in kebab-case, it'll be converted to kebab- 111 | case 112 | ``` 113 | 114 | ### info: prints embedded into Wasm file info 115 | 116 | The `marine_manifest` macro embeds some info into compiled Wasm module that could be obtained with this command: 117 | 118 | ```sh 119 | marine info artifacts/greeting.wasm 120 | 121 | it version: 0.23.0 122 | sdk version: 0.6.0 123 | authors: Fluence Labs 124 | version: 0.1.0 125 | description: The greeting module for the Fluence network 126 | repository: https://github.com/fluencelabs/marine/tree/master/examples/greeting 127 | build time: 2022-04-12 18:16:34.487366668 +00:00 UTC 128 | ``` 129 | 130 | ### it: shows interface-types of the Wasm binary 131 | 132 | Interface-types are embedded into a custom section of a Wasm binary while building with `marine build` 133 | 134 | ```sh 135 | marine it artifacts/greeting.wasm 136 | 137 | (@interface it_version "0.23.0") 138 | 139 | ;; Types 140 | (@interface type (func 141 | (param $size: i32) 142 | (result i32))) ;; 0 143 | ... 144 | ;; Exports 145 | (@interface export "allocate" (func 0)) 146 | (@interface export "release_objects" (func 1)) 147 | ... 148 | 149 | ;; Implementations 150 | (@interface implement (func 12) (func 11)) 151 | (@interface implement (func 14) (func 13)) 152 | ``` 153 | 154 | ### repl: run mrepl 155 | 156 | Runs the `Marine REPL`: 157 | 158 | ```sh 159 | marine repl 160 | 161 | Welcome to the Marine REPL (version 0.16.0) 162 | Minimal supported versions 163 | sdk: 0.6.0 164 | interface-types: 0.20.0 165 | 166 | app service was created with service id = aadec167-2a68-44de-b046-f5838ea77a77 167 | elapsed time 720.874¬µs 168 | 169 | 1> 170 | ``` 171 | 172 | ### set: set IT or SDK version 173 | 174 | ```sh 175 | marine help set 176 | 177 | USAGE: 178 | marine set [SUBCOMMAND] 179 | 180 | FLAGS: 181 | -h, --help Prints help information 182 | -V, --version Prints version information 183 | 184 | SUBCOMMANDS: 185 | help Prints this message or the help of the given subcommand(s) 186 | it Sets given interface types to the provided Wasm file 187 | version Sets given sdk version to the provided Wasm file 188 | ``` 189 | For example: 190 | ```sh 191 | marine set version -i artifacts/greeting.wasm -v 0.7.0 192 | 193 | the version was successfully embedded 194 | ``` 195 | Lets check it worked: 196 | ```sh 197 | marine info artifacts/greeting.wasm 198 | 199 | it version: 0.23.0 200 | sdk version: 0.7.0 201 | authors: Fluence Labs 202 | version: 0.1.0 203 | description: The greeting module for the Fluence network 204 | repository: https://github.com/fluencelabs/marine/tree/master/examples/greeting 205 | build time: 2022-04-12 18:16:34.487366668 +00:00 UTC 206 | ``` 207 | -------------------------------------------------------------------------------- /docs/marine-book/marine-tooling-reference/marine-tooling-reference.md: -------------------------------------------------------------------------------- 1 | # Marine Tooling Reference 2 | 3 | Fluence services are virtual constructs linking Wasm IT modules into addressable compute network services. We use the [Rust](https://www.rust-lang.org/) language to create code that compiles to the [wasm32-wasi](https://doc.rust-lang.org/stable/nightly-rustc/rustc_target/spec/wasm32_wasi/index.html) target with the help of Fluence's [Marine Rust SDK](https://github.com/fluencelabs/marine-rs-sdk/tree/master/crates/main). 4 | 5 | Since the output of our compiled rust code are `wasm` modules that eventually are distributed to one or more network peers, testing of the individual and linked _modules_ is critical before deployment. The Fluence Marine ecosystem equips developers with the: 6 | 7 | * [Marine REPL](https://github.com/fluencelabs/marine/tree/master/tools/repl), which wraps a local Marine runtime to allow developers to locally interact with Wasm module interfaces and business logic 8 | * [Marine CLI](https://github.com/fluencelabs/marine/tree/master/tools/cli) allows developers to build Marine modules and examine various info from them. 9 | -------------------------------------------------------------------------------- /docs/marine-book/quick-start/develop-a-single-module-service.md: -------------------------------------------------------------------------------- 1 | --- 2 | description: Developing the greeting service 3 | --- 4 | 5 | # Develop a single module service 6 | 7 | In this section, we'll fly through the process of the creation of a simple [greeting](https://github.com/fluencelabs/marine/tree/master/examples/greeting) service. 8 | 9 | For a backend module and a service to be compatible with the Marine runtime and able to link with other modules, they must follow a few conventions. With the Marine Rust SDK, these conventions will be enforced automatically. 10 | 11 | ## Create a Marine project 12 | 13 | Let's start with the template project generation: 14 | 15 | ```sh 16 | # create template Marine project 17 | marine generate --name greeting 18 | 19 | # go to the package directory 20 | cd greeting 21 | ``` 22 | 23 | This template project reflects the greeting service that we want to build, let's open `src/main.rs` and see what it's like to write a simple project with Marine: 24 | 25 | ```rust 26 | use marine_rs_sdk::marine; 27 | use marine_rs_sdk::module_manifest; 28 | 29 | module_manifest!(); 30 | 31 | pub fn main() {} 32 | 33 | #[marine] 34 | pub fn greeting(name: String) -> String { 35 | format!("Hi, {}", name) 36 | } 37 | 38 | // --snip-- 39 | ``` 40 | 41 | This code imports the [Marine SDK](https://crates.io/crates/marine-rs-sdk) and wraps the `greeting` function with the `#[marine]` macro. Any function wrapped with the `#[marine]` macro will be exported from the compiled Wasm module. 42 | 43 | ## Compile to Wasm 44 | 45 | To convert the module to a Wasm (`.wasm`) file, run the following command in the `greeting` directory: 46 | 47 | ```sh 48 | # compile the project to Wasm in a compatible with Marine way 49 | ./build.sh 50 | ``` 51 | 52 | To make sure that module compiled correctly, let's retrieve some internal info from it: 53 | 54 | ```sh 55 | # obtain some info from a compiled module 56 | # (build.sh copies compiled Wasm binary to the artifacts folder) 57 | marine info artifacts/greeting.wasm 58 | ``` 59 | ``` 60 | it version: 0.23.1 61 | sdk version: 0.6.0 62 | authors: 63 | version: 0.1.0 64 | description: 65 | repository: 66 | build time: 2022-05-15 14:52:37.865550 +00:00 UTC 67 | ``` 68 | 69 | That's it, you have a module ready to run! 70 | 71 | ## Run greeting with REPL 72 | 73 | To load a module, you need to specify the module name and path to the compiled binary of the module 74 | 75 | ```sh 76 | # run mrepl and load the greeting module 77 | mrepl 78 | 79 | Welcome to the Marine REPL (version 0.16.0) 80 | Minimal supported versions 81 | sdk: 0.6.0 82 | interface-types: 0.20.0 83 | 84 | app service was created with service id = 11d28d35-de26-49a1-9dc5-ad9e0667ab52 85 | elapsed time 46.371831ms 86 | 87 | 1> load greeting artifacts/greeting.wasm 88 | module successfully loaded into App service 89 | elapsed time: 52.153308ms 90 | ``` 91 | 92 | After loading the module, we can examine its interface using the `interface` command: 93 | 94 | ```sh 95 | 2> interface 96 | Application service interface: 97 | 98 | greeting: 99 | fn greeting(name: String) -> String 100 | ``` 101 | 102 | Now the function determined in the module can be called by specifying the module name, the function name, and its arguments in json: 103 | 104 | ```sh 105 | 3> call greeting greeting "user" 106 | result: String("Hi, user") 107 | elapsed time: 132.021µs 108 | ``` 109 | 110 | The complete code of this example can be found on [GitHub](https://github.com/fluencelabs/marine/tree/master/examples/greeting). 111 | -------------------------------------------------------------------------------- /docs/marine-book/quick-start/quick-start.md: -------------------------------------------------------------------------------- 1 | # 🚴 Quick Start 2 | 3 | The best way to get to know Marine is by writing some code. In the section, we will walk through a high-level overview of the process by writing a simple single module service, testing it, and then developing a full-featured multi-module service. 4 | -------------------------------------------------------------------------------- /docs/marine-book/quick-start/setting-up-the-development-environment.md: -------------------------------------------------------------------------------- 1 | # Setting up the development environment 2 | 3 | :::info 4 | The environment will be setup for you automatically if you use [Fluence CLI](../../build/setting-up/installing_cli.md) 5 | ::: 6 | 7 | To build Marine modules you need to install a CLI tool called `marine` that uses the Rust `wasm32-wasi` target and Marine environment to compile Wasm modules. 8 | 9 | First, install Rust and supplementary tools: 10 | 11 | ```sh 12 | # install the Rust compiler and tools to `~/.cargo/bin` 13 | curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh 14 | 15 | # add Rust tools to the current PATH 16 | source $HOME/.cargo/env 17 | 18 | # install the nightly toolchain 19 | rustup install nightly-2023-12-06 20 | ``` 21 | 22 | To be able to compile Rust in Wasm, install the `wasm32-wasi` compilation target: 23 | 24 | ```sh 25 | # install wasm32-wasi target for WebAssembly 26 | rustup +nightly-2023-12-06 target add wasm32-wasi 27 | ``` 28 | 29 | 30 | To be able to use `generate` subcommand of marine, install the `cargo-generate` tool: 31 | 32 | ```sh 33 | # install cargo-generate target for the marine tool 34 | cargo install cargo-generate 35 | ``` 36 | 37 | Then, install `marine` and `mrepl`: 38 | 39 | ```sh 40 | # install marine 41 | cargo +nightly-2023-12-06 install marine 42 | 43 | # install mrepl, it requires nightly toolchain 44 | cargo +nightly-2023-12-06 install mrepl 45 | ``` 46 | -------------------------------------------------------------------------------- /docusaurus.config.ts: -------------------------------------------------------------------------------- 1 | import type { Config } from "@docusaurus/types"; 2 | import type * as Preset from "@docusaurus/preset-classic"; 3 | import { readFileSync } from "fs"; 4 | import { join } from "path"; 5 | import { cwd } from "process"; 6 | 7 | function getFluenceLanguageConfig(langName: string) { 8 | return { 9 | id: langName, 10 | scopeName: `source.${langName}`, 11 | grammar: JSON.parse( 12 | readFileSync( 13 | join( 14 | cwd(), 15 | "node_modules", 16 | "aqua-vscode", 17 | "syntaxes", 18 | `${langName}.tmLanguage.json` 19 | ), 20 | { 21 | encoding: "utf-8", 22 | } 23 | ) 24 | ), 25 | }; 26 | } 27 | 28 | const config: Config = { 29 | title: "Fluence Docs", 30 | tagline: "Decentralized Serverless Platform", 31 | url: "https://fluence.dev", 32 | baseUrl: "/", 33 | onBrokenLinks: "warn", 34 | onBrokenMarkdownLinks: "warn", 35 | favicon: "img/favicon.ico", 36 | i18n: { 37 | defaultLocale: "en", 38 | locales: ["en"], 39 | }, 40 | presets: [ 41 | [ 42 | "classic", 43 | { 44 | docs: { 45 | sidebarPath: require.resolve("./sidebars.js"), 46 | editUrl: "https://github.com/fluencelabs/docs/tree/main", 47 | }, 48 | blog: { 49 | showReadingTime: true, 50 | editUrl: "https://github.com/fluencelabs/docs/tree/main", 51 | }, 52 | theme: { 53 | customCss: require.resolve("./src/css/custom.scss"), 54 | }, 55 | gtag: { 56 | trackingID: "G-Z28T4R4T7P", 57 | anonymizeIP: true, 58 | }, 59 | } satisfies Preset.Options, 60 | ], 61 | [ 62 | "docusaurus-preset-shiki-twoslash", 63 | { 64 | themes: ["min-light", "min-dark"], 65 | langs: [ 66 | "typescript", 67 | "javascript", 68 | "html", 69 | "json", 70 | "rust", 71 | "shell", 72 | "toml", 73 | "yaml", 74 | getFluenceLanguageConfig("aqua"), 75 | getFluenceLanguageConfig("air"), 76 | ], 77 | }, 78 | ], 79 | ], 80 | themeConfig: { 81 | algolia: { 82 | appId: "LDLCNV5Z6K", 83 | apiKey: "8536d4a05a0bddd56f5345c1519ae8ec", 84 | indexName: "fluence", 85 | }, 86 | navbar: { 87 | title: "Fluence", 88 | logo: { 89 | alt: "Fluence Logo", 90 | src: "img/logo.svg", 91 | }, 92 | items: [ 93 | { 94 | type: "doc", 95 | position: "left", 96 | docId: "learn/overview", 97 | label: "Learn", 98 | }, 99 | { 100 | type: "doc", 101 | position: "left", 102 | docId: "build/introducing_fluence", 103 | label: "Build", 104 | }, 105 | { 106 | type: "doc", 107 | position: "left", 108 | docId: "aqua-book/introduction", 109 | label: "Aqua Book", 110 | }, 111 | { 112 | type: "doc", 113 | position: "left", 114 | docId: "marine-book/introduction", 115 | label: "Marine Book", 116 | }, 117 | // { to: "/blog", label: "Blog", position: "left" }, 118 | { 119 | href: "https://github.com/fluencelabs", 120 | label: "GitHub", 121 | position: "right", 122 | }, 123 | ], 124 | }, 125 | footer: { 126 | style: "dark", 127 | links: [ 128 | { 129 | title: "Docs", 130 | items: [ 131 | { 132 | label: "Learn", 133 | to: "/docs/learn/overview", 134 | }, 135 | { 136 | label: "Build", 137 | to: "/docs/build/introduction", 138 | }, 139 | { 140 | label: "Aqua Book", 141 | to: "/docs/aqua-book/introduction", 142 | }, 143 | { 144 | label: "Marine Book", 145 | to: "/docs/marine-book/introduction", 146 | }, 147 | ], 148 | }, 149 | { 150 | title: "Community", 151 | items: [ 152 | { 153 | label: "Telegram", 154 | href: "https://t.me/fluence_project", 155 | }, 156 | { 157 | label: "Discord", 158 | href: "https://discord.com/invite/5qSnPZKh7u", 159 | }, 160 | { 161 | label: "Youtube", 162 | href: "https://www.youtube.com/channel/UC3b5eFyKRFlEMwSJ1BTjpbw", 163 | }, 164 | { 165 | label: "Telegram (ru)", 166 | href: "https://t.me/fluenceru", 167 | }, 168 | ], 169 | }, 170 | { 171 | title: "More", 172 | items: [ 173 | // { 174 | // label: "Blog", 175 | // to: "/blog", 176 | // }, 177 | { 178 | label: "GitHub", 179 | href: "https://github.com/fluencelabs", 180 | }, 181 | { 182 | label: "Telegram Updates", 183 | href: "https://t.me/fluencedev", 184 | }, 185 | ], 186 | }, 187 | ], 188 | copyright: `Copyright © ${new Date().getFullYear()} Fluence Labs`, 189 | }, 190 | } satisfies Preset.ThemeConfig, 191 | plugins: ["docusaurus-plugin-sass"], 192 | scripts: [ 193 | { 194 | src: "https://cdn.jsdelivr.net/npm/mermaid@9.4.0/dist/mermaid.min.js", 195 | defer: true, 196 | }, 197 | { 198 | src: "/mermaid.js", 199 | defer: true, 200 | }, 201 | ], 202 | }; 203 | 204 | export default config; 205 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "fluence-docs", 3 | "version": "0.0.0", 4 | "private": true, 5 | "scripts": { 6 | "docusaurus": "docusaurus", 7 | "dev": "docusaurus start", 8 | "build": "docusaurus build", 9 | "swizzle": "docusaurus swizzle", 10 | "deploy": "docusaurus deploy", 11 | "clear": "docusaurus clear", 12 | "serve": "docusaurus serve", 13 | "write-translations": "docusaurus write-translations", 14 | "write-heading-ids": "docusaurus write-heading-ids", 15 | "typecheck": "tsc" 16 | }, 17 | "dependencies": { 18 | "@docusaurus/core": "3.1.1", 19 | "@docusaurus/plugin-google-gtag": "^3.1.1", 20 | "@docusaurus/preset-classic": "3.1.1", 21 | "@mdx-js/react": "^3.0.0", 22 | "aqua-vscode": "github:fluencelabs/aqua-vscode", 23 | "clsx": "^2.1.0", 24 | "docusaurus-plugin-sass": "^0.2.5", 25 | "docusaurus-preset-shiki-twoslash": "https://gitpkg.now.sh/fluencelabs/twoslash/packages/docusaurus-preset-shiki-twoslash?fix-docusaurus-3", 26 | "mermaid": "^10.7.0", 27 | "react": "^18.2.0", 28 | "react-dom": "^18.2.0", 29 | "react-player": "^2.14.1", 30 | "sass": "^1.70.0" 31 | }, 32 | "devDependencies": { 33 | "@docusaurus/module-type-aliases": "3.1.1", 34 | "@docusaurus/tsconfig": "3.1.1", 35 | "@types/react": "^18.2.0", 36 | "typescript": "~5.2.2" 37 | }, 38 | "browserslist": { 39 | "production": [ 40 | ">0.5%", 41 | "not dead", 42 | "not op_mini all" 43 | ], 44 | "development": [ 45 | "last 1 chrome version", 46 | "last 1 firefox version", 47 | "last 1 safari version" 48 | ] 49 | }, 50 | "engines": { 51 | "node": ">=18.0" 52 | }, 53 | "prettier": {} 54 | } 55 | -------------------------------------------------------------------------------- /src/css/custom.scss: -------------------------------------------------------------------------------- 1 | /** 2 | * Any CSS included here will be global. The classic template 3 | * bundles Infima by default. Infima is a CSS framework designed to 4 | * work well for content-centric websites. 5 | */ 6 | 7 | /* You can override the default Infima variables here. */ 8 | :root { 9 | --ifm-color-primary: #e41c5c; 10 | --ifm-color-primary-dark: #af1a4e; 11 | --ifm-color-primary-darker: #a7194b; 12 | --ifm-color-primary-darkest: #901540; 13 | --ifm-color-primary-light: #c71e59; 14 | --ifm-color-primary-lighter: #d31f5e; 15 | --ifm-color-primary-lightest: #df2a69; 16 | --ifm-code-font-size: 95%; 17 | --docusaurus-highlighted-code-line-bg: rgba(0, 0, 0, 0.1); 18 | --ifm-menu-color: #232529; 19 | --ifm-toc-link-color: #232529; 20 | 21 | &[data-theme="dark"] { 22 | --ifm-color-primary: #e41c5c; 23 | --ifm-color-primary-dark: #bf2450; 24 | --ifm-color-primary-darker: #b8224c; 25 | --ifm-color-primary-darkest: #9b1d41; 26 | --ifm-color-primary-light: #d93664; 27 | --ifm-color-primary-lighter: #db3d6a; 28 | --ifm-color-primary-lightest: #e05a80; 29 | --docusaurus-highlighted-code-line-bg: rgba(0, 0, 0, 0.3); 30 | --ifm-menu-color: #dadde1; 31 | --ifm-toc-link-color: #dadde1; 32 | } 33 | } 34 | 35 | .footer--dark { 36 | --ifm-footer-background-color: #16181c; 37 | 38 | [data-theme="dark"] & { 39 | --ifm-footer-background-color: #0a0a0a; 40 | } 41 | } 42 | 43 | .shiki { 44 | visibility: hidden; 45 | 46 | [data-theme="light"] &.min-dark { 47 | display: none; 48 | } 49 | 50 | [data-theme="dark"] &.min-light { 51 | display: none; 52 | } 53 | 54 | &.visible { 55 | visibility: visible; 56 | } 57 | 58 | .mermaid + & { 59 | display: none; 60 | } 61 | } 62 | 63 | .mermaid { 64 | [data-theme="light"] & { 65 | filter: hue-rotate(100deg) saturate(5) contrast(1.1); 66 | } 67 | 68 | [data-theme="dark"] & { 69 | filter: invert(1) brightness(5) hue-rotate(276deg); 70 | } 71 | } 72 | 73 | .code-container { 74 | max-height: 60vh; 75 | } 76 | -------------------------------------------------------------------------------- /src/pages/index.module.scss: -------------------------------------------------------------------------------- 1 | /** 2 | * CSS files with the .module.css suffix will be treated as CSS modules 3 | * and scoped locally. 4 | */ 5 | 6 | .heroBanner { 7 | padding: 4rem 0; 8 | text-align: center; 9 | position: relative; 10 | overflow: hidden; 11 | min-height: calc(100vh - var(--ifm-navbar-height)); 12 | background-image: radial-gradient( 13 | circle, 14 | rgb(86, 150, 216) 0%, 15 | rgb(64, 120, 224) 6%, 16 | rgb(64, 120, 224) 9%, 17 | rgb(95, 156, 211) 13%, 18 | rgb(103, 155, 205) 15%, 19 | rgb(78, 110, 190) 29%, 20 | rgba(74, 102, 185, 0) 41%, 21 | rgba(0, 212, 255, 0) 100% 22 | ); 23 | background-size: 600vw 100vh; 24 | background-repeat: no-repeat; 25 | background-position: center; 26 | @media screen and (max-width: 996px) { 27 | padding: 2rem; 28 | } 29 | } 30 | 31 | .button { 32 | border-radius: 30px; 33 | padding: 15px 25px; 34 | line-height: 1.4; 35 | color: #FFFFFF; 36 | font-size: 15px; 37 | font-weight: 700; 38 | transition: all 0.2s ease; 39 | background: rgba(0, 0, 0, 0.8); 40 | padding: 16px 51px; 41 | &:hover { 42 | text-decoration: none; 43 | } 44 | } 45 | 46 | .heroSubtitle { 47 | max-width: 600px; 48 | margin: 35px auto 48px; 49 | } 50 | -------------------------------------------------------------------------------- /src/pages/index.tsx: -------------------------------------------------------------------------------- 1 | import React from "react"; 2 | import clsx from "clsx"; 3 | import Link from "@docusaurus/Link"; 4 | import useDocusaurusContext from "@docusaurus/useDocusaurusContext"; 5 | import Layout from "@theme/Layout"; 6 | 7 | import styles from "./index.module.scss"; 8 | 9 | export default function Home() { 10 | const { siteConfig } = useDocusaurusContext(); 11 | 12 | return ( 13 | 17 |
18 |
19 |

{siteConfig.title}

20 |

21 | {siteConfig.tagline} 22 |

23 | 24 | Get started 25 | 26 |
27 |
28 |
29 | ); 30 | } 31 | -------------------------------------------------------------------------------- /src/types.d.ts: -------------------------------------------------------------------------------- 1 | declare module "*.scss" { 2 | const content: Record; 3 | export default content; 4 | } 5 | -------------------------------------------------------------------------------- /static/.nojekyll: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aliezzahn/docs/7af66c0600393eaadff7ffb28ba49a0febfc021a/static/.nojekyll -------------------------------------------------------------------------------- /static/img/aurora-connect-faucet.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aliezzahn/docs/7af66c0600393eaadff7ffb28ba49a0febfc021a/static/img/aurora-connect-faucet.png -------------------------------------------------------------------------------- /static/img/aurora-explorer-inspect-transfers.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aliezzahn/docs/7af66c0600393eaadff7ffb28ba49a0febfc021a/static/img/aurora-explorer-inspect-transfers.png -------------------------------------------------------------------------------- /static/img/aurora-faucet-connect-metamask.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aliezzahn/docs/7af66c0600393eaadff7ffb28ba49a0febfc021a/static/img/aurora-faucet-connect-metamask.png -------------------------------------------------------------------------------- /static/img/aurora-request-eth.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aliezzahn/docs/7af66c0600393eaadff7ffb28ba49a0febfc021a/static/img/aurora-request-eth.png -------------------------------------------------------------------------------- /static/img/aurora-request-success.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aliezzahn/docs/7af66c0600393eaadff7ffb28ba49a0febfc021a/static/img/aurora-request-success.png -------------------------------------------------------------------------------- /static/img/aurora-testnet-success-metamask.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aliezzahn/docs/7af66c0600393eaadff7ffb28ba49a0febfc021a/static/img/aurora-testnet-success-metamask.png -------------------------------------------------------------------------------- /static/img/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aliezzahn/docs/7af66c0600393eaadff7ffb28ba49a0febfc021a/static/img/favicon.ico -------------------------------------------------------------------------------- /static/img/fluence-chain-diagram.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aliezzahn/docs/7af66c0600393eaadff7ffb28ba49a0febfc021a/static/img/fluence-chain-diagram.png -------------------------------------------------------------------------------- /static/img/fluence-faucet-add-tUSDC-metamask.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aliezzahn/docs/7af66c0600393eaadff7ffb28ba49a0febfc021a/static/img/fluence-faucet-add-tUSDC-metamask.png -------------------------------------------------------------------------------- /static/img/fluence-faucet-add-tUSDC.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aliezzahn/docs/7af66c0600393eaadff7ffb28ba49a0febfc021a/static/img/fluence-faucet-add-tUSDC.png -------------------------------------------------------------------------------- /static/img/fluence-faucet-confirm-fluence-transfer.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aliezzahn/docs/7af66c0600393eaadff7ffb28ba49a0febfc021a/static/img/fluence-faucet-confirm-fluence-transfer.png -------------------------------------------------------------------------------- /static/img/fluence-faucet-confirm-tUSDC-added.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aliezzahn/docs/7af66c0600393eaadff7ffb28ba49a0febfc021a/static/img/fluence-faucet-confirm-tUSDC-added.png -------------------------------------------------------------------------------- /static/img/fluence-faucet-login.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aliezzahn/docs/7af66c0600393eaadff7ffb28ba49a0febfc021a/static/img/fluence-faucet-login.png -------------------------------------------------------------------------------- /static/img/fluence-faucet-request-tUSDC.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aliezzahn/docs/7af66c0600393eaadff7ffb28ba49a0febfc021a/static/img/fluence-faucet-request-tUSDC.png -------------------------------------------------------------------------------- /static/img/fluence-faucet-sign-up.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aliezzahn/docs/7af66c0600393eaadff7ffb28ba49a0febfc021a/static/img/fluence-faucet-sign-up.png -------------------------------------------------------------------------------- /static/img/fluence-faucet-tUSDC-transfer-update.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aliezzahn/docs/7af66c0600393eaadff7ffb28ba49a0febfc021a/static/img/fluence-faucet-tUSDC-transfer-update.png -------------------------------------------------------------------------------- /static/img/fluence-functions.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aliezzahn/docs/7af66c0600393eaadff7ffb28ba49a0febfc021a/static/img/fluence-functions.png -------------------------------------------------------------------------------- /static/img/logo.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /static/img/marine.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aliezzahn/docs/7af66c0600393eaadff7ffb28ba49a0febfc021a/static/img/marine.jpg -------------------------------------------------------------------------------- /static/img/marketplace-capacity.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aliezzahn/docs/7af66c0600393eaadff7ffb28ba49a0febfc021a/static/img/marketplace-capacity.png -------------------------------------------------------------------------------- /static/img/marketplace-matching.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aliezzahn/docs/7af66c0600393eaadff7ffb28ba49a0febfc021a/static/img/marketplace-matching.png -------------------------------------------------------------------------------- /static/img/marketplace-provider-resources.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aliezzahn/docs/7af66c0600393eaadff7ffb28ba49a0febfc021a/static/img/marketplace-provider-resources.png -------------------------------------------------------------------------------- /static/img/marketplace-providers.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aliezzahn/docs/7af66c0600393eaadff7ffb28ba49a0febfc021a/static/img/marketplace-providers.png -------------------------------------------------------------------------------- /static/img/metamask-add-manually.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aliezzahn/docs/7af66c0600393eaadff7ffb28ba49a0febfc021a/static/img/metamask-add-manually.png -------------------------------------------------------------------------------- /static/img/metamask-add-network.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aliezzahn/docs/7af66c0600393eaadff7ffb28ba49a0febfc021a/static/img/metamask-add-network.png -------------------------------------------------------------------------------- /static/img/metamask-aurora-chain-info.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aliezzahn/docs/7af66c0600393eaadff7ffb28ba49a0febfc021a/static/img/metamask-aurora-chain-info.png -------------------------------------------------------------------------------- /static/img/metamask-mumbai-chain-info.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aliezzahn/docs/7af66c0600393eaadff7ffb28ba49a0febfc021a/static/img/metamask-mumbai-chain-info.png -------------------------------------------------------------------------------- /static/img/metamask-request-mumbai-tokens.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aliezzahn/docs/7af66c0600393eaadff7ffb28ba49a0febfc021a/static/img/metamask-request-mumbai-tokens.png -------------------------------------------------------------------------------- /static/img/metamask-updated-MATIC-balance.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aliezzahn/docs/7af66c0600393eaadff7ffb28ba49a0febfc021a/static/img/metamask-updated-MATIC-balance.png -------------------------------------------------------------------------------- /static/img/metamask-updated-aeth-balance.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aliezzahn/docs/7af66c0600393eaadff7ffb28ba49a0febfc021a/static/img/metamask-updated-aeth-balance.png -------------------------------------------------------------------------------- /static/img/metamask_tx_prompt.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aliezzahn/docs/7af66c0600393eaadff7ffb28ba49a0febfc021a/static/img/metamask_tx_prompt.png -------------------------------------------------------------------------------- /static/img/mvm/dar_faucet.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aliezzahn/docs/7af66c0600393eaadff7ffb28ba49a0febfc021a/static/img/mvm/dar_faucet.png -------------------------------------------------------------------------------- /static/img/polygon-explorer-inspect-transfers.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aliezzahn/docs/7af66c0600393eaadff7ffb28ba49a0febfc021a/static/img/polygon-explorer-inspect-transfers.png -------------------------------------------------------------------------------- /static/mermaid.js: -------------------------------------------------------------------------------- 1 | mermaid.initialize({ startOnLoad: true }); 2 | const loadMermaid = () => mermaid.contentLoaded(); 3 | 4 | // @ts-check 5 | 6 | function replaceWithMermaid(el) { 7 | const pre = document.createElement("pre"); 8 | pre.classList.add("mermaid"); 9 | pre.textContent = el.children[0].children[0].textContent; 10 | el.replaceWith(pre); 11 | } 12 | 13 | setInterval(() => { 14 | const shikiElements = Array.from(document.getElementsByClassName("shiki")); 15 | shikiElements.forEach((el) => el.classList.add("visible")); 16 | const elementsToReplace = shikiElements.filter((el) => { 17 | return ( 18 | el.parentElement.parentElement.previousElementSibling?.textContent === 19 | "mermaid" 20 | ); 21 | }); 22 | 23 | elementsToReplace.forEach((el) => { 24 | el.parentElement.parentElement.previousElementSibling.remove(); 25 | if (el.classList.contains("min-dark")) { 26 | el.remove(); 27 | return; 28 | } 29 | 30 | replaceWithMermaid(el); 31 | }); 32 | const setOfDiagrams = new Set(); 33 | Array.from(document.getElementsByClassName("mermaid")) 34 | .filter((el) => el.children[0]?.classList.contains("code-container")) 35 | .forEach((el) => { 36 | const textContent = el.children[0].children[0].textContent; 37 | if (setOfDiagrams.has(textContent)) { 38 | el.remove(); 39 | return; 40 | } 41 | replaceWithMermaid(el); 42 | setOfDiagrams.add(textContent); 43 | }); 44 | 45 | if (elementsToReplace.length > 0) { 46 | loadMermaid(); 47 | } 48 | }, 60); 49 | -------------------------------------------------------------------------------- /tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "@docusaurus/tsconfig", 3 | "compilerOptions": { 4 | "baseUrl": "." 5 | } 6 | } 7 | -------------------------------------------------------------------------------- /vercel.json: -------------------------------------------------------------------------------- 1 | { 2 | "redirects": [ 3 | { 4 | "source": "/", 5 | "destination": "/docs/learn/overview", 6 | "permanent": true 7 | }, 8 | { 9 | "source": "/docs", 10 | "destination": "/", 11 | "permanent": true 12 | }, 13 | { 14 | "source": "/docs/", 15 | "destination": "/", 16 | "permanent": true 17 | } 18 | ] 19 | } 20 | --------------------------------------------------------------------------------