filecoin-saturn / L2-node

Saturn L2 Node implementation in Golang
MIT License
35 stars 9 forks source link

Saturn L2 Node

The Saturn L2 Node is a CDN node for the Saturn network that fetches and caches/persists IPLD Dags serialised as CAR files. It fetches CAR files from origin servers that can serve IPLD data such as the IPFS Gateway and Filecoin SPs.

The L2 node is meant to run on NATT'd home machines. This means that the L2 implementation needs to account for:

  1. Limited disk space available for caching CAR files -> we should never exceed the limit set by the home user.
  2. Limited uplink and download bandwidths and the uplink speed will be much lower than the download speeds.
  3. L2's will be NATT'd and not reachable from the public internet.
  4. L2's will have flaky connectivity.

We've documented the important considerations and design of the L2 node that will allows us to build a reliable, low latency and high bandwidth CDN abstraction on top of these resource contrained homne machines with flaky connectivity at https://pl-strflt.notion.site/Building-the-Saturn-L2-network-and-L1-L2-interplay-6518deda51344a9db04bd3037b270ada.

The document also details the implementation path we will be taking to eventually build a robust and feature complete MVP for the Saturn L2.

Features

At present, the L2 implementation has the following features:

Cache misses to the IPFS Gateway as an origin server

Dagstore as a cache for CAR files

HTTP API for fetching L2 node stats

L1 Discovery and serving CAR files to L1s

Setting up the L2 node and invoking the HTTP APIs

  1. Build and Install the Saturn L2 binary located at cmd/saturn-l2.

    cd cmd/saturn-l2
    go build ./...
  2. Run the saturn-l2 binary

    cd cmd/saturn-l2
    ./saturn-l2

    Note that before running the binary, you need to configure/think about the following environment variables:

    1. PORT PORT is the environment variable that determines the port the saturn L2 service will bind to. If this environment variable is not configured, this service will bind to any available port by default.

    2. ROOT_DIR ROOT_DIR is the environment variable that determines the root directory of the Saturn L2 Node. All persistent state and cached CAR files will be persisted under this directory.

      The following state is currently persisted inside the root directory on the user's machine:

      a) CAR files fetched from the IPFS Gateway. This is the data that the Saturn L2 CDN node is caching. These are stored as flat files on disk.

      b) Internal dagstore bookkeeping state. The indices for the cached CARv2 files are persisted as flat files on disk and the state of each dag/shard/CAR file is persisted in a leveldb key-value store on disk.

      c) L2 node stats that the L2 user/Station might be interested in. These are persisted in JSON format in a leveldb key-value store on disk.

    3. MAX_L2_DISK_SPACE MAX_L2_DISK_SPACE is the environment variable that determines the maximum disk space the L2 node can use to store cached CAR files. If this env variable is not configured, it defaults to 200GiB. Note: For efficient operation, the configured value should be greater than or equal to 200Gib.

    4. FIL_WALLET_ADDRESS FIL_WALLET_ADDRESS is the environment variable that determines the Filecoin wallet address of the L2 user. Note: This is a mandatory environment variable -> no default.

    5. L1_DISCOVERY_API_URL L1_DISCOVERY_API_URL is the environment variable that determines the URL of the L1 Discovery API to invoke to get back the L1 nodes this L2 node will connect and serve CAR files to. For the production environment, this is currently https://orchestrator.strn.pl/nodes.

    6. MAX_L1s MAX_L1s is the environment variable that determines the maximum number of L1s this L2 will connect to and join the swarm for. Defaults to 100.

    7. MAX_CONCURRENT_L1_REQUESTS MAX_CONCURRENT_L1_REQUESTS is the environment variable that determines the maximum number of requests that will be processed concurrently for a single L1. Defaults to 3.

  3. One the binary starts, it will print this to the standard output:

./saturn-l2
...
WebUI: http://localhost:52860/webui
API: http://localhost:52860/
...

When an L2 connects/disconnects with an L1 it prints this to standard output:

INFO: Saturn Node is online and connected to 1 peer(s)
INFO: Saturn Node is online and connected to 2 peer(s)
INFO: Saturn Node is online and connected to 1 peer(s)
ERROR: Saturn Node lost connection to the network

If you want to connect to WebUI, also run ./scripts/download-webui.sh.

Note that the Saturn L2 node only binds to the localhost loopback network interface and so will only be reachable from the same machine. In the above snippet, 52860 is the port that the Saturn L2 node binds to on the localhost interface. This port can be configured using the PORT environment variable as mentioned above.

HTTP APIs

  1. GET /stats
curl http://localhost:52860/stats

Response:
{"Version":"v0.0.0",
"BytesCurrentlyStored":0, -> Total space currently taken up by the cached CAR files on the L2 user's machine.
"TotalBytesUploaded":0,   -> Total number of bytes uploaded/served by the L2 node to requesting peers in it's entire lifetime.
"TotalBytesDownloaded":0, -> Total number of bytes downloaded by the L2 node from the IPFS Gateway/origin server in it's entire lifetime.
"NContentRequests":0,     -> Total number of requests received by the L2 node for content from clients in it's entire lifetime.
"NContentNotFoundReqs":0, -> Total number of requests for which the L2 did NOT have a cached CAR file to serve.
"NSuccessfulRetrievals":0 -> Total number of successful retrievals served by the L2 node.
"NContentReqErrors":0}    -> Total number of errors encountered by the L2 node while serving content to client in it's entire lifetime.

Sample cids to test with can be found here. These are cids the IPFS Gateway can serve.

Developer's Guide

Release process

Publishing a new version is easy:

  1. Create a tag
  2. Push it to GitHub

GitHub Actions and GoReleaser will take care of the rest.

Example script:

$ git checkout main
$ git pull
$ git tag -a -s vA.B.C
$ git push origin vA.B.C

Replace vA.B.C with the actual version number, and please follow Semantic Versioning.

You can omit -s if you are not signing your commits.