{"id":28545579,"url":"https://github.com/fluencelabs/frpc-substrate","last_synced_at":"2025-07-14T11:09:16.532Z","repository":{"id":103221731,"uuid":"605680020","full_name":"fluencelabs/fRPC-Substrate","owner":"fluencelabs","description":"Fluence's fRPC Substrate is a starter kit that includes all the components you need to quickly enable your dAPP with decentralized RPC using existing centralized RPC providers, e.g., Infura, Alchemy, QuickNode, etc., without touching your existing frontend Web3 code.","archived":false,"fork":false,"pushed_at":"2025-06-13T19:50:38.000Z","size":2483,"stargazers_count":21,"open_issues_count":16,"forks_count":8,"subscribers_count":5,"default_branch":"main","last_synced_at":"2025-07-10T06:09:46.842Z","etag":null,"topics":["decentralization","eth","fluence","p2p","rpc"],"latest_commit_sha":null,"homepage":"","language":"Rust","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"apache-2.0","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/fluencelabs.png","metadata":{"files":{"readme":"README.md","changelog":"CHANGELOG.md","contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2023-02-23T17:09:38.000Z","updated_at":"2024-06-04T15:09:35.000Z","dependencies_parsed_at":null,"dependency_job_id":"aba7b1e3-72b7-47bf-ad3d-084b6a112866","html_url":"https://github.com/fluencelabs/fRPC-Substrate","commit_stats":null,"previous_names":[],"tags_count":3,"template":false,"template_full_name":null,"purl":"pkg:github/fluencelabs/fRPC-Substrate","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/fluencelabs%2FfRPC-Substrate","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/fluencelabs%2FfRPC-Substrate/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/fluencelabs%2FfRPC-Substrate/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/fluencelabs%2FfRPC-Substrate/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/fluencelabs","download_url":"https://codeload.github.com/fluencelabs/fRPC-Substrate/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/fluencelabs%2FfRPC-Substrate/sbom","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":265281274,"owners_count":23739873,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["decentralization","eth","fluence","p2p","rpc"],"created_at":"2025-06-09T23:08:09.018Z","updated_at":"2025-07-14T11:09:16.522Z","avatar_url":"https://github.com/fluencelabs.png","language":"Rust","funding_links":[],"categories":[],"sub_categories":[],"readme":"# Hacking Decentralized RPC with Fluence\n\n## Overview\n\nRunning blockchain nodes to support your dApps' read and write requirements to/from a node tends to be rather resource intensive. Not surprisingly, Web3 developers have been flocking toward integrating their dApps with hosted blockchain JSON-RPC gateways. Alas, centralized \"RPC as SaaS\" introduces bottlenecks challenging the availability, reliability and Web3 ethos of dApps while quite often raising the exit barriers by providing custom API overlays to the EVM JSON-RPC API convention.\n\nTo accelerate dApp developers' ability to utilize decentralized RPC in their dApps, Fluence is providing a decentralized RPC (fRPC) substrate, i.e., a starter kit that includes a gateway to bridge HTTP and Aqua, a Wasm service to connect to RPC endpoints and Aqua scripts implementing basic availability, failover and verification algorithms. See Figure 1.\n\nFigure 1: Stylized fRPC Workflow With dApp\n\n```mermaid\n    sequenceDiagram\n\n    participant A as dApp\n    participant G as fRPC Gateway\n    participant N as Fluence network\n    participant R as RPC endpoints\n\n    A -\u003e\u003e G: dApp HTTP request\n    G -\u003e\u003e G: map HTTP to Aqua request\n    G -\u003e\u003e G: select algorithm (failover, round robin, quorum, etc.)\n    G -\u003e\u003e N: Aqua call to network peer(s)\n    N -\u003e\u003e R: HTTP call to RPC endpoint(s)\n    R -\u003e\u003e N: Response or timeout\n    alt response\n      N -\u003e\u003e G: response to gateway\n      G -\u003e\u003e A: response to dApp\n    else timeout\n      loop over endpoint urls\n        N -\u003e\u003e R: try another request\n        alt response\n          N -\u003e\u003e G: response to gateway\n          G -\u003e\u003e A: response to dApp -- break\n        end\n      end\n      G -\u003e\u003e G: timeout\n      G -\u003e\u003e A: no response error\n    end\n```\n\nfRPC substrate allows existing dApps to be upgraded to decentralized RPC while not requiring any changes to their frontend other than changing the HTTP transport url and making it easy to implement more complex control algorithms. Moreover, fRPC substrate components are highly customizable allowing developers to quickly and easily extend the substrate to fit their dApps' needs and to improve the fRPC ecosystem with improved services and algorithms.\n\n## Quickstart\n\nClone the repo if you haven't done so already, and in the *gateway* directory, install the dependencies:\n\n```bash\nnpm i\n```\n\nIf you don't have Fluence CLI installed, do:\n\n```bash\nnpm -g i @fluencelabs/cli@unstable\n```\n\nBefore you proceed, you should have, say, three RPC endpoint urls, e.g., Infura, Alchemy and Ankr, for the same EVM-based chain you are using in your dApp. Update the `configs/quickstart_config.json` by providing your endpoint urls and ignore the rest of the parameters for now:\n\n```json\n{\n  \"providers\": [\n    \"\u003creplace with your url_1/api-key\u003e\",   // \u003c- replace\n    \"\u003creplace with your url_2/api-key\u003e\",   // \u003c- replace\n    \"\u003creplace with your url_3/api-key\u003e\"    // \u003c- replace and maybe add more\n  ],\n  \"mode\": \"round-robin\",\n  \"relay\": \"/dns4/stage.fluence.dev/tcp/19002/wss/p2p/12D3KooWMigkP4jkVyufq5JnDJL6nXvyjeaDNpRfEZqQhsG3sYCU\",\n  \"serviceId\": \"e9e32b0b-3b19-4bdd-b1da-f5ff9cc0357f\",\n  \"port\": 3000,\n  \"counterServiceId\": null,\n  \"counterPeerId\": null,\n  \"quorumServiceId\": null,\n  \"quorumPeerId\": null,\n  \"quorumNumber\": null\n}\n```\n\nNow start the gateway:\n\n**Command**:\n\n```bash\nnpm -C gateway run run configs/quickstart_config.json\n```\n\n**Output**:\n\n```bash\n\u003e @fluencelabs/aqua-eth-gateway@0.0.11 run\n\u003e fluence aqua -i aqua/ -o aqua-compiled/ --js \u0026\u0026 node src/index.js configs/my_quickstart_config.json\n\n# Compiling...\nResult /Users/bebo/localdev/fRPC-Substrate/gateway/aqua-compiled/rpc.js: compilation OK (10 functions, 4 services)\nResult /Users/bebo/localdev/fRPC-Substrate/gateway/aqua-compiled/rpc.d.ts: compilation OK (10 functions, 4 services)\nResult /Users/bebo/localdev/fRPC-Substrate/gateway/aqua-compiled/rpc.js: compilation OK (10 functions, 4 services)\nResult /Users/bebo/localdev/fRPC-Substrate/gateway/aqua-compiled/rpc.d.ts: compilation OK (10 functions, 4 services)\n\nRunning server...\nServer was started on port 3000\n\n```\n\nWith the gateway ready for action, all you have to do is change your dApps HTTP transport url to `http://127.0.0.1:3000` and keep using your dApp as usual. In the absence of a dApp, we can interact with the gateway from the command line:\n\n**Command**:\n\n```bash\ncurl http://127.0.0.1:3000  \\\n    -X POST \\\n    -H \"Content-Type: application/json\" \\\n    -d '{\"jsonrpc\":\"2.0\",\"method\":\"eth_blockNumber\",\"params\": [],\"id\":100}'\n```\n\n**Output**:\n\n```bash\n{\"jsonrpc\":\"2.0\",\"id\":100,\"result\":\"0x82b950\"}\n\n# with the corresponding gateway log output\nReceiving request 'eth_blockNumber'\npeerId: 12D3KooWKDnWpCLPJrycSevracdEgGznfDPwG1g5CWbt8uccdL79\nCounter: 1\nWorker used: \"12D3KooWKPcNwR6EMq3sqm4sKtUKmZbMhPQ2dk1zr8YNgjdu9Xqn\"\nCall will be to : https://eth-goerli.g.alchemy.com/v2/\u003cyour api key\u003e\n```\n\nSince we have specified *round-robin* in our config file and have more than one endpoint url in play, re-running the json-rpc call should result in a different endpoint selection:\n\n**Command**:\n\n```bash\ncurl http://127.0.0.1:3000  \\\n    -X POST \\\n    -H \"Content-Type: application/json\" \\\n    -d '{\"jsonrpc\":\"2.0\",\"method\":\"eth_blockNumber\",\"params\": [],\"id\":100}'\n```\n\n**Output**:\n\n```bash\n{\"jsonrpc\":\"2.0\",\"id\":100,\"result\":\"0x82b956\"}\n\n# with the corresponding gateway log output\n\nReceiving request 'eth_blockNumber'\npeerId: 12D3KooWKDnWpCLPJrycSevracdEgGznfDPwG1g5CWbt8uccdL79\nCounter: 2\nWorker used: \"12D3KooWKPcNwR6EMq3sqm4sKtUKmZbMhPQ2dk1zr8YNgjdu9Xqn\"\nCall will be to : https://frequent-sleek-river.ethereum-goerli.discover.quiknode.pro/\u003cyour api key\u003e/\n```\n\nSuccess! Go ahead and replace the `round-robin` mode with the `random` mode in your config file, stop and start the gateway and have a look at the different endpoint management. All available algorithms and their parameters are described in the [fRPC Algorithms](#fRPC-Algorithms) section below.\n\nCongrats, you just took a major step toward keeping your dApp decentralized, available and performant! Now it's time to dive into the Fluence protocol and technology stack to learn how to improve upon the basic substrate.\n\n## Developing With Fluence\n\nFluence's decentralized serverless protocol and solution stack allows developers to quickly create decentralized applications and protocols by distributing services for subsequent execution to peers of the open and permissionless Fluence peer-to-peer compute network. Specifically, developers:\n\n* express their business logic in Rust code compiled to wasm32-wasi\n* create a [Deal](https://fluence.dev/docs/build/glossary#deal), i.e., a construct that links on-chain contract economics and off-chain resources necessary for peers to run a service, which entails escrowing stablecoin, currently limited to (testnet) USDC, to the Deal contract\n* deploy their Wasm modules plus linking instructions as a uniquely addressable *service* to p2p network storage, i.e., IPFS\n\nWith a Deal in place, resource owners, i.e., owner/operators of one or more peers, make a decision whether to host the service and if so, participate in the Deal by providing a stake to the Deal contract and pulling the corresponding service assets required for hosting from IPFS. As a matter of fact, peers utilize [Workers](https://fluence.dev/docs/build/glossary#worker), omitted from Figure 2 for simplicity reasons, to implement their side of a Deal. See Figure 2.\n\n```mermaid\n\nsequenceDiagram\n    title: Figure 2: Stylized Deal Creation For Service Deployment\n\n    actor D as Developer\n    participant CF as Contract factory\n    participant C as Contract\n    participant N as Network storage (IPFS)\n    actor R as Resource owner\n    participant P as Peer i owned by resource owner\n\n    D -\u003e\u003e D: Business logic to Rust To Wasm\n    D -\u003e\u003e CF: request deal contract for service\n    CF -\u003e\u003e C: generate Deal contract  for service\n    par\n        D -\u003e\u003e C: escrow funds\n        D -\u003e\u003e N: upload service package\n    end\n    R -\u003e\u003e CF: listen for new contracts\n      loop listen to on-chain events\n        alt new contract\n        R -\u003e\u003e C: evaluate deal\n        alt like deal\n          R -\u003e\u003e C: join deal with stake\n          P -\u003e\u003e N: request service package\n          P -\u003e\u003e P: host service\n          P -\u003e\u003e P: wait for service request\n          alt get request\n            R -\u003e\u003e C: claim payment\n          end\n        end\n      end\n    end\n\n```\n\nWhile this sounds, and is, elaborate, *Fluence CLI*, see below, takes care of most of the scaffolding and workflow management for you.\n\n\u003e At this point, the marketplace for Fluence's decentralized serverless isn't quite finished. The supply side has not been enabled and on the demand side, parameters are fixed for the testnet. That is, developers are not able to provide custom Deal parameters, such as willingness to pay for service execution. Instead, these parameters, i.e. price of execution per epoch and epoch duration, are hard-coded and used by Fluence CLI to create the corresponding Deal contract and transaction for you to sign. Moreover, economics are limited to the testnet using testnet tokens.\n\n## Setting Up For Developing With Fluence\n\nTo get going, you need to install and set up a few dependencies.\n\n\u003e Fluence tooling works on most \\*nix systems including OSX and Windows Linux Subsystem. At this time, Windows is not supported.\n\n### Off-chain Dependencies\n\n* [node](https://nodejs.org/en/) 18 LTS\n* [Fluence CLI](https://github.com/fluencelabs/fluence-cli)\n* [Rust](https://www.rust-lang.org/tools/install) (optional; Fluence CLI will install if not already in your environment)\n* For VSCode, there is a helpful [Aqua language support](https://marketplace.visualstudio.com/items?itemName=FluenceLabs.aqua) package available\n\n\u003e This Fluence CLI installs missing dependencies as needed (\"lazy install\"). If you want all your dependencies installed at once, use the `fluence dependencies i` command.\n\n### On-chain Dependencies\n\n* Wallectconnect compatible wallet, e.g., MetaMask, set for and funded with:\n  * [Mumbai testnet](https://chainlist.org/chain/80001) parameters\n  * [Mumbai faucet](https://mumbaifaucet.com/)\n  * [Fluence USDC testnet faucet](https://faucet.fluence.dev/)\n\nYou will need Mumbai MATIC and Fluence (testnet) USDC. This is as good a time as any to head over to those faucets and get your allocations. As an experienced Web3 dev, you know it's good hygiene to set up a new account, say, fRPC-dev, for the Mumbai testnet and testnet tokens.\n\n### RPC Endpoints\n\nSince fRPC works with existing centralized or self-hosted RPC providers, you want at least three provider urls with appended API keys to *the* chain of your choice. Multi-chain support is currently not supported by fRPC Substrate. For Ethereum's Goerli testnet, for example:\n\n* Infura: https://goerli.infura.io/v3/\\\u003cyour key\u003e/\n* Alchemy: https://eth-goerli.g.alchemy.com/v2/\\\u003cyour key\u003e/\n* Ankr: https://rpc.ankr.com/eth_goerli/\\\u003cyour key\u003e\n\nEach of the listed providers has a free account option and supports the API key in the url style, rather than the header, which is the current gateway implementation choice; a choice you should feel free to override and customize to your needs.\n\n### Tools And Tooling\n\nThe most prominent developer's helper is [Fluence CLI](https://github.com/fluencelabs/fluence-cli), which allows you to manage the entire lifecycle of a project including Rust and Aqua code as well as Deals. From scaffolding your project, services and modules to Deal creation and service deployment, Fluence CLI has you covered. Moreover, Fluence CLI can scaffold JS projects using [js-client](https://github.com/fluencelabs/js-client) allowing you to create, or integrate, Fluence projects for the browser or node app. See Figure 3 for a quick overview of workflows managed by Fluence CLI and the associated commands. If you have Fluence CLI installed, use `fluence --help` to get a more complete overview of topics and commands.\n\nFigure 3: Stylized Project Creation And Deployment Workflow With Fluence CLI\n\n```mermaid\n\n    stateDiagram\n\n    [*] --\u003e InitProject: fluence init\n    InitProject --\u003e CreateNewService: fluence service new\n    InitProject --\u003e AddExistingService: fluence service add\n    CreateNewService --\u003e Service\n    AddExistingService --\u003e Service\n    Service --\u003e AddNewModules: fluence module new\n    Service --\u003e AddExistingModules: fluence module add\n    Service --\u003e LocalTesting: fluence service repl, cargo test\n    Service --\u003e DeployedService: fluence deal deploy\n    DeployedService --\u003e RunService: fluence run\n```\n\nFluence CLI uses multiple *yaml* config files. You can find the schemas in the [schemas](./.fluence/schemas) directory. Note that Fluence CLI creates config files lazily, i.e., as needed.\n\nSee [FLuence CLI](https://github.com/fluencelabs/fluence-cli) for more details. For implementing your business logic with Rust and compiling it to wasm32-wasi, aka Wasm, module(s), see the [Marine book](https://fluence.dev/docs/marine-book/introduction). To learn more about distributed choreography and composition of services, see the [Aqua book](https://fluence.dev/docs/aqua-book/introduction).\n\n## Hacking On fRPC Substrate\n\nFluence's *fRPC Substrate* is a starter kit that includes all the components you need to quickly enable your dApp with decentralized RPC using existing centralized RPC providers, e.g., Infura, Alchemy, Ankr, etc., without touching your existing frontend Web3 code. fRPC substrate consists of the following code components, see Figure 4:\n\n* RPC API \"adapter\" code written in Rust and compiled to wasm32-wasi modules that are deployable to any peer in the Fluence p2p network\n* Aqua code for distributed algorithms, such as Random and Round Robin selection, using the distributed Wasm connectors for request-response handling over libp2p\n* A gateway app server that bridges libp2p transport to the HTTP transport expected by your dApps' Web3 SDK, such as web3js, ethers, etc. Note that the expectation at this point is for you to *self-host* the gateway at a location of your choosing.\n\nFigure 4: Stylized fRPC Use With dApps\n\n```mermaid\n    sequenceDiagram\n\n    participant D as dApp\n    participant G as Gateway\n    participant N as Fluence p2p network\n    participant R as Centralized RPC providers\n\n    G -\u003e\u003e G: Configure and start Gateway\n    D -\u003e\u003e D: Use gateway Address:port in web3 sdk setup\n    D -\u003e\u003e G: Make Web3 request\n    G -\u003e\u003e N: Call one or more Fluence services\n    N -\u003e\u003e R: Call one or more different RPC providers\n    R -\u003e\u003e N: Services processes response based on specified algo\n    N -\u003e\u003e G: Gateway receives \"curated\" response\n    G -\u003e\u003e D: dApp receives response\n    D -\u003e\u003e D: dApp does its thing\n```\n\n### fRPC Wasm Components\n\nfRPC Substrate comes with one *service* comprised of two Wasm modules, which you can find in the [wasm-modules](\"./wasm-modules/\") directory. The service is called 'eth_rpc' and the included modules are a [curl_adapater](\"./../wasm-modules/curl-adapter\") and [eth_rpc](\"./../wasm-modules/eth-rpc\"). The *curl_adapter* module is a generic, re-usable module allowing access to a peer's curl binary, if permissioned by the peer, and exposes the *curl_request* function. Any modules requiring curl access may use the curl_adapter modules via [FFI linking](https://doc.rust-lang.org/nomicon/ffi.html) with the *curl_request* function.\n\nThe *eth_rpc* module manages the json-rpc requests and responses initiated and consumed by Aqua scripts as the result of some frontend event, e.g. our dApp or curl request. Once available on peers of the Fluence p2p network, the *eth-rpc* services, aka RPC endpoint adapter, allows us to call one or more RPC endpoints using Aqua for choreography and composition of services.\n\nBefore you can deploy your service, use `fluence build` in the root dir to compile each module's Rust code to wasm32-wasi output:\n\n**Command**:\n\n```bash\nfluence build\n```\n\n**Output**:\n\n```bash\n# Making sure all services are downloaded...\n# Making sure all services are built...\n    Finished release [optimized] target(s) in 0.61s\n```\n\nSee [target dir](\"./target/wasm32-wasi/release\") for *curl_adapter.wasm* and *eth_erpc.wasm*, respectively. With the wasm modules available, you can locally interact with them using [Marine REPL](https://crates.io/crates/mrepl):\n\n`fluence service repl`\n\n**Command**:\n\n```bash\nfluence service repl\n```\n\n**Output**:\n\n```bash\n? Enter service name from fluence.yaml, path to a service or url to .tar.gz archive wasm-modules\n# Making sure service and modules are downloaded and built...\n    Finished release [optimized] target(s) in 0.18s\n\n^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^\n\nExecute help inside repl to see available commands.\nCurrent service \u003cmodule_name\u003e is: eth_rpc\nCall eth_rpc service functions in repl like this:\n\ncall eth_rpc \u003cfunction_name\u003e [\u003carg1\u003e, \u003carg2\u003e]\n\n^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^\n\nWelcome to the Marine REPL (version 0.19.1)\nMinimal supported versions\n  sdk: 0.6.0\n  interface-types: 0.20.0\n\napp service was created with service id = f0fc66d9-1fc6-494f-bcc1-104970875730\nelapsed time 254.67135ms\n\n1\u003e i\nLoaded modules interface:\nexported data types (combined from all modules):\ndata MountedBinaryResult:\n  ret_code: i32\n  error: string\n  stdout: []u8\n  stderr: []u8\ndata U64Value:\n  value: u64\n  success: bool\n  error: string\ndata BytesValue:\n  value: []u8\n  success: bool\n  error: string\ndata JsonString:\n  value: string\n  success: bool\n  error: string\n\nexported functions:\ncurl_adapter:\n  func curl_request(cmd: []string) -\u003e MountedBinaryResult\neth_rpc:\n  func block_number(uri: string) -\u003e U64Value\n  func call_get_accounts(uri: string) -\u003e [][]u8\n  func accounts(uri: string) -\u003e []JsonString\n  func call(uri: string, req: string, block: u64) -\u003e BytesValue\n  func eth_call(uri: string, method: string, json_args: []string) -\u003e JsonString\n\n2\u003ecall eth_rpc eth_call [\"https://\u003cyour network\u003e.infura.io/v3/\u003cyour api key\u003e\", \"eth_blockNumber\", []]\nresult: {\n  \"error\": \"\",\n  \"success\": true,\n  \"value\": \"\\\"0x82a08d\\\"\"\n}\n elapsed time: 588.092888ms\n\n3\u003e\n```\n\nThe *i* command lists all the exported interfaces from the wasm modules in Aqua instead of Rust notation. In *exported* functions you see the module namespace, e.g., *curl_adapter*, and exported functions, e.g., *curl_request*. To execute a function, use `call \u003cnamespace\u003e \u003cfunction name\u003e [\u003cparameters\u003e]`.\n\n### Adding Modules To A Service\n\nRegardless of your customization requirements, you probably will have no reason to modify the *curl_adapter* and *eth_rpc* modules. However, you may want to add new modules, or even services, to handle your additional business logic requirements. For example, you may want to capture RPC endpoint performance data, such as response times and availability, to some Web3 storage, e.g., IPFS or Ceramic, for further analysis to, say, derive a weighting scheme for endpoint selection.\n\nFluence CLI allows you to quickly create a new, or add an existing, module to your project. For example,\n\n**Command**:\n\n```bash\nfluence module new --path ./wasm-modules demo-module\n```\n\n**Output**:\n\n```bash\nSuccessfully generated template for new module at demo-module\n```\n\nWhich created a Rust project in the *wasm-module/demo-module* directory ready for you to customize. When you're done, you add the new module to your service config, service.yaml:\n\n**Command**:\n\n```bash\nfluence module add\n```\n\n**Output**:\n\n```bash\n? Enter path to a module or url to .tar.gz archive wasm-modules/demo\n? Enter service name from fluence.yaml or path to the service directory wasm-modules\nAdded demo to ~/localdev/fRPC-Substrate/wasm-modules/service.yaml\n```\n\nThe demo module is now part of the service and `fluence build`, for example, now compiles the *demo* module as part of the project build. You can create a new service with the `fluence service new` command. Note that the implication of creating a new service, possibly in a new project directory, is that you intend to deploy that service separately from the *eth-rpc* service. Of course, you will need to write Aqua code to be able to interact with your new module.\n\nTo get rid of the demo project for now, use `fluence module remove` to unlink the module from the *fluence.yaml* and *service.yaml* files; the old *rm -r \u003cpath/demo\u003e* gets rid of the code template.\n\n### Deploying Services With A Deal\n\n\u003e :warning: **Warning**: For quickstart, services are already deployed for you. But if you want to deploy services in this repository yourself, you should remove old deployment information first:\n\u003e ```bash\n\u003e mv .fluence/workers.yaml .fluence/workers.yaml.backup\n\u003e ```\n\u003e `fluence deal deploy` is capable of redeploying services, so you don't have to do this manual management every time you want to (re)deploy deal. But one can't redeploy a deal he doesn't own, so you will get a error unless you are working to modify a Deal you created.\n\n\nWith a service, in this case the *eth-rpc* service, ready for deployment, we simply use the `fluence deal deploy`:\n\n**Command**:\n\n```bash\nfluence deal deploy\n```\n\n**Output**:\n\n```bash\nUsing kras environment to sign contracts\n    Finished release [optimized] target(s) in 0.05s # (1)\nConnecting to kras relay: /dns4/7-kras.fluence.dev/tcp/9000/wss/p2p/12D3KooWDUszU2NeWyUVjCXhGEt1MoZrhvdmaQQwtZUriuGN1jTr\nConnected\n\nCreating deal for worker defaultWorker # (2)\n\nTo approve transactions to your wallet using metamask, open the following url: # (3)\n\nhttps://cli-connector.fluence.dev/?wc=3df74b36a4459be644172d82e114297a65330ada4e77bc8afba67688064f033e%402\u0026relay-protocol=irn\u0026symKey=5b9b1773203cfe98c86bb8d611ff7945173430f5fb056fcd95f79919adbb0bae\n\nor go to https://cli-connector.fluence.dev and enter the following connection string there:\n\nwc:3df74b36a4459be644172d82e114297a65330ada4e77bc8afba67688064f033e@2?relay-protocol=irn\u0026symKey=5b9b1773203cfe98c86bb8d611ff7945173430f5fb056fcd95f79919adbb0bae\n\nConfirm transaction in your wallet...\n# Waiting for transaction to be mined......\nTo approve transactions to your wallet using metamask, open the following url: # (4)\n\nhttps://cli-connector.fluence.dev/?wc=4c6084bf73667a0f02795048002dfdaff8e6b1be22495f989e6d04995ad2e8ba%402\u0026relay-protocol=irn\u0026symKey=8b19aba8c445bd37819f60ef0bafe2e4098424dc5d570a8dfeaf4b57cc1e794d\n\nor go to https://cli-connector.fluence.dev and enter the following connection string there:\n\nwc:4c6084bf73667a0f02795048002dfdaff8e6b1be22495f989e6d04995ad2e8ba@2?relay-protocol=irn\u0026symKey=8b19aba8c445bd37819f60ef0bafe2e4098424dc5d570a8dfeaf4b57cc1e794d\n\nConfirm transaction in your wallet...\n# Waiting for transaction to be mined......\n3 workers joined the deal 0x06AAe83F938890c47FA7C667392e01D9E3052961 # (5)\n\n\nSuccess!\n\ncreated deals: # (6)\n  defaultWorker:\n    deal: https://mumbai.polygonscan.com/address/0x06AAe83F938890c47FA7C667392e01D9E3052961\n    worker definition: bafkreigzfyfis2pmfr425dwpeql4hsrat5d7hpdthlxwzhefd23kw7gtey\n    timestamp: 2023-10-12T14:39:21.570Z\n```\n\nOne little command is doing quite a bit so you don't have to. Let's work through the process:\n\n* for an up-to-date look, all service assets, i.e., modules, are (re-) compiled (1)\n* a (new) Deal with both on-chain and off-chain activities is created (2)\n  * the wasm modules and config are uploaded to IPFS node where deal-participating peer's workers can fetch the package by CID\n* now you have to get involved! You are presented with two transactions, one after the other, for you to sign. To sign a transaction, copy and paste the uri to your browser and Metamask should pop up with a signing request eventually. Before signing a transaction, carefully inspect its origin and content. Different wallets have different security features. If you are using MetaMask, carefully review your Security \u0026 Privacy settings. This is what you should see when you sign a transaction:\n![Sign TX](./images/metamask_tx_prompt.png)\n  * first transaction is for the Deal on-chain creation (3)\n  * second transaction is for the Deal's on-chain matching (4)\n* once you sign the transactions, the deal is created and workers join the deal, deploying your services (5)\n* finally, deployment information is saved for future use in Aqua scripts (6)\n\nFluence CLI did a bunch of work for us behind the scenes and signing the transaction is a lot quicker than entering (virtual) credit card information. Fluence CLI organized a set of parameters needed by our Aqua scripts in [deals.aqua](./.fluence/aqua/deals.aqua) for easy importing.\n\nNote that the deal's section in [fluence.yaml](./fluence.yaml) specifies the minimum and maximum workers that should be deployed under the *defaultWorker* namespace. Fluence CLI currently provides default values for min and max workers of one (1) and three (3), respectively. In the near future, you will be able to provide your spot price for service execution, hosting targets in the form of named capacity providers and more.\n\nAfter successful deal deployment it is possible to retrieve logs for the deployed deal.\n\n**Command**:\n\n```bash\nfluence deal logs\n```\n\n**Output**:\n\n```bash                                                                     \nConnecting to random stage relay: /dns4/0-stage.fluence.dev/tcp/9000/wss/p2p/12D3KooWDcpWuyrMTDinqNgmXAuRdfd2mTdY9VoXZSAet2pDzh6r\nConnected\ndefaultWorker (host_id: 12D3KooWMMGdfVEJ1rWe1nH1nehYDzNEHhg5ogdfiGk88AupCMnf, worker_id: 12D3KooWGctQEUKcgWBetu9aiR3owMZcBGNcpDC5ZE3H6dL16uSP, spell_id: 679acf1c-57e2-4dd7-aa78-bb181df7a00a): \n\n2023-10-25 14:41:48 Installing worker for deal 0x02ab47b7b2737e16a516421c1b8ad36475e0f7ce\n2023-10-25 14:41:48 parsed worker definition bafkreifp4gbp3emepswptldwlpbhpybt47uy2c3ksm3y7rut6cmcdnljwa {\n  \"services\": [\n    {\n      \"modules\": [\n        {\n          \"config\": \"bafkreia2wftbxfd4blycnvlxw2yl7ibhan2g7vauexv7fspibodlu34que\",\n          \"wasm\": \"bafkreiarl3nin4jtauc52k76h4ze7yekvc5d2uno5fkgpotmcekwm7cnqa\"\n        },\n        {\n          \"config\": \"bafkreiaclbxbmtydpwdcpoh2yggcd6uimicmbb6rxzab7bgp342w5vcz2m\",\n          \"wasm\": \"bafybeieeemeldllgokrkgybbrrjqeehyin3blv5cgehhdp3nlrfyj4eqoa\"\n        }\n      ],\n      \"name\": \"eth_rpc\"\n    }\n  ],\n  \"spells\": []\n}\n2023-10-25 14:41:50 Created service eth_rpc 2b5967ae-e5f9-4929-8668-d2039593af28\n2023-10-25 14:41:50 Installation finished\n2023-10-25 14:41:50 Worker installation finished with status {\n  \"message\": \"\",\n  \"state\": \"INSTALLATION_SUCCESSFUL\",\n  \"timestamp\": 1698244910\n}\n\ndefaultWorker (host_id: 12D3KooWJ4bTHirdTFNZpCS72TAzwtdmavTBkkEXtzo6wHL25CtE, worker_id: unknown, spell_id: unknown): Worker is not installed yet\n\ndefaultWorker (host_id: 12D3KooWAKNos2KogexTXhrkMZzFYpLHuWJ4PgoAhurSAv7o5CWA, worker_id: unknown, spell_id: unknown): Worker is not installed yet\n```\n\nIn the example output above, we see that the worker for the *defaultWorker* namespace was installed successfully. The worker is now ready to receive requests from the gateway. The other two workers are not installed yet. It should happen in a while and one can check the logs again to see the progress.\n\n### fRPC Aqua Code\n\nNow that we have our services deployed and ready for action, it's time to look at Aqua, which is utilized by the Gateway to bridge HTTP to/from libp2p. Let's have a look at the Aqua code and structure.\n\nFile [rpc.aqua](\"./gateway/aqua/rpc.aqua\") is the file where fRPC algorithms and entrypoints used by gateway are defined.\n\n```aqua\n-- rpc.aqua\naqua RPC\n\nimport \"@fluencelabs/aqua-lib/builtin.aqua\"\nimport Subnet, Worker from \"@fluencelabs/aqua-lib/subnet.aqua\"\n\nimport \"services.aqua\"\nuse \"deals.aqua\"\n```\n\nTwo of the dependencies (should) stand out: *deals.aqua* and *services.aqua* as they are local files located in the project *.fluence* directory: *services.aqua* contains the interface exports from the *eth-rpc* wasm module and  *deals.aqua* maps the values from *deployed.yaml* to data structures usable by your aqua code. Since these files are dynamically generated by Fluence CLI, you need to (re-) compile your Aqua after every change to your Wasm code or deal deploy updates. For further details and examples, consult the [Aqua book](https://fluence.dev/docs/aqua-book/introduction), explore the [aqua playground](https://github.com/fluencelabs/aqua-playground) and visit the relevant repositories: [aqua-lib](https://github.com/fluencelabs/aqua-lib), [registry](https://github.com/fluencelabs/registry), [spell](https://github.com/fluencelabs/spell).\n\n### fRPC Gateway Configuration\n\nThe gateway config file, e.g., [quickstart_config.json](./configs/quickstart_config.json), contains the parameters for Fluence p2p network connection and gateway behavior. Key parameters include:\n\n* *providers*: an array of RPC endpoint urls, e.g., Infura, Alchemy, Ankr, etc.\n* *mode*: one of \"random\", \"round-robin\" or \"quorum\" to specify the endpoint selection algorithm\n* *relay*: the Fluence p2p network relay address for [js-client](https://github.com/fluencelabs/js-client) to use\n* *port*: the port the gateway listens on\n* other parameters related to the fRPC Algorithms, see below\n\n### fRPC Algorithms\n\nThe fRPC substrate offers basic algorithms to enhance reliability, addressing issues related to RPC endpoint availability and trustworthiness.\n\nLet's first examine *balancedEthCall* in [rpc.aqua](\"./gateway/aqua/rpc.aqua\"):\n\n```aqua\n-- Call RPC method with load balancing\nfunc balancedEthCall{Logger, Balancer}(method: string, jsonArgs: []string) -\u003e JsonString: -- (1)\n  on HOST_PEER_ID: -- (2)\n    worker, provider \u003c- Balancer.next() -- (3)\n    Logger.logWorker(worker) -- (4)\n    Logger.logCall(provider) -- (4)\n    rpc \u003c- fromWorkerProvider(worker, provider) -- (5)\n    result \u003c- rpcCall{rpc}(method, jsonArgs) -- (6)\n  \u003c- result -- (7)\n```\n\nThis function is a building block for other algorithms that allows to make a call to a RPC endpoint with some balancing logic. Let's go through the code line by line:\n\n* (1) Function declaration states that two abilities are required to execute it: *Logger* and *Balancer*. To learn more about abilities, see [Abilities](https://fluence.dev/docs/aqua-book/language/abilities).\n* (2) The function is executed on the host peer, i.e. the relay peer we used to connect to Fluence p2p network.\n* (3) Worker and RPC provider are determined by *Balancer*.\n* (4) Worker and provider are logged for debugging purposes.\n* (5) RPC ability is created from worker and provider with a helper function *fromWorkerProvider*.\n* (6) RPC ability is passed to *rpcCall* function to make the actual call.\n* (7) Result of the call is returned.\n\n#### Random\n\n**Use: Set `mode` to \"random\" in your gateway config file**\n\nRandomization the selection of one out of many RPC endpoints by itself is a weak algorithm to mitigate a single point of failure or byzantine behavior. However, it can be an important building block for more effective algorithms such as failover and quorum/consensus from both RPC providers and network peers.\n\nThe fRPC substrate implementation is very basic from a business logic perspective but illustrates how to randomly choose both a worker, which represents the deployed service on a particular peer, and an RPC endpoint:\n\n```aqua\nfunc randomLoadBalancingEth(uris: []string, method: string, jsonArgs: []string) -\u003e JsonString:\n  result: ?JsonString\n\n  workers, error \u003c- getWorkers() -- (1)\n  if error != nil:\n    result \u003c- errorJsonString(error!)\n  else:\n    log \u003c- initPeerLogger() -- (2)\n    random \u003c- timeRandom() -- (2)\n    balancer \u003c- randomBalancer{random}(workers, uris) -- (2)\n    result \u003c- balancedEthCall{log, balancer}(method, jsonArgs) -- (3)\n  \n  \u003c- result!\n```\n\nThe *randomLoadBalancingEth* function is build upon *balancedEthCall*:\n* (1) Workers that are part of the deal are fetched from the network.\n* (2) Logger and random balancer are initialized.\n* (3) *balancedEthCall* is called with logger and balancer.\n\nNote that time service is used to generate random numbers. This is not a good idea for production, but it's good enough for demonstration.\n\n#### Round robin\n\n**Use: Set `mode` to \"round-robin\" in your gateway config file**\n\n[Config Parameters](#fRPC-Gateway-Configuration):\n* *counterServiceId*: the service id of the counter service\n* *counterPeerId*: the peer id of the counter service\n\nA round robin algorithm cycles through the different options usually in a predictable manner. This substrate implementation is no different:\n\n```aqua\nfunc roundRobinEth(uris: []string, method: string, jsonArgs: []string, counterServiceId: string, counterPeerId: string) -\u003e JsonString:\n  result: ?JsonString\n\n  workers, error \u003c- getWorkers()\n  if error != nil:\n    result \u003c- errorJsonString(error!)\n  else:\n    log \u003c- initPeerLogger()\n    counter \u003c- onPeerCounter(counterPeerId, counterServiceId) -- (1)\n    balancer \u003c- cycleBalancer{counter}(workers, uris) -- (2)\n    result \u003c- balancedEthCall{log, balancer}(method, jsonArgs)\n  \n  \u003c- result!\n```\n\nThe *roundRobinEth* function is very similar to *randomLoadBalancingEth*, except for the balancer:\n* (1) Counter ability is created from peer id and service id.\n* (2) Cycle balancer is created from counter and workers.\n\nTo keep the state of the *cycle index*, we use a counter based on a local, [js-client](https://github.com/fluencelabs/js-client) based [service](./gateway/src/index.js). The peer executing the *Counter* service is the (local) client-peer implemented by the gateway. Note that the state of the counter is limited to the life of the gateway.\n\n#### Quorum\n\n**Use: Set `mode` to \"quorum\" in your gateway config file**\n\n[Config Parameters](#fRPC-Gateway-Configuration):\n* *quorumServiceId*: the service id of the quorum service\n* *quorumPeerId*: the peer id of the quorum service\n* *quorumNumber*: the number of results that must be equal to determine a quorum result\n\nA quorum, aka \"off-chain consensus\", \"determines\" a result by a ranked frequency distribution of the results pool and makes a selection against a quorum threshold value, e.g., 2/3 of items in the results pool must be equal for a quorum result to be accepted. Moreover, additional parameters such as the minimum number of items in the result pool may be added. Depending on your trust in the peers processing the endpoint requests or even the peer executing the quorum algorithm, additional verification steps may have to be added. There is one more pertinent consideration when it comes to designing quorum algorithms: the differentiation between (on-chain) read and write operations.\n\nIn the fRPC substrate implementation, we provide a basic quorum algorithm:\n\n```aqua\nfunc quorum{ProviderBalancer, QuorumChecker}(workers: []Worker, quorumNumber: u32, timeout: u32, method: string, jsonArgs: []string) -\u003e QuorumResult: -- (1)\n  results: *JsonString\n  on HOST_PEER_ID: -- (2)\n    for worker \u003c- workers par: -- (3)\n      provider \u003c- ProviderBalancer.nextProvider() -- (4)\n      rpc \u003c- fromWorkerProvider(worker, provider) -- (5)\n      results \u003c- rpcCall{rpc}(method, jsonArgs) -- (6)\n\n  -- wait all results from all workers with timeout\n  join results[workers.length - 1] -- (7)\n  par Peer.timeout(timeout, \"Workers timeout\") -- (7)\n\n  \u003c- QuorumChecker.check(results, quorumNumber) -- (8)\n```\n\nLet's examine the code line by line:\n* (1) Function declaration states that two abilities are required to execute it: *ProviderBalancer* and *QuorumChecker*. To learn more about abilities, see [Abilities](https://fluence.dev/docs/aqua-book/language/abilities).\n* (2) The function is executed on the host peer, i.e. the relay peer we used to connect to Fluence p2p network.\n* (3) For each worker in parallel:\n  * (4) Provider is determined by *ProviderBalancer*.\n  * (5) RPC ability is created from worker and provider with a helper function *fromWorkerProvider*.\n  * (6) RPC ability is passed to *rpcCall* function to make the actual call. Result is saved in *results* stream variable.\n* (7) Results from all workers are waited for with a timeout. For more information, see [Timeout and race patterns](https://fluence.dev/docs/aqua-book/language/flow/parallel#timeout-and-race-patterns).\n* (8) Final result is determined by *QuorumChecker* based on all results gathered at this point.\n\nAs evidenced by the code, no considerations to differentiate between read and write operations are made, which might prove disadvantageous when submitting, for example, a signed transaction.\n\nThe actual entrypoint, *quorumEthCall*, is a wrapper around *quorum*:\n\n```aqua\nfunc quorumEth(uris: []string, quorumNumber: u32, timeout: u32, method: string, jsonArgs: []string, quorumServiceId: string, quorumPeerId: string) -\u003e QuorumResult:\n  result: *QuorumResult\n\n  workers, error \u003c- getWorkers()\n  if error != nil:\n    result \u003c- errorQuorumResult(error!)\n  else:\n    random \u003c- timeRandom()\n    balancer \u003c- randomBalancer{random}(workers, uris)\n    quorumChecker \u003c- onPeerQuorumChecker(quorumPeerId, quorumServiceId)\n    result \u003c- quorum{balancer, quorumChecker}(workers, quorumNumber, timeout, method, jsonArgs)\n\n  \u003c- result!\n```\n\nIt is very similar to *randomLoadBalancingEth* and *roundRobinEth*, except for the balancer and quorum checker initialization. To determine the quorum result, we use a local, [js-client](https://github.com/fluencelabs/js-client) based [service](./gateway/src/index.js). The peer executing the *QuorumChecker* service is the (local) client-peer implemented by the gateway.\n\n## Summary\n\nfRPC is a design pattern to efficiently mitigate risks inherent in centralized RPC providers for dApps using Fluence's decentralized serverless compute protocol. fRPC Substrate is a basic implementation of the fRPC design pattern that dApp users can use out of the box with no changes to their frontend. Once you tried fRPC, feel free to experiment with the code and let us know about your journey in the [Fluence Discord](https://fluence.chat) developer channel.\n\nFor support, to discuss your ideas or to schedule presentations of your solutions to the Fluence and fRPC community at large, reach out in [discord](\"https://fluence.chat\") or [telegram](https://t.me/fluence_project).\n\nHappy Hacking!\n\n## Contribution\n\nFound a mistake, inaccuracy or have other improvement suggestions? Open an issue or a pull request! Note that contributions submitted will be licensed according to the terms of [LICENSE](./LICENSE).\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Ffluencelabs%2Ffrpc-substrate","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Ffluencelabs%2Ffrpc-substrate","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Ffluencelabs%2Ffrpc-substrate/lists"}