Code Monkey home page Code Monkey logo

lassie's Introduction

Lassie

Fetches from Filecoin, every time

Table of Contents

Overview

Lassie is a simple retrieval client for Filecoin. It finds and fetches your data over the best retrieval protocols available. Lassie makes Filecoin retrieval.

Installation

Download the lassie binary form the latest release based on your system architecture, or download and install the lassie package using the Go package manager:

$ go install github.com/filecoin-project/lassie/cmd/lassie@latest

go: downloading github.com/filecoin-project/lassie v0.3.1
go: downloading github.com/libp2p/go-libp2p v0.23.2
go: downloading github.com/filecoin-project/go-state-types v0.9.9

...

Optionally, download the go-car binary from the latest release based on your system architecture, or install the go-car package using the Go package manager:

$ go install github.com/ipld/go-car/cmd/car@latest

go: downloading github.com/ipld/go-car v0.6.0
go: downloading github.com/ipld/go-car/cmd v0.0.0-20230215023242-a2a8d2f9f60f
go: downloading github.com/ipld/go-codec-dagpb v1.6.0 

...

The go-car package makes it easier to work with files in the content-addressed archive (CAR) format, which is what Lassie uses to return the content it fetches. For the lassie use-case, go-car will be used to extract the contents of the CAR into usable files.

Methods of Retrieval

Command Line Interface

The lassie command line interface (CLI) is the simplest way to retrieve content from the Filecoin/IPFS network. The CLI is best used when needing to fetch content from the network on an ad-hoc basis. The CLI is also useful for testing and debugging purposes, such as making sure that a CID is retrievable from the network or from a specific provider.

The CLI can be used to retrieve content from the network by passing a CID to the lassie fetch command:

$ lassie fetch [-o <output file>] [-t <timeout>] <CID>[/path/to/content]

The lassie fetch command will return the content of the CID to a file in the current working directory by the name of <CID>.car. If the -o output flag is used, the content will be written to the specified file. If the -t timeout flag is used, the timeout will be set to the specified value. The default timeout is 20 seconds.

fetch will also take as input IPFS Trustless Gateway style paths. If the CID is prefixed with /ipfs/, the remainder will be interpreted as a URL query, accepting query parameters that the Trustless Gateway spec accepts, including dag-scope=, entity-bytes=. For example, lassie fetch '/ipfs/<CID>/path/to/content?dag-scope=all' will fetch the CID, the blocks required to navigate the path, and all the content at the terminus of the path.

More information about available flags can be found by running lassie fetch --help.

Extracting Content from a CAR

The go-car package can be used to extract the contents of the CAR file into usable files. For example, if the content of the CID is a video, the go-car package can be used to extract the video into a file on the local filesystem.

$ car extract -f <CID>.car

The -f flag is used to specify the CAR file to extract the contents from. The contents of the CAR will be extracted into the current working directory.

Fetch Example

Let's grab some content from the Filecoin/IPFS network using the lassie fetch command:

$ lassie fetch -o fetch-example.car -p bafybeic56z3yccnla3cutmvqsn5zy3g24muupcsjtoyp3pu5pm5amurjx4

This will fetch the bafybeic56z3yccnla3cutmvqsn5zy3g24muupcsjtoyp3pu5pm5amurjx4 CID from the network and save it to a file named fetch-example.car in our current working directory.

The -p progress flag is used to get more detailed information about the state of the retrieval.

Note: If you received a timeout issue, try using the -t flag to increase your timeout time to something longer than 20 seconds. Retrievability of some CIDs is highly variable on local network characteristics.

Note: For the internet cautious out there, the bafybeic56z3yccnla3cutmvqsn5zy3g24muupcsjtoyp3pu5pm5amurjx4 CID is a directory that has a video titled birb.mp4, which is a video of a bird bouncing to the song "Around the World" by Daft Punk. We've been using it internally during the development of Lassie to test with.

To extract the contents of the fetch-example.car file we created in the previous example, we would run:

$ car extract -f fetch-example.car

To fetch and extract at the same time, we can use the lassie fetch command and pipe the output to the car extract command:

$ lassie fetch -o - -p bafybeic56z3yccnla3cutmvqsn5zy3g24muupcsjtoyp3pu5pm5amurjx4 | car extract

The -o output flag is used with the - character to specify that the output should be written to stdout. The car extract command reads input via stdin by default, so the output of the lassie fetch command is piped to the car extract command.

You should now have a birb.mp4 file in your current working directory. Feel free to play it with your favorite video player!

HTTP API

The lassie HTTP API allows one to run a web server that can be used to retrieve content from the Filecoin/IPFS network via HTTP requests. The HTTP API is best used when needing to retrieve content from the network via HTTP requests, whether that be from a browser or a programmatic tool like curl. We will be using curl for the following examples but know that any HTTP client can be used including a web browser. Curl specific behavior will be noted when applicable.

The API server can be started with the lassie daemon command:

$ lassie daemon

Lassie daemon listening on address 127.0.0.1:41443
Hit CTRL-C to stop the daemon

The port can be changed by using the -p port flag. Any available port will be used by default.

More information about available flags can be found by running lassie daemon --help.

To fetch content using the HTTP API, make a GET request to the /ipfs/<CID>[/path/to/content] endpoint:

$ curl http://127.0.0.1:41443/ipfs/<CID>[/path/to/content]

By default, this will output the contents of the CID to stdout.

To save the output to a file, use the filename query parameter:

$ curl http://127.0.0.1:41443/ipfs/<CID>[/path/to/content]?filename=<filename> --output <filename>

CURL Note: With curl we need to also specify the --output <filename> option. However, putting the above URL into a browser will download the file with the given filename parameter value upon a successful fetch.

More information about HTTP API requests and responses, as well as the numerous request parameters that can be used to control fetch behavior on a per request basis, can be found in the HTTP Specification document.

Daemon Example

We can start the lassie daemon by running:

$ lassie daemon

Lassie daemon listening on address 127.0.0.1:41443
Hit CTRL-C to stop the daemon

We can now fetch the same content we did in the CLI example by running:

$ curl http://127.0.0.1:41443/ipfs/bafybeic56z3yccnla3cutmvqsn5zy3g24muupcsjtoyp3pu5pm5amurjx4?filename=daemon-example.car --output daemon-example.car

CURL Note: With curl we need to also specify the --output <filename> option. However, putting the above URL into a browser will download the file with the given filename parameter value upon a successful fetch.

To extract the contents of the daemon-example.car file we created in the above example, we would run:

$ car extract -f daemon-example.car

Golang Library

The lassie library allows one to integrate lassie into their own Go programs. The library is best used when needing to retrieve content from the network programmatically.

The lassie dependency can be added to a project with the following command:

$ go install github.com/filecoin-project/lassie/cmd/lassie@latest

The lassie library can then be imported into a project with the following import statement:

import "github.com/filecoin-project/lassie/pkg/lassie"

The following code shows a small example for how to use the lassie library to fetch a CID:

package main

import (
	"context"
	"fmt"
	"os"

	"github.com/filecoin-project/lassie/pkg/lassie"
	"github.com/filecoin-project/lassie/pkg/storage"
	"github.com/filecoin-project/lassie/pkg/types"
	"github.com/ipfs/go-cid"
	trustlessutils "github.com/ipld/go-trustless-utils"
)

// main creates a default lassie instance and fetches a CID
func main() {
	ctx := context.Background()

	// Create a default lassie instance
	lassie, err := lassie.NewLassie(ctx)
	if err != nil {
		panic(err)
	}

	// Prepare the fetch
	rootCid := cid.MustParse("bafybeic56z3yccnla3cutmvqsn5zy3g24muupcsjtoyp3pu5pm5amurjx4")       // The CID to fetch
	store := storage.NewDeferredStorageCar(os.TempDir(), rootCid)                                 // The place to put the CAR file
	request, err := types.NewRequestForPath(store, rootCid, "", trustlessutils.DagScopeAll, nil)  // The fetch request
	if err != nil {
		panic(err)
	}

	// Fetch the CID
	stats, err := lassie.Fetch(ctx, request)
	if err != nil {
		panic(err)
	}

	// Print the stats
	fmt.Printf("Fetched %d blocks in %d bytes\n", stats.Blocks, stats.Size)
}

Let's break down the above code.

First, we create a default lassie instance:

ctx := context.Background()

// Create a default lassie instance
lassie, err := lassie.NewLassie(ctx)
if err != nil {
	panic(err)
}

The NewLassie function creates a new lassie instance with default settings, taking a context.Context. The context is used to control the lifecycle of the lassie instance. The function returns a *Lassie instance and an error. The *Lassie instance is used to make fetch requests. The error is used to indicate if there was an error creating the lassie instance.

Additionally, the NewLassie function takes a variable number of LassieOptions. These options can be used to customize the lassie instance. For example, the WithGlobalTimeout option can be used to set a global timeout for all fetch requests made with the lassie instance. More information about the available options can be found in the lassie.go file.

Next, we prepare the fetch request:

// Prepare the fetch
rootCid := cid.MustParse("bafybeic56z3yccnla3cutmvqsn5zy3g24muupcsjtoyp3pu5pm5amurjx4")       // The CID to fetch
store := storage.NewDeferredStorageCar(os.TempDir(), rootCid)                                 // The place to put the CAR file
request, err := types.NewRequestForPath(store, rootCid, "", trustlessutils.DagScopeAll, nil)  // The fetch request
if err != nil {
	panic(err)
}

The rootCid is the CID we want to fetch. The store is where we want to write the car file. In this case we are choosing to store it in the OS's temp directory. The request is the resulting fetch request that we'll hand to the lassie.Fetch function.

The request is created using the NewRequestForPath function. The only new information that this function takes that we haven't discussed is the path and the dagScope. The path is an optional path string to a file in the CID being requested. In this case we don't have a path, so pass an empty string. The dagScope has to do with traversal and describes the shape of the DAG fetched at the terminus of the specified path whose blocks are included in the returned CAR file after the blocks required to traverse path segments. More information on dagScope can be found in the dag-scope HTTP Specification section. In this case we use trustlessutils.DagScopeAll to specify we want everything from the root CID onward.

The function returns a *types.Request and an error. The *types.Request is the resulting fetch request we'll pass to lassie.Fetch, and the error is used to indicate if there was an error creating the fetch request.

Finally, we fetch the CID:

// Fetch the CID
stats, err := lassie.Fetch(ctx, request)
if err != nil {
	panic(err)
}

The Fetch function takes a context.Context, a *types.Request, and a *types.FetchOptions. The context.Context is used to control the lifecycle of the fetch. The *types.Request is the fetch request we made above. The *types.FetchOptions is used to control the behavior of the fetch, but it's variadic, so we don't pass anything. The function returns a *types.FetchStats and an error. The *types.FetchStats is the fetch stats. The error is used to indicate if there was an error fetching the CID.

Roots, pieces and payloads

Lassie uses the term Root to refer to the head block of a potential graph (DAG) of IPLD blocks. This is typically the block you request, using its CID, when you perform a fetch with Lassie. Of course a root could also be a sub-root of a larger graph, but when performing a retrieval with Lassie, you are focusing on the graph underneath the block you are fetching, and considerations of larger DAGs are not relevant.

In the Filecoin ecosystem, there exists terminology related to "pieces" and "payloads" and there may be confusion between the way lassie uses the term "root CID" and some of the language used in Filecoin. A Piece is a Filecoin storage deal unit, typically containing user data organized into a CAR; then padded to size to form a portion of a Filecoin sector. Filecoin pieces have their own CIDs, and it is possible to retrieve a whole, raw piece, from Filecoin. This can lead to terminology such as "piece root CID". Lassie currently does not perform whole-piece retrievals, and is not intended to be able to handle piece CIDs. Additionally, in Filecoin the term Payload is sometimes used in reference to the IPLD data inside a piece when performing a storage or retrieval deal. This is closer to the way Lassie uses the term Root and historical Lassie code contains some references to "payloads" that are actually referring to the root CID of a graph.

Contribute

Early days PRs are welcome!

License

This library is dual-licensed under Apache 2.0 and MIT terms.

Copyright 2022. Protocol Labs, Inc.

lassie's People

Contributors

anjor avatar bajtos avatar criadoperez avatar dependabot[bot] avatar dtbuchholz avatar elijaharita avatar galargh avatar gammazero avatar guanzo avatar hannahhoward avatar jorropo avatar jtsmedley avatar kylehuntsman avatar masih avatar rvagg avatar web-flow avatar web3-bot avatar willscott avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

lassie's Issues

Architectural Docs

Doc's that explain:

  • The basic repo structure
  • Some or all core architectural choices (cli vs HTTP vs libary, Retriever interface design, how we query/retrieve from FC, flow w/ indexer, how we work with go-bitswap, etc)

HTTP Daemon

What

I should be able to run lassie server

This should start an API listening on a default port. (which I should be able to change with a CLI arg/env variable)

I should be able to issue a request to GET /ipfs/{cid} with an Accept request header with the value application/vnd.ipld.car and receive back a valid CARv1 file containing the root CID specified as well as the remaining blocks of the DAG. The result should be equivalent (but does not need to be byte identifical) to the same request made the Kubo HTTP Gateway API .

Response codes:

For this ticket, we should support 200, 404, and 500, where:
200 = success
404 = not found in the indexer or able to retrieve from a provider
500 = any processing errors

Acceptance criteria

I can CURL a retrievable CID and get a valid CAR file back containing the blocks needed to verify the DAG. I can verify response headers.

I can CURL a non existent CID and get a 404.

Suggested Implementation

DO NOT ADD A BIG BLOCKSTORE TO LASSIE

