2024-03-15 21:38:13 +00:00
|
|
|
// Package deps provides the dependencies for the curio node.
|
2023-12-05 04:30:40 +00:00
|
|
|
package deps
|
|
|
|
|
|
|
|
import (
|
|
|
|
"context"
|
|
|
|
"database/sql"
|
|
|
|
"encoding/base64"
|
|
|
|
"errors"
|
|
|
|
"fmt"
|
2024-02-20 16:06:54 +00:00
|
|
|
"net"
|
|
|
|
"net/http"
|
2024-03-15 21:38:13 +00:00
|
|
|
"net/url"
|
2024-02-20 16:06:54 +00:00
|
|
|
"os"
|
2024-03-15 21:38:13 +00:00
|
|
|
"path/filepath"
|
2024-02-20 16:06:54 +00:00
|
|
|
"strings"
|
|
|
|
|
2023-12-15 00:13:44 +00:00
|
|
|
"github.com/BurntSushi/toml"
|
|
|
|
"github.com/gbrlsnchs/jwt/v3"
|
2023-12-05 04:30:40 +00:00
|
|
|
ds "github.com/ipfs/go-datastore"
|
|
|
|
dssync "github.com/ipfs/go-datastore/sync"
|
|
|
|
logging "github.com/ipfs/go-log/v2"
|
2024-03-15 21:38:13 +00:00
|
|
|
"github.com/samber/lo"
|
2023-12-15 00:13:44 +00:00
|
|
|
"github.com/urfave/cli/v2"
|
|
|
|
"golang.org/x/xerrors"
|
2023-12-05 04:30:40 +00:00
|
|
|
|
|
|
|
"github.com/filecoin-project/go-address"
|
|
|
|
"github.com/filecoin-project/go-jsonrpc/auth"
|
2024-02-23 10:53:49 +00:00
|
|
|
"github.com/filecoin-project/go-state-types/abi"
|
2023-12-05 04:30:40 +00:00
|
|
|
"github.com/filecoin-project/go-statestore"
|
2023-12-15 00:13:44 +00:00
|
|
|
|
2023-12-05 04:30:40 +00:00
|
|
|
"github.com/filecoin-project/lotus/api"
|
2024-03-15 21:38:13 +00:00
|
|
|
curio "github.com/filecoin-project/lotus/curiosrc"
|
|
|
|
"github.com/filecoin-project/lotus/curiosrc/multictladdr"
|
2023-12-05 04:30:40 +00:00
|
|
|
"github.com/filecoin-project/lotus/journal"
|
|
|
|
"github.com/filecoin-project/lotus/journal/alerting"
|
|
|
|
"github.com/filecoin-project/lotus/journal/fsjournal"
|
|
|
|
"github.com/filecoin-project/lotus/lib/harmony/harmonydb"
|
|
|
|
"github.com/filecoin-project/lotus/node/config"
|
2024-02-23 10:53:49 +00:00
|
|
|
"github.com/filecoin-project/lotus/node/modules"
|
2023-12-05 04:30:40 +00:00
|
|
|
"github.com/filecoin-project/lotus/node/modules/dtypes"
|
|
|
|
"github.com/filecoin-project/lotus/node/repo"
|
|
|
|
"github.com/filecoin-project/lotus/storage/paths"
|
|
|
|
"github.com/filecoin-project/lotus/storage/sealer"
|
|
|
|
"github.com/filecoin-project/lotus/storage/sealer/ffiwrapper"
|
|
|
|
"github.com/filecoin-project/lotus/storage/sealer/storiface"
|
|
|
|
)
|
|
|
|
|
2024-03-15 21:38:13 +00:00
|
|
|
var log = logging.Logger("curio/deps")
|
2023-12-05 04:30:40 +00:00
|
|
|
|
|
|
|
func MakeDB(cctx *cli.Context) (*harmonydb.DB, error) {
|
2024-03-15 21:38:13 +00:00
|
|
|
// #1 CLI opts
|
|
|
|
fromCLI := func() (*harmonydb.DB, error) {
|
|
|
|
dbConfig := config.HarmonyDB{
|
|
|
|
Username: cctx.String("db-user"),
|
|
|
|
Password: cctx.String("db-password"),
|
|
|
|
Hosts: strings.Split(cctx.String("db-host"), ","),
|
|
|
|
Database: cctx.String("db-name"),
|
|
|
|
Port: cctx.String("db-port"),
|
|
|
|
}
|
|
|
|
return harmonydb.NewFromConfig(dbConfig)
|
|
|
|
}
|
|
|
|
|
|
|
|
readToml := func(path string) (*harmonydb.DB, error) {
|
|
|
|
cfg, err := config.FromFile(path)
|
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
if c, ok := cfg.(*config.StorageMiner); ok {
|
|
|
|
return harmonydb.NewFromConfig(c.HarmonyDB)
|
|
|
|
}
|
|
|
|
return nil, errors.New("not a miner config")
|
|
|
|
}
|
|
|
|
|
|
|
|
// #2 Try local miner config
|
|
|
|
fromMinerEnv := func() (*harmonydb.DB, error) {
|
|
|
|
v := os.Getenv("LOTUS_MINER_PATH")
|
|
|
|
if v == "" {
|
|
|
|
return nil, errors.New("no miner env")
|
|
|
|
}
|
|
|
|
return readToml(filepath.Join(v, "config.toml"))
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
fromMiner := func() (*harmonydb.DB, error) {
|
|
|
|
u, err := os.UserHomeDir()
|
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
return readToml(filepath.Join(u, ".lotusminer/config.toml"))
|
|
|
|
}
|
|
|
|
fromEnv := func() (*harmonydb.DB, error) {
|
|
|
|
// #3 Try env
|
|
|
|
u, err := url.Parse(os.Getenv("CURIO_DB"))
|
|
|
|
if err != nil {
|
|
|
|
return nil, errors.New("no db connection string found in CURIO_DB env")
|
|
|
|
}
|
|
|
|
cfg := config.DefaultStorageMiner().HarmonyDB
|
|
|
|
if u.User.Username() != "" {
|
|
|
|
cfg.Username = u.User.Username()
|
|
|
|
}
|
|
|
|
if p, ok := u.User.Password(); ok && p != "" {
|
|
|
|
cfg.Password = p
|
|
|
|
}
|
|
|
|
if u.Hostname() != "" {
|
|
|
|
cfg.Hosts = []string{u.Hostname()}
|
|
|
|
}
|
|
|
|
if u.Port() != "" {
|
|
|
|
cfg.Port = u.Port()
|
|
|
|
}
|
|
|
|
if strings.TrimPrefix(u.Path, "/") != "" {
|
|
|
|
cfg.Database = strings.TrimPrefix(u.Path, "/")
|
|
|
|
}
|
|
|
|
|
|
|
|
return harmonydb.NewFromConfig(cfg)
|
|
|
|
}
|
|
|
|
|
|
|
|
for _, f := range []func() (*harmonydb.DB, error){fromCLI, fromMinerEnv, fromMiner, fromEnv} {
|
|
|
|
db, err := f()
|
|
|
|
if err != nil {
|
|
|
|
continue
|
|
|
|
}
|
|
|
|
return db, nil
|
|
|
|
}
|
|
|
|
log.Error("No db connection string found. User CLI args or env var: set CURIO_DB=postgres://USER:PASSWORD@HOST:PORT/DATABASE")
|
|
|
|
return fromCLI() //in-case it's not about bad config.
|
2023-12-05 04:30:40 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
type JwtPayload struct {
|
|
|
|
Allow []auth.Permission
|
|
|
|
}
|
|
|
|
|
|
|
|
func StorageAuth(apiKey string) (sealer.StorageAuth, error) {
|
|
|
|
if apiKey == "" {
|
|
|
|
return nil, xerrors.Errorf("no api key provided")
|
|
|
|
}
|
|
|
|
|
|
|
|
rawKey, err := base64.StdEncoding.DecodeString(apiKey)
|
|
|
|
if err != nil {
|
|
|
|
return nil, xerrors.Errorf("decoding api key: %w", err)
|
|
|
|
}
|
|
|
|
|
|
|
|
key := jwt.NewHS256(rawKey)
|
|
|
|
|
|
|
|
p := JwtPayload{
|
|
|
|
Allow: []auth.Permission{"admin"},
|
|
|
|
}
|
|
|
|
|
|
|
|
token, err := jwt.Sign(&p, key)
|
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
|
|
|
|
headers := http.Header{}
|
|
|
|
headers.Add("Authorization", "Bearer "+string(token))
|
|
|
|
return sealer.StorageAuth(headers), nil
|
|
|
|
}
|
|
|
|
|
2023-12-05 16:41:32 +00:00
|
|
|
func GetDeps(ctx context.Context, cctx *cli.Context) (*Deps, error) {
|
2023-12-12 03:10:15 +00:00
|
|
|
var deps Deps
|
|
|
|
return &deps, deps.PopulateRemainingDeps(ctx, cctx, true)
|
2023-12-05 16:41:32 +00:00
|
|
|
}
|
|
|
|
|
2023-12-05 04:30:40 +00:00
|
|
|
type Deps struct {
|
2024-03-15 21:38:13 +00:00
|
|
|
Cfg *config.CurioConfig // values
|
|
|
|
DB *harmonydb.DB // has itest capability
|
2023-12-05 04:30:40 +00:00
|
|
|
Full api.FullNode
|
|
|
|
Verif storiface.Verifier
|
|
|
|
LW *sealer.LocalWorker
|
2024-02-13 01:03:45 +00:00
|
|
|
As *multictladdr.MultiAddressSelector
|
|
|
|
Maddrs map[dtypes.MinerAddress]bool
|
2024-02-23 10:53:49 +00:00
|
|
|
ProofTypes map[abi.RegisteredSealProof]bool
|
2023-12-05 04:30:40 +00:00
|
|
|
Stor *paths.Remote
|
|
|
|
Si *paths.DBIndex
|
|
|
|
LocalStore *paths.Local
|
2024-02-08 12:27:46 +00:00
|
|
|
LocalPaths *paths.BasicLocalStorage
|
2023-12-05 04:30:40 +00:00
|
|
|
ListenAddr string
|
|
|
|
}
|
|
|
|
|
|
|
|
const (
|
|
|
|
FlagRepoPath = "repo-path"
|
|
|
|
)
|
|
|
|
|
|
|
|
func (deps *Deps) PopulateRemainingDeps(ctx context.Context, cctx *cli.Context, makeRepo bool) error {
|
|
|
|
var err error
|
|
|
|
if makeRepo {
|
|
|
|
// Open repo
|
|
|
|
repoPath := cctx.String(FlagRepoPath)
|
|
|
|
fmt.Println("repopath", repoPath)
|
|
|
|
r, err := repo.NewFS(repoPath)
|
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
|
|
|
|
ok, err := r.Exists()
|
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
if !ok {
|
2024-03-15 21:38:13 +00:00
|
|
|
if err := r.Init(repo.Curio); err != nil {
|
2023-12-05 04:30:40 +00:00
|
|
|
return err
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if deps.Cfg == nil {
|
|
|
|
deps.DB, err = MakeDB(cctx)
|
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if deps.Cfg == nil {
|
|
|
|
// The config feeds into task runners & their helpers
|
|
|
|
deps.Cfg, err = GetConfig(cctx, deps.DB)
|
|
|
|
if err != nil {
|
2024-02-17 12:01:19 +00:00
|
|
|
return xerrors.Errorf("populate config: %w", err)
|
2023-12-05 04:30:40 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
log.Debugw("config", "config", deps.Cfg)
|
|
|
|
|
|
|
|
if deps.Verif == nil {
|
|
|
|
deps.Verif = ffiwrapper.ProofVerifier
|
|
|
|
}
|
|
|
|
|
|
|
|
if deps.As == nil {
|
2024-03-15 21:38:13 +00:00
|
|
|
deps.As, err = curio.AddressSelector(deps.Cfg.Addresses)()
|
2023-12-05 04:30:40 +00:00
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if deps.Si == nil {
|
|
|
|
de, err := journal.ParseDisabledEvents(deps.Cfg.Journal.DisabledEvents)
|
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
j, err := fsjournal.OpenFSJournalPath(cctx.String("journal"), de)
|
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
2023-12-15 00:13:44 +00:00
|
|
|
go func() {
|
2023-12-05 04:30:40 +00:00
|
|
|
<-ctx.Done()
|
|
|
|
_ = j.Close()
|
|
|
|
}()
|
|
|
|
|
|
|
|
al := alerting.NewAlertingSystem(j)
|
|
|
|
deps.Si = paths.NewDBIndex(al, deps.DB)
|
|
|
|
}
|
|
|
|
|
|
|
|
if deps.Full == nil {
|
|
|
|
var fullCloser func()
|
2023-12-30 15:37:04 +00:00
|
|
|
cfgApiInfo := deps.Cfg.Apis.ChainApiInfo
|
|
|
|
if v := os.Getenv("FULLNODE_API_INFO"); v != "" {
|
|
|
|
cfgApiInfo = []string{v}
|
|
|
|
}
|
2024-03-15 21:38:13 +00:00
|
|
|
deps.Full, fullCloser, err = getFullNodeAPIV1Curio(cctx, cfgApiInfo)
|
2023-12-05 04:30:40 +00:00
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
|
|
|
|
go func() {
|
|
|
|
<-ctx.Done()
|
|
|
|
fullCloser()
|
|
|
|
}()
|
|
|
|
}
|
|
|
|
|
2024-02-08 12:27:46 +00:00
|
|
|
deps.LocalPaths = &paths.BasicLocalStorage{
|
2023-12-05 04:30:40 +00:00
|
|
|
PathToJSON: cctx.String("storage-json"),
|
|
|
|
}
|
|
|
|
|
|
|
|
if deps.ListenAddr == "" {
|
|
|
|
listenAddr := cctx.String("listen")
|
|
|
|
const unspecifiedAddress = "0.0.0.0"
|
|
|
|
addressSlice := strings.Split(listenAddr, ":")
|
|
|
|
if ip := net.ParseIP(addressSlice[0]); ip != nil {
|
|
|
|
if ip.String() == unspecifiedAddress {
|
|
|
|
rip, err := deps.DB.GetRoutableIP()
|
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
deps.ListenAddr = rip + ":" + addressSlice[1]
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if deps.LocalStore == nil {
|
2024-02-08 12:27:46 +00:00
|
|
|
deps.LocalStore, err = paths.NewLocal(ctx, deps.LocalPaths, deps.Si, []string{"http://" + deps.ListenAddr + "/remote"})
|
2023-12-05 04:30:40 +00:00
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
sa, err := StorageAuth(deps.Cfg.Apis.StorageRPCSecret)
|
|
|
|
if err != nil {
|
|
|
|
return xerrors.Errorf(`'%w' while parsing the config toml's
|
|
|
|
[Apis]
|
|
|
|
StorageRPCSecret=%v
|
|
|
|
Get it with: jq .PrivateKey ~/.lotus-miner/keystore/MF2XI2BNNJ3XILLQOJUXMYLUMU`, err, deps.Cfg.Apis.StorageRPCSecret)
|
|
|
|
}
|
|
|
|
if deps.Stor == nil {
|
|
|
|
deps.Stor = paths.NewRemote(deps.LocalStore, deps.Si, http.Header(sa), 10, &paths.DefaultPartialFileHandler{})
|
|
|
|
}
|
|
|
|
if deps.LW == nil {
|
|
|
|
wstates := statestore.New(dssync.MutexWrap(ds.NewMapDatastore()))
|
|
|
|
|
|
|
|
// todo localWorker isn't the abstraction layer we want to use here, we probably want to go straight to ffiwrapper
|
2024-03-15 21:38:13 +00:00
|
|
|
// maybe with a curio specific abstraction. LocalWorker does persistent call tracking which we probably
|
2023-12-05 04:30:40 +00:00
|
|
|
// don't need (ehh.. maybe we do, the async callback system may actually work decently well with harmonytask)
|
2024-02-18 19:04:02 +00:00
|
|
|
deps.LW = sealer.NewLocalWorker(sealer.WorkerConfig{
|
|
|
|
MaxParallelChallengeReads: deps.Cfg.Proving.ParallelCheckLimit,
|
|
|
|
}, deps.Stor, deps.LocalStore, deps.Si, nil, wstates)
|
2023-12-05 04:30:40 +00:00
|
|
|
}
|
2024-02-17 00:13:18 +00:00
|
|
|
if deps.Maddrs == nil {
|
|
|
|
deps.Maddrs = map[dtypes.MinerAddress]bool{}
|
|
|
|
}
|
2023-12-05 04:30:40 +00:00
|
|
|
if len(deps.Maddrs) == 0 {
|
2024-01-20 00:48:29 +00:00
|
|
|
for _, s := range deps.Cfg.Addresses {
|
|
|
|
for _, s := range s.MinerAddresses {
|
|
|
|
addr, err := address.NewFromString(s)
|
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
2024-02-13 01:03:45 +00:00
|
|
|
deps.Maddrs[dtypes.MinerAddress(addr)] = true
|
2023-12-05 04:30:40 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2024-03-05 09:03:49 +00:00
|
|
|
|
2024-02-23 10:53:49 +00:00
|
|
|
if deps.ProofTypes == nil {
|
|
|
|
deps.ProofTypes = map[abi.RegisteredSealProof]bool{}
|
|
|
|
}
|
|
|
|
if len(deps.ProofTypes) == 0 {
|
|
|
|
for maddr := range deps.Maddrs {
|
|
|
|
spt, err := modules.SealProofType(maddr, deps.Full)
|
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
deps.ProofTypes[spt] = true
|
|
|
|
}
|
|
|
|
}
|
2024-02-27 18:47:58 +00:00
|
|
|
|
2023-12-05 04:30:40 +00:00
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
2024-03-15 21:38:13 +00:00
|
|
|
func LoadConfigWithUpgrades(text string, curioConfigWithDefaults *config.CurioConfig) (toml.MetaData, error) {
|
2024-01-30 22:44:08 +00:00
|
|
|
// allow migration from old config format that was limited to 1 wallet setup.
|
2024-03-15 21:38:13 +00:00
|
|
|
newText := strings.Join(lo.Map(strings.Split(text, "\n"), func(line string, _ int) string {
|
|
|
|
if strings.EqualFold(line, "[addresses]") {
|
|
|
|
return "[[addresses]]"
|
|
|
|
}
|
|
|
|
return line
|
|
|
|
}), "\n")
|
|
|
|
meta, err := toml.Decode(newText, &curioConfigWithDefaults)
|
|
|
|
for i := range curioConfigWithDefaults.Addresses {
|
|
|
|
if curioConfigWithDefaults.Addresses[i].PreCommitControl == nil {
|
|
|
|
curioConfigWithDefaults.Addresses[i].PreCommitControl = []string{}
|
|
|
|
}
|
|
|
|
if curioConfigWithDefaults.Addresses[i].CommitControl == nil {
|
|
|
|
curioConfigWithDefaults.Addresses[i].CommitControl = []string{}
|
|
|
|
}
|
|
|
|
if curioConfigWithDefaults.Addresses[i].TerminateControl == nil {
|
|
|
|
curioConfigWithDefaults.Addresses[i].TerminateControl = []string{}
|
|
|
|
}
|
2024-02-17 12:01:19 +00:00
|
|
|
}
|
2024-01-30 22:44:08 +00:00
|
|
|
return meta, err
|
|
|
|
}
|
2024-03-15 21:38:13 +00:00
|
|
|
func GetConfig(cctx *cli.Context, db *harmonydb.DB) (*config.CurioConfig, error) {
|
|
|
|
curioConfig := config.DefaultCurioConfig()
|
2023-12-05 04:30:40 +00:00
|
|
|
have := []string{}
|
2024-03-06 09:41:37 +00:00
|
|
|
layers := append([]string{"base"}, cctx.StringSlice("layers")...) // Always stack on top of "base" layer
|
2023-12-05 04:30:40 +00:00
|
|
|
for _, layer := range layers {
|
|
|
|
text := ""
|
|
|
|
err := db.QueryRow(cctx.Context, `SELECT config FROM harmony_config WHERE title=$1`, layer).Scan(&text)
|
|
|
|
if err != nil {
|
|
|
|
if strings.Contains(err.Error(), sql.ErrNoRows.Error()) {
|
|
|
|
return nil, fmt.Errorf("missing layer '%s' ", layer)
|
|
|
|
}
|
|
|
|
if layer == "base" {
|
2024-03-15 21:38:13 +00:00
|
|
|
return nil, errors.New(`curio defaults to a layer named 'base'.
|
|
|
|
Either use 'migrate' command or edit a base.toml and upload it with: curio config set base.toml`)
|
2023-12-05 04:30:40 +00:00
|
|
|
}
|
|
|
|
return nil, fmt.Errorf("could not read layer '%s': %w", layer, err)
|
|
|
|
}
|
2024-01-20 00:48:29 +00:00
|
|
|
|
2024-03-15 21:38:13 +00:00
|
|
|
meta, err := LoadConfigWithUpgrades(text, curioConfig)
|
2023-12-05 04:30:40 +00:00
|
|
|
if err != nil {
|
2024-03-15 21:38:13 +00:00
|
|
|
return curioConfig, fmt.Errorf("could not read layer, bad toml %s: %w", layer, err)
|
2023-12-05 04:30:40 +00:00
|
|
|
}
|
|
|
|
for _, k := range meta.Keys() {
|
|
|
|
have = append(have, strings.Join(k, " "))
|
|
|
|
}
|
2024-04-03 16:31:43 +00:00
|
|
|
log.Debugw("Using layer", "layer", layer, "config", curioConfig)
|
2023-12-05 04:30:40 +00:00
|
|
|
}
|
|
|
|
_ = have // FUTURE: verify that required fields are here.
|
|
|
|
// If config includes 3rd-party config, consider JSONSchema as a way that
|
|
|
|
// 3rd-parties can dynamically include config requirements and we can
|
|
|
|
// validate the config. Because of layering, we must validate @ startup.
|
2024-03-15 21:38:13 +00:00
|
|
|
return curioConfig, nil
|
|
|
|
}
|
|
|
|
|
|
|
|
func GetDefaultConfig(comment bool) (string, error) {
|
|
|
|
c := config.DefaultCurioConfig()
|
|
|
|
cb, err := config.ConfigUpdate(c, nil, config.Commented(comment), config.DefaultKeepUncommented(), config.NoEnv())
|
|
|
|
if err != nil {
|
|
|
|
return "", err
|
|
|
|
}
|
|
|
|
return string(cb), nil
|
2023-12-05 04:30:40 +00:00
|
|
|
}
|
2023-12-18 11:02:48 +00:00
|
|
|
|
|
|
|
func GetDepsCLI(ctx context.Context, cctx *cli.Context) (*Deps, error) {
|
|
|
|
db, err := MakeDB(cctx)
|
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
|
|
|
|
cfg, err := GetConfig(cctx, db)
|
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
|
2024-03-15 21:38:13 +00:00
|
|
|
full, fullCloser, err := getFullNodeAPIV1Curio(cctx, cfg.Apis.ChainApiInfo)
|
2023-12-18 11:02:48 +00:00
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
go func() {
|
|
|
|
select {
|
|
|
|
case <-ctx.Done():
|
|
|
|
fullCloser()
|
|
|
|
}
|
|
|
|
}()
|
|
|
|
|
|
|
|
return &Deps{
|
|
|
|
Cfg: cfg,
|
|
|
|
DB: db,
|
|
|
|
Full: full,
|
|
|
|
}, nil
|
|
|
|
}
|