Complete #33 on top of filecoin-project/go-data-transfer#362

  • For each request, open a CarV2 read/write blockstore to a temporary file and pass to retrieve
  • For first iteration just write the whole file, then send the Response and delete the file. (we'll work on streaming as well in subsequent ticket)

Out of scope

Range requests
Path requests (subsequent tickets)
Any other path gateway spec behavior (some things tackled in subsequent tickets)

Failed CIDs that worked with "ipfs get"

397949554
bafkreib5c5duczdyz7guvmmzb3aimdopwkycrbjs47vkblgdedurvcogty
bafkreidr4veonzw2yplrxd7fls4ipwkn34e3j2zz5vc7pgbplu3xe2eoju
bafkreif6hgpdytwmewaqja67iwjdbho3yckhwpdmyvyudvjkp2jp7ocvcm
bafkreifjclskm7pswbryqhtak6wmqp3iujkcwkh3pxgiryjzwdpgviqxtu
bafkreigdvytd54m663k6cr5jxl7swy4awhtze4ebg27ps57dra6c7q3n44
bafkreigylprnghfdhkoy7a6r5r63rubtzklihzgujzec7fpg7kbpnbvy5y
bafkreihfzbkynaxw642fzm7ibtjd7jnrotojusd2uq3vcn4i2tbrl2xucy
bafybeia43f5a3cyx6zebqhqndyfzhovxle5mqhplnctu4h63p6zji7wjry
bafybeiafwcfyji34xgbno7akhofj42ol2ixh6srgelho4ekieunm7b2n2e
bafybeiamy3zpjan6rsnnp235qyddctbyxb57y3axmptksy77eutsavyzdm
bafybeiaodexv43yfbw6ndhjofnsv2vn3ps2racghdoe6jcwzc6355oabze
bafybeicwgdb3tlnqhwnapf65uqc3v2dde2q65n2afmxdzsxc2mzk3pjxky
bafybeicz6l23m6yh7wuvummqyrnml4nanx7yzv63eq75cywcidhrwys4zu
bafybeid5nqxvs5hxhhucohuish7clpr4gjfi5tvcm3x7pjnecqs4n6pmiy
bafybeidcp3ekowof5inaznccyl3zucheuoecomigf4ry7u7wgsfdcueahy
bafybeidd7ptaad6fyh67j7zobhf5c77oz6ijjczw4hy6xxjj6owzs6iu3u
bafybeiddhel4k3yhufe4fxn23islbtimqf5jv727r5aucb6woszclbkay4
bafybeiddzovp3v33vxqia4uxlbldqsa7tow5gswo6dnniok7oeeiacnr6i
bafybeideizvnnmsx5nyc4w3oiptcrf7qlkmk36lw7ks3g7xay7hmutriwe
bafybeidmrzh5oikkoup4kcwyhoaug6gqwusuiiybesnyiaurbhn5fposua
bafybeidpc32c6zuv2t7vpxijaiduru6g4jtdvfa3kinnxncnpmxb2m3yli
bafybeiduulslab7eywjkori3lh4atgamebwwkbu2iape5lezwoyyy5dg2a
bafybeidxd5ehr2q6j2yyz3u3el322yxvlgt6j4qoplenxvysgymiry5pyu
bafybeiee73qcuk5o6pquxb3z5zmmoqlkcy2lnv6owok22skpe3igs3rliq
bafybeier6qy7iefnjdufvgmyld5p6uaagoaizrs3zsiei774bmk7w6jkge
bafybeif6jwv2sudg4hr55hpswnrolubbi5fgd734pfkfgtfoxqcmztsntq
bafybeifneyqnf2kcocoxmi5mxeafh75iobr2xeigko3jp6gx52iux6ikbq
bafybeifriuasmq53fwtu7cgpwj7vgjm4lzd6fabjlnwxtn4i7ngdbiykqu
bafybeigsj6an6xipkj4j2aert2qeatapqtkcvhtpuvze565atnnflqa7e4
bafybeihrfhfe2y5vu477zgq666yxiela5gknyyuczm4hfmsagkyctqg56m
bafybeihupsf6lzdxksfam27ifpcgshjiasbu3pxwbvujbhksvtb55mqjwa
bafykbzacecpef7vwu4cbijgjgvrtm4gxwawt7oke7nua3qduflffzlvycpsa2
Qma8VZhc5ZboDnaAGkv8RZRVUbyCzAiqxRrVqtFawXYssX
Qma984q7rhAuQ8RkfAaxym696uLzvYjUVPeZ7EBdzSAxzn
Qmab8AbgsYD8KMZP2h7ZCjLrkQNAyGouiVgg4HYfiroyKQ
QmabkQ7uqLHjaGvo3qdxEWQ8zm6v2XsmacoAGyBqtJQAvj
QmacUEHyWcuRCoSxQKMnUqkuFRNwcEfvDkbiYqDcW1sTAF
QmaiA6YhLgU9THF3xbyTwxKHACGTXzx8BgUByyNG9itweW
QmaJ3uewfSxyDadWBbFrbrEaYSo78hY36XfW5mc3rsz2Jq
QmaJTdJw7dBby2RSjoV4YY5QFXdC2Y36vsGrgVgte4Q5JZ
QmaN8kBUeKvVPoLsz7AmBCs9YP5en2v5WfBQg5emmDbAYu
QmarjLJ9PiTVUQdeZhq3gnQmYvaUMj4iXtMYGXKNU8yfDr
QmaTRgUWPAeS6FWMfBFnUd2dBR4g9t58qVYkyfUYTHAw1g
QmavHL4veHrtBTJews47KhCVW65Xr5fN5XxSPQPSaKgt9b
QmawCtt7mf7ckiFfgCNUgPQU9M6RGJeesBcx2gqtJBh1vB
QmaYT7wuZELvdG9hzpSTrVhikHS5wDrnLjSFPb86RpyBGr
Qmb1uQahNY2Gy2LAZtyTg3wtX3zMfyXx6MBfEMaaJsH75Y
Qmb2faBpBdDVS1QC2X7niq6gRgrsdiKRKuhEV8TpsVvoxG
Qmb2tJMdrSLEbMim4HqtzwKaospwW4FUwpBA8qiKAyQ42Z
Qmb9J96BAxguiB1g3XRamYvDRJep1NjEtRsE1H93gCm39f
QmbA9iUWDzmnPxFvkp3bSBE6gTU8xTbs9tamMeigDnQ1VR
QmbdWr7kEX7vHdRWhV2V5qDnZLD33b7fME4amrF8Uuw6Fg
Qmbg5JiygUB3HP6ADa3ef5PBeRp2cbDfb41uNr1CCNRB7b
QmbgKHLSud256LHbiM5YzrHtqRHcQb7NRM969tunbRAdpQ
QmbhfEZhMVFgBBHaZ2ESKFV2JYHL1AfKu7a4mKJHPvoxu2
QmbTbdSjbwq8cpf1M78MMQuwGHQL7GKhnPitQp2965qzFb
QmbvaA1nCBvGkx5iELghz9ohYM8oVt7RvthxtB5KimF3QB
QmbWGCpZ5h19qg7XC1pnC9D3X6hko6QccLMtJgsFqxNMm4
Qmc6cmdwoL48Rd12US2oEHvLM3dnTrJC1cNBediVs4e6UY
Qmc9dFsPrzbmtrCQ55p5BbycVkuttyCbDgkzm9ZGF2uRAx
QmcdQvMUEqjTJ3zPZ464QzCR9Z1NajnE9X6BeKTKgXhK2e
QmcJD8AQ5DfRyZvyxzK5Vtn31QwAkGjK1aUFKKWmdSGCwG
QmcjKma1DsPkYArZG1vsLbR7cvTZLRKPShNVxi9M2GWYUY
QmcLNoWtoR7tL65SoeHqp5zhbCJzdtwwZtiRHn3qr4dDx1
QmcrcdMhMguk8GSk5GJL6cjuMyNZPjB4AZsr9TBP6UGmKr
QmcuQ5ZPqhQspiK9zYMSZwBEzSgVWrfftHVvgodX6EGeVe
QmcYYc3tH9uhc1BuVnR7BCT55syv8WYcS4Nq7DgZkn7VuL
Qmd78raYyXQvCChX386awb1nvYWD2diVbkC1TMf4jTXtcf
QmdaTxahFHFS6JzEjJHccb6tMJxyAcyTB6SnJ7a7R7KrTW
QmdBrbL2RgJVsdY6zcFDdNFyLCeKFTgEPrL2Nm1Mx75PAH
QmdcpKmTjzLERdd4nUY8bU4tCz5BXZkfhM5iFfDVWe5TET
QmdeUKYq18VSphfeQYSHYgUBaPyBTjujDN1nLW11s6iJCs
QmdeymS4jefx7BdTDQoxUBmFZZz2PG9sTauB1JhQeC8iRi
QmdFaogNMKQ1UXZuV4Rh8Rp4Z1ZBJJLP6LMj3DCFaVaVTq
QmdhePWWYhcp7AhSjccSpkXeTScXJgotWkU8nVniCufQw3
QmdJnTYyxZVPPQ5PL1FDCwwo9wtVMXU649BWstE3Upr2Ep
QmdKgtP5uwhgkoGibMYpVL8Sj9S5H9tepep31UG9fScJdb
QmdKnaVe5pxJD65nQ8RwjxoPBmUHK3ZV6Nb1ZYShakioqU
QmdnEHs81sGyoZpnLtbsD4MKSPCWgDbdnKVmkzEQuXhHyp
QmdnHxfUNwcPrxneqsqNY1cixbjbkPk8G8sPHKNKbjVAUC
Qmdt4Dmn4BsLnPMa4TsUsiASKAa6Gi2416pppNGQ8mv3op
QmduHCqFgi76aSag7wKSUyMzteBYmDN3Fvne1cMTxVNnKp
QmdUWpv4XzdcbPPDvPcmrSY8PsTdxzpT1ALRdfJDYAj8fG
QmdwAVVusk9onqKtNfL8NCH2moSyzzeixvp78zDDdMZnyp
QmdyvWYXDGQ6Txi7nkvWmH8aHaEfJnuJYtvDi7YzLNZFJK
Qme12P2k7zXrfGMds38PGBtkQoexahTYH4fQb5cV4kP9Er
Qme1zZaExiBUuXR7rfBCmUYwZbFbFo7eKCFgsDh7k2GroW
QmeDxntCDQFpfY3Z4wX3v7XptiuABuDvgPd5WTf1GCoq2v
Qmeek5twqht6N68LP2xG4FH3KbP3RCcrTAr1oFzeckUEjn
Qmeh5XHdWDugebnkWK8J5Jw6MLdty56feaS5ShzvcXEgrf
Qmei18PLDeHvaAPExcDsMv888Er5nQRriPc1LRvRUHeiG5
Qmek4j1FBmySHuCo5e2ujfSgvhMAeZxzwRnPB2qN2v61NC
Qmeo3KJeJ3DNwzuCsvsecKXaPs8LJU5ssiBYfD5tv9Y36Z
QmepBsHZ6j36xRDR9u2SM4E8DHkjtKHBS7dUyoRFzpDKND
QmePEfKNBoZuPD6fNSGftrbN938bEp4BXAZtnMp12npSEG
QmeQTZpb7P762vxLyJHhErff4YDjuMbdTK1pvpYfn136Je
QmeTuyKoeF7u2Vfin7KLBkfD3RDRFmoZ2FdsNrcdes4BLX
QmeXGGGnhbQwnSiHAPVt7b9p2ieJ8wH65DaYyee7bin3hG
QmexnZioes9bSdufGT9eCxkKEJkn9eqSLyxv8jAtqfuSP3
Qmf6SCiiCvkLDYUjqLxXswMojNW4WBxXraEDgXP6f1HnoL
QmfEehtUMApWyte7DsRVdpQ41uw9aZkhNsNFZAP8HQi6K2
QmfJCoH7o81RsFPNLsBLDABTvRyKqjoUxPmnEgmwUR7QDk
QmfKY5FP4MDy1sinYGB2UqbMKoLEXsDoGzeGd6EFRDxr7T
QmfNUkGd1ii4sF9CxWLH61XoeGwWKZUn8kwpBQ1KjRE9pm
QmNN3Y8ExQy1LP6SLjfpyyhW664vpYqG6eqheU1wCQ9s2z
QmNnQvzfJ18pyRU5A4DjNcWaSCNFFX2XbU98HdyoV3s6fy
QmNnUJrPjadbg2XE8o7JL9SkdA8Tn31vpjDqbm94ASdLCa
QmNqgKJTKqepbSJkX2sbAfN2sNNphz5bN92yvgjTbubfNf
QmNWw2cLv4ZU9r3JLS8TiU332p9tdYZymCzdtg7tKw2s5N
QmNWxthCgZfaYN8DtnLXK7wTtG3abvTejCxTZCHmRqTqA6
QmNXpxjJQmXXKnURwQkQE3wSBBUVGmPU1FA54oxx46gX3J
QmNzJypZAXEZKxv9RTDfhqhvDyfqyRzoLeQ7VerhEGamrj
QmP3oBzsanA32K3CbF4xdv8oDjmd9cMhagMcUFuQKPv3WW
QmP51BSor3gFNiAzrprBSjWUeUazBmFCudBWAGLeQP2Sgx
QmP6Z61zbc7PTBxDDHqQP3eZe4qjF9RoUTU2B3mGXoLKm7
QmP9HZ4ufcNeXLaxCGPeq1mqFYsk5szSDrkF4zZs3RM84h
QmPao5SGqUrvZSc8kmsQwmFrw4N1fU9TTcDxWj3S2qrNCi
QmPCDA3JwBW5Ny9n4bkpQaSsdwdv7c7c9YzAmS6j3ouxrv
QmPfBSQ8JXMcsTSgqC141XWwjc5eoRqCCnu7Wqpig3oQyB
QmPgQcFEBiSo2XVqTt1RCd8gc5fwfBtjTFx7Ft5YexpjuC
QmPhbnJuFcLCgpqbnQR3fSeE366mWhMR6BjsAFqQbcy4Du
QmPiVXSoKnYMQk8GYXqGqhgyLorskMq1aS5tEo3AbY4f9g
QmPMUcTsieFFHMEMUShzhgg5qP9xRB3Bz9f9K6ewx41ZkK
QmPo5zBTSPEEEvAtpViscjw2iubZTE8p7XJvjLrtQPwQpT
QmPryt2UdC7ojJ1mgn6UmfaxZuQkTAHJJ4JXw7nrWjpd61
QmPUPAeLMufr58n2z5CU3hoDrcfWSTuTa5qz5eUAzATo1e
QmPWP2uaRgKg2SjZ6dbccVTd8xog9xPpwvymg2VxLCY8YH
QmPXkTvxKQtVen5B9zE6o7amLhp3DpfidaxKVNZ9mgY8Jh
QmQ3ATgS3R4Bg4FAr4MzWp8oGK263Jy2rEygpR5paHC12Q
QmQ7raSxBLsjMGp94H7LR45Doc7jqvT45pFNrkevkHSKqy
QmQB4YS3toyozH5kMJbHBYajX9b21eusqE28DVceQiSfxW
QmQby3zRWwruNDzX7vG2vHZNLH9HTLuWCnmwdjkiaZwvRc
QmQHzK5iyGBw9ncdux9UciaZjFX84ASFw8XQdXRfgBaofh
QmQkhH58N35r7jjoYSJQA7cW3f3KkCCkrn1fUdC1dR33aY
QmQKN843iq44wbQkfk2jpeiSB2A4B7UDFtr3GAfTPWtk13
QmQMyxyoi5RGyxz73TeL3UpdrYoLupoHaQopRW6QwuBJdN
QmQrqGSsXuq7CDSmbhs6dz9R6VLZbYk1bJ3A3kBj6nz1WU
QmQST2LBa4Ty6E5f1R6ynHvKok3mQxjVxeQymA8Y52mEFR
QmQu2iCWF2Y4Li7gU4Qh5tf1VF8C1HRRtuAziL1R5NgPDA
QmQV5krhtqA7pN1vSHCf8PpisncbpN1MYR8647PAziF1pT
QmQvkH9mWr2gmdP5BjzYKrwMTkWnkc2JEngyxFF1u2fWG3
QmQvPbJ7RqnRfd3SjvSxr3wSVwufehD4mFNeevu2aLedd7
QmQZqKFtMBp7xzUpWAC3qDnfUVtdPYRrj5ciFtd5QBvcLr
QmR2agqhiGKtTD5Hzpurqum1FyZAr8UUdiA5TtDcZ6Bgaj
QmR2whiYECsPYfpC4vK9zGpGz8UcGehDW7kCuweAxuKcvo
QmR4HgRfcegaGecoBTuk5SpKAm2fM6sL4VhnVpXqpmJZ8j
QmR5Q4eNs2nJMS8akbjbJvqmZ8V7FY5FGVzaVSr6X3ip85
QmR9eBQ6yZmwHVBp3r71k4nXuzeyoqtLZ9c6mB42aK2ED9
QmRacTSBFjxVsKnb2DT7mATDBwpG9VyMkAkAUYtm9UoBFH
QmRAknPLCofP5kcDr3xfgmue7vQb8STGwXzNWTEz4YneP8
QmREJvj4Dzare5vch8RpberGvcTGPKN2CT3JrFuCJnZxyG
QmRGKFWVWtsVSyinvRm5cG5gxsLsnVGvmv9PLp3ABP9khG
QmRjY8vcoNgtaSnrVU1WUUWGLUTVGCkB6dmMeGuboTZnZ4
QmRS1MYrSviKtvNcAto8DSkG9C4xUi9xgx5jbxrshC4ioQ
QmRsi4rWV9ggQ4b6fJCUSYPn1prk5ZfdLfandV78cPXgj6
QmRTsKEdfUMVfGj5BjHRjba6eYPJFTcoPkyNVFs82h5sTz
QmRyJy4ppfzCJDePH2jB4WJzVoeWNdZJFL5r9LtQ5NqPAy
QmS11ES7Whu5GBzmPELv22d3hAS8meajowHbEKiKanUvq6
QmS4di7WzR15gv72XpVkAhK2dAorPXeGGXdfPuz27QbYnt
QmSfsuxT6wVJVdKHBFJDL5THop6dkjoVKZQqfJyLqr19uv
QmSKSJiHWu4vG5WgJNVGrPmRV2XpeoPvr5Pr9YPBWLe1me
QmSL1Uj4pQ3W1JkneMBxyQosBwZeTascNwmbP6ywxLETYV
QmSo2Tp6ubAMHCGy2FUnoA77ZSaD6eFp8jWfFMjQWMDq8c
QmSrQgaVWruL3QKK9oFPe69rqdDk2YdKR9e8PvoLAr5gyk
QmSs9piPbfu5YJbbfZxfDE4KMSgdMyq4xeqfSSKhVHnC23
QmSYWjMszHKtNydN2wgbs2EHtuAXHpQKpLBpsSJoGsHd7F
QmSZRvhAsYrnXmdDoScD7TomYe2DfffhZUyo37Uiq74Ebq
QmSzXBXMYWcDxvC7SJTvu7zZzmhxBmZ5wUwUfuXANphB52
QmT6jpZAyZGgXiHyz5dxLFqrrNNjg9CUB4BcdLozGJYmZ5
QmTBqyNpt39qFwMHv59rsZCYvqexEruf6UYgV5RMx8G8Cg
QmTK9GSj9fhLu5GwFXQAZJvxFd5Eznysiyz3pXVxL1RA5W
QmTMvobZcUsuMucoVpXXzjYJR6cmAYXuLp62JCaKtnGy9Y
QmTWmbCFaJuEnhY7odzgWJynpPmgh9r9KQg7hfJaPHYWJt
QmTxbgq2jnVZHSzQUfonRLqyYN1HVJtm5xGUKCoMJqxZbQ
QmTYAsZ7UJegYwJXoQvo3DBYLd3uqBEPhx8TTCs4YrMcrW
QmU2Jumcf5krg7vEreKoZ6wcB7fRARTSdZGwyj76VuXLrp
QmU58vXtCzaWRMqpX1zX4tN8B1NmtgtHoEXDtRBxyYJ8Gx
QmU74gUJUQtZkYDVKJQLwp85YxHftcggnErZoQfZaPyy3g
QmU8zTq23wny2TtVsaCT1agR5xCA4Hao6cB8kPqo5qKG4c
QmUbcBoFvJNyFowByoNsgifvJna8FJFUjLPXBkCKxe53YX
QmUguY6Kwit8H4XMVnVW4hWGwmWRCHc1Ki3JFRYoXUcgbh
QmUjoH6bBh8gnZoHAQUNz8dN2w2rJuJ1SM3v7z5TK9AJDW
QmUWnai3CREPmGT97P2VNpBkwphdBBvhfbFRpjRdPBmseV
QmUXFnWcUF3JN4iMaKJMbfYdp7PhLhP7icLu3qB1Nt8vum
QmUYnHtAAGSFGnYeQsUDt2apXTMMv43AkFCcZyvpFMiWYp
QmUzEAm5t5AfXiBj5rDvJ3sbrTZxmAqXTxpX7FAtbdzLdq
QmV3BjxZTGSuyjUVCnMDLMaFmmF5vzDDs2oe2CR4TE2PFb
QmV6exCTVDstb5iznbf6djyXpGYeRx7F392qmh3WjJM2nK
QmV8WctksfvzejKbHtE4htLwpbFpfBnz1maY9M2J9ezLrd
QmVbWbAzC8PBXFxtmDj2tRiBJNvV4XxeMsmczhvN1McGDJ
QmVdp98UX9EPbZpJqjnv5ysrq5MzZLTJURhZ7aymTxDKvp
QmVGFJJQVDtNeeew6r41oY95SpV2hZ4SbrimXirKhr2bjH
QmVgXp1spumQ9NWJzf7sbwxfekXnRSbNMpPfgPS9TsWU1t
QmVJFKSdTWaxfVCYDEgu7QHDnXtcYwoof77XWecHrFGusp
QmVkmAzQrANqN9VWbHatNfwrx4NBskPVE9Mf9vWziBtVnE
QmVkQtMe1BcznrtY3qSqjTGmQQ8jMi5QCvJ9KPf8gWFTJA
QmVmqPr9tyYaCCyMtwC6ngPVaRBQBWaVD9TajQnNJWKc38
QmVq4bZHa9fmDHU2P3zFsg2YNsqFMbfiKPfdJVBgfzgDax
QmVQkLsnNDmkWADXmHMBDnfmguBW6scWXzZwtjhX9k82Ye
QmVrAnpNxvx9kfPptUySvdjgZ4H8XX5gXPyK92m15A7oiv
QmVSAyuk4y9BFzg3MngKHFg4fn45vHX1m9ETLHxon7e3yz
QmVtrfqdwmxXanujAvpU9NYwnuAeELTtrbCX6mc8ifdtEd
QmVVD3N1R4a6fPKaUqRcmX1iKuYPBomJ6Ys3PNc9YczBLE
QmVx5RDHWpJJHC65icSX9M9bEapaiPqdQrz8oz1C4hDVH3
QmVYuygtwvRi4FpAbBotSouhpi4FyiBL8WTwps6C7pr1Yh
QmVzdK3tLDBoUURn7rMLwohqkwJAwe34hsPEYoZGesG32N
QmW8F51aDY6gs6Rpj2EXzTrp4Kvk1Q9VVtJUdr9SYCBwfL
QmW8iup1f75jYN9TVRqK3xCnhKshVHR3UNJrpc2TiiquSw
QmWaD6xkooRQG4H3rJZaFiuDtLhsD6vDUKV77riBTCugkH
QmWaNrtpTmuFNH4KewQWyXt4q3SYj4yRvfNeTz89zgWXhK
QmWbDwReTGvL8m3bD5eTw2hmtugqaJ6q57wVni6LHrHBFT
QmWfKQy6osf1C52sYLHrLsPEWbRdkHRrmWWe6HEurXrJZF
QmWhZcK3V3tEMSJLbVcFqb763qxXJyxWBNmSeBoGhtCKP8
QmWJ8WqpkfLZGMhnnYFHsn9QoyepFyCeka5EmM3Pnwnnda
QmWja1kfj3WbHQZFxswqE4ACKS1ipSX95L59Th1wkgaSyd
QmWnoXSvtXQiUS9aNGNBCWz9fTg7FjtW8uGDhQmrVUu78b
QmWPNPnaNd6hwdyDNo1hh5sqtEZ77Q8ZuNBCurrkraKWjM
QmWUVqVVCEh8mugMCJjx5z9PtZ4heqXe4r3xrv7i8x3HvC
QmWvotVDj7roziPuEzg2SJwqpUMszv6QmmeZxcZMKqWKNo
QmWZNKVeUG48S6Y2wCHFA5GPJw58GvW6anUuaqULB6X4xA
QmX7HhBzKBUhLd7NbFoB97yGhXNZAGXrqjsnW7ZMkCzdho
QmX82uS2xENpV8gu1GaAAawfNcxdgKSfkQjAVCYqRnpt6X
QmXAz42dL2CokjWy4ByVavr4yQBrB2YQvrcrWSZ6UGtUs7
QmXCDNSoVSdsQQtsFTyL3SPrWs3kMLY8JiwVTXHANYAG4N
QmXeouUDnFgzK2zJFhvjNgPJUq99ySytXXuDcks2yxFe2e
QmXGNK4GBKmKYVPFJmwFDpWWqK2q9eT2JEBAJCKYfzVLw8
QmXgrMB9n99YiDD5evLr6pBZ5HTbJm5SAVZnT9muRAtFaB
QmXHe2aVad8mEtfAVSyXGTNeF2WbKomJ7HYcKpdtKJy6W5
QmXLktkzdnBKykLZovZK8JFADsLQXNyPgt7PrGjiQBiM9i
QmXoXZ566Zs5LXPynYqbx66jewKzR8M8VERNZ5SH8zgsU3
QmXPfYmqksP6ikSowahSJHFmAF3TgpffGAMMx6LfaYFcjf
QmXQVrsQc3AwtNkczep8hYa7FXuYhcQEtFqdXWsACrE6kA
QmXS6s7EfzkcFWgXrAyDngAdggG7ngejHDfMY6UXjPbgNq
QmXTqXmKDjudzy7CMPLmvvVwYhnnLKMhqygszGH2fKL3zh
QmXybuev2HgdUEyFHD7NbXoyvAfN7GfVSpz4ukFhWuPxYv
QmY6pg54qy7FWugzk32Y6SAxx6i5kUk15SpKkUK7JaXVRF
QmY7HQriiFyKfkj1pHapSq4c4nznXRMPGTwPKJMnG8F3iC
QmYbMJi8hjeQciFKbwh3twdC1Gtr2HrzPpBiEnomz835Q2
QmYbNRGBKoowViH9Z9KSNdLkAfRMJz1aUwfTr1dx4reDRi
QmYbT7ZKhnu8zkpUWVcKKEknRowy4wz1ChB1Zz8tXLree7
QmYDURwa6mJYLVNZmZc2ZCiJLhFEZyENPDnuy3tBCwiATa
QmYdv5njk9w4TFmAedUSMaCMf2DvGtJE2BqoaacdGMcqzt
QmYGWA1FGyJ7bxq6YdtNBPkAHL9Z1DfAHtn1ZmBb8aaD8H
QmYJNyHaLR8nHEvU6382NPcRW6W1qZ4k44PyRi9nFm5SZp
QmYkaDjFhmLGmAoPvRR4r6vSyac2MQt8feygsxPvweik6y
QmYKahC6K7biCT8CrfuyyEJ93GSSmuLnmKRcitxiNuqxZi
QmYkgST9cnjrD3aDK5PnPhsBjxTBbpmzH2f6K6nsyiszi7
QmYtHx6WdgFYBQTY6CqXuG8fQkRhXV5Fcgb9xioHbBLqun
QmYz4mxeAupDc2ueh7kYf8NMq6eBsqaUBxpDhr3hTaQ1b3
QmZ1at1G9bm1jEGcXn3bwyHe8TWjS6UbC7CDLrGxHM2zMJ
QmZ1b3qYh3xCAFLoBwfSdvCqKMUBtj3M6oNrW5rekCK1LZ
QmZ5oYked8CWEfg9J51RRbaghryLrRyBhygf2skPBKfF6A
QmZCP1y2jc7zQHFPJZ4o25cakcXwcHSxg99QoK9x4aEqwo
QmZDGw62Ss2RJ8NNKV4LDn1GUZ3z394TZLhpbjspwPbi4G
QmZHy5ibUZqveriiX1C6i3mK45PynvhHafbyTjRSv4Lzbj
QmZJZHUrt2nNtcJLV7CjdRpPqMjeYb6p7Xr3JPWQeTwW6P
QmZkZ5AoPNHb9gtBhNNBwW8LDmtGDCot6fTUoJCJQLoGQi
QmZMvCcjmeoybbufUkDuN452pauoCk7Tv5PJNpx5TFxwAr
QmZtFmbRyyWoVLjuoWtd1uVHMrhL912FkCwXuRfQeSwdmz
QmZVeykur1xDdLEH6zjj5eoNs4Ch4796gAs6iRh9UmFWTR
QmZvSjRMLwHLN3TbE9ZmgWtU8T9Ev9pxyoqSn3qyuoXGiZ
QmZXuq8iWSUgTJyzwX3Y62ovrhxPeDs7RHfdE9Qxuj1X1C
QmZyfVMti26AytTMSMnpiWZJR9JAdJLRDhUfLQ8C7vTXBW

Clean up temporary files

Lassie is leaving a lot of lassie_carstore* files that I don't think will ever be cleaned up, some are 5+ days old.

potential solution is to delete all temp files on shutdown.

Deleting on shutdown is great as a final cleanup, but it doesn't help for long running containers. Ideally each temp file is deleted when it's no longer needed. Perhaps returning early on this err is why some files are left behind?

if ss.f != nil {
err := ss.f.Close()
if err != nil {
return err
}
return os.Remove(ss.f.Name())

Retrieval per-SP concurrency accounted across whole retrieval flow

Current behaviour, specifically through autoretrieve using bedrock-dev defaults:

  • When we start performing an actual retrieval from an SP, we mark their activity up by 1
  • When we fail, or succeed in the retrieval, we mark their activity down by 1
  • When considering an indexer candidate list for a CID, we remove any SPs who have an activity of >0 (configurable)
  • When we have the final list of SPs to attempt actual retrieval from, having performed a successful query and filtering out paid results, we skip over attempting a retrieval from SPs who have an activity of >1 (this could be more than 1 minute after the indexer list - query timeout = 1m, and retrieval attempts happen in parallel, each with a timeout of 1m)

Proposed behaviour:

  • When we receive a list of SPs from the indexer for a CID, we discard any SPs with an activity of >0 (configurable)
  • Of the remaining SPs in the indexer candidate list, we mark all of their activity up by 1
  • When we successfully retrieve from that SP, or have an error or other fail, or we bail because we got the CID from another SP, we mark their activity down by 1

Therefore, "we are currently talking to this SP X times" is our per-SP concurrency and this includes the entire flow through query and retrieval and accounts for SPs who we have successfully queried but are blocked on retrieving from because we are currently trying one that returned our query faster.

Per-retrieval linksystem data-transfer startup error

Seen at the begining of an autoretrieve restart:

	/go/pkg/mod/github.com/ipfs/[email protected]/taskqueue/taskqueue.go:97 +0x3a
created by github.com/ipfs/go-graphsync/taskqueue.(*WorkerTaskQueue).Startup
	/go/pkg/mod/github.com/ipfs/[email protected]/taskqueue/taskqueue.go:139 +0x3b5
github.com/ipfs/go-graphsync/taskqueue.(*WorkerTaskQueue).worker(0xc003b74320, {0x3af2880, 0xc0018369c0})
	/go/pkg/mod/github.com/ipfs/[email protected]/requestmanager/executor/executor.go:83 +0x566
github.com/ipfs/go-graphsync/requestmanager/executor.(*Executor).ExecuteTask(0xc0018369c0, {0x3b05150, 0xc001e08e00}, {0xc03b0de900, 0x26}, 0x1?)
	/go/pkg/mod/github.com/ipfs/[email protected]/requestmanager/executor/executor.go:131 +0x1e5
github.com/ipfs/go-graphsync/requestmanager/executor.(*Executor).traverse(0xc018c299c0?, {{0x3b05150, 0xc01e518640}, {0x3b12420, 0xc015e8e690}, {{{0xc03b0de8d0, 0x22}}, {0x3b1bd00, 0xc047e61ae0}, 0x0, ...}, ...})
	/go/pkg/mod/github.com/ipfs/[email protected]/requestmanager/reconciledloader/load.go:33 +0x178
github.com/ipfs/go-graphsync/requestmanager/reconciledloader.(*ReconciledLoader).BlockReadOpener(0xc0144aee10, {{0x3b05150, 0xc003d61540}, {{0x0, 0x0, 0x0}}, {0x0, 0x0}, {0x0, 0x0}, ...}, ...)
	/go/pkg/mod/github.com/ipfs/[email protected]/requestmanager/reconciledloader/load.go:53 +0x350
github.com/ipfs/go-graphsync/requestmanager/reconciledloader.(*ReconciledLoader).blockReadOpener(0xc0144aee10, {{0x3b05150, 0xc003d61540}, {{0x0, 0x0, 0x0}}, {0x0, 0x0}, {0x0, 0x0}, ...}, ...)
	/go/pkg/mod/github.com/ipfs/[email protected]/requestmanager/reconciledloader/load.go:71 +0x61
github.com/ipfs/go-graphsync/requestmanager/reconciledloader.(*ReconciledLoader).loadLocal(0x0?, {{0x3b05150, 0xc003d61540}, {{0x0, 0x0, 0x0}}, {0x0, 0x0}, {0x0, 0x0}, ...}, ...)
goroutine 223 [running]:

[signal SIGSEGV: segmentation violation code=0x1 addr=0x0 pc=0x184b9c1]
panic: runtime error: invalid memory address or nil pointer dereference

I guess this is the restarts problem suggested in filecoin-project/go-data-transfer#362

This probably isn't an ideal thing to ship a lassie daemon with.

Per protocol request percentage filter

Goals

As an operator of a Lassie daemon, I should be able to configure a percentage of requests where Lassie will attempt retrievals on a given protocol. For example: I only want to attempt graphsync on 10% of requests.

Implementation

  • probably a good opportunity to write a more flexible protocol splitter

Acceptance Criteria

-- lassie daemon should accept a --protocol-percentages parameter. The parameter should be a comma seperated list where each value is in the format 'protocol-name=percentage as decimal'. i.e:

lassie daemon --protocol-percentages graphsync=0.1

Any protocol not included is assume to receive 100% of requests

When passed, the percentage of total requests where a specified protocol is considered should be equal to the passed in parameter

Priortise FastRetrieval candidates from indexer

From #35 (comment)

This has been discussed in the context of autoretrieve for some time now but I think originally they were all set to true but now it appears Boost has this wired up so keep-unsealed-copy config = FastRetrieval metadata.

How:

  1. The Metadata field from the indexer results is base64 (padded) encoded varint-prefixed dag-cbor which can be decoded via https://github.com/ipni/index-provider/blob/19931fd5c692e5efd38093c1764cf0a3ca464af4/metadata/graphsync_filecoinv1.go#L66
  2. FastRetrieval = true entries should get priority in the queryCompare function for the prioritywaitqueue when we have multiple queries returned and waiting for attempts.

Questions:

  1. Should prioritisation be even higher than this? If candidate A is FastRetrieval=false and B is FastRetrieval=true and A returns its query first, should we hold off on attempting a retrieval and give B a chance to come back first?
  2. Perhaps we should shorten the first-byte timeout for FastRetrieval=false candidates under the assumption that they may be attempting an unseal?
  3. If we have >X candidates and some high percentage of them are FastRetrieval=true, perhaps we should filter out the others and only attempt the ones we assume have unsealed copies? e.g. 10 candidates for a CID, 7 of them are FastRetrieval=false, don't even bother attempting the other 3?

Per retrieval failure event

What

When we reach the end of a retrieval, if all attempts fail across all protocols, we should record a failure event, but with no sp associated, and a phase of "summary". This will make it easier to tell in the DB when a retrieval has failed completely.

Setup CI

We should probably setup github actions to run CI. Assuming we keep Lotus out of the dep chain, we should be able to copy over CI from one of the IPFS repos.

Copy over relevant filclient code

Goals

MVP includes:

  • copy the filclient code for retrieval
  • delete everything else
  • reduce dependencies as much as possible
  • remove dependency on Lotus -- we should have our own interface only for the Lotus methods we need, specifically the payment channel apis

Unit test the HTTP Server

What

  • inject lassie as an interface rather than struct to indexer
  • verify given input HTTP request, expected HTTP response

`lassie fetch` creates CAR file even when there are no candidates found

It seems a CAR file is created even if no candidates for a CID is found when executing fetch subcommand. Example:

$ lassie fetch bafkreicl5473u3g5c2l34n5oh5trtpft56ep6mbqv57affzgkfppcitfl4
Fetching bafkreicl5473u3g5c2l34n5oh5trtpft56ep6mbqv57affzgkfppcitfl4
2023/01/16 15:30:57 no candidates

But:

$ ls -alh *.car
-rw-r--r--  1 fish  staff   110B 16 Jan 15:30 bafkreicl5473u3g5c2l34n5oh5trtpft56ep6mbqv57affzgkfppcitfl4.car

HTTP API Spec

Documentation of the HTTP API modelled after IPNI docs

Allow configuration of a default selector

when being embedded in saturn, the current http api should by default (maybe in a pre-pathing world) allow configuration to assume a default selector on requests.

e.g. we should be able to configure that by default when a cid is requested to only fetch the dag to depth 2.

CARv1 streaming

Goals

As soon as we start to get data back from a provider, we should start streaming data over HTTP

Implementation

We need a linksystem that:

  • holds a temporary car file to support graphsync's need for a blockstore
  • also writes data over HTTP as it's written to disk for the car file

Various approaches considered:

  • more abstract CAR file ReadWrite interface, with abstract file teeing on write
  • dual CAR file writing (one readwrite, one append only over HTTP stream)

Discussion

  • how we handle intermediate fails

Fetch via CLI should be able to attempt to extract unixfs data

Based on user-feedback, the expectation from a naive user was that they expected to get files back but got a CAR which they didn't know what to do with (and which is really difficult to research what to do with!).

Implement an --extract flag, or perhaps attempt to do it automatically (IMO not a good idea), that will attempt to load the data as UnixFS and then export any directories or files found. Top-level names may have to be made up, but we could use the CID for that (e.g. if we just get a single block that's a file then we have no name so we'd have to make it up).

This would make a really nice unarchive tool if you have your data nicely packed into a single piece.

Accept X-Request-ID request header and propagate value across metrics

We could use the user provided X-Request-ID value in our metrics to be able to easily correlate specific requests to the logs we get. Additionally, we would return this value in the X-Trace-ID response header as specified in the Gateway Spec. Since we're currently using a randomly generated retrieval ID as the unique ID across our metrics, it would be hard to correlate requests to specific Lassie fetch calls.

Make HTTP request logging conditional

Per @guanzo on Saturn team:

[@hannah](https://filecoinproject.slack.com/team/UKT0DQF98)
 Can we make these logs conditional? https://github.com/filecoin-project/lassie/blob/1744b10a726a2c4569dd9460ef5c55bf24e8e005/pkg/server/http/ipfs.go#L196-L209

Dedupe indexer candidates

We've made an assumption that candidates are unique from the indexer. Apparently they're not.

Noticed with:

lassie fetch -p bafkreiezpw37sdf3u7qsewjnsxbcqx4prjxg3nrk42xx5v7l7bth4sqswa
Fetching bafkreiezpw37sdf3u7qsewjnsxbcqx4prjxg3nrk42xx5v7l7bth4sqswa
Querying indexer for bafkreiezpw37sdf3u7qsewjnsxbcqx4prjxg3nrk42xx5v7l7bth4sqswa...
Found 34 storage providers candidates from the indexer, querying all of them:
        12D3KooWR8nkLuyBc4VFsN5r8EYWoVHuE9z8SZJRq85z562Hpw5J
        12D3KooWR8nkLuyBc4VFsN5r8EYWoVHuE9z8SZJRq85z562Hpw5J
        12D3KooWR8nkLuyBc4VFsN5r8EYWoVHuE9z8SZJRq85z562Hpw5J
        12D3KooWR8nkLuyBc4VFsN5r8EYWoVHuE9z8SZJRq85z562Hpw5J
        12D3KooWR8nkLuyBc4VFsN5r8EYWoVHuE9z8SZJRq85z562Hpw5J
        12D3KooWR8nkLuyBc4VFsN5r8EYWoVHuE9z8SZJRq85z562Hpw5J
        12D3KooWR8nkLuyBc4VFsN5r8EYWoVHuE9z8SZJRq85z562Hpw5J
        12D3KooWR8nkLuyBc4VFsN5r8EYWoVHuE9z8SZJRq85z562Hpw5J
        12D3KooWR8nkLuyBc4VFsN5r8EYWoVHuE9z8SZJRq85z562Hpw5J
        12D3KooWR8nkLuyBc4VFsN5r8EYWoVHuE9z8SZJRq85z562Hpw5J
        12D3KooWR8nkLuyBc4VFsN5r8EYWoVHuE9z8SZJRq85z562Hpw5J
        12D3KooWR8nkLuyBc4VFsN5r8EYWoVHuE9z8SZJRq85z562Hpw5J
        12D3KooWKAd5C78zMyqbaMCm7Pt9CMyAy6eoJNzedadUuiDBkfhY
        12D3KooWKAd5C78zMyqbaMCm7Pt9CMyAy6eoJNzedadUuiDBkfhY
        12D3KooWKAd5C78zMyqbaMCm7Pt9CMyAy6eoJNzedadUuiDBkfhY
        12D3KooWPNbkEgjdBNeaCGpsgCrPRETe4uBZf1ShFXStobdN18ys
        12D3KooWPNbkEgjdBNeaCGpsgCrPRETe4uBZf1ShFXStobdN18ys
        12D3KooW9yi2xLhXds9HC4x9vRN99mphq6ds8qN2YRf8zks1F32G
        12D3KooWL1AMeTdrwpC7wHmwrMNhZroAtPDccc2wjWvG9YriBUvv
        12D3KooWHwRmkj4Jxfo2YnKJC4YBzTNEGDW6Et4E68r7RYVXk46h
        12D3KooWL3yguPd2SJBUgichgLHVuuaMeANpG8L3J9dNUSebsVsB
        12D3KooWL3yguPd2SJBUgichgLHVuuaMeANpG8L3J9dNUSebsVsB
        12D3KooWL3yguPd2SJBUgichgLHVuuaMeANpG8L3J9dNUSebsVsB
        12D3KooWHQiG6uHU9ZrFtPipRT9uD24WxeYV13ixeDnVvh3Rn9Uu
        12D3KooWKyQ5yN39BbCqyG2JVxVA3pGCw6BQkaXRiBVTL7raczg4
        12D3KooWDMJSprsuxhjJVnuQQcyibc5GxanUUxpDzHU74rhknqkU
        12D3KooWPNbkEgjdBNeaCGpsgCrPRETe4uBZf1ShFXStobdN18ys
        12D3KooWPNbkEgjdBNeaCGpsgCrPRETe4uBZf1ShFXStobdN18ys
        12D3KooWSPtnggJL5wkoAmtgGCosViEC6Z2heTmt7ZTF98GYPyKq
        12D3KooWM4wsQ3kdd8CDHiVDQthU9JZ9KqsxSdSQT2xj6TAdDth5
        12D3KooWM4wsQ3kdd8CDHiVDQthU9JZ9KqsxSdSQT2xj6TAdDth5
        12D3KooWM4wsQ3kdd8CDHiVDQthU9JZ9KqsxSdSQT2xj6TAdDth5
        12D3KooWPPiZzBZKiY5XwhmRwhhKyXiFXxGNkEXmzZmjtjrxa8ps
        12D3KooWPPiZzBZKiY5XwhmRwhhKyXiFXxGNkEXmzZmjtjrxa8ps
Querying [12D3KooWR8nkLuyBc4VFsN5r8EYWoVHuE9z8SZJRq85z562Hpw5J] (started)...
Querying [12D3KooWR8nkLuyBc4VFsN5r8EYWoVHuE9z8SZJRq85z562Hpw5J] (started)...
Querying [12D3KooWR8nkLuyBc4VFsN5r8EYWoVHuE9z8SZJRq85z562Hpw5J] (started)...
Querying [12D3KooWR8nkLuyBc4VFsN5r8EYWoVHuE9z8SZJRq85z562Hpw5J] (started)...
Querying [12D3KooWR8nkLuyBc4VFsN5r8EYWoVHuE9z8SZJRq85z562Hpw5J] (started)...
...

See indexer return for this: https://cid.contact/multihash/QmYfpGpK38jcxYwpKg2tShrHpyi6rRghQxa2SirrNsqQTH

Captured result at time of writing issue, click to expand
{"MultihashResults":[{"Multihash":"EiCZfbf5DLun4SJZLZXCKF+Pim5ttirmr37X6/hmfkoSsA==","ProviderResults":[{"ContextID":"AXESIKX1BuaGyWSTKcyl13AwRkTAXlQ6opOQ0KnUwwLQE/4l","Metadata":"kBKjaFBpZWNlQ0lE2CpYKAABgeIDkiAgn0NVjVGmlOhY44KHkBz6YwK3XQU+ZbwZRBzOGq0dbD5sVmVyaWZpZWREZWFs9W1GYXN0UmV0cmlldmFs9Q==","Provider":{"ID":"12D3KooWR8nkLuyBc4VFsN5r8EYWoVHuE9z8SZJRq85z562Hpw5J","Addrs":["/ip4/62.66.210.70/tcp/10241"]}},{"ContextID":"AXESIL0MRIWqRwocLbjBDE5zggpHTOS2qUUDc2HSeOybPQ6v","Metadata":"kBKjaFBpZWNlQ0lE2CpYKAABgeIDkiAgsfQ2tfW6BWAgbEDhb7rzSU0LTmvQQAA6K7V1PBj2LBRsVmVyaWZpZWREZWFs9W1GYXN0UmV0cmlldmFs9Q==","Provider":{"ID":"12D3KooWR8nkLuyBc4VFsN5r8EYWoVHuE9z8SZJRq85z562Hpw5J","Addrs":["/ip4/62.66.210.70/tcp/10241"]}},{"ContextID":"AXESIKxtTI+VxdQaLatqWHqgrs6n73aCQjbfVy501kSVvNdQ","Metadata":"kBKjaFBpZWNlQ0lE2CpYKAABgeIDkiAgsfQ2tfW6BWAgbEDhb7rzSU0LTmvQQAA6K7V1PBj2LBRsVmVyaWZpZWREZWFs9W1GYXN0UmV0cmlldmFs9Q==","Provider":{"ID":"12D3KooWR8nkLuyBc4VFsN5r8EYWoVHuE9z8SZJRq85z562Hpw5J","Addrs":["/ip4/62.66.210.70/tcp/10241"]}},{"ContextID":"AXESIHyc72vcFxPJJZY3IF3V0qTVy6Dms4cQyCZTaOyCTy42","Metadata":"kBKjaFBpZWNlQ0lE2CpYKAABgeIDkiAgKxEsAACeHD+hkk7UIFHGv/OAo2MedlT5c3rNbcH9qApsVmVyaWZpZWREZWFs9W1GYXN0UmV0cmlldmFs9Q==","Provider":{"ID":"12D3KooWR8nkLuyBc4VFsN5r8EYWoVHuE9z8SZJRq85z562Hpw5J","Addrs":["/ip4/62.66.210.70/tcp/10241"]}},{"ContextID":"AXESIBwABoSCAN+44SL9FpVcidISUfd6hb531xU+C5Ry5Y03","Metadata":"kBKjaFBpZWNlQ0lE2CpYKAABgeIDkiAgw7Tg27Skp1R3Gd4Tri/1OLfxjp0xBCdOY5kwVJMFAT5sVmVyaWZpZWREZWFs9W1GYXN0UmV0cmlldmFs9Q==","Provider":{"ID":"12D3KooWR8nkLuyBc4VFsN5r8EYWoVHuE9z8SZJRq85z562Hpw5J","Addrs":["/ip4/62.66.210.70/tcp/10241"]}},{"ContextID":"AXESIAN8KGElmLtv2eSjgpkurEqF9j1xewK5/LzSNpCxbt/W","Metadata":"kBKjaFBpZWNlQ0lE2CpYKAABgeIDkiAg8hBY3IJgqDthdZKy4wXgR9ipmMkWLQrcNKj0889iISZsVmVyaWZpZWREZWFs9W1GYXN0UmV0cmlldmFs9Q==","Provider":{"ID":"12D3KooWR8nkLuyBc4VFsN5r8EYWoVHuE9z8SZJRq85z562Hpw5J","Addrs":["/ip4/62.66.210.70/tcp/10241"]}},{"ContextID":"AXESILzqPddO0EqQSG1ybncivXPTz96SBQCw7+AcQh6ct/Vg","Metadata":"kBKjaFBpZWNlQ0lE2CpYKAABgeIDkiAgkXO9w3SvFXgka8+9ls0TSUynPt2HVgkH0Yv5gLkdEAZsVmVyaWZpZWREZWFs9W1GYXN0UmV0cmlldmFs9Q==","Provider":{"ID":"12D3KooWR8nkLuyBc4VFsN5r8EYWoVHuE9z8SZJRq85z562Hpw5J","Addrs":["/ip4/62.66.210.70/tcp/10241"]}},{"ContextID":"AXESIHHIVBaTXjruf2CRa8qMvyjNMWOh3HiTQSTLTBolmOQi","Metadata":"kBKjaFBpZWNlQ0lE2CpYKAABgeIDkiAgKxEsAACeHD+hkk7UIFHGv/OAo2MedlT5c3rNbcH9qApsVmVyaWZpZWREZWFs9W1GYXN0UmV0cmlldmFs9Q==","Provider":{"ID":"12D3KooWR8nkLuyBc4VFsN5r8EYWoVHuE9z8SZJRq85z562Hpw5J","Addrs":["/ip4/62.66.210.70/tcp/10241"]}},{"ContextID":"AXESIIDIAKxzn6t3HSW4ytPEru+dZMrwAQ/wmG4Xw0eyWEc/","Metadata":"kBKjaFBpZWNlQ0lE2CpYKAABgeIDkiAgkXO9w3SvFXgka8+9ls0TSUynPt2HVgkH0Yv5gLkdEAZsVmVyaWZpZWREZWFs9W1GYXN0UmV0cmlldmFs9Q==","Provider":{"ID":"12D3KooWR8nkLuyBc4VFsN5r8EYWoVHuE9z8SZJRq85z562Hpw5J","Addrs":["/ip4/62.66.210.70/tcp/10241"]}},{"ContextID":"AXESILZTsEjcr4Gwl910qvVbFXRwQos5BrmVVA+fSjjRwRA9","Metadata":"kBKjaFBpZWNlQ0lE2CpYKAABgeIDkiAgsfQ2tfW6BWAgbEDhb7rzSU0LTmvQQAA6K7V1PBj2LBRsVmVyaWZpZWREZWFs9W1GYXN0UmV0cmlldmFs9Q==","Provider":{"ID":"12D3KooWR8nkLuyBc4VFsN5r8EYWoVHuE9z8SZJRq85z562Hpw5J","Addrs":["/ip4/62.66.210.70/tcp/10241"]}},{"ContextID":"AXESICNWIuVKZAC2T1FO7w9xB+atM3x5QzxjRH/E/sHFKyRA","Metadata":"kBKjaFBpZWNlQ0lE2CpYKAABgeIDkiAgsfQ2tfW6BWAgbEDhb7rzSU0LTmvQQAA6K7V1PBj2LBRsVmVyaWZpZWREZWFs9W1GYXN0UmV0cmlldmFs9Q==","Provider":{"ID":"12D3KooWR8nkLuyBc4VFsN5r8EYWoVHuE9z8SZJRq85z562Hpw5J","Addrs":["/ip4/62.66.210.70/tcp/10241"]}},{"ContextID":"AXESICOPqMrpjT7fqMG2aw3LpCtuHfdirKeV6rbWHGnM7h6O","Metadata":"kBKjaFBpZWNlQ0lE2CpYKAABgeIDkiAg8hBY3IJgqDthdZKy4wXgR9ipmMkWLQrcNKj0889iISZsVmVyaWZpZWREZWFs9W1GYXN0UmV0cmlldmFs9Q==","Provider":{"ID":"12D3KooWR8nkLuyBc4VFsN5r8EYWoVHuE9z8SZJRq85z562Hpw5J","Addrs":["/ip4/62.66.210.70/tcp/10241"]}},{"ContextID":"MmuWV86WL2WCPnQ7lwdo60XwWaYZQiwKraUKFld9vOQ=","Metadata":"gBI=","Provider":{"ID":"12D3KooWHVXoJnv2ifmr9K6LWwJPXxkfvzZRHzjiTZMvybeTnwPy","Addrs":["/ip4/145.40.89.101/tcp/4001","/ip4/145.40.89.101/tcp/4002/ws","/ip4/145.40.89.101/udp/4001/quic","/ip6/2604:1380:45f1:d800::1/tcp/4001","/ip6/2604:1380:45f1:d800::1/tcp/4002/ws","/ip6/2604:1380:45f1:d800::1/udp/4001/quic"]}},{"ContextID":"zBCQ/ATrtfPXEyfnuLe6nbkv2ddv+uHPUYKyyRY7xWU=","Metadata":"gBI=","Provider":{"ID":"12D3KooWHVXoJnv2ifmr9K6LWwJPXxkfvzZRHzjiTZMvybeTnwPy","Addrs":["/ip4/145.40.89.101/tcp/4001","/ip4/145.40.89.101/tcp/4002/ws","/ip4/145.40.89.101/udp/4001/quic","/ip6/2604:1380:45f1:d800::1/tcp/4001","/ip6/2604:1380:45f1:d800::1/tcp/4002/ws","/ip6/2604:1380:45f1:d800::1/udp/4001/quic"]}},{"ContextID":"zoZlENcPvYTiPf3FwdvLo+rs9a8Ut8GBNakDXbVCsvY=","Metadata":"gBI=","Provider":{"ID":"12D3KooWCrBiagtZMzpZePCr1tfBbrZTh4BRQf7JurRqNMRi8YHF","Addrs":["/ip4/147.75.87.65/tcp/4001","/ip4/147.75.87.65/tcp/4002/ws","/ip4/147.75.87.65/udp/4001/quic","/ip6/2604:1380:4601:f600::1/tcp/4001","/ip6/2604:1380:4601:f600::1/tcp/4002/ws","/ip6/2604:1380:4601:f600::1/udp/4001/quic"]}},{"ContextID":"0gnnf8PgaOAoGInQ9pOpaktHUw0mdrdyExylsa3JYrA=","Metadata":"gBI=","Provider":{"ID":"12D3KooWHVXoJnv2ifmr9K6LWwJPXxkfvzZRHzjiTZMvybeTnwPy","Addrs":["/ip4/145.40.89.101/tcp/4001","/ip4/145.40.89.101/tcp/4002/ws","/ip4/145.40.89.101/udp/4001/quic","/ip6/2604:1380:45f1:d800::1/tcp/4001","/ip6/2604:1380:45f1:d800::1/tcp/4002/ws","/ip6/2604:1380:45f1:d800::1/udp/4001/quic"]}},{"ContextID":"owH1vRMlrygdOBfmQRquJePYR7GpuHPS17HOWQ4OFXE=","Metadata":"gBI=","Provider":{"ID":"12D3KooWHVXoJnv2ifmr9K6LWwJPXxkfvzZRHzjiTZMvybeTnwPy","Addrs":["/ip4/145.40.89.101/tcp/4001","/ip4/145.40.89.101/tcp/4002/ws","/ip4/145.40.89.101/udp/4001/quic","/ip6/2604:1380:45f1:d800::1/tcp/4001","/ip6/2604:1380:45f1:d800::1/tcp/4002/ws","/ip6/2604:1380:45f1:d800::1/udp/4001/quic"]}},{"ContextID":"g3y0PY8Ae/9WKn2VXX9CbRdSL9esYxi4OLz9RrAVjuI=","Metadata":"gBI=","Provider":{"ID":"12D3KooWRNijznEQoXrxBeNLb2TqbSFm8gG8jKtfEsbC1C9nPqce","Addrs":["/ip4/147.75.87.211/tcp/4001","/ip4/147.75.87.211/tcp/4002/ws","/ip4/147.75.87.211/udp/4001/quic","/ip6/2604:1380:4601:f600::3/tcp/4001","/ip6/2604:1380:4601:f600::3/tcp/4002/ws","/ip6/2604:1380:4601:f600::3/udp/4001/quic"]}},{"ContextID":"W53VDNgknaGyF8uI4K1Q6UtK1buEjvTYfR+XjZU9oO8=","Metadata":"gBI=","Provider":{"ID":"12D3KooWCrBiagtZMzpZePCr1tfBbrZTh4BRQf7JurRqNMRi8YHF","Addrs":["/ip4/147.75.87.65/tcp/4001","/ip4/147.75.87.65/tcp/4002/ws","/ip4/147.75.87.65/udp/4001/quic","/ip6/2604:1380:4601:f600::1/tcp/4001","/ip6/2604:1380:4601:f600::1/tcp/4002/ws","/ip6/2604:1380:4601:f600::1/udp/4001/quic"]}},{"ContextID":"76i3tSAlVB2+9Oikj3EM/toanCTHAd2G1sptpkLYNgQ=","Metadata":"gBI=","Provider":{"ID":"12D3KooWCrBiagtZMzpZePCr1tfBbrZTh4BRQf7JurRqNMRi8YHF","Addrs":["/ip4/147.75.87.65/tcp/4001","/ip4/147.75.87.65/tcp/4002/ws","/ip4/147.75.87.65/udp/4001/quic","/ip6/2604:1380:4601:f600::1/tcp/4001","/ip6/2604:1380:4601:f600::1/tcp/4002/ws","/ip6/2604:1380:4601:f600::1/udp/4001/quic"]}},{"ContextID":"1WfVjO3QJPTpNohsrevI8m1LdWH66R+OOM52mEHZXH4=","Metadata":"gBI=","Provider":{"ID":"12D3KooWCrBiagtZMzpZePCr1tfBbrZTh4BRQf7JurRqNMRi8YHF","Addrs":["/ip4/147.75.87.65/tcp/4001","/ip4/147.75.87.65/tcp/4002/ws","/ip4/147.75.87.65/udp/4001/quic","/ip6/2604:1380:4601:f600::1/tcp/4001","/ip6/2604:1380:4601:f600::1/tcp/4002/ws","/ip6/2604:1380:4601:f600::1/udp/4001/quic"]}},{"ContextID":"8RDgxrdtZRQ9zO18oOO2nZBpSapaZU4m9xtiHg6PrDA=","Metadata":"gBI=","Provider":{"ID":"12D3KooWRNijznEQoXrxBeNLb2TqbSFm8gG8jKtfEsbC1C9nPqce","Addrs":["/ip4/147.75.87.211/tcp/4001","/ip4/147.75.87.211/tcp/4002/ws","/ip4/147.75.87.211/udp/4001/quic","/ip6/2604:1380:4601:f600::3/tcp/4001","/ip6/2604:1380:4601:f600::3/tcp/4002/ws","/ip6/2604:1380:4601:f600::3/udp/4001/quic"]}},{"ContextID":"ECvZdl+miIPLPua8/1pwoyfwb5z6riPjvD6tbZVkk2A=","Metadata":"gBI=","Provider":{"ID":"12D3KooWCrBiagtZMzpZePCr1tfBbrZTh4BRQf7JurRqNMRi8YHF","Addrs":["/ip4/147.75.87.65/tcp/4001","/ip4/147.75.87.65/tcp/4002/ws","/ip4/147.75.87.65/udp/4001/quic","/ip6/2604:1380:4601:f600::1/tcp/4001","/ip6/2604:1380:4601:f600::1/tcp/4002/ws","/ip6/2604:1380:4601:f600::1/udp/4001/quic"]}},{"ContextID":"QdWnHqwk3IEgcPlccWk2PaLlO+SZ+mOQNdOYQHwlELo=","Metadata":"gBI=","Provider":{"ID":"12D3KooWRNijznEQoXrxBeNLb2TqbSFm8gG8jKtfEsbC1C9nPqce","Addrs":["/ip4/147.75.87.211/tcp/4001","/ip4/147.75.87.211/tcp/4002/ws","/ip4/147.75.87.211/udp/4001/quic","/ip6/2604:1380:4601:f600::3/tcp/4001","/ip6/2604:1380:4601:f600::3/tcp/4002/ws","/ip6/2604:1380:4601:f600::3/udp/4001/quic"]}},{"ContextID":"hKDyt8PIAgHRNW5KnZDXc/kKyCwdBHymlm4JsieBJFs=","Metadata":"gBI=","Provider":{"ID":"12D3KooWCrBiagtZMzpZePCr1tfBbrZTh4BRQf7JurRqNMRi8YHF","Addrs":["/ip4/147.75.87.65/tcp/4001","/ip4/147.75.87.65/tcp/4002/ws","/ip4/147.75.87.65/udp/4001/quic","/ip6/2604:1380:4601:f600::1/tcp/4001","/ip6/2604:1380:4601:f600::1/tcp/4002/ws","/ip6/2604:1380:4601:f600::1/udp/4001/quic"]}},{"ContextID":"8nipmXkqIFv8mATFoExubw144QjaMenaULb3JoMJ5io=","Metadata":"gBI=","Provider":{"ID":"12D3KooWCrBiagtZMzpZePCr1tfBbrZTh4BRQf7JurRqNMRi8YHF","Addrs":["/ip4/147.75.87.65/tcp/4001","/ip4/147.75.87.65/tcp/4002/ws","/ip4/147.75.87.65/udp/4001/quic","/ip6/2604:1380:4601:f600::1/tcp/4001","/ip6/2604:1380:4601:f600::1/tcp/4002/ws","/ip6/2604:1380:4601:f600::1/udp/4001/quic"]}},{"ContextID":"0LDAsL63H4YxDpUwAKEfZCUUNivI1mzN+vAsfw7FRns=","Metadata":"gBI=","Provider":{"ID":"12D3KooWCrBiagtZMzpZePCr1tfBbrZTh4BRQf7JurRqNMRi8YHF","Addrs":["/ip4/147.75.87.65/tcp/4001","/ip4/147.75.87.65/tcp/4002/ws","/ip4/147.75.87.65/udp/4001/quic","/ip6/2604:1380:4601:f600::1/tcp/4001","/ip6/2604:1380:4601:f600::1/tcp/4002/ws","/ip6/2604:1380:4601:f600::1/udp/4001/quic"]}},{"ContextID":"7gLXDH7sArEmjfoonz7VZUyBnkb6mU8eWBQVv9cnswU=","Metadata":"gBI=","Provider":{"ID":"12D3KooWRNijznEQoXrxBeNLb2TqbSFm8gG8jKtfEsbC1C9nPqce","Addrs":["/ip4/147.75.87.211/tcp/4001","/ip4/147.75.87.211/tcp/4002/ws","/ip4/147.75.87.211/udp/4001/quic","/ip6/2604:1380:4601:f600::3/tcp/4001","/ip6/2604:1380:4601:f600::3/tcp/4002/ws","/ip6/2604:1380:4601:f600::3/udp/4001/quic"]}},{"ContextID":"jx8n6blHzjLz2j/NlLPSySNjzM1APue3ulrvu+XGWWY=","Metadata":"gBI=","Provider":{"ID":"12D3KooWCrBiagtZMzpZePCr1tfBbrZTh4BRQf7JurRqNMRi8YHF","Addrs":["/ip4/147.75.87.65/tcp/4001","/ip4/147.75.87.65/tcp/4002/ws","/ip4/147.75.87.65/udp/4001/quic","/ip6/2604:1380:4601:f600::1/tcp/4001","/ip6/2604:1380:4601:f600::1/tcp/4002/ws","/ip6/2604:1380:4601:f600::1/udp/4001/quic"]}},{"ContextID":"JOZaa6r2GMjamNLFwHgbSTVYQyQQFwggDLgOaBtsHGQ=","Metadata":"gBI=","Provider":{"ID":"12D3KooWCrBiagtZMzpZePCr1tfBbrZTh4BRQf7JurRqNMRi8YHF","Addrs":["/ip4/147.75.87.65/tcp/4001","/ip4/147.75.87.65/tcp/4002/ws","/ip4/147.75.87.65/udp/4001/quic","/ip6/2604:1380:4601:f600::1/tcp/4001","/ip6/2604:1380:4601:f600::1/tcp/4002/ws","/ip6/2604:1380:4601:f600::1/udp/4001/quic"]}},{"ContextID":"AXESIGOxh+b1xe7aOtPinj+zHYNkqpm3CZVHF9olbum44RU/","Metadata":"kBKjaFBpZWNlQ0lE2CpYKAABgeIDkiAg8hBY3IJgqDthdZKy4wXgR9ipmMkWLQrcNKj0889iISZsVmVyaWZpZWREZWFs9W1GYXN0UmV0cmlldmFs9Q==","Provider":{"ID":"12D3KooWKAd5C78zMyqbaMCm7Pt9CMyAy6eoJNzedadUuiDBkfhY","Addrs":["/ip4/185.37.216.82/tcp/1347","/ip6/2a04:7340:0:1002::4/tcp/1347"]}},{"ContextID":"AXESIGc/GV+FGTKPQZGeiBYEYFMdUimbdvhkkKc1wZB3ZuRx","Metadata":"kBKjaFBpZWNlQ0lE2CpYKAABgeIDkiAgZ7VCD2GDtHskNufLmIZrXtT1SQL1txA3R3H0J6hAcShsVmVyaWZpZWREZWFs9W1GYXN0UmV0cmlldmFs9Q==","Provider":{"ID":"12D3KooWKAd5C78zMyqbaMCm7Pt9CMyAy6eoJNzedadUuiDBkfhY","Addrs":["/ip4/185.37.216.82/tcp/1347","/ip6/2a04:7340:0:1002::4/tcp/1347"]}},{"ContextID":"AXESIFgRTzEu5tHiOD64I+fMpUzmeG+7JUuas4aL//J7Wxau","Metadata":"kBKjaFBpZWNlQ0lE2CpYKAABgeIDkiAgKxEsAACeHD+hkk7UIFHGv/OAo2MedlT5c3rNbcH9qApsVmVyaWZpZWREZWFs9W1GYXN0UmV0cmlldmFs9Q==","Provider":{"ID":"12D3KooWKAd5C78zMyqbaMCm7Pt9CMyAy6eoJNzedadUuiDBkfhY","Addrs":["/ip4/185.37.216.82/tcp/1347","/ip6/2a04:7340:0:1002::4/tcp/1347"]}},{"ContextID":"Yps3zXhVWrQ2SuPCMa6yRuMB0oEHpyaQVAKpDaPN57w=","Metadata":"gBI=","Provider":{"ID":"12D3KooWDpp7U7W9Q8feMZPPEpPP5FKXTUakLgnVLbavfjb9mzrT","Addrs":["/ip4/147.75.80.75/tcp/4001","/ip4/147.75.80.75/tcp/4002/ws","/ip4/147.75.80.75/udp/4001/quic","/ip6/2604:1380:4601:f600::5/tcp/4001","/ip6/2604:1380:4601:f600::5/tcp/4002/ws","/ip6/2604:1380:4601:f600::5/udp/4001/quic"]}},{"ContextID":"0EOdtHk0GTAJKIGSTOyH21S11QdyYqPBBNMKs+dt/M0=","Metadata":"gBI=","Provider":{"ID":"12D3KooWCrBiagtZMzpZePCr1tfBbrZTh4BRQf7JurRqNMRi8YHF","Addrs":["/ip4/147.75.87.65/tcp/4001","/ip4/147.75.87.65/tcp/4002/ws","/ip4/147.75.87.65/udp/4001/quic","/ip6/2604:1380:4601:f600::1/tcp/4001","/ip6/2604:1380:4601:f600::1/tcp/4002/ws","/ip6/2604:1380:4601:f600::1/udp/4001/quic"]}},{"ContextID":"AXESIC9d2V6h7Bv/GBtoe0k6gbMHVdfPUjNF76MNpHk3BYlQ","Metadata":"kBKjaFBpZWNlQ0lE2CpYKAABgeIDkiAgsfQ2tfW6BWAgbEDhb7rzSU0LTmvQQAA6K7V1PBj2LBRsVmVyaWZpZWREZWFs9W1GYXN0UmV0cmlldmFs9Q==","Provider":{"ID":"12D3KooWPNbkEgjdBNeaCGpsgCrPRETe4uBZf1ShFXStobdN18ys","Addrs":["/ip4/76.219.232.45/tcp/24001"]}},{"ContextID":"AXESILJdh+THGOiXDWg5JZ/P1LmN8tmUZmhXwZ2IY223By5a","Metadata":"kBKjaFBpZWNlQ0lE2CpYKAABgeIDkiAgKxEsAACeHD+hkk7UIFHGv/OAo2MedlT5c3rNbcH9qApsVmVyaWZpZWREZWFs9W1GYXN0UmV0cmlldmFs9Q==","Provider":{"ID":"12D3KooWPNbkEgjdBNeaCGpsgCrPRETe4uBZf1ShFXStobdN18ys","Addrs":["/ip4/76.219.232.45/tcp/24001"]}},{"ContextID":"AXESIKWozLr5D146af6mKhu/GRERXehrN30VJlNxrqSt3t/L","Metadata":"kBKjaFBpZWNlQ0lE2CpYKAABgeIDkiAgsfQ2tfW6BWAgbEDhb7rzSU0LTmvQQAA6K7V1PBj2LBRsVmVyaWZpZWREZWFs9W1GYXN0UmV0cmlldmFs9Q==","Provider":{"ID":"12D3KooW9yi2xLhXds9HC4x9vRN99mphq6ds8qN2YRf8zks1F32G","Addrs":["/ip4/149.5.22.10/tcp/24002"]}},{"ContextID":"On8s5MiStY6Q2fvjt6kNw8uaGn92K496Z8EUP1T7yVk=","Metadata":"gBI=","Provider":{"ID":"12D3KooWDpp7U7W9Q8feMZPPEpPP5FKXTUakLgnVLbavfjb9mzrT","Addrs":["/ip4/147.75.80.75/tcp/4001","/ip4/147.75.80.75/tcp/4002/ws","/ip4/147.75.80.75/udp/4001/quic","/ip6/2604:1380:4601:f600::5/tcp/4001","/ip6/2604:1380:4601:f600::5/tcp/4002/ws","/ip6/2604:1380:4601:f600::5/udp/4001/quic"]}},{"ContextID":"ehI08yX+oRRzqjxSb5qKg1cSO6XPtFr9DAG2ApA1r/Q=","Metadata":"gBI=","Provider":{"ID":"12D3KooWDpp7U7W9Q8feMZPPEpPP5FKXTUakLgnVLbavfjb9mzrT","Addrs":["/ip4/147.75.80.75/tcp/4001","/ip4/147.75.80.75/tcp/4002/ws","/ip4/147.75.80.75/udp/4001/quic","/ip6/2604:1380:4601:f600::5/tcp/4001","/ip6/2604:1380:4601:f600::5/tcp/4002/ws","/ip6/2604:1380:4601:f600::5/udp/4001/quic"]}},{"ContextID":"cuHYy+oHAPcM6XJKHUp9ExXw9s6mKXhnQMqY+io5p1Y=","Metadata":"gBI=","Provider":{"ID":"12D3KooWDpp7U7W9Q8feMZPPEpPP5FKXTUakLgnVLbavfjb9mzrT","Addrs":["/ip4/147.75.80.75/tcp/4001","/ip4/147.75.80.75/tcp/4002/ws","/ip4/147.75.80.75/udp/4001/quic","/ip6/2604:1380:4601:f600::5/tcp/4001","/ip6/2604:1380:4601:f600::5/tcp/4002/ws","/ip6/2604:1380:4601:f600::5/udp/4001/quic"]}},{"ContextID":"9smFG+qxJS1CMmVGpAiufmy+VQ7UvcRVhFaepL/gW6s=","Metadata":"gBI=","Provider":{"ID":"12D3KooWCrBiagtZMzpZePCr1tfBbrZTh4BRQf7JurRqNMRi8YHF","Addrs":["/ip4/147.75.87.65/tcp/4001","/ip4/147.75.87.65/tcp/4002/ws","/ip4/147.75.87.65/udp/4001/quic","/ip6/2604:1380:4601:f600::1/tcp/4001","/ip6/2604:1380:4601:f600::1/tcp/4002/ws","/ip6/2604:1380:4601:f600::1/udp/4001/quic"]}},{"ContextID":"AXESIA9+EBMKqPJ3WXH5f0qDY3SE/EMUlqnP7a6JcSJ1c8Ve","Metadata":"kBKjaFBpZWNlQ0lE2CpYKAABgeIDkiAgKxEsAACeHD+hkk7UIFHGv/OAo2MedlT5c3rNbcH9qApsVmVyaWZpZWREZWFs9W1GYXN0UmV0cmlldmFs9Q==","Provider":{"ID":"12D3KooWL1AMeTdrwpC7wHmwrMNhZroAtPDccc2wjWvG9YriBUvv","Addrs":["/ip4/50.223.141.42/tcp/24001"]}},{"ContextID":"AXESILRKKCR9BIJKQjpkv+pVcfe6tWaXP0KEAzchz1y0Pk7R","Metadata":"kBKjaFBpZWNlQ0lE2CpYKAABgeIDkiAg8hBY3IJgqDthdZKy4wXgR9ipmMkWLQrcNKj0889iISZsVmVyaWZpZWREZWFs9W1GYXN0UmV0cmlldmFs9Q==","Provider":{"ID":"12D3KooWHwRmkj4Jxfo2YnKJC4YBzTNEGDW6Et4E68r7RYVXk46h","Addrs":["/ip4/211.48.44.65/tcp/24001"]}},{"ContextID":"AXESIIgSmHCLIUsn7YFtnYELL3zJWsPR+ajjj0O/h5Bkkhbc","Metadata":"kBKjaFBpZWNlQ0lE2CpYKAABgeIDkiAgkXO9w3SvFXgka8+9ls0TSUynPt2HVgkH0Yv5gLkdEAZsVmVyaWZpZWREZWFs9W1GYXN0UmV0cmlldmFs9Q==","Provider":{"ID":"12D3KooWL3yguPd2SJBUgichgLHVuuaMeANpG8L3J9dNUSebsVsB","Addrs":["/ip4/212.6.53.82/tcp/24002"]}},{"ContextID":"AXESICGxOFy//bw1XelIYMim66zOYvpjfWFMt6Gb2eGCRaHg","Metadata":"kBKjaFBpZWNlQ0lE2CpYKAABgeIDkiAgw7Tg27Skp1R3Gd4Tri/1OLfxjp0xBCdOY5kwVJMFAT5sVmVyaWZpZWREZWFs9W1GYXN0UmV0cmlldmFs9Q==","Provider":{"ID":"12D3KooWL3yguPd2SJBUgichgLHVuuaMeANpG8L3J9dNUSebsVsB","Addrs":["/ip4/212.6.53.82/tcp/24002"]}},{"ContextID":"AXESIKxiPWnhqJoRV8yht93RpjmyrKHQw+casWXYHHpkg/67","Metadata":"kBKjaFBpZWNlQ0lE2CpYKAABgeIDkiAgsfQ2tfW6BWAgbEDhb7rzSU0LTmvQQAA6K7V1PBj2LBRsVmVyaWZpZWREZWFs9W1GYXN0UmV0cmlldmFs9Q==","Provider":{"ID":"12D3KooWL3yguPd2SJBUgichgLHVuuaMeANpG8L3J9dNUSebsVsB","Addrs":["/ip4/212.6.53.82/tcp/24002"]}},{"ContextID":"AXESIHeupSDmKGLHpNfQ1Gu/DS2jWPfcXYwRJsEHs7h64fdC","Metadata":"kBKjaFBpZWNlQ0lE2CpYKAABgeIDkiAgKxEsAACeHD+hkk7UIFHGv/OAo2MedlT5c3rNbcH9qApsVmVyaWZpZWREZWFs9W1GYXN0UmV0cmlldmFs9Q==","Provider":{"ID":"12D3KooWHQiG6uHU9ZrFtPipRT9uD24WxeYV13ixeDnVvh3Rn9Uu","Addrs":["/ip4/159.203.96.29/tcp/64591"]}},{"ContextID":"AXESIGPux/WDPJsW1gH/WiTq2tmxGe15CSEcmyG9hUclTuJU","Metadata":"kBKjaFBpZWNlQ0lE2CpYKAABgeIDkiAgsfQ2tfW6BWAgbEDhb7rzSU0LTmvQQAA6K7V1PBj2LBRsVmVyaWZpZWREZWFs9W1GYXN0UmV0cmlldmFs9Q==","Provider":{"ID":"12D3KooWKyQ5yN39BbCqyG2JVxVA3pGCw6BQkaXRiBVTL7raczg4","Addrs":["/ip4/208.185.75.114/tcp/10003"]}},{"ContextID":"AXESIFRyTaxSjZuPEPtuuXnLpiB9YQY7hXjM9bOweKWaV18Q","Metadata":"kBKjaFBpZWNlQ0lE2CpYKAABgeIDkiAgkXO9w3SvFXgka8+9ls0TSUynPt2HVgkH0Yv5gLkdEAZsVmVyaWZpZWREZWFs9W1GYXN0UmV0cmlldmFs9Q==","Provider":{"ID":"12D3KooWDMJSprsuxhjJVnuQQcyibc5GxanUUxpDzHU74rhknqkU","Addrs":["/ip4/89.20.96.58/tcp/24001"]}},{"ContextID":"AXESIKZamo264gByvkSr4V2UuxFZIwvv1p166t+gPELUhBlU","Metadata":"kBKjaFBpZWNlQ0lE2CpYKAABgeIDkiAgLuhcq5j9U8XiwzhG5x9onSE+pQ9BHqMK33PERwvdICxsVmVyaWZpZWREZWFs9W1GYXN0UmV0cmlldmFs9Q==","Provider":{"ID":"12D3KooWPNbkEgjdBNeaCGpsgCrPRETe4uBZf1ShFXStobdN18ys","Addrs":["/ip4/76.219.232.45/tcp/24001"]}},{"ContextID":"AXESILfZzM9SD/r6jKL0QkbnZhztDw6bnq7FUTwMxg07ELk4","Metadata":"kBKjaFBpZWNlQ0lE2CpYKAABgeIDkiAg8hBY3IJgqDthdZKy4wXgR9ipmMkWLQrcNKj0889iISZsVmVyaWZpZWREZWFs9W1GYXN0UmV0cmlldmFs9Q==","Provider":{"ID":"12D3KooWPNbkEgjdBNeaCGpsgCrPRETe4uBZf1ShFXStobdN18ys","Addrs":["/ip4/76.219.232.45/tcp/24001"]}},{"ContextID":"AXESIL3PcPoZfvgLXU82e2jiVVKw/quCvUK3Ophd7ImtSIEw","Metadata":"kBKjaFBpZWNlQ0lE2CpYKAABgeIDkiAg8hBY3IJgqDthdZKy4wXgR9ipmMkWLQrcNKj0889iISZsVmVyaWZpZWREZWFs9W1GYXN0UmV0cmlldmFs9Q==","Provider":{"ID":"12D3KooWSPtnggJL5wkoAmtgGCosViEC6Z2heTmt7ZTF98GYPyKq","Addrs":["/ip4/59.138.253.69/tcp/55555"]}},{"ContextID":"PTJzxLgyjPm4LgiciUw55LSGDJj/YC2M5CI0x21KFeM=","Metadata":"gBI=","Provider":{"ID":"12D3KooWDpp7U7W9Q8feMZPPEpPP5FKXTUakLgnVLbavfjb9mzrT","Addrs":["/ip4/147.75.80.75/tcp/4001","/ip4/147.75.80.75/tcp/4002/ws","/ip4/147.75.80.75/udp/4001/quic","/ip6/2604:1380:4601:f600::5/tcp/4001","/ip6/2604:1380:4601:f600::5/tcp/4002/ws","/ip6/2604:1380:4601:f600::5/udp/4001/quic"]}},{"ContextID":"Oq46wmcJcUqei3GeP/mZ63cE8et/khKfQ3Zz8O11XMk=","Metadata":"gBI=","Provider":{"ID":"12D3KooWDpp7U7W9Q8feMZPPEpPP5FKXTUakLgnVLbavfjb9mzrT","Addrs":["/ip4/147.75.80.75/tcp/4001","/ip4/147.75.80.75/tcp/4002/ws","/ip4/147.75.80.75/udp/4001/quic","/ip6/2604:1380:4601:f600::5/tcp/4001","/ip6/2604:1380:4601:f600::5/tcp/4002/ws","/ip6/2604:1380:4601:f600::5/udp/4001/quic"]}},{"ContextID":"AXESIKWZpBTdNUA5UZwOUcZvq9c5POSE2VXRWhvUAw0sRvhg","Metadata":"kBKjaFBpZWNlQ0lE2CpYKAABgeIDkiAgkXO9w3SvFXgka8+9ls0TSUynPt2HVgkH0Yv5gLkdEAZsVmVyaWZpZWREZWFs9W1GYXN0UmV0cmlldmFs9Q==","Provider":{"ID":"12D3KooWM4wsQ3kdd8CDHiVDQthU9JZ9KqsxSdSQT2xj6TAdDth5","Addrs":["/ip4/61.38.42.252/tcp/20000"]}},{"ContextID":"AXESIN4lR9oKUPvFhQIRae9foLCOYS4CzxTSHah0SJM149ev","Metadata":"kBKjaFBpZWNlQ0lE2CpYKAABgeIDkiAgsfQ2tfW6BWAgbEDhb7rzSU0LTmvQQAA6K7V1PBj2LBRsVmVyaWZpZWREZWFs9W1GYXN0UmV0cmlldmFs9Q==","Provider":{"ID":"12D3KooWM4wsQ3kdd8CDHiVDQthU9JZ9KqsxSdSQT2xj6TAdDth5","Addrs":["/ip4/61.38.42.252/tcp/20000"]}},{"ContextID":"AXESIJz/ju5FFOje2CoJiJBkytxOfaR/R5xZJ6gE07qfOGbU","Metadata":"kBKjaFBpZWNlQ0lE2CpYKAABgeIDkiAgZ7VCD2GDtHskNufLmIZrXtT1SQL1txA3R3H0J6hAcShsVmVyaWZpZWREZWFs9W1GYXN0UmV0cmlldmFs9Q==","Provider":{"ID":"12D3KooWM4wsQ3kdd8CDHiVDQthU9JZ9KqsxSdSQT2xj6TAdDth5","Addrs":["/ip4/61.38.42.252/tcp/20000"]}},{"ContextID":"AXESICy08rkWKsxjHnLmV8dy/K6/rp80d1EVDXrrk4q5btXq","Metadata":"kBKjaFBpZWNlQ0lE2CpYKAABgeIDkiAgsfQ2tfW6BWAgbEDhb7rzSU0LTmvQQAA6K7V1PBj2LBRsVmVyaWZpZWREZWFs9W1GYXN0UmV0cmlldmFs9Q==","Provider":{"ID":"12D3KooWPPiZzBZKiY5XwhmRwhhKyXiFXxGNkEXmzZmjtjrxa8ps","Addrs":["/ip4/212.6.53.83/tcp/24002"]}},{"ContextID":"AXESILot4S8ue5x2RK5WKeAtU4N2Qh9hIuZCIUASiYF7EhoF","Metadata":"kBKjaFBpZWNlQ0lE2CpYKAABgeIDkiAgkXO9w3SvFXgka8+9ls0TSUynPt2HVgkH0Yv5gLkdEAZsVmVyaWZpZWREZWFs9W1GYXN0UmV0cmlldmFs9Q==","Provider":{"ID":"12D3KooWPPiZzBZKiY5XwhmRwhhKyXiFXxGNkEXmzZmjtjrxa8ps","Addrs":["/ip4/212.6.53.83/tcp/24002"]}},{"ContextID":"0G5gj0X83KnYTe1x43ui3PJ5FolkcHu5W+q3WADrmoQ=","Metadata":"gBI=","Provider":{"ID":"12D3KooWCrBiagtZMzpZePCr1tfBbrZTh4BRQf7JurRqNMRi8YHF","Addrs":["/ip4/147.75.87.65/tcp/4001","/ip4/147.75.87.65/tcp/4002/ws","/ip4/147.75.87.65/udp/4001/quic","/ip6/2604:1380:4601:f600::1/tcp/4001","/ip6/2604:1380:4601:f600::1/tcp/4002/ws","/ip6/2604:1380:4601:f600::1/udp/4001/quic"]}},{"ContextID":"NTiIklQuT3JB4J6dEMncofAj+rArweQmbzMMzoVsmDo=","Metadata":"gBI=","Provider":{"ID":"12D3KooWCrBiagtZMzpZePCr1tfBbrZTh4BRQf7JurRqNMRi8YHF","Addrs":["/ip4/147.75.87.65/tcp/4001","/ip4/147.75.87.65/tcp/4002/ws","/ip4/147.75.87.65/udp/4001/quic","/ip6/2604:1380:4601:f600::1/tcp/4001","/ip6/2604:1380:4601:f600::1/tcp/4002/ws","/ip6/2604:1380:4601:f600::1/udp/4001/quic"]}}]}]}

The PieceCIDs are different in the metadata for these entries. Conceivably FastRetrieval may be different for some too so we'll need to make sure we don't lose that when we dedupe.

Extract retrieval code from autoretrieve

Goals

Absolute MVP includes

  • Copy the filecoin directory out of autoretrieve
  • Copy the indexer code out of /endpoint
  • Copy over relevant metrics code
  • maybe make a super mini CLI for now we can use to prove a roundtrip works (in /bin)

Lassie Design Doc

What

A general overview document of what Lassie is, why we're building in, and a rough roadmap

Include a percentage complete for fetching data

[Dogfooding feedback]

Feedback:

  • got the last 2 cids with lassie (but cancelled part way through as I didn't know how long they'd be - it would be great if they had a percentage complete like the ipfs client)
  • For bigger downloads, progress bar just keeps going without any eta in sight, and keeps filling your terminal for an unknown duration and length.

The cids that were being fetched are 8GB and 32GB.

lassie fails at protocol check for graphsync retrieval to specific provider

Problem

I update lassie to v0.4.3, I was previously on 8a18cf9.

When fetching from a local Boost node on v0.4.3 it appears that lassie hangs checking the protocols supported by Boost until the command times out:

$ lassie fetch -p --provider=/ip4/127.0.0.1/tcp/50000/p2p/12D3KooWCv32JXqivqTXQ2WQXny9TFs65DmguPfvPSfJnEE8VX9Q -o bafykbzacedlzwjihuj6ym2345dkulyjpf4vwyrqgrraye2k3zpuyq4ii4efiq.2.car bafykbzacedlzwjihuj6ym2345dkulyjpf4vwyrqgrraye2k3zpuyq4ii4efiq
Fetching bafykbzacedlzwjihuj6ym2345dkulyjpf4vwyrqgrraye2k3zpuyq4ii4efiq from {12D3KooWCv32JXqivqTXQ2WQXny9TFs65DmguPfvPSfJnEE8VX9Q: [/ip4/127.0.0.1/tcp/50000]}
Querying indexer for bafykbzacedlzwjihuj6ym2345dkulyjpf4vwyrqgrraye2k3zpuyq4ii4efiq...
Using the explicitly specified storage provider, querying it:
	12D3KooWCv32JXqivqTXQ2WQXny9TFs65DmguPfvPSfJnEE8VX9Q, Protocols: []

When performing the same fetch on lassie commit 8a18cf9, the file downloads:

$ lassie fetch -p --provider=/ip4/127.0.0.1/tcp/50000/p2p/12D3KooWCv32JXqivqTXQ2WQXny9TFs65DmguPfvPSfJnEE8VX9Q -o bafykbzacedlzwjihuj6ym2345dkulyjpf4vwyrqgrraye2k3zpuyq4ii4efiq.car bafykbzacedlzwjihuj6ym2345dkulyjpf4vwyrqgrraye2k3zpuyq4ii4efiq
Fetching bafykbzacedlzwjihuj6ym2345dkulyjpf4vwyrqgrraye2k3zpuyq4ii4efiq from {12D3KooWCv32JXqivqTXQ2WQXny9TFs65DmguPfvPSfJnEE8VX9Q: [/ip4/127.0.0.1/tcp/50000]}
Querying indexer for bafykbzacedlzwjihuj6ym2345dkulyjpf4vwyrqgrraye2k3zpuyq4ii4efiq...
Found 1 storage providers candidates from the indexer, querying it:
	12D3KooWCv32JXqivqTXQ2WQXny9TFs65DmguPfvPSfJnEE8VX9Q
Querying [12D3KooWCv32JXqivqTXQ2WQXny9TFs65DmguPfvPSfJnEE8VX9Q] (started)...
Querying [12D3KooWCv32JXqivqTXQ2WQXny9TFs65DmguPfvPSfJnEE8VX9Q] (connected)...
Query response from [12D3KooWCv32JXqivqTXQ2WQXny9TFs65DmguPfvPSfJnEE8VX9Q]: size=7.9 MiB, price-per-byte=0, unseal-price=0, message=
Retrieving from [12D3KooWCv32JXqivqTXQ2WQXny9TFs65DmguPfvPSfJnEE8VX9Q] (started)...
Retrieving from [12D3KooWCv32JXqivqTXQ2WQXny9TFs65DmguPfvPSfJnEE8VX9Q] (proposed)...
Retrieving from [12D3KooWCv32JXqivqTXQ2WQXny9TFs65DmguPfvPSfJnEE8VX9Q] (accepted)...
Retrieving from [12D3KooWCv32JXqivqTXQ2WQXny9TFs65DmguPfvPSfJnEE8VX9Q] (first-byte-received)...
Received 10 blocks...
Received 20 blocks...
Received 30 blocks...
Received 40 blocks...
[...]

I attempted to add --vv to get more info, but there are no additional logs.

Return more information from HTTP error response

It'd be nice to return some more error information from the HTTP daemon when responding with an error. Right now most of our errors don't return anything and some return a plain text message. It'd be nice to return some JSON on error statuses.

I'm thinking something along the lines of...

type ErrResponseBody struct {
  code string `json:"code"`
  message string `json:"message"`
}

Some examples:

400

{
  "code": "ERR_INVALID_ACCEPT"
  "message": "No valid value provided in Accept header. Accept header must include MIME type 'application/vnd.ipld.car' either explicitly or implicity."
}

404

{
  "code": "ERR_NO_CANDIDATES"
  "message": "No candidates found"
}

500

{
  "code": "ERR_CAR_WRITE"
  "message": "Failed to write to CAR: ..."
}

Lassie interface design and general design thoughts

We've discussed as a team while we've been extracting FilClient and Lotus from Lassie that we have ideas around the Lassie interface as a whole that we'd like to fix and better design once Lassie is fully extracted. This issue is for dumping those thoughts. We can discuss and extract separate issues from individual thoughts.

Libp2p Host Optimizations & Configs

What

We should run a more optimized Libp2p host for Lassie.

How

Operational Docs

We want to add to the read me some basic "how do I use this thing" documentation to either the readme or in seperate docs directory.

Some things to cover:

  • What do each of the commands do? How do I use them?
  • Outline of how to use it for some basic use cases
    • Just wanna use the CLI to get my stuff back
    • Want to integrate as a library to support my project
    • Want to use HTTP (? -- api is so specialized for Saturn I'm less inclined to publish this a lot right now)

Support pathing semantics

What

Lassie should support the following semantics for paths, which match the gateway semantics:

lassie fetch CID/path/to/file

This should return a CAR containing the blocks for CID, intermediate CIDs between the CID and the root CID of file, and all of the cids that make up file.

lassie fetch CID/path/to/subdir

This should return a CAR containing the blocks for CID, intermediate CIDs between the CID and the root CID of subdir, and all of the cids that make up the directory tree for subdir, but NOT any files or directories associated with subdir (ultimately this means just a single block unless the directory is a HAMT)

lassie fetch CID/path/to/subdir?all

This should return a CAR containing the blocks for CID, intermediate CIDs between the CID and the root CID of subdir, and all of the cids that make up the directory tree for subdir, AND any files or directories associated with subdir AND any additional subdirectories recursively

Selector conversion

I believe there is a relatively straight forward conversion between this structure and selectors:

For each segment of the path, I think we need an ExploreInterpretAs with KnownADL "unixfs" followed by an ExploreFields.

At the end of the path, I believe we want an ExploreInterpretAs "unixfs-preload" followed by a "Matcher" selector, except in the case of the all query parameter where I believe we can simply use an ExploreRecursiveAll selector

Paramater passing

We will need to add either a path & query string to the RetrievalRequest type, or a selector -- it's kind of implementors choice and I'm not sure I have an opinion myself, though early conversion to selector locks us into selector traversal for bitswap (see https://github.com/ipfs/go-fetcher for what this ends up looking like)

Remove go-fil-markets types

What

go-fil-markets brings in a big dependency chain and is a large repo, but we only use it for a few types from it. we should remove it as a dependency.

Suggested Implementation

Two possible routes:

  • simply copy relevant types over from go-fil-markets
  • extract relevant types to their own repo shared by go-fil-markets and lassie

The first is likely much simpler.
The second is may be more sustainable long term and make integration of Lassie into repos that also use go-fil-markets easier.

Acceptance Criteria

Lassie can be compiled without go-fil-markets

Add support to fetch from a specified peer/multiaddr

I've been using Lassie for fetching graphsync data which has been really helpful for announced records. However, it can't currently fetch data from a known provider that has not announced indexes to the network, which could include local environments or just unannounced data.

Request

  • Add the ability to supply a multiaddr in the fetch command, such as:
lassie fetch --provider=/ip4/127.0.0.1/tcp/8080/p2p/$PEER_ID $CID

Notes

  • Having to specify the transport type is fine for this. Ideally it could figure it out, but not necessary for a base version.

Smarter SP retrieval selection logic

Currently, we monitor failures in sending queries/retrievals to SPs, and put SPs in timeout when they fail repeatedly. We also have a hard concurrency limit for SPs of 1 for most of our production systems.

Our current prioritization algorthim for graphsync for those peers that are NOT in SP timeout or over their concurrency limit is:

  1. verified deal status
  2. fast retrieval status
  3. connect time

This is a somewhat open ended issue to improve our selection algorithm. I propose a fairly complex algorithm, based on the fact that I just finished tutoring someone in a statistics class, but we can get there incrementally.

First, I think we should move to only using hard filtering for concurrency and bad success rate for more extreme circumstances, and instead factor success rate and lower concurrency into prioritization for most cases.

I think we should also include time to first byte and bandwidth.

That gives us the following factors:

  1. verified deal status
  2. fast retrieval status
  3. connect time
  4. success rate
  5. concurrency
  6. ttfb
  7. bandwidth

For success rate, ttfb, and bandwidth, we can use a decaying based on some time decay factor.

i.e if S = Success Rate and Dₛ is the decay rate for success rate
As each new value new success/fail N that comes (where 0 = fail, 1 = success) in we do:
S' = Dₛ*S + (1-Dₛ)*N ?

Then rather than an if else chain, I imagine calculating a weighted score based on 0 or 1 for binary options and normalized percentile for all others. For concurrency the score should be inverted to prioritize lower concurrency

i.e. Score P = W(verified) * Verified + W(fast retrieval) * Fast Retrieval + W(Connect Time) * Connect Time ...

Then we normalize the scores against each other so they all add up to 1 (i.e. normalized Score = score / (sum of all scores)

We pick a random value between 0&1 and make a probabilistic selection based on the scores normalized against each other

Determining weights

I suggest we make some guesses about weights (they should add up to 1 between them probably), and then fine tune them against running the load test, then maybe fine tune them against real world metrics.

An extreme version sees us running fine tuning with a training algorithm and the load test using the weights as the model, plus probably the decay factors also. (yay ML) But I expect we don't get there right away.

Calculating normalized percentile

While for each choice between n peers we could normalize the values against each other, but simply doing percentile = (percentile - min) / (max-min), a better estimate would be to assume a normal distribution of values over time and calculate percentiles based on z-score.

z score for normal distribution is calculated by the formula z = (x - mean)/standard deviation (giving range of 3 to -3 for about 99% of values), then can be converted to percentile by measuring the area under the curve in a standard normal distribution. However, in this case, we can probably just use a library like https://github.com/gregscott94/z-table-golang

tracking mean can be done with the same decay formula as above but using the each new peer average to calculate a decaying average among the peers.

tracking std deviation is a bit tougher -- you probably need to use the decay formula for variance
𝜎²ᵢ=𝑆ᵢ=(1−𝛼)(𝑆ᵢ₋₁+𝛼(𝑥ᵢ−𝜇ᵢ₋₁)²)

And then use square root to get std deviation when you need it.

Whether we need all these statistics is ? :)

Show CLI fetch progress as a percentage

CLI progress output is currently a forever output of loading dots. This leaves the user with no estimate to how long the fetch might take. Having a fetch percentage would give the user a better understanding of how long the fetch might take and where they're currently at in the fetch.

Importing lassie as a library throws BadImport compiler error

Description

Importing the lassie project as a library into a go project fails to compile due to a BadImport.

Expected

I expected to be able to import github.com/filecoin-project/lassie@lastest, create a new Lassie instance, and then successfully build.

Actual

I tried importing lassie into an empty project and received the following error on build:

$ go build main.go
main.go:6:2 no required module provides package github.com/filecoin-project/lassie/pkg/lassie; to add it:
        go get github.com/filecoin-project/lassie/pkg/lassie

Steps to Reproduce

  1. Make a new project, go mod init badimport
  2. Run go get github.com/filecoin-project/lassie@latest
  3. Use the following code in main.go:
package main

import (
	"context"
	"github.com/filecoin-project/lassie/pkg/lassie"
)

func main() {
    _, err := lassie.NewLassie(context.Background())
    if err != nil {
        return
    }
}
  1. Run go build main.go

Tracking Metrics to Assess Retrieval Network Health

  • Overall Boost Retrieval Volume - We already track this weekly in Bedrock, and it did show a significant drop from last week --> track daily
    • Breakdown volume of requests from Gateway and Autoretrieve sources
    • [Nice-to-have] Further Breakdown based on the transport protocol
  • Overall Retrieval Success Rate - We track this from autoretrieve weekly in Bedrock, and it also showed a significant drop from last week --> track daily
    • Breakdown volume of requests from Gateway and Autoretrieve sources
    • [Nice-to-have] Further Breakdown based on the transport protocol
  • [New] Distinct Number of SPs serving a successful retrieval - A quantitative indicator of SP sentiment in serving retrievals, to go along with slack DMs
    • Breakdown volume of requests from Gateway and Autoretrieve sources
    • [Nice-to-have] Further Breakdown based on the transport protocol
  • [New] Percentage of Lassie retrievals served by SPs - Answers the Rhea goal of serving Filecoin content from SPs
  • [Nice-To-Have] - Distribution of the volume of Lassie retrieval requests per SP - Helps us understand how evenly distributed the gateway traffic is w.r.t. to SPs

Throw error when payment is required but we have nil PayChannelManager

Part of #7 was abstracting out the PayChannelManager into an interface and requiring the user to implement the interface. This created a scenario in which the PayChannelManager could be nil, whereas before it could never be nil under happy circumstances. Work was done in #7 to account for a nil PayChannelManager under happy circumstances. We need to also account for the scenario in which a PayChannelManager is nil and payment is required, ie. !willingToPay && paymentRequired.

Panic in logs whilst using daemon

I tried using the daemon mode earlier today, and even though the file was retrieved just fine, I noticed a panic in the logs:

assie daemon listening on address 127.0.0.1:57520
Hit CTRL-C to stop the daemon
2023-03-03T10:50:04Z	GET	/ipfs/bafybeibhc3giz64wmwctoswot7bydrn6ghu6cvt4kmrbyrtbvpesndskni
2023-03-03T10:50:06Z	GET	/ipfs/bafybeibhc3giz64wmwctoswot7bydrn6ghu6cvt4kmrbyrtbvpesndskni	OK
2023-03-03T10:50:31Z	GET	/ipfs/bafybeibhc3giz64wmwctoswot7bydrn6ghu6cvt4kmrbyrtbvpesndskni
2023-03-03T10:50:32Z	GET	/ipfs/bafybeibhc3giz64wmwctoswot7bydrn6ghu6cvt4kmrbyrtbvpesndskni	OK
2023-03-03T10:50:51Z	GET	/ipfs/bafybeibhc3giz64wmwctoswot7bydrn6ghu6cvt4kmrbyrtbvpesndskni
2023-03-03T10:50:51Z	GET	/ipfs/bafybeibhc3giz64wmwctoswot7bydrn6ghu6cvt4kmrbyrtbvpesndskni	OK
panic: runtime error: invalid memory address or nil pointer dereference
[signal SIGSEGV: segmentation violation code=0x2 addr=0x18 pc=0x1054e8700]

goroutine 225 [running]:
github.com/filecoin-project/lassie/pkg/server/http.ipfsHandler.func1.2({0x1400057a080, 0x14000000000})
	/Users/anjor/repos/filecoin-project/lassie/pkg/server/http/ipfs.go:177 +0x50
github.com/filecoin-project/lassie/pkg/internal/streamingstore.(*StreamingStore).GetStream(0x1400057a080, {0x105c553d0, 0x14000aaa680}, {0x1400013be00, 0x24})
	/Users/anjor/repos/filecoin-project/lassie/pkg/internal/streamingstore/streamingstore.go:88 +0x70
github.com/ipld/go-ipld-prime/storage.GetStream({0x105c553d0, 0x14000aaa680}, {0x12e12ffc8, 0x1400057a080}, {0x1400013be00, 0x24})
	/Users/anjor/repos/go_workspace/pkg/mod/github.com/ipld/[email protected]/storage/funcs.go:42 +0x12c
github.com/ipld/go-ipld-prime/linking.(*LinkSystem).SetReadStorage.func1({{0x105c553d0, 0x14000aaa680}, {{0x1400091e900, 0x6, 0x6}}, {0x105c678e0, 0x14000546460}, {0x0, 0x0}, {0x105c67980, ...}}, ...)
	/Users/anjor/repos/go_workspace/pkg/mod/github.com/ipld/[email protected]/linking/setup.go:21 +0x8c
github.com/ipfs/go-graphsync/requestmanager/reconciledloader.(*ReconciledLoader).loadLocal(0x14000ac6000?, {{0x105c553d0, 0x14000aaa680}, {{0x1400091e900, 0x6, 0x6}}, {0x105c678e0, 0x14000546460}, {0x0, 0x0}, ...}, ...)
	/Users/anjor/repos/go_workspace/pkg/mod/github.com/ipfs/[email protected]/requestmanager/reconciledloader/load.go:71 +0xa4
github.com/ipfs/go-graphsync/requestmanager/reconciledloader.(*ReconciledLoader).blockReadOpener(0x14000ac6000, {{0x105c553d0, 0x14000aaa680}, {{0x1400091e900, 0x6, 0x6}}, {0x105c678e0, 0x14000546460}, {0x0, 0x0}, ...}, ...)
	/Users/anjor/repos/go_workspace/pkg/mod/github.com/ipfs/[email protected]/requestmanager/reconciledloader/load.go:53 +0x298
github.com/ipfs/go-graphsync/requestmanager/reconciledloader.(*ReconciledLoader).BlockReadOpener(0x14000ac6000, {{0x105c553d0, 0x14000aaa680}, {{0x1400091e900, 0x6, 0x6}}, {0x105c678e0, 0x14000546460}, {0x0, 0x0}, ...}, ...)
	/Users/anjor/repos/go_workspace/pkg/mod/github.com/ipfs/[email protected]/requestmanager/reconciledloader/load.go:33 +0x150
github.com/ipfs/go-graphsync/requestmanager/reconciledloader.(*ReconciledLoader).RetryLastLoad(0x14000ac6000)
	/Users/anjor/repos/go_workspace/pkg/mod/github.com/ipfs/[email protected]/requestmanager/reconciledloader/reconciledloader.go:124 +0x1c4
github.com/ipfs/go-graphsync/requestmanager/executor.(*Executor).traverse(0x104a3ddbc?, {{0x105c553d0, 0x1400004e980}, {0x105c60fd8, 0x14000736320}, {{{0x140008fa000, 0x24}}, {0x105c681a0, 0x14000a8a160}, 0x0, ...}, ...})
	/Users/anjor/repos/go_workspace/pkg/mod/github.com/ipfs/[email protected]/requestmanager/executor/executor.go:144 +0x1f0
github.com/ipfs/go-graphsync/requestmanager/executor.(*Executor).ExecuteTask(0x14000509b00, {0x105c553d0, 0x14000563640}, {0x140006a6180, 0x26}, 0x1?)
	/Users/anjor/repos/go_workspace/pkg/mod/github.com/ipfs/[email protected]/requestmanager/executor/executor.go:83 +0x3a8
github.com/ipfs/go-graphsync/taskqueue.(*WorkerTaskQueue).worker(0x14000302190, {0x105c47e40, 0x14000509b00})
	/Users/anjor/repos/go_workspace/pkg/mod/github.com/ipfs/[email protected]/taskqueue/taskqueue.go:139 +0x458
created by github.com/ipfs/go-graphsync/taskqueue.(*WorkerTaskQueue).Startup
	/Users/anjor/repos/go_workspace/pkg/mod/github.com/ipfs/[email protected]/taskqueue/taskqueue.go:97 +0x38
anjor@seven lassie (main)*$

HTTP RequestLogger should accept io.Writer

The RequestLogger in the IPFS Handler should accept an io.Writer to allow for writing out to places other than stdout. This probably comes through all the way from the daemon CLI through an output flag that accepts a file location? There's a bigger conversation here around logging possibly going to stderr while CLI output goes to stdout by default. The daemon output flag would control the CLI output in this case.

support an operation mode that doesn't dial private IP addresses

There are reports from operators of Netscan detected and similar.

This is also present in IPFS nodes, and often comes from attempts to dial peers that have private-space ip addresses
(in this case the data center observed the VM attempting to dial into the 192.168.x.x and 10.x.x.x spaces)

  • there shouldn't be any multiaddrs returned from the indexer that are in these private address spaces (they are filtered out)
  • Perhaps upon connecting to peers as part of identify we learn the other addresses they claim to be listening on, and subsequent dials may attempt those?

this is likely a libp2p configuration tweak. we may want help from libp2p stewards to identify what the optimal configuration will be to limit our exposure to triggering this sort of issue.

Timeout requests in daemon

Goals

We want to avoid indefinite requests on extremely large data when running the HTTP daemon.

Implementation

This is dependent on the streaming CAR implementation being complete but:

  • in the Daemon, after a configurable amount of streamed data is exceeeded, close the connection
  • return status 206 (Partial Content) if possible (though maybe this isn't possible -- I'm not sure I understand HTTP :P)

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.