Merge remote-tracking branch 'origin/master' into feat/lpdeal-cache

This commit is contained in:
Łukasz Magiera
2024-03-17 17:31:26 +01:00
134 changed files with 6328 additions and 1977 deletions
@@ -18,8 +18,8 @@ import (
"github.com/filecoin-project/lotus/api"
lcli "github.com/filecoin-project/lotus/cli"
"github.com/filecoin-project/lotus/cmd/lotus-provider/deps"
"github.com/filecoin-project/lotus/cmd/lotus-provider/rpc"
"github.com/filecoin-project/lotus/cmd/curio/deps"
"github.com/filecoin-project/lotus/cmd/curio/rpc"
)
const providerEnvVar = "PROVIDER_API_INFO"
@@ -177,7 +177,7 @@ var cliCmd = &cli.Command{
}
{
api, closer, err := rpc.GetProviderAPI(cctx)
api, closer, err := rpc.GetCurioAPI(cctx)
if err != nil {
return err
}
@@ -15,7 +15,7 @@ import (
"github.com/urfave/cli/v2"
"golang.org/x/xerrors"
"github.com/filecoin-project/lotus/cmd/lotus-provider/deps"
"github.com/filecoin-project/lotus/cmd/curio/deps"
"github.com/filecoin-project/lotus/lib/harmony/harmonydb"
"github.com/filecoin-project/lotus/node/config"
)
@@ -48,7 +48,7 @@ var configDefaultCmd = &cli.Command{
},
Action: func(cctx *cli.Context) error {
comment := !cctx.Bool("no-comment")
cfg, err := getDefaultConfig(comment)
cfg, err := deps.GetDefaultConfig(comment)
if err != nil {
return err
}
@@ -58,15 +58,6 @@ var configDefaultCmd = &cli.Command{
},
}
func getDefaultConfig(comment bool) (string, error) {
c := config.DefaultLotusProvider()
cb, err := config.ConfigUpdate(c, nil, config.Commented(comment), config.DefaultKeepUncommented(), config.NoEnv())
if err != nil {
return "", err
}
return string(cb), nil
}
var configSetCmd = &cli.Command{
Name: "set",
Aliases: []string{"add", "update", "create"},
@@ -106,12 +97,12 @@ var configSetCmd = &cli.Command{
return fmt.Errorf("cannot read stream/file %w", err)
}
lp := config.DefaultLotusProvider() // ensure it's toml
_, err = deps.LoadConfigWithUpgrades(string(bytes), lp)
curioConfig := config.DefaultCurioConfig() // ensure it's toml
_, err = deps.LoadConfigWithUpgrades(string(bytes), curioConfig)
if err != nil {
return fmt.Errorf("cannot decode file: %w", err)
}
_ = lp
_ = curioConfig
err = setConfig(db, name, string(bytes))
@@ -216,7 +207,7 @@ var configRmCmd = &cli.Command{
var configViewCmd = &cli.Command{
Name: "interpret",
Aliases: []string{"view", "stacked", "stack"},
Usage: "Interpret stacked config layers by this version of lotus-provider, with system-generated comments.",
Usage: "Interpret stacked config layers by this version of curio, with system-generated comments.",
ArgsUsage: "a list of layers to be interpreted as the final config",
Flags: []cli.Flag{
&cli.StringSliceFlag{
@@ -230,11 +221,11 @@ var configViewCmd = &cli.Command{
if err != nil {
return err
}
lp, err := deps.GetConfig(cctx, db)
curioConfig, err := deps.GetConfig(cctx, db)
if err != nil {
return err
}
cb, err := config.ConfigUpdate(lp, config.DefaultLotusProvider(), config.Commented(true), config.DefaultKeepUncommented(), config.NoEnv())
cb, err := config.ConfigUpdate(curioConfig, config.DefaultCurioConfig(), config.Commented(true), config.DefaultKeepUncommented(), config.NoEnv())
if err != nil {
return xerrors.Errorf("cannot interpret config: %w", err)
}
@@ -299,12 +290,12 @@ var configEditCmd = &cli.Command{
}
if cctx.IsSet("source") && source != layer && !cctx.Bool("no-interpret-source") {
lp := config.DefaultLotusProvider()
lp := config.DefaultCurioConfig()
if _, err := toml.Decode(sourceConfig, lp); err != nil {
return xerrors.Errorf("parsing source config: %w", err)
}
cb, err := config.ConfigUpdate(lp, config.DefaultLotusProvider(), config.Commented(true), config.DefaultKeepUncommented(), config.NoEnv())
cb, err := config.ConfigUpdate(lp, config.DefaultCurioConfig(), config.Commented(true), config.DefaultKeepUncommented(), config.NoEnv())
if err != nil {
return xerrors.Errorf("interpreting source config: %w", err)
}
@@ -362,9 +353,18 @@ var configEditCmd = &cli.Command{
},
}
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
}
func diff(sourceConf, newConf string) (string, error) {
lpSrc := config.DefaultLotusProvider()
lpNew := config.DefaultLotusProvider()
lpSrc := config.DefaultCurioConfig()
lpNew := config.DefaultCurioConfig()
_, err := toml.Decode(sourceConf, lpSrc)
if err != nil {
@@ -18,7 +18,7 @@ import (
"github.com/filecoin-project/lotus/api"
"github.com/filecoin-project/lotus/chain/types"
cliutil "github.com/filecoin-project/lotus/cli/util"
"github.com/filecoin-project/lotus/cmd/lotus-provider/deps"
"github.com/filecoin-project/lotus/cmd/curio/deps"
"github.com/filecoin-project/lotus/node/config"
"github.com/filecoin-project/lotus/node/repo"
)
@@ -73,7 +73,7 @@ var configNewCmd = &cli.Command{
msg := "Layer " + configColor(name) + ` created. `
// setup config
lpCfg := config.DefaultLotusProvider()
lpCfg := config.DefaultCurioConfig()
for _, addr := range cctx.Args().Slice() {
maddr, err := address.NewFromString(addr)
@@ -86,7 +86,7 @@ var configNewCmd = &cli.Command{
return xerrors.Errorf("Failed to get miner info: %w", err)
}
lpCfg.Addresses = append(lpCfg.Addresses, config.LotusProviderAddresses{
lpCfg.Addresses = append(lpCfg.Addresses, config.CurioAddresses{
PreCommitControl: nil,
CommitControl: nil,
TerminateControl: nil,
+94
View File
@@ -0,0 +1,94 @@
package deps
import (
"fmt"
"net/http"
"github.com/urfave/cli/v2"
"golang.org/x/xerrors"
"github.com/filecoin-project/go-jsonrpc"
"github.com/filecoin-project/lotus/api"
"github.com/filecoin-project/lotus/api/client"
"github.com/filecoin-project/lotus/api/v1api"
cliutil "github.com/filecoin-project/lotus/cli/util"
)
func getFullNodeAPIV1Curio(ctx *cli.Context, ainfoCfg []string, opts ...cliutil.GetFullNodeOption) (v1api.FullNode, jsonrpc.ClientCloser, error) {
if tn, ok := ctx.App.Metadata["testnode-full"]; ok {
return tn.(v1api.FullNode), func() {}, nil
}
var options cliutil.GetFullNodeOptions
for _, opt := range opts {
opt(&options)
}
var rpcOpts []jsonrpc.Option
if options.EthSubHandler != nil {
rpcOpts = append(rpcOpts, jsonrpc.WithClientHandler("Filecoin", options.EthSubHandler), jsonrpc.WithClientHandlerAlias("eth_subscription", "Filecoin.EthSubscription"))
}
var httpHeads []httpHead
version := "v1"
{
if len(ainfoCfg) == 0 {
return nil, nil, xerrors.Errorf("could not get API info: none configured. \nConsider getting base.toml with './curio config get base >/tmp/base.toml' \nthen adding \n[APIs] \n ChainApiInfo = [\" result_from lotus auth api-info --perm=admin \"]\n and updating it with './curio config set /tmp/base.toml'")
}
for _, i := range ainfoCfg {
ainfo := cliutil.ParseApiInfo(i)
addr, err := ainfo.DialArgs(version)
if err != nil {
return nil, nil, xerrors.Errorf("could not get DialArgs: %w", err)
}
httpHeads = append(httpHeads, httpHead{addr: addr, header: ainfo.AuthHeader()})
}
}
if cliutil.IsVeryVerbose {
_, _ = fmt.Fprintln(ctx.App.Writer, "using full node API v1 endpoint:", httpHeads[0].addr)
}
var fullNodes []api.FullNode
var closers []jsonrpc.ClientCloser
for _, head := range httpHeads {
v1api, closer, err := client.NewFullNodeRPCV1(ctx.Context, head.addr, head.header, rpcOpts...)
if err != nil {
log.Warnf("Not able to establish connection to node with addr: %s, Reason: %s", head.addr, err.Error())
continue
}
fullNodes = append(fullNodes, v1api)
closers = append(closers, closer)
}
// When running in cluster mode and trying to establish connections to multiple nodes, fail
// if less than 2 lotus nodes are actually running
if len(httpHeads) > 1 && len(fullNodes) < 2 {
return nil, nil, xerrors.Errorf("Not able to establish connection to more than a single node")
}
finalCloser := func() {
for _, c := range closers {
c()
}
}
var v1API api.FullNodeStruct
cliutil.FullNodeProxy(fullNodes, &v1API)
v, err := v1API.Version(ctx.Context)
if err != nil {
return nil, nil, err
}
if !v.APIVersion.EqMajorMinor(api.FullAPIVersion1) {
return nil, nil, xerrors.Errorf("Remote API version didn't match (expected %s, remote %s)", api.FullAPIVersion1, v.APIVersion)
}
return &v1API, finalCloser, nil
}
type httpHead struct {
addr string
header http.Header
}
@@ -1,4 +1,4 @@
// Package deps provides the dependencies for the lotus provider node.
// Package deps provides the dependencies for the curio node.
package deps
import (
@@ -9,8 +9,9 @@ import (
"fmt"
"net"
"net/http"
"net/url"
"os"
"regexp"
"path/filepath"
"strings"
"github.com/BurntSushi/toml"
@@ -18,6 +19,7 @@ import (
ds "github.com/ipfs/go-datastore"
dssync "github.com/ipfs/go-datastore/sync"
logging "github.com/ipfs/go-log/v2"
"github.com/samber/lo"
"github.com/urfave/cli/v2"
"golang.org/x/xerrors"
@@ -27,7 +29,8 @@ import (
"github.com/filecoin-project/go-statestore"
"github.com/filecoin-project/lotus/api"
cliutil "github.com/filecoin-project/lotus/cli/util"
curio "github.com/filecoin-project/lotus/curiosrc"
"github.com/filecoin-project/lotus/curiosrc/multictladdr"
"github.com/filecoin-project/lotus/journal"
"github.com/filecoin-project/lotus/journal/alerting"
"github.com/filecoin-project/lotus/journal/fsjournal"
@@ -36,25 +39,90 @@ import (
"github.com/filecoin-project/lotus/node/modules"
"github.com/filecoin-project/lotus/node/modules/dtypes"
"github.com/filecoin-project/lotus/node/repo"
"github.com/filecoin-project/lotus/provider"
"github.com/filecoin-project/lotus/provider/multictladdr"
"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"
)
var log = logging.Logger("lotus-provider/deps")
var log = logging.Logger("curio/deps")
func MakeDB(cctx *cli.Context) (*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"),
// #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)
}
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.
}
type JwtPayload struct {
@@ -93,8 +161,8 @@ func GetDeps(ctx context.Context, cctx *cli.Context) (*Deps, error) {
}
type Deps struct {
Cfg *config.LotusProviderConfig
DB *harmonydb.DB
Cfg *config.CurioConfig // values
DB *harmonydb.DB // has itest capability
Full api.FullNode
Verif storiface.Verifier
LW *sealer.LocalWorker
@@ -128,7 +196,7 @@ func (deps *Deps) PopulateRemainingDeps(ctx context.Context, cctx *cli.Context,
return err
}
if !ok {
if err := r.Init(repo.Provider); err != nil {
if err := r.Init(repo.Curio); err != nil {
return err
}
}
@@ -156,7 +224,7 @@ func (deps *Deps) PopulateRemainingDeps(ctx context.Context, cctx *cli.Context,
}
if deps.As == nil {
deps.As, err = provider.AddressSelector(deps.Cfg.Addresses)()
deps.As, err = curio.AddressSelector(deps.Cfg.Addresses)()
if err != nil {
return err
}
@@ -186,7 +254,7 @@ func (deps *Deps) PopulateRemainingDeps(ctx context.Context, cctx *cli.Context,
if v := os.Getenv("FULLNODE_API_INFO"); v != "" {
cfgApiInfo = []string{v}
}
deps.Full, fullCloser, err = cliutil.GetFullNodeAPIV1LotusProvider(cctx, cfgApiInfo)
deps.Full, fullCloser, err = getFullNodeAPIV1Curio(cctx, cfgApiInfo)
if err != nil {
return err
}
@@ -236,7 +304,7 @@ Get it with: jq .PrivateKey ~/.lotus-miner/keystore/MF2XI2BNNJ3XILLQOJUXMYLUMU`,
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
// maybe with a lotus-provider specific abstraction. LocalWorker does persistent call tracking which we probably
// maybe with a curio specific abstraction. LocalWorker does persistent call tracking which we probably
// don't need (ehh.. maybe we do, the async callback system may actually work decently well with harmonytask)
deps.LW = sealer.NewLocalWorker(sealer.WorkerConfig{
MaxParallelChallengeReads: deps.Cfg.Proving.ParallelCheckLimit,
@@ -273,21 +341,30 @@ Get it with: jq .PrivateKey ~/.lotus-miner/keystore/MF2XI2BNNJ3XILLQOJUXMYLUMU`,
return nil
}
var oldAddresses = regexp.MustCompile("(?i)^\\[addresses\\]$")
func LoadConfigWithUpgrades(text string, lp *config.LotusProviderConfig) (toml.MetaData, error) {
func LoadConfigWithUpgrades(text string, curioConfigWithDefaults *config.CurioConfig) (toml.MetaData, error) {
// allow migration from old config format that was limited to 1 wallet setup.
newText := oldAddresses.ReplaceAllString(text, "[[addresses]]")
if text != newText {
log.Warnw("Upgraded config!", "old", text, "new", newText)
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{}
}
}
meta, err := toml.Decode(newText, &lp)
return meta, err
}
func GetConfig(cctx *cli.Context, db *harmonydb.DB) (*config.LotusProviderConfig, error) {
lp := config.DefaultLotusProvider()
func GetConfig(cctx *cli.Context, db *harmonydb.DB) (*config.CurioConfig, error) {
curioConfig := config.DefaultCurioConfig()
have := []string{}
layers := append([]string{"base"}, cctx.StringSlice("layers")...) // Always stack on top of "base" layer
for _, layer := range layers {
@@ -298,26 +375,35 @@ func GetConfig(cctx *cli.Context, db *harmonydb.DB) (*config.LotusProviderConfig
return nil, fmt.Errorf("missing layer '%s' ", layer)
}
if layer == "base" {
return nil, errors.New(`lotus-provider defaults to a layer named 'base'.
Either use 'migrate' command or edit a base.toml and upload it with: lotus-provider config set base.toml`)
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`)
}
return nil, fmt.Errorf("could not read layer '%s': %w", layer, err)
}
meta, err := LoadConfigWithUpgrades(text, lp)
meta, err := LoadConfigWithUpgrades(text, curioConfig)
if err != nil {
return lp, fmt.Errorf("could not read layer, bad toml %s: %w", layer, err)
return curioConfig, fmt.Errorf("could not read layer, bad toml %s: %w", layer, err)
}
for _, k := range meta.Keys() {
have = append(have, strings.Join(k, " "))
}
log.Infow("Using layer", "layer", layer, "config", lp)
log.Infow("Using layer", "layer", layer, "config", curioConfig)
}
_ = 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.
return lp, nil
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
}
func GetDepsCLI(ctx context.Context, cctx *cli.Context) (*Deps, error) {
@@ -331,7 +417,7 @@ func GetDepsCLI(ctx context.Context, cctx *cli.Context) (*Deps, error) {
return nil, err
}
full, fullCloser, err := cliutil.GetFullNodeAPIV1LotusProvider(cctx, cfg.Apis.ChainApiInfo)
full, fullCloser, err := getFullNodeAPIV1Curio(cctx, cfg.Apis.ChainApiInfo)
if err != nil {
return nil, err
}
+590
View File
@@ -0,0 +1,590 @@
// guidedSetup for migration from lotus-miner to Curio
//
// IF STRINGS CHANGED {
// follow instructions at ../internal/translations/translations.go
// }
package guidedsetup
import (
"bytes"
"context"
"encoding/base64"
"encoding/json"
"fmt"
"io"
"math/bits"
"net/http"
"os"
"os/signal"
"path"
"reflect"
"strings"
"syscall"
"time"
"github.com/BurntSushi/toml"
"github.com/charmbracelet/lipgloss"
"github.com/manifoldco/promptui"
"github.com/mitchellh/go-homedir"
"github.com/samber/lo"
"github.com/urfave/cli/v2"
"golang.org/x/text/language"
"golang.org/x/text/message"
"github.com/filecoin-project/go-address"
"github.com/filecoin-project/go-jsonrpc"
"github.com/filecoin-project/lotus/api"
"github.com/filecoin-project/lotus/api/v0api"
"github.com/filecoin-project/lotus/build"
"github.com/filecoin-project/lotus/chain/types"
cliutil "github.com/filecoin-project/lotus/cli/util"
_ "github.com/filecoin-project/lotus/cmd/curio/internal/translations"
"github.com/filecoin-project/lotus/lib/harmony/harmonydb"
"github.com/filecoin-project/lotus/node/config"
"github.com/filecoin-project/lotus/node/repo"
)
// URL to upload user-selected fields to help direct developer's focus.
const DeveloperFocusRequestURL = "https://curiostorage.org/cgi-bin/savedata.php"
var GuidedsetupCmd = &cli.Command{
Name: "guided-setup",
Usage: "Run the guided setup for migrating from lotus-miner to Curio",
Flags: []cli.Flag{
&cli.StringFlag{ // for cliutil.GetFullNodeAPI
Name: "repo",
EnvVars: []string{"LOTUS_PATH"},
Hidden: true,
Value: "~/.lotus",
},
},
Action: func(cctx *cli.Context) (err error) {
T, say := SetupLanguage()
setupCtrlC(say)
say(header, "This interactive tool migrates lotus-miner to Curio in 5 minutes.")
say(notice, "Each step needs your confirmation and can be reversed. Press Ctrl+C to exit at any time.")
// Run the migration steps
migrationData := MigrationData{
T: T,
say: say,
selectTemplates: &promptui.SelectTemplates{
Help: T("Use the arrow keys to navigate: ↓ ↑ → ← "),
},
cctx: cctx,
}
for _, step := range migrationSteps {
step(&migrationData)
}
for _, closer := range migrationData.closers {
closer()
}
return nil
},
}
func setupCtrlC(say func(style lipgloss.Style, key message.Reference, a ...interface{})) {
c := make(chan os.Signal, 1)
signal.Notify(c, os.Interrupt, syscall.SIGTERM)
go func() {
<-c
say(notice, "Ctrl+C pressed in Terminal")
os.Exit(2)
}()
}
var (
header = lipgloss.NewStyle().
Align(lipgloss.Left).
Foreground(lipgloss.Color("#00FF00")).
Background(lipgloss.Color("#242424")).
BorderStyle(lipgloss.NormalBorder()).
Width(60).Margin(1)
notice = lipgloss.NewStyle().
Align(lipgloss.Left).
Bold(true).
Foreground(lipgloss.Color("#CCCCCC")).
Background(lipgloss.Color("#333300")).MarginBottom(1)
green = lipgloss.NewStyle().
Align(lipgloss.Left).
Foreground(lipgloss.Color("#00FF00")).
Background(lipgloss.Color("#000000"))
plain = lipgloss.NewStyle().Align(lipgloss.Left)
section = lipgloss.NewStyle().
Align(lipgloss.Left).
Foreground(lipgloss.Color("#000000")).
Background(lipgloss.Color("#FFFFFF")).
Underline(true)
code = lipgloss.NewStyle().
Align(lipgloss.Left).
Foreground(lipgloss.Color("#00FF00")).
Background(lipgloss.Color("#f8f9fa"))
)
func SetupLanguage() (func(key message.Reference, a ...interface{}) string, func(style lipgloss.Style, key message.Reference, a ...interface{})) {
langText := "en"
problem := false
if len(os.Getenv("LANG")) > 1 {
langText = os.Getenv("LANG")[:2]
} else {
problem = true
}
lang, err := language.Parse(langText)
if err != nil {
lang = language.English
problem = true
fmt.Println("Error parsing language")
}
langs := message.DefaultCatalog.Languages()
have := lo.SliceToMap(langs, func(t language.Tag) (string, bool) { return t.String(), true })
if _, ok := have[lang.String()]; !ok {
lang = language.English
problem = true
}
if problem {
_ = os.Setenv("LANG", "en-US") // for later users of this function
notice.Copy().AlignHorizontal(lipgloss.Right).
Render("$LANG=" + langText + " unsupported. Available: " + strings.Join(lo.Keys(have), ", "))
fmt.Println("Defaulting to English. Please reach out to the Curio team if you would like to have additional language support.")
}
return func(key message.Reference, a ...interface{}) string {
return message.NewPrinter(lang).Sprintf(key, a...)
}, func(sty lipgloss.Style, key message.Reference, a ...interface{}) {
msg := message.NewPrinter(lang).Sprintf(key, a...)
fmt.Println(sty.Render(msg))
}
}
type migrationStep func(*MigrationData)
var migrationSteps = []migrationStep{
readMinerConfig, // Tells them to be on the miner machine
yugabyteConnect, // Miner is updated
configToDB, // work on base configuration migration.
verifySectors, // Verify the sectors are in the database
doc,
oneLastThing,
complete,
}
type MigrationData struct {
T func(key message.Reference, a ...interface{}) string
say func(style lipgloss.Style, key message.Reference, a ...interface{})
selectTemplates *promptui.SelectTemplates
MinerConfigPath string
MinerConfig *config.StorageMiner
DB *harmonydb.DB
MinerID address.Address
full v0api.FullNode
cctx *cli.Context
closers []jsonrpc.ClientCloser
}
func complete(d *MigrationData) {
stepCompleted(d, d.T("Lotus-Miner to Curio Migration."))
d.say(plain, "Try the web interface with %s for further guided improvements.", "--layers=gui")
d.say(plain, "You can now migrate your market node (%s), if applicable.", "Boost")
}
func configToDB(d *MigrationData) {
d.say(section, "Migrating lotus-miner config.toml to Curio in-database configuration.")
{
var closer jsonrpc.ClientCloser
var err error
d.full, closer, err = cliutil.GetFullNodeAPI(d.cctx)
d.closers = append(d.closers, closer)
if err != nil {
d.say(notice, "Error getting API: %s", err.Error())
os.Exit(1)
}
}
ainfo, err := cliutil.GetAPIInfo(d.cctx, repo.FullNode)
if err != nil {
d.say(notice, "could not get API info for FullNode: %w", err)
os.Exit(1)
}
token, err := d.full.AuthNew(context.Background(), api.AllPermissions)
if err != nil {
d.say(notice, "Error getting token: %s", err.Error())
os.Exit(1)
}
chainApiInfo := fmt.Sprintf("%s:%s", string(token), ainfo.Addr)
d.MinerID, err = SaveConfigToLayer(d.MinerConfigPath, "", false, chainApiInfo)
if err != nil {
d.say(notice, "Error saving config to layer: %s. Aborting Migration", err.Error())
os.Exit(1)
}
}
// bucket returns the power's 4 highest bits (rounded down).
func bucket(power *api.MinerPower) uint64 {
rawQAP := power.TotalPower.QualityAdjPower.Uint64()
magnitude := lo.Max([]int{bits.Len64(rawQAP), 5})
// shifting erases resolution so we cannot distinguish SPs of similar scales.
return rawQAP >> (uint64(magnitude) - 4) << (uint64(magnitude - 4))
}
type uploadType int
const uploadTypeIndividual uploadType = 0
const uploadTypeAggregate uploadType = 1
// const uploadTypeHint uploadType = 2
const uploadTypeNothing uploadType = 3
func oneLastThing(d *MigrationData) {
d.say(section, "The Curio team wants to improve the software you use. Tell the team you're using `%s`.", "curio")
i, _, err := (&promptui.Select{
Label: d.T("Select what you want to share with the Curio team."),
Items: []string{
d.T("Individual Data: Miner ID, Curio version, chain (%s or %s). Signed.", "mainnet", "calibration"),
d.T("Aggregate-Anonymous: version, chain, and Miner power (bucketed)."),
d.T("Hint: I am someone running Curio on whichever chain."),
d.T("Nothing.")},
Templates: d.selectTemplates,
}).Run()
preference := uploadType(i)
if err != nil {
d.say(notice, "Aborting remaining steps.", err.Error())
os.Exit(1)
}
if preference != uploadTypeNothing {
msgMap := map[string]any{
"domain": "curio-newuser",
"net": build.BuildTypeString(),
}
if preference == uploadTypeIndividual || preference == uploadTypeAggregate {
// articles of incorporation
power, err := d.full.StateMinerPower(context.Background(), d.MinerID, types.EmptyTSK)
if err != nil {
d.say(notice, "Error getting miner power: %s", err.Error())
os.Exit(1)
}
msgMap["version"] = build.BuildVersion
msgMap["net"] = build.BuildType
msgMap["power"] = map[uploadType]uint64{
uploadTypeIndividual: power.MinerPower.QualityAdjPower.Uint64(),
uploadTypeAggregate: bucket(power)}[preference]
if preference == uploadTypeIndividual { // Sign it
msgMap["miner_id"] = d.MinerID
msg, err := json.Marshal(msgMap)
if err != nil {
d.say(notice, "Error marshalling message: %s", err.Error())
os.Exit(1)
}
mi, err := d.full.StateMinerInfo(context.Background(), d.MinerID, types.EmptyTSK)
if err != nil {
d.say(notice, "Error getting miner info: %s", err.Error())
os.Exit(1)
}
sig, err := d.full.WalletSign(context.Background(), mi.Worker, msg)
if err != nil {
d.say(notice, "Error signing message: %s", err.Error())
os.Exit(1)
}
msgMap["signature"] = base64.StdEncoding.EncodeToString(sig.Data)
}
}
msg, err := json.Marshal(msgMap)
if err != nil {
d.say(notice, "Error marshalling message: %s", err.Error())
os.Exit(1)
}
resp, err := http.DefaultClient.Post(DeveloperFocusRequestURL, "application/json", bytes.NewReader(msg))
if err != nil {
d.say(notice, "Error sending message: %s", err.Error())
}
if resp != nil {
defer func() { _ = resp.Body.Close() }()
if resp.StatusCode != 200 {
b, err := io.ReadAll(resp.Body)
if err == nil {
d.say(notice, "Error sending message: Status %s, Message: ", resp.Status, string(b))
}
} else {
stepCompleted(d, d.T("Message sent."))
}
}
}
}
func doc(d *MigrationData) {
d.say(plain, "Documentation: ")
d.say(plain, "The '%s' layer stores common configuration. All curio instances can include it in their %s argument.", "base", "--layers")
d.say(plain, "You can add other layers for per-machine configuration changes.")
d.say(plain, "Filecoin %s channels: %s and %s", "Slack", "#fil-curio-help", "#fil-curio-dev")
d.say(plain, "Start multiple Curio instances with the '%s' layer to redundancy.", "post")
//d.say(plain, "Point your browser to your web GUI to complete setup with %s and advanced featues.", "Boost")
d.say(plain, "One database can serve multiple miner IDs: Run a migration for each lotus-miner.")
}
func verifySectors(d *MigrationData) {
var i []int
var lastError string
fmt.Println()
d.say(section, "Please start (or restart) %s now that database credentials are in %s.", "lotus-miner", "config.toml")
d.say(notice, "Waiting for %s to write sectors into Yugabyte.", "lotus-miner")
mid, err := address.IDFromAddress(d.MinerID)
if err != nil {
d.say(notice, "Error interpreting miner ID: %s: ID: %s", err.Error(), d.MinerID.String())
os.Exit(1)
}
for {
err := d.DB.Select(context.Background(), &i, `
SELECT count(*) FROM sector_location WHERE miner_id=$1`, mid)
if err != nil {
if err.Error() != lastError {
d.say(notice, "Error verifying sectors: %s", err.Error())
lastError = err.Error()
}
continue
}
if i[0] > 0 {
break
}
fmt.Print(".")
time.Sleep(5 * time.Second)
}
d.say(plain, "The sectors are in the database. The database is ready for %s.", "Curio")
d.say(notice, "Now shut down lotus-miner and move the systems to %s.", "Curio")
_, err = (&promptui.Prompt{Label: d.T("Press return to continue")}).Run()
if err != nil {
d.say(notice, "Aborting migration.")
os.Exit(1)
}
stepCompleted(d, d.T("Sectors verified. %d sector locations found.", i))
}
func yugabyteConnect(d *MigrationData) {
harmonyCfg := config.DefaultStorageMiner().HarmonyDB //copy the config to a local variable
if d.MinerConfig != nil {
harmonyCfg = d.MinerConfig.HarmonyDB //copy the config to a local variable
}
var err error
d.DB, err = harmonydb.NewFromConfig(harmonyCfg)
if err == nil {
goto yugabyteConnected
}
for {
i, _, err := (&promptui.Select{
Label: d.T("Enter the info to connect to your Yugabyte database installation (https://download.yugabyte.com/)"),
Items: []string{
d.T("Host: %s", strings.Join(harmonyCfg.Hosts, ",")),
d.T("Port: %s", harmonyCfg.Port),
d.T("Username: %s", harmonyCfg.Username),
d.T("Password: %s", harmonyCfg.Password),
d.T("Database: %s", harmonyCfg.Database),
d.T("Continue to connect and update schema.")},
Size: 6,
Templates: d.selectTemplates,
}).Run()
if err != nil {
d.say(notice, "Database config error occurred, abandoning migration: %s ", err.Error())
os.Exit(1)
}
switch i {
case 0:
host, err := (&promptui.Prompt{
Label: d.T("Enter the Yugabyte database host(s)"),
}).Run()
if err != nil {
d.say(notice, "No host provided")
continue
}
harmonyCfg.Hosts = strings.Split(host, ",")
case 1, 2, 3, 4:
val, err := (&promptui.Prompt{
Label: d.T("Enter the Yugabyte database %s", []string{"port", "username", "password", "database"}[i-1]),
}).Run()
if err != nil {
d.say(notice, "No value provided")
continue
}
switch i {
case 1:
harmonyCfg.Port = val
case 2:
harmonyCfg.Username = val
case 3:
harmonyCfg.Password = val
case 4:
harmonyCfg.Database = val
}
continue
case 5:
d.DB, err = harmonydb.NewFromConfig(harmonyCfg)
if err != nil {
if err.Error() == "^C" {
os.Exit(1)
}
d.say(notice, "Error connecting to Yugabyte database: %s", err.Error())
continue
}
goto yugabyteConnected
}
}
yugabyteConnected:
d.say(plain, "Connected to Yugabyte. Schema is current.")
if !reflect.DeepEqual(harmonyCfg, d.MinerConfig.HarmonyDB) || !d.MinerConfig.Subsystems.EnableSectorIndexDB {
d.MinerConfig.HarmonyDB = harmonyCfg
d.MinerConfig.Subsystems.EnableSectorIndexDB = true
d.say(plain, "Enabling Sector Indexing in the database.")
buf, err := config.ConfigUpdate(d.MinerConfig, config.DefaultStorageMiner())
if err != nil {
d.say(notice, "Error encoding config.toml: %s", err.Error())
os.Exit(1)
}
_, err = (&promptui.Prompt{
Label: d.T("Press return to update %s with Yugabyte info. A Backup file will be written to that folder before changes are made.", "config.toml")}).Run()
if err != nil {
os.Exit(1)
}
p, err := homedir.Expand(d.MinerConfigPath)
if err != nil {
d.say(notice, "Error expanding path: %s", err.Error())
os.Exit(1)
}
tomlPath := path.Join(p, "config.toml")
stat, err := os.Stat(tomlPath)
if err != nil {
d.say(notice, "Error reading filemode of config.toml: %s", err.Error())
os.Exit(1)
}
fBackup, err := os.CreateTemp(p, "config-backup-*.toml")
if err != nil {
d.say(notice, "Error creating backup file: %s", err.Error())
os.Exit(1)
}
fBackupContents, err := os.ReadFile(tomlPath)
if err != nil {
d.say(notice, "Error reading config.toml: %s", err.Error())
os.Exit(1)
}
_, err = fBackup.Write(fBackupContents)
if err != nil {
d.say(notice, "Error writing backup file: %s", err.Error())
os.Exit(1)
}
err = fBackup.Close()
if err != nil {
d.say(notice, "Error closing backup file: %s", err.Error())
os.Exit(1)
}
filemode := stat.Mode()
err = os.WriteFile(path.Join(p, "config.toml"), buf, filemode)
if err != nil {
d.say(notice, "Error writing config.toml: %s", err.Error())
os.Exit(1)
}
d.say(section, "Restart Lotus Miner. ")
}
stepCompleted(d, d.T("Connected to Yugabyte"))
}
func readMinerConfig(d *MigrationData) {
d.say(plain, "To start, ensure your sealing pipeline is drained and shut-down lotus-miner.")
verifyPath := func(dir string) (*config.StorageMiner, error) {
cfg := config.DefaultStorageMiner()
dir, err := homedir.Expand(dir)
if err != nil {
return nil, err
}
_, err = toml.DecodeFile(path.Join(dir, "config.toml"), &cfg)
return cfg, err
}
dirs := map[string]*config.StorageMiner{"~/.lotusminer": nil, "~/.lotus-miner-local-net": nil}
if v := os.Getenv("LOTUS_MINER_PATH"); v != "" {
dirs[v] = nil
}
for dir := range dirs {
cfg, err := verifyPath(dir)
if err != nil {
delete(dirs, dir)
}
dirs[dir] = cfg
}
var otherPath bool
if len(dirs) > 0 {
_, str, err := (&promptui.Select{
Label: d.T("Select the location of your lotus-miner config directory?"),
Items: append(lo.Keys(dirs), d.T("Other")),
Templates: d.selectTemplates,
}).Run()
if err != nil {
if err.Error() == "^C" {
os.Exit(1)
}
otherPath = true
} else {
if str == d.T("Other") {
otherPath = true
} else {
d.MinerConfigPath = str
d.MinerConfig = dirs[str]
}
}
}
if otherPath {
minerPathEntry:
str, err := (&promptui.Prompt{
Label: d.T("Enter the path to the configuration directory used by %s", "lotus-miner"),
}).Run()
if err != nil {
d.say(notice, "No path provided, abandoning migration ")
os.Exit(1)
}
cfg, err := verifyPath(str)
if err != nil {
d.say(notice, "Cannot read the config.toml file in the provided directory, Error: %s", err.Error())
goto minerPathEntry
}
d.MinerConfigPath = str
d.MinerConfig = cfg
}
// Try to lock Miner repo to verify that lotus-miner is not running
{
r, err := repo.NewFS(d.MinerConfigPath)
if err != nil {
d.say(plain, "Could not create repo from directory: %s. Aborting migration", err.Error())
os.Exit(1)
}
lr, err := r.Lock(repo.StorageMiner)
if err != nil {
d.say(plain, "Could not lock miner repo. Your miner must be stopped: %s\n Aborting migration", err.Error())
os.Exit(1)
}
_ = lr.Close()
}
stepCompleted(d, d.T("Read Miner Config"))
}
func stepCompleted(d *MigrationData, step string) {
fmt.Print(green.Render("✔ "))
d.say(plain, "Step Complete: %s\n", step)
}
+264
View File
@@ -0,0 +1,264 @@
package guidedsetup
import (
"bytes"
"context"
"encoding/base64"
"errors"
"fmt"
"os"
"path"
"strings"
"github.com/BurntSushi/toml"
"github.com/ipfs/go-datastore"
"github.com/samber/lo"
"golang.org/x/xerrors"
"github.com/filecoin-project/go-address"
"github.com/filecoin-project/lotus/cmd/curio/deps"
"github.com/filecoin-project/lotus/lib/harmony/harmonydb"
"github.com/filecoin-project/lotus/node/config"
"github.com/filecoin-project/lotus/node/modules"
"github.com/filecoin-project/lotus/node/repo"
)
const (
FlagMinerRepo = "miner-repo"
)
const FlagMinerRepoDeprecation = "storagerepo"
func SaveConfigToLayer(minerRepoPath, layerName string, overwrite bool, chainApiInfo string) (minerAddress address.Address, err error) {
_, say := SetupLanguage()
ctx := context.Background()
r, err := repo.NewFS(minerRepoPath)
if err != nil {
return minerAddress, err
}
ok, err := r.Exists()
if err != nil {
return minerAddress, err
}
if !ok {
return minerAddress, fmt.Errorf("repo not initialized at: %s", minerRepoPath)
}
lr, err := r.LockRO(repo.StorageMiner)
if err != nil {
return minerAddress, fmt.Errorf("locking repo: %w", err)
}
defer func() {
err = lr.Close()
if err != nil {
fmt.Println("error closing repo: ", err)
}
}()
cfgNode, err := lr.Config()
if err != nil {
return minerAddress, fmt.Errorf("getting node config: %w", err)
}
smCfg := cfgNode.(*config.StorageMiner)
db, err := harmonydb.NewFromConfig(smCfg.HarmonyDB)
if err != nil {
return minerAddress, fmt.Errorf("could not reach the database. Ensure the Miner config toml's HarmonyDB entry"+
" is setup to reach Yugabyte correctly: %w", err)
}
var titles []string
err = db.Select(ctx, &titles, `SELECT title FROM harmony_config WHERE LENGTH(config) > 0`)
if err != nil {
return minerAddress, fmt.Errorf("miner cannot reach the db. Ensure the config toml's HarmonyDB entry"+
" is setup to reach Yugabyte correctly: %s", err.Error())
}
// Copy over identical settings:
buf, err := os.ReadFile(path.Join(lr.Path(), "config.toml"))
if err != nil {
return minerAddress, fmt.Errorf("could not read config.toml: %w", err)
}
curioCfg := config.DefaultCurioConfig()
ensureEmptyArrays(curioCfg)
_, err = deps.LoadConfigWithUpgrades(string(buf), curioCfg)
if err != nil {
return minerAddress, fmt.Errorf("could not decode toml: %w", err)
}
// Populate Miner Address
mmeta, err := lr.Datastore(ctx, "/metadata")
if err != nil {
return minerAddress, xerrors.Errorf("opening miner metadata datastore: %w", err)
}
defer func() {
// _ = mmeta.Close()
}()
maddrBytes, err := mmeta.Get(ctx, datastore.NewKey("miner-address"))
if err != nil {
return minerAddress, xerrors.Errorf("getting miner address datastore entry: %w", err)
}
addr, err := address.NewFromBytes(maddrBytes)
if err != nil {
return minerAddress, xerrors.Errorf("parsing miner actor address: %w", err)
}
minerAddress = addr
curioCfg.Addresses = []config.CurioAddresses{{
MinerAddresses: []string{addr.String()},
PreCommitControl: smCfg.Addresses.PreCommitControl,
CommitControl: smCfg.Addresses.CommitControl,
TerminateControl: smCfg.Addresses.TerminateControl,
DisableOwnerFallback: smCfg.Addresses.DisableOwnerFallback,
DisableWorkerFallback: smCfg.Addresses.DisableWorkerFallback,
}}
ks, err := lr.KeyStore()
if err != nil {
return minerAddress, xerrors.Errorf("keystore err: %w", err)
}
js, err := ks.Get(modules.JWTSecretName)
if err != nil {
return minerAddress, xerrors.Errorf("error getting JWTSecretName: %w", err)
}
curioCfg.Apis.StorageRPCSecret = base64.StdEncoding.EncodeToString(js.PrivateKey)
curioCfg.Apis.ChainApiInfo = append(curioCfg.Apis.ChainApiInfo, chainApiInfo)
// Express as configTOML
configTOML := &bytes.Buffer{}
if err = toml.NewEncoder(configTOML).Encode(curioCfg); err != nil {
return minerAddress, err
}
if lo.Contains(titles, "base") {
// append addresses
var baseCfg = config.DefaultCurioConfig()
var baseText string
err = db.QueryRow(ctx, "SELECT config FROM harmony_config WHERE title='base'").Scan(&baseText)
if err != nil {
return minerAddress, xerrors.Errorf("Cannot load base config: %w", err)
}
ensureEmptyArrays(baseCfg)
_, err := deps.LoadConfigWithUpgrades(baseText, baseCfg)
if err != nil {
return minerAddress, xerrors.Errorf("Cannot load base config: %w", err)
}
for _, addr := range baseCfg.Addresses {
if lo.Contains(addr.MinerAddresses, curioCfg.Addresses[0].MinerAddresses[0]) {
goto skipWritingToBase
}
}
// write to base
{
baseCfg.Addresses = append(baseCfg.Addresses, curioCfg.Addresses[0])
baseCfg.Addresses = lo.Filter(baseCfg.Addresses, func(a config.CurioAddresses, _ int) bool {
return len(a.MinerAddresses) > 0
})
cb, err := config.ConfigUpdate(baseCfg, config.DefaultCurioConfig(), config.Commented(true), config.DefaultKeepUncommented(), config.NoEnv())
if err != nil {
return minerAddress, xerrors.Errorf("cannot interpret config: %w", err)
}
_, err = db.Exec(ctx, "UPDATE harmony_config SET config=$1 WHERE title='base'", string(cb))
if err != nil {
return minerAddress, xerrors.Errorf("cannot update base config: %w", err)
}
say(plain, "Configuration 'base' was updated to include this miner's address and its wallet setup.")
}
say(plain, "Compare the configurations %s to %s. Changes between the miner IDs other than wallet addreses should be a new, minimal layer for runners that need it.", "base", "mig-"+curioCfg.Addresses[0].MinerAddresses[0])
skipWritingToBase:
} else if layerName == "" {
cfg, err := deps.GetDefaultConfig(true)
if err != nil {
return minerAddress, xerrors.Errorf("Cannot get default config: %w", err)
}
_, err = db.Exec(ctx, `INSERT INTO harmony_config (title, config) VALUES ('base', $1)
ON CONFLICT(title) DO UPDATE SET config=EXCLUDED.config`, cfg)
if err != nil {
return minerAddress, xerrors.Errorf("Cannot insert base config: %w", err)
}
say(notice, "Configuration 'base' was created to include this miner's address and its wallet setup.")
}
if layerName == "" { // only make mig if base exists and we are different. // compare to base.
layerName = fmt.Sprintf("mig-%s", curioCfg.Addresses[0].MinerAddresses[0])
overwrite = true
} else {
if lo.Contains(titles, layerName) && !overwrite {
return minerAddress, errors.New("the overwrite flag is needed to replace existing layer: " + layerName)
}
}
if overwrite {
_, err := db.Exec(ctx, "DELETE FROM harmony_config WHERE title=$1", layerName)
if err != nil {
return minerAddress, xerrors.Errorf("Cannot delete existing layer: %w", err)
}
}
_, err = db.Exec(ctx, "INSERT INTO harmony_config (title, config) VALUES ($1, $2)", layerName, configTOML.String())
if err != nil {
return minerAddress, xerrors.Errorf("Cannot insert layer after layer created message: %w", err)
}
say(plain, "Layer %s created. ", layerName)
dbSettings := getDBSettings(*smCfg)
say(plain, "To work with the config: ")
fmt.Println(code.Render(`curio ` + dbSettings + ` config edit base`))
say(plain, `To run Curio: With machine or cgroup isolation, use the command (with example layer selection):`)
fmt.Println(code.Render(`curio ` + dbSettings + ` run --layer=post`))
return minerAddress, nil
}
func getDBSettings(smCfg config.StorageMiner) string {
dbSettings := ""
def := config.DefaultStorageMiner().HarmonyDB
if def.Hosts[0] != smCfg.HarmonyDB.Hosts[0] {
dbSettings += ` --db-host="` + strings.Join(smCfg.HarmonyDB.Hosts, ",") + `"`
}
if def.Port != smCfg.HarmonyDB.Port {
dbSettings += " --db-port=" + smCfg.HarmonyDB.Port
}
if def.Username != smCfg.HarmonyDB.Username {
dbSettings += ` --db-user="` + smCfg.HarmonyDB.Username + `"`
}
if def.Password != smCfg.HarmonyDB.Password {
dbSettings += ` --db-password="` + smCfg.HarmonyDB.Password + `"`
}
if def.Database != smCfg.HarmonyDB.Database {
dbSettings += ` --db-name="` + smCfg.HarmonyDB.Database + `"`
}
return dbSettings
}
func ensureEmptyArrays(cfg *config.CurioConfig) {
if cfg.Addresses == nil {
cfg.Addresses = []config.CurioAddresses{}
} else {
for i := range cfg.Addresses {
if cfg.Addresses[i].PreCommitControl == nil {
cfg.Addresses[i].PreCommitControl = []string{}
}
if cfg.Addresses[i].CommitControl == nil {
cfg.Addresses[i].CommitControl = []string{}
}
if cfg.Addresses[i].TerminateControl == nil {
cfg.Addresses[i].TerminateControl = []string{}
}
}
}
if cfg.Apis.ChainApiInfo == nil {
cfg.Apis.ChainApiInfo = []string{}
}
}
+331
View File
@@ -0,0 +1,331 @@
// Code generated by running "go generate" in golang.org/x/text. DO NOT EDIT.
package translations
import (
"golang.org/x/text/language"
"golang.org/x/text/message"
"golang.org/x/text/message/catalog"
)
type dictionary struct {
index []uint32
data string
}
func (d *dictionary) Lookup(key string) (data string, ok bool) {
p, ok := messageKeyToIndex[key]
if !ok {
return "", false
}
start, end := d.index[p], d.index[p+1]
if start == end {
return "", false
}
return d.data[start:end], true
}
func init() {
dict := map[string]catalog.Dictionary{
"en": &dictionary{index: enIndex, data: enData},
"ko": &dictionary{index: koIndex, data: koData},
"zh": &dictionary{index: zhIndex, data: zhData},
}
fallback := language.MustParse("en")
cat, err := catalog.NewFromMap(dict, catalog.Fallback(fallback))
if err != nil {
panic(err)
}
message.DefaultCatalog = cat
}
var messageKeyToIndex = map[string]int{
"Aborting migration.": 41,
"Aborting remaining steps.": 19,
"Aggregate-Anonymous: version, net, and Miner power (bucketed).": 16,
"Cannot read the config.toml file in the provided directory, Error: %s": 70,
"Compare the configurations %s to %s. Changes between the miner IDs other than wallet addreses should be a new, minimal layer for runners that need it.": 76,
"Configuration 'base' was created to include this miner's address and its wallet setup.": 77,
"Configuration 'base' was updated to include this miner's address and its wallet setup.": 75,
"Connected to Yugabyte": 64,
"Connected to Yugabyte. Schema is current.": 56,
"Continue to connect and update schema.": 49,
"Could not create repo from directory: %s. Aborting migration": 71,
"Could not lock miner repo. Your miner must be stopped: %s\n Aborting migration": 72,
"Ctrl+C pressed in Terminal": 3,
"Database config error occurred, abandoning migration: %s ": 50,
"Database: %s": 48,
"Documentation: ": 27,
"Each step needs your confirmation and can be reversed. Press Ctrl+C to exit at any time.": 1,
"Enabling Sector Indexing in the database.": 57,
"Enter the Yugabyte database %s": 53,
"Enter the Yugabyte database host(s)": 51,
"Enter the info to connect to your Yugabyte database installation (https://download.yugabyte.com/)": 43,
"Enter the path to the configuration directory used by %s": 68,
"Error connecting to Yugabyte database: %s": 55,
"Error connecting to lotus node: %s %s": 9,
"Error encoding config.toml: %s": 58,
"Error expanding path: %s": 60,
"Error getting miner info: %s": 22,
"Error getting miner power: %s": 20,
"Error getting token: %s": 11,
"Error interpreting miner ID: %s: ID: %s": 36,
"Error marshalling message: %s": 21,
"Error reading filemode of config.toml: %s": 61,
"Error reading from database: %s. Aborting Migration.": 8,
"Error saving config to layer: %s. Aborting Migration": 12,
"Error sending message: %s": 24,
"Error sending message: Status %s, Message: ": 25,
"Error signing message: %s": 23,
"Error verifying sectors: %s": 37,
"Error writing config.toml: %s": 62,
"Filecoin %s channels: %s and %s": 30,
"Hint: I am someone running Curio on net.": 17,
"Host: %s": 44,
"Individual Data: Miner ID, Curio version, net (%s or %s). Signed.": 15,
"Layer %s created. ": 78,
"Lotus-Miner to Curio Migration.": 4,
"Message sent.": 26,
"Migrating config.toml to database.": 7,
"No host provided": 52,
"No path provided, abandoning migration ": 69,
"No value provided": 54,
"Nothing.": 18,
"Now shut down lotus-miner and move the systems to %s.": 39,
"One database can serve multiple miner IDs: Run a migration for each lotus-miner.": 33,
"Other": 67,
"Password: %s": 47,
"Please start (or restart) %s now that database credentials are in %s.": 34,
"Point your browser to your web GUI to complete setup with %s and advanced featues.": 32,
"Port: %s": 45,
"Press return to continue": 40,
"Press return to update %s with Yugabyte info. Backup the file now.": 59,
"Protocol Labs wants to improve the software you use. Tell the team you're using Curio.": 13,
"Read Miner Config": 73,
"Restart Lotus Miner. ": 63,
"Sectors verified. %d sector locations found.": 42,
"Select the location of your lotus-miner config directory?": 66,
"Select what you want to share with the Curio team.": 14,
"Start multiple Curio instances with the '%s' layer to redundancy.": 31,
"Step Complete: %s\n": 74,
"The '%s' layer stores common configuration. All curio instances can include it in their %s argument.": 28,
"The sectors are in the database. The database is ready for %s.": 38,
"This interactive tool migrates lotus-miner to Curio in 5 minutes.": 0,
"To run Curio: With machine or cgroup isolation, use the command (with example layer selection):": 80,
"To start, ensure your sealing pipeline is drained and shut-down lotus-miner.": 65,
"To work with the config: ": 79,
"Try the web interface with %s for further guided improvements.": 5,
"Use the arrow keys to navigate: ↓ ↑ → ← ": 2,
"Username: %s": 46,
"Waiting for %s to write sectors into Yugabyte.": 35,
"You can add other layers for per-machine configuration changes.": 29,
"You can now migrate your market node (%s), if applicable.": 6,
"could not get API info for FullNode: %w": 10,
}
var enIndex = []uint32{ // 82 elements
// Entry 0 - 1F
0x00000000, 0x00000042, 0x0000009b, 0x000000d0,
0x000000eb, 0x0000010b, 0x0000014d, 0x0000018a,
0x000001ad, 0x000001e5, 0x00000211, 0x0000023c,
0x00000257, 0x0000028f, 0x000002e6, 0x00000319,
0x00000361, 0x000003a0, 0x000003c9, 0x000003d2,
0x000003ec, 0x0000040d, 0x0000042e, 0x0000044e,
0x0000046b, 0x00000488, 0x000004bb, 0x000004c9,
0x000004dd, 0x00000548, 0x00000588, 0x000005b1,
// Entry 20 - 3F
0x000005f6, 0x0000064c, 0x0000069d, 0x000006e9,
0x0000071b, 0x00000749, 0x00000768, 0x000007aa,
0x000007e3, 0x000007fc, 0x00000810, 0x00000840,
0x000008a2, 0x000008ae, 0x000008ba, 0x000008ca,
0x000008da, 0x000008ea, 0x00000911, 0x00000952,
0x00000976, 0x00000987, 0x000009a9, 0x000009bb,
0x000009e8, 0x00000a12, 0x00000a3c, 0x00000a5e,
0x00000aa4, 0x00000ac0, 0x00000aed, 0x00000b0e,
// Entry 40 - 5F
0x00000b28, 0x00000b3e, 0x00000b8b, 0x00000bc5,
0x00000bcb, 0x00000c07, 0x00000c33, 0x00000c7c,
0x00000cbc, 0x00000d0d, 0x00000d1f, 0x00000d39,
0x00000d90, 0x00000e2d, 0x00000e84, 0x00000e9e,
0x00000ebc, 0x00000f1c,
} // Size: 352 bytes
const enData string = "" + // Size: 3868 bytes
"\x02This interactive tool migrates lotus-miner to Curio in 5 minutes." +
"\x02Each step needs your confirmation and can be reversed. Press Ctrl+C " +
"to exit at any time.\x04\x00\x01 0\x02Use the arrow keys to navigate: ↓ " +
"↑ → ←\x02Ctrl+C pressed in Terminal\x02Lotus-Miner to Curio Migration." +
"\x02Try the web interface with %[1]s for further guided improvements." +
"\x02You can now migrate your market node (%[1]s), if applicable.\x02Migr" +
"ating config.toml to database.\x02Error reading from database: %[1]s. Ab" +
"orting Migration.\x02Error connecting to lotus node: %[1]s %[2]s\x02coul" +
"d not get API info for FullNode: %[1]w\x02Error getting token: %[1]s\x02" +
"Error saving config to layer: %[1]s. Aborting Migration\x02Protocol Labs" +
" wants to improve the software you use. Tell the team you're using Curio" +
".\x02Select what you want to share with the Curio team.\x02Individual Da" +
"ta: Miner ID, Curio version, net (%[1]s or %[2]s). Signed.\x02Aggregate-" +
"Anonymous: version, net, and Miner power (bucketed).\x02Hint: I am someo" +
"ne running Curio on net.\x02Nothing.\x02Aborting remaining steps.\x02Err" +
"or getting miner power: %[1]s\x02Error marshalling message: %[1]s\x02Err" +
"or getting miner info: %[1]s\x02Error signing message: %[1]s\x02Error se" +
"nding message: %[1]s\x04\x00\x01 .\x02Error sending message: Status %[1]" +
"s, Message:\x02Message sent.\x04\x00\x01 \x0f\x02Documentation:\x02The '" +
"%[1]s' layer stores common configuration. All curio instances can includ" +
"e it in their %[2]s argument.\x02You can add other layers for per-machin" +
"e configuration changes.\x02Filecoin %[1]s channels: %[2]s and %[3]s\x02" +
"Start multiple Curio instances with the '%[1]s' layer to redundancy.\x02" +
"Point your browser to your web GUI to complete setup with %[1]s and adva" +
"nced featues.\x02One database can serve multiple miner IDs: Run a migrat" +
"ion for each lotus-miner.\x02Please start (or restart) %[1]s now that da" +
"tabase credentials are in %[2]s.\x02Waiting for %[1]s to write sectors i" +
"nto Yugabyte.\x02Error interpreting miner ID: %[1]s: ID: %[2]s\x02Error " +
"verifying sectors: %[1]s\x02The sectors are in the database. The databas" +
"e is ready for %[1]s.\x02Now shut down lotus-miner and move the systems " +
"to %[1]s.\x02Press return to continue\x02Aborting migration.\x02Sectors " +
"verified. %[1]d sector locations found.\x02Enter the info to connect to " +
"your Yugabyte database installation (https://download.yugabyte.com/)\x02" +
"Host: %[1]s\x02Port: %[1]s\x02Username: %[1]s\x02Password: %[1]s\x02Data" +
"base: %[1]s\x02Continue to connect and update schema.\x04\x00\x01 <\x02D" +
"atabase config error occurred, abandoning migration: %[1]s\x02Enter the " +
"Yugabyte database host(s)\x02No host provided\x02Enter the Yugabyte data" +
"base %[1]s\x02No value provided\x02Error connecting to Yugabyte database" +
": %[1]s\x02Connected to Yugabyte. Schema is current.\x02Enabling Sector " +
"Indexing in the database.\x02Error encoding config.toml: %[1]s\x02Press " +
"return to update %[1]s with Yugabyte info. Backup the file now.\x02Error" +
" expanding path: %[1]s\x02Error reading filemode of config.toml: %[1]s" +
"\x02Error writing config.toml: %[1]s\x04\x00\x01 \x15\x02Restart Lotus M" +
"iner.\x02Connected to Yugabyte\x02To start, ensure your sealing pipeline" +
" is drained and shut-down lotus-miner.\x02Select the location of your lo" +
"tus-miner config directory?\x02Other\x02Enter the path to the configurat" +
"ion directory used by %[1]s\x04\x00\x01 '\x02No path provided, abandonin" +
"g migration\x02Cannot read the config.toml file in the provided director" +
"y, Error: %[1]s\x02Could not create repo from directory: %[1]s. Aborting" +
" migration\x02Could not lock miner repo. Your miner must be stopped: %[1" +
"]s\x0a Aborting migration\x02Read Miner Config\x04\x00\x01\x0a\x15\x02St" +
"ep Complete: %[1]s\x02Configuration 'base' was updated to include this m" +
"iner's address and its wallet setup.\x02Compare the configurations %[1]s" +
" to %[2]s. Changes between the miner IDs other than wallet addreses shou" +
"ld be a new, minimal layer for runners that need it.\x02Configuration 'b" +
"ase' was created to include this miner's address and its wallet setup." +
"\x04\x00\x01 \x15\x02Layer %[1]s created.\x04\x00\x01 \x19\x02To work wi" +
"th the config:\x02To run Curio: With machine or cgroup isolation, use th" +
"e command (with example layer selection):"
var koIndex = []uint32{ // 82 elements
// Entry 0 - 1F
0x00000000, 0x0000004d, 0x000000c8, 0x0000010c,
0x0000012d, 0x00000150, 0x00000150, 0x000001a0,
0x000001da, 0x0000022f, 0x0000022f, 0x0000022f,
0x0000022f, 0x00000287, 0x00000315, 0x0000034e,
0x000003aa, 0x000003f4, 0x00000437, 0x00000452,
0x00000477, 0x000004b1, 0x000004e4, 0x0000051e,
0x00000548, 0x00000572, 0x000005b4, 0x000005d8,
0x000005e5, 0x0000066b, 0x000006bd, 0x000006bd,
// Entry 20 - 3F
0x000006bd, 0x0000071e, 0x0000071e, 0x0000071e,
0x00000762, 0x00000762, 0x00000789, 0x000007f4,
0x0000083e, 0x00000865, 0x00000880, 0x000008cf,
0x0000093d, 0x0000094e, 0x0000095c, 0x00000974,
0x00000988, 0x000009a2, 0x000009cc, 0x00000a2f,
0x00000a6b, 0x00000a95, 0x00000acd, 0x00000af1,
0x00000b45, 0x00000b86, 0x00000b86, 0x00000bcd,
0x00000c39, 0x00000c39, 0x00000c88, 0x00000cc6,
// Entry 40 - 5F
0x00000cea, 0x00000d00, 0x00000d6b, 0x00000dba,
0x00000dc1, 0x00000e09, 0x00000e5b, 0x00000eb5,
0x00000eb5, 0x00000eb5, 0x00000ecd, 0x00000ee7,
0x00000f51, 0x0000100b, 0x0000106f, 0x0000109e,
0x0000109e, 0x0000112a,
} // Size: 352 bytes
const koData string = "" + // Size: 4394 bytes
"\x02이 대화형 도구는 5분 안에 lotus-miner를 Curio로 이주합니다.\x02각 단계는 확인이 필요하며 되돌릴 수 있" +
"습니다. 언제든지 Ctrl+C를 눌러 종료할 수 있습니다.\x04\x00\x01 ?\x02화살표 키를 사용하여 이동하세요: ↓" +
" ↑ → ←\x02터미널에서 Ctrl+C가 눌림\x02Lotus-Miner에서 Curio로 이주.\x02해당하는 경우 이제 시장 " +
"노드를 이주할 수 있습니다 (%[1]s).\x02config.toml을 데이터베이스로 이주 중입니다.\x02데이터베이스에서 읽" +
"는 중 오류 발생: %[1]s. 마이그레이션 중단.\x02레이어에 구성을 저장하는 중 오류 발생: %[1]s. 마이그레이션 중" +
"단\x02Protocol Labs는 당신이 사용하는 소프트웨어를 개선하고 싶어합니다. Curio를 사용 중이라고 팀에 알려주세" +
"요.\x02Curio 팀과 공유하고 싶은 것을 선택하세요.\x02개별 데이터: 마이너 ID, Curio 버전, 네트워크 (%[" +
"1]s 또는 %[2]s). 서명됨.\x02집계-익명: 버전, 네트워크, 그리고 마이너 파워 (버킷).\x02힌트: 네트워크에서 C" +
"urio를 실행 중인 사람입니다.\x02아무것도 없습니다.\x02나머지 단계를 중단합니다.\x02마이너 파워를 가져오는 중 오류 " +
"발생: %[1]s\x02메시지를 마샬하는 중 오류 발생: %[1]s\x02마이너 정보를 가져오는 중 오류 발생: %[1]s" +
"\x02메시지 서명 중 오류 발생: %[1]s\x02메시지 전송 중 오류 발생: %[1]s\x04\x00\x01 =\x02메시지 " +
"전송 중 오류 발생: 상태 %[1]s, 메시지:\x02메시지가 전송되었습니다.\x04\x00\x01 \x08\x02문서:" +
"\x02'%[1]s' 레이어에는 공통 구성이 저장됩니다. 모든 Curio 인스턴스는 %[2]s 인수에 포함시킬 수 있습니다." +
"\x02기계별 구성 변경을 위해 다른 레이어를 추가할 수 있습니다.\x02브라우저를 웹 GUI로 이동하여 %[1]s 및 고급 기능" +
"으로 설정을 완료하세요.\x02%[1]s가 Yugabyte에 섹터를 기록하도록 대기 중입니다.\x02섹터 확인 중 오류 발생:" +
" %[1]s\x02섹터가 데이터베이스에 있습니다. 데이터베이스가 %[1]s를 위해 준비되었습니다.\x02이제 lotus-miner" +
"를 종료하고 시스템을 %[1]s로 이동하세요.\x02계속하려면 리턴을 누르세요\x02마이그레이션 중단.\x02섹터가 확인되었습" +
"니다. %[1]d개의 섹터 위치를 찾았습니다.\x02Yugabyte 데이터베이스 설치에 연결할 정보를 입력하십시오 (https" +
"://download.yugabyte.com/)\x02호스트: %[1]s\x02포트: %[1]s\x02사용자 이름: %[1]s" +
"\x02비밀번호: %[1]s\x02데이터베이스: %[1]s\x02계속 연결 및 스키마 업데이트.\x04\x00\x01 ^\x02데" +
"이터베이스 구성 오류가 발생하여 마이그레이션을 포기합니다: %[1]s\x02Yugabyte 데이터베이스 호스트를 입력하십시오" +
"\x02호스트가 제공되지 않았습니다\x02Yugabyte 데이터베이스 %[1]s을 입력하십시오\x02값이 제공되지 않았습니다" +
"\x02Yugabyte 데이터베이스에 연결하는 중 오류가 발생했습니다: %[1]s\x02Yugabyte에 연결되었습니다. 스키마가" +
" 현재입니다.\x02config.toml을 인코딩하는 중 오류가 발생했습니다: %[1]s\x02%[1]s을 Yugabyte 정보로" +
" 업데이트하려면 리턴을 누르세요. 지금 파일을 백업하세요.\x02config.toml의 파일 모드를 읽는 중 오류가 발생했습니다:" +
" %[1]s\x02config.toml을 쓰는 중 오류가 발생했습니다: %[1]s\x04\x00\x01 \x1f\x02로터스 마이" +
"너 재시작.\x02Yugabyte에 연결됨\x02시작하려면 밀봉 파이프라인이 비어 있고 lotus-miner가 종료되었는지 확" +
"인하세요.\x02로터스 마이너 구성 디렉토리의 위치를 선택하시겠습니까?\x02기타\x02%[1]s에서 사용하는 구성 디렉터리 " +
"경로를 입력하세요.\x04\x00\x01 M\x02경로가 제공되지 않았으므로 마이그레이션을 포기합니다\x02제공된 디렉토리에서" +
" config.toml 파일을 읽을 수 없습니다. 오류: %[1]s\x02마이너 구성 읽기\x04\x00\x01\x0a\x15" +
"\x02단계 완료: %[1]s\x02이 마이너의 주소와 지갑 설정을 포함하도록 구성 'base'가 업데이트되었습니다.\x02구성 " +
"%[1]s를 %[2]s과 비교하세요. 지갑 주소 이외의 마이너 ID 사이의 변경 사항은 필요한 실행자를 위한 새로운 최소한의 레이" +
"어여야 합니다.\x02이 마이너의 주소와 지갑 설정을 포함하도록 구성 'base'가 생성되었습니다.\x04\x00\x01 *" +
"\x02레이어 %[1]s가 생성되었습니다.\x02Curio를 실행하려면: 기계 또는 cgroup 격리를 사용하여 다음 명령을 사용" +
"하세요 (예제 레이어 선택과 함께):"
var zhIndex = []uint32{ // 82 elements
// Entry 0 - 1F
0x00000000, 0x00000048, 0x00000097, 0x000000ca,
0x000000e3, 0x00000100, 0x00000100, 0x00000141,
0x0000016b, 0x000001a4, 0x000001a4, 0x000001a4,
0x000001a4, 0x000001dd, 0x0000022f, 0x0000025c,
0x000002a9, 0x000002e7, 0x00000317, 0x00000321,
0x00000337, 0x0000035b, 0x00000379, 0x0000039d,
0x000003bb, 0x000003d9, 0x0000040e, 0x00000421,
0x00000430, 0x0000048a, 0x000004c7, 0x000004c7,
// Entry 20 - 3F
0x000004c7, 0x0000051e, 0x0000051e, 0x0000051e,
0x00000544, 0x00000544, 0x00000562, 0x0000059e,
0x000005d0, 0x000005e0, 0x000005f0, 0x00000623,
0x0000067d, 0x0000068c, 0x0000069b, 0x000006ad,
0x000006bc, 0x000006ce, 0x000006ed, 0x00000725,
0x0000074a, 0x0000075a, 0x00000778, 0x00000785,
0x000007b1, 0x000007de, 0x000007de, 0x00000801,
0x00000845, 0x00000845, 0x00000874, 0x00000897,
// Entry 40 - 5F
0x000008b7, 0x000008cc, 0x00000917, 0x00000947,
0x0000094e, 0x00000978, 0x0000099c, 0x000009e0,
0x000009e0, 0x000009e0, 0x000009f3, 0x00000a0d,
0x00000a59, 0x00000adb, 0x00000b27, 0x00000b41,
0x00000b41, 0x00000b98,
} // Size: 352 bytes
const zhData string = "" + // Size: 2968 bytes
"\x02这个交互式工具可以在5分钟内将lotus-miner迁移到Curio。\x02每一步都需要您的确认,并且可以撤销。随时按Ctrl+C退出" +
"。\x04\x00\x01 .\x02使用箭头键进行导航:↓ ↑ → ←\x02在终端中按下Ctrl+C\x02Lotus-Miner到Cu" +
"rio迁移。\x02如果适用,您现在可以迁移您的市场节点(%[1]s)。\x02正在将config.toml迁移到数据库。\x02读取数据库时出" +
"错:%[1]s。正在中止迁移。\x02保存配置到层时出错:%[1]s。正在中止迁移\x02Protocol Labs希望改进您使用的软件。告" +
"诉团队您正在使用Curio。\x02选择您想与Curio团队分享的内容。\x02个人数据:矿工ID、Curio版本、网络(%[1]s或%[2" +
"]s)。已签名。\x02聚合-匿名:版本、网络和矿工功率(分桶)。\x02提示:我是在网络上运行Curio的人。\x02没有。\x02中止剩余步" +
"骤。\x02获取矿工功率时出错:%[1]s\x02整理消息时出错:%[1]s\x02获取矿工信息时出错:%[1]s\x02签署消息时出错:%" +
"[1]s\x02发送消息时出错:%[1]s\x04\x00\x01 0\x02发送消息时出错:状态%[1]s,消息:\x02消息已发送。\x04" +
"\x00\x01 \x0a\x02文档:\x02'%[1]s'层存储通用配置。所有Curio实例都可以在其%[2]s参数中包含它。\x02您可以" +
"添加其他层进行每台机器的配置更改。\x02将您的浏览器指向您的网络GUI,以使用%[1]s和高级功能完成设置。\x02等待%[1]s将扇区写" +
"入Yugabyte。\x02验证扇区时出错:%[1]s\x02扇区在数据库中。数据库已准备好用于%[1]s。\x02现在关闭lotus-mi" +
"ner并将系统移至%[1]s。\x02按回车继续\x02中止迁移。\x02扇区已验证。发现了%[1]d个扇区位置。\x02输入连接到您的Yuga" +
"byte数据库安装的信息(https://download.yugabyte.com/\x02主机:%[1]s\x02端口:%[1]s\x02" +
"用户名:%[1]s\x02密码:%[1]s\x02数据库:%[1]s\x02继续连接和更新架构。\x04\x00\x01 3\x02发生数据" +
"库配置错误,放弃迁移:%[1]s\x02输入Yugabyte数据库主机(S\x02未提供主机\x02输入Yugabyte数据库 %[1]s" +
"\x02未提供值\x02连接到Yugabyte数据库时出错:%[1]s\x02已连接到Yugabyte。模式是当前的。\x02编码config." +
"toml时出错:%[1]s\x02按回车更新%[1]s以获取Yugabyte信息。现在备份文件。\x02读取config.toml文件模式时出错" +
"%[1]s\x02写入config.toml时出错:%[1]s\x04\x00\x01 \x1b\x02重新启动Lotus Miner。" +
"\x02已连接到Yugabyte\x02开始之前,请确保您的密封管道已排空并关闭lotus-miner。\x02选择您的lotus-miner配" +
"置目录的位置?\x02其他\x02输入%[1]s使用的配置目录的路径\x04\x00\x01 \x1f\x02未提供路径,放弃迁移\x02无" +
"法读取提供的目录中的config.toml文件,错误:%[1]s\x02读取矿工配置\x04\x00\x01\x0a\x15\x02步骤完成" +
"%[1]s\x02配置'base'已更新,包含了这个矿工的地址和其钱包设置。\x02比较配置%[1]s和%[2]s。矿工ID之间除了钱包地" +
"址的变化应该是需要的运行者的一个新的、最小的层。\x02配置'base'已创建,包括了这个矿工的地址和其钱包设置。\x04\x00\x01 " +
"\x15\x02层%[1]s已创建。\x02运行Curio:使用机器或cgroup隔离,使用命令(附带示例层选择):"
// Total table size 12286 bytes (11KiB); checksum: 15B16994
@@ -0,0 +1,82 @@
package main
import (
"bytes"
"encoding/json"
"fmt"
"os"
"path"
"github.com/samber/lo"
)
func main() {
for _, arg := range os.Args {
handleKnowns(arg)
}
}
func handleKnowns(pathStart string) {
outpath := path.Join(pathStart, "out.gotext.json")
b, err := os.ReadFile(outpath)
if err != nil {
fmt.Println("cannot open "+outpath+":", err)
return
}
type TMsg struct {
ID string `json:"id"`
Translation string `json:"translation"`
Message string `json:"message"`
Placeholder json.RawMessage `json:"placeholder"`
}
type Dataformat struct {
Language string `json:"language"`
Messages []TMsg `json:"messages"`
}
var outData Dataformat
err = json.NewDecoder(bytes.NewBuffer(b)).Decode(&outData)
if err != nil {
fmt.Println("cannot decode "+outpath+":", err)
return
}
f, err := os.Open(path.Join(pathStart, "messages.gotext.json"))
if err != nil {
fmt.Println("cannot open "+path.Join(pathStart, "messages.gotext.json")+":", err)
return
}
defer func() { _ = f.Close() }()
var msgData Dataformat
err = json.NewDecoder(f).Decode(&msgData)
if err != nil {
fmt.Println("cannot decode "+path.Join(pathStart, "messages.gotext.json")+":", err)
return
}
knowns := map[string]string{}
for _, msg := range msgData.Messages {
knowns[msg.ID] = msg.Translation
}
toTranslate := lo.Filter(outData.Messages, func(msg TMsg, _ int) bool {
_, ok := knowns[msg.ID]
return !ok
})
outData.Messages = toTranslate // drop the "done" messages
var outJSON bytes.Buffer
enc := json.NewEncoder(&outJSON)
enc.SetIndent(" ", " ")
err = enc.Encode(outData)
if err != nil {
fmt.Println("cannot encode "+outpath+":", err)
return
}
err = os.WriteFile(outpath, outJSON.Bytes(), 0644)
if err != nil {
fmt.Println("cannot write "+outpath+":", err)
return
}
fmt.Println("rearranged successfully")
}
File diff suppressed because it is too large Load Diff
@@ -0,0 +1,704 @@
{
"language": "ko",
"messages": [
{
"id": "This interactive tool will walk you through migration of Curio.\nPress Ctrl+C to exit at any time.",
"message": "This interactive tool will walk you through migration of Curio.\nPress Ctrl+C to exit at any time.",
"translation": "이 대화형 도구는 Curio 마이그레이션 과정을 안내합니다.\n언제든지 종료하려면 Ctrl+C를 누르십시오."
},
{
"id": "This tool confirms each action it does.",
"message": "This tool confirms each action it does.",
"translation": "이 도구는 수행하는 각 작업을 확인합니다."
},
{
"id": "Ctrl+C pressed in Terminal",
"message": "Ctrl+C pressed in Terminal",
"translation": "터미널에서 Ctrl+C가 눌림"
},
{
"id": "Verifying Sectors exist in Yugabyte.",
"message": "Verifying Sectors exist in Yugabyte.",
"translation": "Yugabyte에 섹터가 존재하는지 확인 중."
},
{
"id": "Error verifying sectors: {Error}",
"message": "Error verifying sectors: {Error}",
"translation": "섹터 확인 중 오류 발생: {Error}",
"placeholders": [
{
"id": "Error",
"string": "%[1]s",
"type": "string",
"underlyingType": "string",
"argNum": 1,
"expr": "err.Error()"
}
]
},
{
"id": "Sectors verified. {I} sectors found.",
"message": "Sectors verified. {I} sectors found.",
"translation": "섹터가 확인되었습니다. {I}개의 섹터가 발견되었습니다.",
"placeholders": [
{
"id": "I",
"string": "%[1]d",
"type": "[]int",
"underlyingType": "[]int",
"argNum": 1,
"expr": "i"
}
]
},
{
"id": "Never remove the database info from the config.toml for lotus-miner as it avoids double PoSt.",
"message": "Never remove the database info from the config.toml for lotus-miner as it avoids double PoSt.",
"translation": "로터스 마이너의 config.toml에서 데이터베이스 정보를 제거하지 마십시오. 두 번의 PoSt를 피하기 위함입니다."
},
{
"id": "Enter the info to connect to your Yugabyte database installation (https://download.yugabyte.com/)",
"message": "Enter the info to connect to your Yugabyte database installation (https://download.yugabyte.com/)",
"translation": "Yugabyte 데이터베이스 설치에 연결할 정보를 입력하십시오 (https://download.yugabyte.com/)"
},
{
"id": "Host: {Hosts_}",
"message": "Host: {Hosts_}",
"translation": "호스트: {Hosts_}",
"placeholders": [
{
"id": "Hosts_",
"string": "%[1]s",
"type": "string",
"underlyingType": "string",
"argNum": 1,
"expr": "strings.Join(harmonycfg.Hosts, \",\")"
}
]
},
{
"id": "Port: {Port}",
"message": "Port: {Port}",
"translation": "포트: {Port}",
"placeholders": [
{
"id": "Port",
"string": "%[1]s",
"type": "string",
"underlyingType": "string",
"argNum": 1,
"expr": "harmonycfg.Port"
}
]
},
{
"id": "Username: {Username}",
"message": "Username: {Username}",
"translation": "사용자 이름: {Username}",
"placeholders": [
{
"id": "Username",
"string": "%[1]s",
"type": "string",
"underlyingType": "string",
"argNum": 1,
"expr": "harmonycfg.Username"
}
]
},
{
"id": "Password: {Password}",
"message": "Password: {Password}",
"translation": "비밀번호: {Password}",
"placeholders": [
{
"id": "Password",
"string": "%[1]s",
"type": "string",
"underlyingType": "string",
"argNum": 1,
"expr": "harmonycfg.Password"
}
]
},
{
"id": "Database: {Database}",
"message": "Database: {Database}",
"translation": "데이터베이스: {Database}",
"placeholders": [
{
"id": "Database",
"string": "%[1]s",
"type": "string",
"underlyingType": "string",
"argNum": 1,
"expr": "harmonycfg.Database"
}
]
},
{
"id": "Continue to connect and update schema.",
"message": "Continue to connect and update schema.",
"translation": "계속 연결 및 스키마 업데이트."
},
{
"id": "Database config error occurred, abandoning migration: {Error}",
"message": "Database config error occurred, abandoning migration: {Error}",
"translation": "데이터베이스 구성 오류가 발생하여 마이그레이션을 포기합니다: {Error}",
"placeholders": [
{
"id": "Error",
"string": "%[1]s",
"type": "string",
"underlyingType": "string",
"argNum": 1,
"expr": "err.Error()"
}
]
},
{
"id": "Enter the Yugabyte database host(s)",
"message": "Enter the Yugabyte database host(s)",
"translation": "Yugabyte 데이터베이스 호스트를 입력하십시오"
},
{
"id": "No host provided",
"message": "No host provided",
"translation": "호스트가 제공되지 않았습니다"
},
{
"id": "Enter the Yugabyte database {Stringport_username_password_databasei_1}",
"message": "Enter the Yugabyte database {Stringport_username_password_databasei_1}",
"translation": "Yugabyte 데이터베이스 {Stringport_username_password_databasei_1}을 입력하십시오",
"placeholders": [
{
"id": "Stringport_username_password_databasei_1",
"string": "%[1]s",
"type": "string",
"underlyingType": "string",
"argNum": 1,
"expr": "[]string{\"port\", \"username\", \"password\", \"database\"}[i-1]"
}
]
},
{
"id": "No value provided",
"message": "No value provided",
"translation": "값이 제공되지 않았습니다"
},
{
"id": "Error connecting to Yugabyte database: {Error}",
"message": "Error connecting to Yugabyte database: {Error}",
"translation": "Yugabyte 데이터베이스에 연결하는 중 오류가 발생했습니다: {Error}",
"placeholders": [
{
"id": "Error",
"string": "%[1]s",
"type": "string",
"underlyingType": "string",
"argNum": 1,
"expr": "err.Error()"
}
]
},
{
"id": "Connected to Yugabyte. Schema is current.",
"message": "Connected to Yugabyte. Schema is current.",
"translation": "Yugabyte에 연결되었습니다. 스키마가 현재입니다."
},
{
"id": "Error encoding config.toml: {Error}",
"message": "Error encoding config.toml: {Error}",
"translation": "config.toml을 인코딩하는 중 오류가 발생했습니다: {Error}",
"placeholders": [
{
"id": "Error",
"string": "%[1]s",
"type": "string",
"underlyingType": "string",
"argNum": 1,
"expr": "err.Error()"
}
]
},
{
"id": "Error reading filemode of config.toml: {Error}",
"message": "Error reading filemode of config.toml: {Error}",
"translation": "config.toml의 파일 모드를 읽는 중 오류가 발생했습니다: {Error}",
"placeholders": [
{
"id": "Error",
"string": "%[1]s",
"type": "string",
"underlyingType": "string",
"argNum": 1,
"expr": "err.Error()"
}
]
},
{
"id": "Error writing config.toml: {Error}",
"message": "Error writing config.toml: {Error}",
"translation": "config.toml을 쓰는 중 오류가 발생했습니다: {Error}",
"placeholders": [
{
"id": "Error",
"string": "%[1]s",
"type": "string",
"underlyingType": "string",
"argNum": 1,
"expr": "err.Error()"
}
]
},
{
"id": "Restart Lotus Miner.",
"message": "Restart Lotus Miner.",
"translation": "로터스 마이너 재시작."
},
{
"id": "Connected to Yugabyte",
"message": "Connected to Yugabyte",
"translation": "Yugabyte에 연결됨"
},
{
"id": "Select the location of your lotus-miner config directory?",
"message": "Select the location of your lotus-miner config directory?",
"translation": "로터스 마이너 구성 디렉토리의 위치를 선택하시겠습니까?"
},
{
"id": "Other",
"message": "Other",
"translation": "기타"
},
{
"id": "Enter the path to the configuration directory used by lotus-miner",
"message": "Enter the path to the configuration directory used by lotus-miner",
"translation": "로터스 마이너에서 사용하는 구성 디렉토리의 경로를 입력하십시오"
},
{
"id": "No path provided, abandoning migration",
"message": "No path provided, abandoning migration",
"translation": "경로가 제공되지 않았으므로 마이그레이션을 포기합니다"
},
{
"id": "Cannot read the config.toml file in the provided directory, Error: {Error}",
"message": "Cannot read the config.toml file in the provided directory, Error: {Error}",
"translation": "제공된 디렉토리에서 config.toml 파일을 읽을 수 없습니다. 오류: {Error}",
"placeholders": [
{
"id": "Error",
"string": "%[1]s",
"type": "string",
"underlyingType": "string",
"argNum": 1,
"expr": "err.Error()"
}
]
},
{
"id": "Read Miner Config",
"message": "Read Miner Config",
"translation": "마이너 구성 읽기"
},
{
"id": "Completed Step: {Step}",
"message": "Completed Step: {Step}",
"translation": "단계 완료: {Step}",
"placeholders": [
{
"id": "Step",
"string": "%[1]s",
"type": "string",
"underlyingType": "string",
"argNum": 1,
"expr": "step"
}
]
},
{
"id": "This interactive tool migrates lotus-miner to Curio in 5 minutes.",
"translation": "이 대화형 도구는 5분 안에 lotus-miner를 Curio로 이주합니다.",
"message": "This interactive tool migrates lotus-miner to Curio in 5 minutes.",
"placeholder": null
},
{
"id": "Each step needs your confirmation and can be reversed. Press Ctrl+C to exit at any time.",
"translation": "각 단계는 확인이 필요하며 되돌릴 수 있습니다. 언제든지 Ctrl+C를 눌러 종료할 수 있습니다.",
"message": "Each step needs your confirmation and can be reversed. Press Ctrl+C to exit at any time.",
"placeholder": null
},
{
"id": "Use the arrow keys to navigate: ↓ ↑ → ←",
"translation": "화살표 키를 사용하여 이동하세요: ↓ ↑ → ←",
"message": "Use the arrow keys to navigate: ↓ ↑ → ←",
"placeholder": null
},
{
"id": "Lotus-Miner to Curio Migration.",
"translation": "Lotus-Miner에서 Curio로 이주.",
"message": "Lotus-Miner to Curio Migration.",
"placeholder": null
},
{
"id": "Try the web interface with for further guided improvements.",
"translation": "더 나은 안내를 위해 웹 인터페이스를 사용해보세요.",
"message": "Try the web interface with for further guided improvements.",
"placeholder": null
},
{
"id": "You can now migrate your market node ({Boost}), if applicable.",
"translation": "해당하는 경우 이제 시장 노드를 이주할 수 있습니다 ({Boost}).",
"message": "You can now migrate your market node ({Boost}), if applicable.",
"placeholder": null
},
{
"id": "Migrating config.toml to database.",
"translation": "config.toml을 데이터베이스로 이주 중입니다.",
"message": "Migrating config.toml to database.",
"placeholder": null
},
{
"id": "Error reading from database: {Error}. Aborting Migration.",
"translation": "데이터베이스에서 읽는 중 오류 발생: {Error}. 마이그레이션 중단.",
"message": "Error reading from database: {Error}. Aborting Migration.",
"placeholder": null
},
{
"id": "cannot read API: {Error}. Aborting Migration",
"translation": "API를 읽을 수 없습니다: {Error}. 마이그레이션 중단",
"message": "cannot read API: {Error}. Aborting Migration",
"placeholder": null
},
{
"id": "Error saving config to layer: {Error}. Aborting Migration",
"translation": "레이어에 구성을 저장하는 중 오류 발생: {Error}. 마이그레이션 중단",
"message": "Error saving config to layer: {Error}. Aborting Migration",
"placeholder": null
},
{
"id": "Protocol Labs wants to improve the software you use. Tell the team you're using Curio.",
"translation": "Protocol Labs는 당신이 사용하는 소프트웨어를 개선하고 싶어합니다. Curio를 사용 중이라고 팀에 알려주세요.",
"message": "Protocol Labs wants to improve the software you use. Tell the team you're using Curio.",
"placeholder": null
},
{
"id": "Select what you want to share with the Curio team.",
"translation": "Curio 팀과 공유하고 싶은 것을 선택하세요.",
"message": "Select what you want to share with the Curio team.",
"placeholder": null
},
{
"id": "Individual Data: Miner ID, Curio version, net ({Mainnet} or {Testnet}). Signed.",
"translation": "개별 데이터: 마이너 ID, Curio 버전, 네트워크 ({Mainnet} 또는 {Testnet}). 서명됨.",
"message": "Individual Data: Miner ID, Curio version, net ({Mainnet} or {Testnet}). Signed.",
"placeholder": null
},
{
"id": "Aggregate-Anonymous: version, net, and Miner power (bucketed).",
"translation": "집계-익명: 버전, 네트워크, 그리고 마이너 파워 (버킷).",
"message": "Aggregate-Anonymous: version, net, and Miner power (bucketed).",
"placeholder": null
},
{
"id": "Hint: I am someone running Curio on net.",
"translation": "힌트: 네트워크에서 Curio를 실행 중인 사람입니다.",
"message": "Hint: I am someone running Curio on net.",
"placeholder": null
},
{
"id": "Nothing.",
"translation": "아무것도 없습니다.",
"message": "Nothing.",
"placeholder": null
},
{
"id": "Aborting remaining steps.",
"translation": "나머지 단계를 중단합니다.",
"message": "Aborting remaining steps.",
"placeholder": null
},
{
"id": "Error connecting to lotus node: {Error}",
"translation": "로터스 노드에 연결하는 중 오류 발생: {Error}",
"message": "Error connecting to lotus node: {Error}",
"placeholder": null
},
{
"id": "Error getting miner power: {Error}",
"translation": "마이너 파워를 가져오는 중 오류 발생: {Error}",
"message": "Error getting miner power: {Error}",
"placeholder": null
},
{
"id": "Error marshalling message: {Error}",
"translation": "메시지를 마샬하는 중 오류 발생: {Error}",
"message": "Error marshalling message: {Error}",
"placeholder": null
},
{
"id": "Error getting miner info: {Error}",
"translation": "마이너 정보를 가져오는 중 오류 발생: {Error}",
"message": "Error getting miner info: {Error}",
"placeholder": null
},
{
"id": "Error signing message: {Error}",
"translation": "메시지 서명 중 오류 발생: {Error}",
"message": "Error signing message: {Error}",
"placeholder": null
},
{
"id": "Error sending message: {Error}",
"translation": "메시지 전송 중 오류 발생: {Error}",
"message": "Error sending message: {Error}",
"placeholder": null
},
{
"id": "Error sending message: Status {Status}, Message:",
"translation": "메시지 전송 중 오류 발생: 상태 {Status}, 메시지:",
"message": "Error sending message: Status {Status}, Message:",
"placeholder": null
},
{
"id": "Message sent.",
"translation": "메시지가 전송되었습니다.",
"message": "Message sent.",
"placeholder": null
},
{
"id": "Documentation:",
"translation": "문서:",
"message": "Documentation:",
"placeholder": null
},
{
"id": "The '{Base}' layer stores common configuration. All curio instances can include it in their {__layers} argument.",
"translation": "'{Base}' 레이어에는 공통 구성이 저장됩니다. 모든 Curio 인스턴스는 {__layers} 인수에 포함시킬 수 있습니다.",
"message": "The '{Base}' layer stores common configuration. All curio instances can include it in their {__layers} argument.",
"placeholder": null
},
{
"id": "You can add other layers for per-machine configuration changes.",
"translation": "기계별 구성 변경을 위해 다른 레이어를 추가할 수 있습니다.",
"message": "You can add other layers for per-machine configuration changes.",
"placeholder": null
},
{
"id": "Join {Fil_curio_help} in Filecoin {Slack} for help.",
"translation": "도움을 위해 Filecoin {Slack}의 {Fil_curio_help}에 가입하세요.",
"message": "Join {Fil_curio_help} in Filecoin {Slack} for help.",
"placeholder": null
},
{
"id": "Join {Fil_curio_dev} in Filecoin {Slack} to follow development and feedback!",
"translation": "개발과 피드백을 따르려면 Filecoin {Slack}의 {Fil_curio_dev}에 가입하세요!",
"message": "Join {Fil_curio_dev} in Filecoin {Slack} to follow development and feedback!",
"placeholder": null
},
{
"id": "Want PoST redundancy? Run many Curio instances with the '{Post}' layer.",
"translation": "PoST 중복성이 필요하신가요? '{Post}' 레이어와 함께 여러 Curio 인스턴스를 실행하세요.",
"message": "Want PoST redundancy? Run many Curio instances with the '{Post}' layer.",
"placeholder": null
},
{
"id": "Point your browser to your web GUI to complete setup with {Boost} and advanced featues.",
"translation": "브라우저를 웹 GUI로 이동하여 {Boost} 및 고급 기능으로 설정을 완료하세요.",
"message": "Point your browser to your web GUI to complete setup with {Boost} and advanced featues.",
"placeholder": null
},
{
"id": "For SPs with multiple Miner IDs, run 1 migration per lotus-miner all to the same 1 database. The cluster will serve all Miner IDs.",
"translation": "여러 마이너 ID가 있는 SP의 경우 각 lotus-miner당 1회 마이그레이션을 동일한 1개의 데이터베이스로 모두 실행하세요. 클러스터는 모든 마이너 ID를 제공합니다.",
"message": "For SPs with multiple Miner IDs, run 1 migration per lotus-miner all to the same 1 database. The cluster will serve all Miner IDs.",
"placeholder": null
},
{
"id": "Please start {Lotus_miner} now that database credentials are in {Toml}.",
"translation": "데이터베이스 자격 증명이 {Toml}에 있으므로 이제 {Lotus_miner}를 시작하세요.",
"message": "Please start {Lotus_miner} now that database credentials are in {Toml}.",
"placeholder": null
},
{
"id": "Waiting for {Lotus_miner} to write sectors into Yugabyte.",
"translation": "{Lotus_miner}가 Yugabyte에 섹터를 기록하도록 대기 중입니다.",
"message": "Waiting for {Lotus_miner} to write sectors into Yugabyte.",
"placeholder": null
},
{
"id": "The sectors are in the database. The database is ready for {Curio}.",
"translation": "섹터가 데이터베이스에 있습니다. 데이터베이스가 {Curio}를 위해 준비되었습니다.",
"message": "The sectors are in the database. The database is ready for {Curio}.",
"placeholder": null
},
{
"id": "Now shut down lotus-miner and move the systems to {Curio}.",
"translation": "이제 lotus-miner를 종료하고 시스템을 {Curio}로 이동하세요.",
"message": "Now shut down lotus-miner and move the systems to {Curio}.",
"placeholder": null
},
{
"id": "Press return to continue",
"translation": "계속하려면 리턴을 누르세요",
"message": "Press return to continue",
"placeholder": null
},
{
"id": "Aborting migration.",
"translation": "마이그레이션 중단.",
"message": "Aborting migration.",
"placeholder": null
},
{
"id": "Sectors verified. {I} sector locations found.",
"translation": "섹터가 확인되었습니다. {I}개의 섹터 위치를 찾았습니다.",
"message": "Sectors verified. {I} sector locations found.",
"placeholder": null
},
{
"id": "Press return to update {Toml} with Yugabyte info. Backup the file now.",
"translation": "{Toml}을 Yugabyte 정보로 업데이트하려면 리턴을 누르세요. 지금 파일을 백업하세요.",
"message": "Press return to update {Toml} with Yugabyte info. Backup the file now.",
"placeholder": null
},
{
"id": "To start, ensure your sealing pipeline is drained and shut-down lotus-miner.",
"translation": "시작하려면 밀봉 파이프라인이 비어 있고 lotus-miner가 종료되었는지 확인하세요.",
"message": "To start, ensure your sealing pipeline is drained and shut-down lotus-miner.",
"placeholder": null
},
{
"id": "Enter the path to the configuration directory used by {Lotus_miner}",
"translation": "{Lotus_miner}에서 사용하는 구성 디렉터리 경로를 입력하세요.",
"message": "Enter the path to the configuration directory used by {Lotus_miner}",
"placeholder": null
},
{
"id": "Step Complete: {Step}",
"translation": "단계 완료: {Step}",
"message": "Step Complete: {Step}",
"placeholder": null
},
{
"id": "Configuration 'base' was updated to include this miner's address and its wallet setup.",
"translation": "이 마이너의 주소와 지갑 설정을 포함하도록 구성 'base'가 업데이트되었습니다.",
"message": "Configuration 'base' was updated to include this miner's address and its wallet setup.",
"placeholder": null
},
{
"id": "Compare the configurations {Base} to {MinerAddresses0}. Changes between the miner IDs other than wallet addreses should be a new, minimal layer for runners that need it.",
"translation": "구성 {Base}를 {MinerAddresses0}과 비교하세요. 지갑 주소 이외의 마이너 ID 사이의 변경 사항은 필요한 실행자를 위한 새로운 최소한의 레이어여야 합니다.",
"message": "Compare the configurations {Base} to {MinerAddresses0}. Changes between the miner IDs other than wallet addreses should be a new, minimal layer for runners that need it.",
"placeholder": null
},
{
"id": "Configuration 'base' was created to include this miner's address and its wallet setup.",
"translation": "이 마이너의 주소와 지갑 설정을 포함하도록 구성 'base'가 생성되었습니다.",
"message": "Configuration 'base' was created to include this miner's address and its wallet setup.",
"placeholder": null
},
{
"id": "Layer {LayerName} created.",
"translation": "레이어 {LayerName}가 생성되었습니다.",
"message": "Layer {LayerName} created.",
"placeholder": null
},
{
"id": "To work with the config: \\n",
"translation": "구성을 사용하려면: \\n",
"message": "To work with the config: \\n",
"placeholder": null
},
{
"id": "To run Curio: With machine or cgroup isolation, use the command (with example layer selection):",
"translation": "Curio를 실행하려면: 기계 또는 cgroup 격리를 사용하여 다음 명령을 사용하세요 (예제 레이어 선택과 함께):",
"message": "To run Curio: With machine or cgroup isolation, use the command (with example layer selection):",
"placeholder": null
},
{
"id": "Try the web interface with {__layersgui} for further guided improvements.",
"translation": "더 많은 안내를 위해 {__layersgui}를 사용하여 웹 인터페이스를 시도하세요.",
"message": "Try the web interface with {__layersgui} for further guided improvements.",
"placeholder": null
},
{
"id": "Error connecting to lotus node: {Error} {Error_1}",
"translation": "lotus 노드에 연결하는 중 오류 발생: {Error} {Error_1}",
"message": "Error connecting to lotus node: {Error} {Error_1}",
"placeholder": null
},
{
"id": "could not get API info for FullNode: {Err}",
"translation": "FullNode의 API 정보를 가져올 수 없습니다: {Err}",
"message": "could not get API info for FullNode: {Err}",
"placeholder": null
},
{
"id": "Error getting token: {Error}",
"translation": "토큰을 가져오는 중 오류 발생: {Error}",
"message": "Error getting token: {Error}",
"placeholder": null
},
{
"id": "Filecoin {Slack} channels: {Fil_curio_help} and {Fil_curio_dev}",
"translation": "Filecoin {Slack} 채널: {Fil_curio_help} 및 {Fil_curio_dev}",
"message": "Filecoin {Slack} channels: {Fil_curio_help} and {Fil_curio_dev}",
"placeholder": null
},
{
"id": "Start multiple Curio instances with the '{Post}' layer to redundancy.",
"translation": "'{Post}' 레이어로 여러 Curio 인스턴스를 시작하여 중복성을 확보하세요.",
"message": "Start multiple Curio instances with the '{Post}' layer to redundancy.",
"placeholder": null
},
{
"id": "One database can serve multiple miner IDs: Run a migration for each lotus-miner.",
"translation": "한 개의 데이터베이스는 여러 광부 ID를 제공할 수 있습니다: 각 lotus-miner에 대해 마이그레이션을 실행하세요.",
"message": "One database can serve multiple miner IDs: Run a migration for each lotus-miner.",
"placeholder": null
},
{
"id": "Please start (or restart) {Lotus_miner} now that database credentials are in {Toml}.",
"translation": "데이터베이스 자격 증명이 {Toml}에 입력되었으므로 지금 {Lotus_miner}을 시작하거나 다시 시작하세요.",
"message": "Please start (or restart) {Lotus_miner} now that database credentials are in {Toml}.",
"placeholder": null
},
{
"id": "Error interpreting miner ID: {Error}: ID: {String}",
"translation": "광부 ID를 해석하는 중 오류 발생: {Error}: ID: {String}",
"message": "Error interpreting miner ID: {Error}: ID: {String}",
"placeholder": null
},
{
"id": "Enabling Sector Indexing in the database.",
"translation": "데이터베이스에서 Sector Indexing을 활성화합니다.",
"message": "Enabling Sector Indexing in the database.",
"placeholder": null
},
{
"id": "Error expanding path: {Error}",
"translation": "경로를 확장하는 중 오류 발생: {Error}",
"message": "Error expanding path: {Error}",
"placeholder": null
},
{
"id": "Could not create repo from directory: {Error}. Aborting migration",
"translation": "디렉토리에서 저장소를 생성할 수 없습니다: {Error}. 마이그레이션을 중단합니다.",
"message": "Could not create repo from directory: {Error}. Aborting migration",
"placeholder": null
},
{
"id": "Could not lock miner repo. Your miner must be stopped: {Error}\n Aborting migration",
"translation": "광부 저장소를 잠금 해제할 수 없습니다. 귀하의 광부를 중지해야 합니다: {Error}\n 마이그레이션을 중단합니다.",
"message": "Could not lock miner repo. Your miner must be stopped: {Error}\n Aborting migration",
"placeholder": null
},
{
"id": "To work with the config:",
"translation": "구성 파일을 사용하려면:",
"message": "To work with the config:",
"placeholder": null
}
]
}
@@ -0,0 +1,89 @@
{
"language": "ko",
"messages": [
{
"id": "Try the web interface with {__layersgui} for further guided improvements.",
"translation": "",
"message": "Try the web interface with {__layersgui} for further guided improvements.",
"placeholder": null
},
{
"id": "Error connecting to lotus node: {Error} {Error_1}",
"translation": "",
"message": "Error connecting to lotus node: {Error} {Error_1}",
"placeholder": null
},
{
"id": "could not get API info for FullNode: {Err}",
"translation": "",
"message": "could not get API info for FullNode: {Err}",
"placeholder": null
},
{
"id": "Error getting token: {Error}",
"translation": "",
"message": "Error getting token: {Error}",
"placeholder": null
},
{
"id": "Filecoin {Slack} channels: {Fil_curio_help} and {Fil_curio_dev}",
"translation": "",
"message": "Filecoin {Slack} channels: {Fil_curio_help} and {Fil_curio_dev}",
"placeholder": null
},
{
"id": "Start multiple Curio instances with the '{Post}' layer to redundancy.",
"translation": "",
"message": "Start multiple Curio instances with the '{Post}' layer to redundancy.",
"placeholder": null
},
{
"id": "One database can serve multiple miner IDs: Run a migration for each lotus-miner.",
"translation": "",
"message": "One database can serve multiple miner IDs: Run a migration for each lotus-miner.",
"placeholder": null
},
{
"id": "Please start (or restart) {Lotus_miner} now that database credentials are in {Toml}.",
"translation": "",
"message": "Please start (or restart) {Lotus_miner} now that database credentials are in {Toml}.",
"placeholder": null
},
{
"id": "Error interpreting miner ID: {Error}: ID: {String}",
"translation": "",
"message": "Error interpreting miner ID: {Error}: ID: {String}",
"placeholder": null
},
{
"id": "Enabling Sector Indexing in the database.",
"translation": "",
"message": "Enabling Sector Indexing in the database.",
"placeholder": null
},
{
"id": "Error expanding path: {Error}",
"translation": "",
"message": "Error expanding path: {Error}",
"placeholder": null
},
{
"id": "Could not create repo from directory: {Error}. Aborting migration",
"translation": "",
"message": "Could not create repo from directory: {Error}. Aborting migration",
"placeholder": null
},
{
"id": "Could not lock miner repo. Your miner must be stopped: {Error}\n Aborting migration",
"translation": "",
"message": "Could not lock miner repo. Your miner must be stopped: {Error}\n Aborting migration",
"placeholder": null
},
{
"id": "To work with the config:",
"translation": "",
"message": "To work with the config:",
"placeholder": null
}
]
}
@@ -0,0 +1,704 @@
{
"language": "zh",
"messages": [
{
"id": "This interactive tool will walk you through migration of Curio.\nPress Ctrl+C to exit at any time.",
"message": "This interactive tool will walk you through migration of Curio.\nPress Ctrl+C to exit at any time.",
"translation": "此互动工具将引导您完成Curio的迁移。\n随时按Ctrl+C退出。"
},
{
"id": "This tool confirms each action it does.",
"message": "This tool confirms each action it does.",
"translation": "此工具确认其执行的每个操作。"
},
{
"id": "Ctrl+C pressed in Terminal",
"message": "Ctrl+C pressed in Terminal",
"translation": "在终端中按下Ctrl+C"
},
{
"id": "Verifying Sectors exist in Yugabyte.",
"message": "Verifying Sectors exist in Yugabyte.",
"translation": "正在验证Yugabyte中的扇区是否存在。"
},
{
"id": "Error verifying sectors: {Error}",
"message": "Error verifying sectors: {Error}",
"translation": "验证扇区时出错:{Error}",
"placeholders": [
{
"id": "Error",
"string": "%[1]s",
"type": "string",
"underlyingType": "string",
"argNum": 1,
"expr": "err.Error()"
}
]
},
{
"id": "Sectors verified. {I} sectors found.",
"message": "Sectors verified. {I} sectors found.",
"translation": "已验证扇区。找到了{I}个扇区。",
"placeholders": [
{
"id": "I",
"string": "%[1]d",
"type": "[]int",
"underlyingType": "[]int",
"argNum": 1,
"expr": "i"
}
]
},
{
"id": "Never remove the database info from the config.toml for lotus-miner as it avoids double PoSt.",
"message": "Never remove the database info from the config.toml for lotus-miner as it avoids double PoSt.",
"translation": "从config.toml中永远不要删除lotus-miner的数据库信息,因为它避免了双PoSt。"
},
{
"id": "Enter the info to connect to your Yugabyte database installation (https://download.yugabyte.com/)",
"message": "Enter the info to connect to your Yugabyte database installation (https://download.yugabyte.com/)",
"translation": "输入连接到您的Yugabyte数据库安装的信息(https://download.yugabyte.com/"
},
{
"id": "Host: {Hosts_}",
"message": "Host: {Hosts_}",
"translation": "主机:{Hosts_}",
"placeholders": [
{
"id": "Hosts_",
"string": "%[1]s",
"type": "string",
"underlyingType": "string",
"argNum": 1,
"expr": "strings.Join(harmonycfg.Hosts, \",\")"
}
]
},
{
"id": "Port: {Port}",
"message": "Port: {Port}",
"translation": "端口:{Port}",
"placeholders": [
{
"id": "Port",
"string": "%[1]s",
"type": "string",
"underlyingType": "string",
"argNum": 1,
"expr": "harmonycfg.Port"
}
]
},
{
"id": "Username: {Username}",
"message": "Username: {Username}",
"translation": "用户名:{Username}",
"placeholders": [
{
"id": "Username",
"string": "%[1]s",
"type": "string",
"underlyingType": "string",
"argNum": 1,
"expr": "harmonycfg.Username"
}
]
},
{
"id": "Password: {Password}",
"message": "Password: {Password}",
"translation": "密码:{Password}",
"placeholders": [
{
"id": "Password",
"string": "%[1]s",
"type": "string",
"underlyingType": "string",
"argNum": 1,
"expr": "harmonycfg.Password"
}
]
},
{
"id": "Database: {Database}",
"message": "Database: {Database}",
"translation": "数据库:{Database}",
"placeholders": [
{
"id": "Database",
"string": "%[1]s",
"type": "string",
"underlyingType": "string",
"argNum": 1,
"expr": "harmonycfg.Database"
}
]
},
{
"id": "Continue to connect and update schema.",
"message": "Continue to connect and update schema.",
"translation": "继续连接和更新架构。"
},
{
"id": "Database config error occurred, abandoning migration: {Error}",
"message": "Database config error occurred, abandoning migration: {Error}",
"translation": "发生数据库配置错误,放弃迁移:{Error}",
"placeholders": [
{
"id": "Error",
"string": "%[1]s",
"type": "string",
"underlyingType": "string",
"argNum": 1,
"expr": "err.Error()"
}
]
},
{
"id": "Enter the Yugabyte database host(s)",
"message": "Enter the Yugabyte database host(s)",
"translation": "输入Yugabyte数据库主机(S"
},
{
"id": "No host provided",
"message": "No host provided",
"translation": "未提供主机"
},
{
"id": "Enter the Yugabyte database {Stringport_username_password_databasei_1}",
"message": "Enter the Yugabyte database {Stringport_username_password_databasei_1}",
"translation": "输入Yugabyte数据库 {Stringport_username_password_databasei_1}",
"placeholders": [
{
"id": "Stringport_username_password_databasei_1",
"string": "%[1]s",
"type": "string",
"underlyingType": "string",
"argNum": 1,
"expr": "[]string{\"port\", \"username\", \"password\", \"database\"}[i-1]"
}
]
},
{
"id": "No value provided",
"message": "No value provided",
"translation": "未提供值"
},
{
"id": "Error connecting to Yugabyte database: {Error}",
"message": "Error connecting to Yugabyte database: {Error}",
"translation": "连接到Yugabyte数据库时出错:{Error}",
"placeholders": [
{
"id": "Error",
"string": "%[1]s",
"type": "string",
"underlyingType": "string",
"argNum": 1,
"expr": "err.Error()"
}
]
},
{
"id": "Connected to Yugabyte. Schema is current.",
"message": "Connected to Yugabyte. Schema is current.",
"translation": "已连接到Yugabyte。模式是当前的。"
},
{
"id": "Error encoding config.toml: {Error}",
"message": "Error encoding config.toml: {Error}",
"translation": "编码config.toml时出错:{Error}",
"placeholders": [
{
"id": "Error",
"string": "%[1]s",
"type": "string",
"underlyingType": "string",
"argNum": 1,
"expr": "err.Error()"
}
]
},
{
"id": "Error reading filemode of config.toml: {Error}",
"message": "Error reading filemode of config.toml: {Error}",
"translation": "读取config.toml文件模式时出错:{Error}",
"placeholders": [
{
"id": "Error",
"string": "%[1]s",
"type": "string",
"underlyingType": "string",
"argNum": 1,
"expr": "err.Error()"
}
]
},
{
"id": "Error writing config.toml: {Error}",
"message": "Error writing config.toml: {Error}",
"translation": "写入config.toml时出错:{Error}",
"placeholders": [
{
"id": "Error",
"string": "%[1]s",
"type": "string",
"underlyingType": "string",
"argNum": 1,
"expr": "err.Error()"
}
]
},
{
"id": "Restart Lotus Miner.",
"message": "Restart Lotus Miner.",
"translation": "重新启动Lotus Miner。"
},
{
"id": "Connected to Yugabyte",
"message": "Connected to Yugabyte",
"translation": "已连接到Yugabyte"
},
{
"id": "Select the location of your lotus-miner config directory?",
"message": "Select the location of your lotus-miner config directory?",
"translation": "选择您的lotus-miner配置目录的位置?"
},
{
"id": "Other",
"message": "Other",
"translation": "其他"
},
{
"id": "Enter the path to the configuration directory used by lotus-miner",
"message": "Enter the path to the configuration directory used by lotus-miner",
"translation": "输入lotus-miner使用的配置目录的路径"
},
{
"id": "No path provided, abandoning migration",
"message": "No path provided, abandoning migration",
"translation": "未提供路径,放弃迁移"
},
{
"id": "Cannot read the config.toml file in the provided directory, Error: {Error}",
"message": "Cannot read the config.toml file in the provided directory, Error: {Error}",
"translation": "无法读取提供的目录中的config.toml文件,错误:{Error}",
"placeholders": [
{
"id": "Error",
"string": "%[1]s",
"type": "string",
"underlyingType": "string",
"argNum": 1,
"expr": "err.Error()"
}
]
},
{
"id": "Read Miner Config",
"message": "Read Miner Config",
"translation": "读取矿工配置"
},
{
"id": "Completed Step: {Step}",
"message": "Completed Step: {Step}",
"translation": "完成步骤:{Step}",
"placeholders": [
{
"id": "Step",
"string": "%[1]s",
"type": "string",
"underlyingType": "string",
"argNum": 1,
"expr": "step"
}
]
},
{
"id": "This interactive tool migrates lotus-miner to Curio in 5 minutes.",
"translation": "这个交互式工具可以在5分钟内将lotus-miner迁移到Curio。",
"message": "This interactive tool migrates lotus-miner to Curio in 5 minutes.",
"placeholder": null
},
{
"id": "Each step needs your confirmation and can be reversed. Press Ctrl+C to exit at any time.",
"translation": "每一步都需要您的确认,并且可以撤销。随时按Ctrl+C退出。",
"message": "Each step needs your confirmation and can be reversed. Press Ctrl+C to exit at any time.",
"placeholder": null
},
{
"id": "Use the arrow keys to navigate: ↓ ↑ → ←",
"translation": "使用箭头键进行导航:↓ ↑ → ←",
"message": "Use the arrow keys to navigate: ↓ ↑ → ←",
"placeholder": null
},
{
"id": "Lotus-Miner to Curio Migration.",
"translation": "Lotus-Miner到Curio迁移。",
"message": "Lotus-Miner to Curio Migration.",
"placeholder": null
},
{
"id": "Try the web interface with for further guided improvements.",
"translation": "尝试使用网页界面进行进一步的指导改进。",
"message": "Try the web interface with for further guided improvements.",
"placeholder": null
},
{
"id": "You can now migrate your market node ({Boost}), if applicable.",
"translation": "如果适用,您现在可以迁移您的市场节点({Boost})。",
"message": "You can now migrate your market node ({Boost}), if applicable.",
"placeholder": null
},
{
"id": "Migrating config.toml to database.",
"translation": "正在将config.toml迁移到数据库。",
"message": "Migrating config.toml to database.",
"placeholder": null
},
{
"id": "Error reading from database: {Error}. Aborting Migration.",
"translation": "读取数据库时出错:{Error}。正在中止迁移。",
"message": "Error reading from database: {Error}. Aborting Migration.",
"placeholder": null
},
{
"id": "cannot read API: {Error}. Aborting Migration",
"translation": "无法读取API{Error}。正在中止迁移",
"message": "cannot read API: {Error}. Aborting Migration",
"placeholder": null
},
{
"id": "Error saving config to layer: {Error}. Aborting Migration",
"translation": "保存配置到层时出错:{Error}。正在中止迁移",
"message": "Error saving config to layer: {Error}. Aborting Migration",
"placeholder": null
},
{
"id": "Protocol Labs wants to improve the software you use. Tell the team you're using Curio.",
"translation": "Protocol Labs希望改进您使用的软件。告诉团队您正在使用Curio。",
"message": "Protocol Labs wants to improve the software you use. Tell the team you're using Curio.",
"placeholder": null
},
{
"id": "Select what you want to share with the Curio team.",
"translation": "选择您想与Curio团队分享的内容。",
"message": "Select what you want to share with the Curio team.",
"placeholder": null
},
{
"id": "Individual Data: Miner ID, Curio version, net ({Mainnet} or {Testnet}). Signed.",
"translation": "个人数据:矿工ID、Curio版本、网络({Mainnet}或{Testnet})。已签名。",
"message": "Individual Data: Miner ID, Curio version, net ({Mainnet} or {Testnet}). Signed.",
"placeholder": null
},
{
"id": "Aggregate-Anonymous: version, net, and Miner power (bucketed).",
"translation": "聚合-匿名:版本、网络和矿工功率(分桶)。",
"message": "Aggregate-Anonymous: version, net, and Miner power (bucketed).",
"placeholder": null
},
{
"id": "Hint: I am someone running Curio on net.",
"translation": "提示:我是在网络上运行Curio的人。",
"message": "Hint: I am someone running Curio on net.",
"placeholder": null
},
{
"id": "Nothing.",
"translation": "没有。",
"message": "Nothing.",
"placeholder": null
},
{
"id": "Aborting remaining steps.",
"translation": "中止剩余步骤。",
"message": "Aborting remaining steps.",
"placeholder": null
},
{
"id": "Error connecting to lotus node: {Error}",
"translation": "连接到莲花节点时出错:{Error}",
"message": "Error connecting to lotus node: {Error}",
"placeholder": null
},
{
"id": "Error getting miner power: {Error}",
"translation": "获取矿工功率时出错:{Error}",
"message": "Error getting miner power: {Error}",
"placeholder": null
},
{
"id": "Error marshalling message: {Error}",
"translation": "整理消息时出错:{Error}",
"message": "Error marshalling message: {Error}",
"placeholder": null
},
{
"id": "Error getting miner info: {Error}",
"translation": "获取矿工信息时出错:{Error}",
"message": "Error getting miner info: {Error}",
"placeholder": null
},
{
"id": "Error signing message: {Error}",
"translation": "签署消息时出错:{Error}",
"message": "Error signing message: {Error}",
"placeholder": null
},
{
"id": "Error sending message: {Error}",
"translation": "发送消息时出错:{Error}",
"message": "Error sending message: {Error}",
"placeholder": null
},
{
"id": "Error sending message: Status {Status}, Message:",
"translation": "发送消息时出错:状态{Status},消息:",
"message": "Error sending message: Status {Status}, Message:",
"placeholder": null
},
{
"id": "Message sent.",
"translation": "消息已发送。",
"message": "Message sent.",
"placeholder": null
},
{
"id": "Documentation:",
"translation": "文档:",
"message": "Documentation:",
"placeholder": null
},
{
"id": "The '{Base}' layer stores common configuration. All curio instances can include it in their {__layers} argument.",
"translation": "'{Base}'层存储通用配置。所有Curio实例都可以在其{__layers}参数中包含它。",
"message": "The '{Base}' layer stores common configuration. All curio instances can include it in their {__layers} argument.",
"placeholder": null
},
{
"id": "You can add other layers for per-machine configuration changes.",
"translation": "您可以添加其他层进行每台机器的配置更改。",
"message": "You can add other layers for per-machine configuration changes.",
"placeholder": null
},
{
"id": "Join {Fil_curio_help} in Filecoin {Slack} for help.",
"translation": "加入Filecoin {Slack}中的{Fil_curio_help}寻求帮助。",
"message": "Join {Fil_curio_help} in Filecoin {Slack} for help.",
"placeholder": null
},
{
"id": "Join {Fil_curio_dev} in Filecoin {Slack} to follow development and feedback!",
"translation": "加入Filecoin {Slack}中的{Fil_curio_dev}来跟踪开发和反馈!",
"message": "Join {Fil_curio_dev} in Filecoin {Slack} to follow development and feedback!",
"placeholder": null
},
{
"id": "Want PoST redundancy? Run many Curio instances with the '{Post}' layer.",
"translation": "需要PoST冗余?使用'{Post}'层运行多个Curio实例。",
"message": "Want PoST redundancy? Run many Curio instances with the '{Post}' layer.",
"placeholder": null
},
{
"id": "Point your browser to your web GUI to complete setup with {Boost} and advanced featues.",
"translation": "将您的浏览器指向您的网络GUI,以使用{Boost}和高级功能完成设置。",
"message": "Point your browser to your web GUI to complete setup with {Boost} and advanced featues.",
"placeholder": null
},
{
"id": "For SPs with multiple Miner IDs, run 1 migration per lotus-miner all to the same 1 database. The cluster will serve all Miner IDs.",
"translation": "对于具有多个矿工ID的SP,针对所有lotus-miner运行1次迁移到同一个数据库。集群将服务所有矿工ID。",
"message": "For SPs with multiple Miner IDs, run 1 migration per lotus-miner all to the same 1 database. The cluster will serve all Miner IDs.",
"placeholder": null
},
{
"id": "Please start {Lotus_miner} now that database credentials are in {Toml}.",
"translation": "现在数据库凭证在{Toml}中,请启动{Lotus_miner}。",
"message": "Please start {Lotus_miner} now that database credentials are in {Toml}.",
"placeholder": null
},
{
"id": "Waiting for {Lotus_miner} to write sectors into Yugabyte.",
"translation": "等待{Lotus_miner}将扇区写入Yugabyte。",
"message": "Waiting for {Lotus_miner} to write sectors into Yugabyte.",
"placeholder": null
},
{
"id": "The sectors are in the database. The database is ready for {Curio}.",
"translation": "扇区在数据库中。数据库已准备好用于{Curio}。",
"message": "The sectors are in the database. The database is ready for {Curio}.",
"placeholder": null
},
{
"id": "Now shut down lotus-miner and move the systems to {Curio}.",
"translation": "现在关闭lotus-miner并将系统移至{Curio}。",
"message": "Now shut down lotus-miner and move the systems to {Curio}.",
"placeholder": null
},
{
"id": "Press return to continue",
"translation": "按回车继续",
"message": "Press return to continue",
"placeholder": null
},
{
"id": "Aborting migration.",
"translation": "中止迁移。",
"message": "Aborting migration.",
"placeholder": null
},
{
"id": "Sectors verified. {I} sector locations found.",
"translation": "扇区已验证。发现了{I}个扇区位置。",
"message": "Sectors verified. {I} sector locations found.",
"placeholder": null
},
{
"id": "Press return to update {Toml} with Yugabyte info. Backup the file now.",
"translation": "按回车更新{Toml}以获取Yugabyte信息。现在备份文件。",
"message": "Press return to update {Toml} with Yugabyte info. Backup the file now.",
"placeholder": null
},
{
"id": "To start, ensure your sealing pipeline is drained and shut-down lotus-miner.",
"translation": "开始之前,请确保您的密封管道已排空并关闭lotus-miner。",
"message": "To start, ensure your sealing pipeline is drained and shut-down lotus-miner.",
"placeholder": null
},
{
"id": "Enter the path to the configuration directory used by {Lotus_miner}",
"translation": "输入{Lotus_miner}使用的配置目录的路径",
"message": "Enter the path to the configuration directory used by {Lotus_miner}",
"placeholder": null
},
{
"id": "Step Complete: {Step}",
"translation": "步骤完成:{Step}",
"message": "Step Complete: {Step}",
"placeholder": null
},
{
"id": "Configuration 'base' was updated to include this miner's address and its wallet setup.",
"translation": "配置'base'已更新,包含了这个矿工的地址和其钱包设置。",
"message": "Configuration 'base' was updated to include this miner's address and its wallet setup.",
"placeholder": null
},
{
"id": "Compare the configurations {Base} to {MinerAddresses0}. Changes between the miner IDs other than wallet addreses should be a new, minimal layer for runners that need it.",
"translation": "比较配置{Base}和{MinerAddresses0}。矿工ID之间除了钱包地址的变化应该是需要的运行者的一个新的、最小的层。",
"message": "Compare the configurations {Base} to {MinerAddresses0}. Changes between the miner IDs other than wallet addreses should be a new, minimal layer for runners that need it.",
"placeholder": null
},
{
"id": "Configuration 'base' was created to include this miner's address and its wallet setup.",
"translation": "配置'base'已创建,包括了这个矿工的地址和其钱包设置。",
"message": "Configuration 'base' was created to include this miner's address and its wallet setup.",
"placeholder": null
},
{
"id": "Layer {LayerName} created.",
"translation": "层{LayerName}已创建。",
"message": "Layer {LayerName} created.",
"placeholder": null
},
{
"id": "To work with the config: \\n",
"translation": "要使用配置:\\n",
"message": "To work with the config: \\n",
"placeholder": null
},
{
"id": "To run Curio: With machine or cgroup isolation, use the command (with example layer selection):",
"translation": "运行Curio:使用机器或cgroup隔离,使用命令(附带示例层选择):",
"message": "To run Curio: With machine or cgroup isolation, use the command (with example layer selection):",
"placeholder": null
},
{
"id": "Try the web interface with {__layersgui} for further guided improvements.",
"translation": "尝试使用{__layersgui}的Web界面进行进一步引导式改进。",
"message": "Try the web interface with {__layersgui} for further guided improvements.",
"placeholder": null
},
{
"id": "Error connecting to lotus node: {Error} {Error_1}",
"translation": "连接到lotus节点时出错:{Error} {Error_1}",
"message": "Error connecting to lotus node: {Error} {Error_1}",
"placeholder": null
},
{
"id": "could not get API info for FullNode: {Err}",
"translation": "无法获取FullNode的API信息:{Err}",
"message": "could not get API info for FullNode: {Err}",
"placeholder": null
},
{
"id": "Error getting token: {Error}",
"translation": "获取令牌时出错:{Error}",
"message": "Error getting token: {Error}",
"placeholder": null
},
{
"id": "Filecoin {Slack} channels: {Fil_curio_help} and {Fil_curio_dev}",
"translation": "Filecoin {Slack} 频道:{Fil_curio_help} 和 {Fil_curio_dev}",
"message": "Filecoin {Slack} channels: {Fil_curio_help} and {Fil_curio_dev}",
"placeholder": null
},
{
"id": "Start multiple Curio instances with the '{Post}' layer to redundancy.",
"translation": "使用'{Post}'层启动多个Curio实例以实现冗余。",
"message": "Start multiple Curio instances with the '{Post}' layer to redundancy.",
"placeholder": null
},
{
"id": "One database can serve multiple miner IDs: Run a migration for each lotus-miner.",
"translation": "一个数据库可以服务多个矿工ID:为每个lotus-miner运行迁移。",
"message": "One database can serve multiple miner IDs: Run a migration for each lotus-miner.",
"placeholder": null
},
{
"id": "Please start (or restart) {Lotus_miner} now that database credentials are in {Toml}.",
"translation": "请立即启动(或重新启动){Lotus_miner},因为数据库凭据已在{Toml}中。",
"message": "Please start (or restart) {Lotus_miner} now that database credentials are in {Toml}.",
"placeholder": null
},
{
"id": "Error interpreting miner ID: {Error}: ID: {String}",
"translation": "解释矿工ID时出错:{Error}ID{String}",
"message": "Error interpreting miner ID: {Error}: ID: {String}",
"placeholder": null
},
{
"id": "Enabling Sector Indexing in the database.",
"translation": "在数据库中启用扇区索引。",
"message": "Enabling Sector Indexing in the database.",
"placeholder": null
},
{
"id": "Error expanding path: {Error}",
"translation": "扩展路径时出错:{Error}",
"message": "Error expanding path: {Error}",
"placeholder": null
},
{
"id": "Could not create repo from directory: {Error}. Aborting migration",
"translation": "无法从目录创建repo{Error}。 中止迁移",
"message": "Could not create repo from directory: {Error}. Aborting migration",
"placeholder": null
},
{
"id": "Could not lock miner repo. Your miner must be stopped: {Error}\n Aborting migration",
"translation": "无法锁定矿工repo。 您的矿工必须停止:{Error}\n 中止迁移",
"message": "Could not lock miner repo. Your miner must be stopped: {Error}\n Aborting migration",
"placeholder": null
},
{
"id": "To work with the config:",
"translation": "要使用配置:",
"message": "To work with the config:",
"placeholder": null
}
]
}
@@ -0,0 +1,89 @@
{
"language": "zh",
"messages": [
{
"id": "Try the web interface with {__layersgui} for further guided improvements.",
"translation": "",
"message": "Try the web interface with {__layersgui} for further guided improvements.",
"placeholder": null
},
{
"id": "Error connecting to lotus node: {Error} {Error_1}",
"translation": "",
"message": "Error connecting to lotus node: {Error} {Error_1}",
"placeholder": null
},
{
"id": "could not get API info for FullNode: {Err}",
"translation": "",
"message": "could not get API info for FullNode: {Err}",
"placeholder": null
},
{
"id": "Error getting token: {Error}",
"translation": "",
"message": "Error getting token: {Error}",
"placeholder": null
},
{
"id": "Filecoin {Slack} channels: {Fil_curio_help} and {Fil_curio_dev}",
"translation": "",
"message": "Filecoin {Slack} channels: {Fil_curio_help} and {Fil_curio_dev}",
"placeholder": null
},
{
"id": "Start multiple Curio instances with the '{Post}' layer to redundancy.",
"translation": "",
"message": "Start multiple Curio instances with the '{Post}' layer to redundancy.",
"placeholder": null
},
{
"id": "One database can serve multiple miner IDs: Run a migration for each lotus-miner.",
"translation": "",
"message": "One database can serve multiple miner IDs: Run a migration for each lotus-miner.",
"placeholder": null
},
{
"id": "Please start (or restart) {Lotus_miner} now that database credentials are in {Toml}.",
"translation": "",
"message": "Please start (or restart) {Lotus_miner} now that database credentials are in {Toml}.",
"placeholder": null
},
{
"id": "Error interpreting miner ID: {Error}: ID: {String}",
"translation": "",
"message": "Error interpreting miner ID: {Error}: ID: {String}",
"placeholder": null
},
{
"id": "Enabling Sector Indexing in the database.",
"translation": "",
"message": "Enabling Sector Indexing in the database.",
"placeholder": null
},
{
"id": "Error expanding path: {Error}",
"translation": "",
"message": "Error expanding path: {Error}",
"placeholder": null
},
{
"id": "Could not create repo from directory: {Error}. Aborting migration",
"translation": "",
"message": "Could not create repo from directory: {Error}. Aborting migration",
"placeholder": null
},
{
"id": "Could not lock miner repo. Your miner must be stopped: {Error}\n Aborting migration",
"translation": "",
"message": "Could not lock miner repo. Your miner must be stopped: {Error}\n Aborting migration",
"placeholder": null
},
{
"id": "To work with the config:",
"translation": "",
"message": "To work with the config:",
"placeholder": null
}
]
}
@@ -0,0 +1,27 @@
// Usage:
// To UPDATE translations:
//
// 1. add/change strings in guidedsetup folder that use d.T() or d.say().
//
// 2. run `go generate` in the cmd/curio/internal/translations/ folder.
//
// 3. ChatGPT 3.5 can translate the ./locales/??/out.gotext.json files'
// which ONLY include the un-translated messages.
// APPEND to the messages.gotext.json files's array.
//
// ChatGPT fuss:
// - on a good day, you may need to hit "continue generating".
// - > 60? you'll need to give it sections of the file.
//
// 4. Re-import with `go generate` again.
//
// To ADD a language:
// 1. Add it to the list in updateLang.sh
// 2. Run `go generate` in the cmd/curio/internal/translations/ folder.
// 3. Follow the "Update translations" steps here.
// 4. Code will auto-detect the new language and use it.
//
// FUTURE Reliability: OpenAPI automation.
package translations
//go:generate ./updateLang.sh
+8
View File
@@ -0,0 +1,8 @@
#!/bin/bash
#OP: Only run if some file in ../guidedsetup* is newer than catalog.go
# Change this condition if using translations more widely.
if [ "$(find ../../guidedsetup/* -newermt "$(date -d '1 minute ago')" -newer catalog.go)" ] || [ "$(find locales/* -newermt "$(date -d '1 minute ago')" -newer catalog.go)" ]; then
gotext -srclang=en update -out=catalog.go -lang=en,zh,ko github.com/filecoin-project/lotus/cmd/curio/guidedsetup
go run knowns/main.go locales/zh locales/ko
fi
@@ -16,7 +16,8 @@ import (
"github.com/filecoin-project/lotus/build"
lcli "github.com/filecoin-project/lotus/cli"
cliutil "github.com/filecoin-project/lotus/cli/util"
"github.com/filecoin-project/lotus/cmd/lotus-provider/deps"
"github.com/filecoin-project/lotus/cmd/curio/deps"
"github.com/filecoin-project/lotus/cmd/curio/guidedsetup"
"github.com/filecoin-project/lotus/lib/lotuslog"
"github.com/filecoin-project/lotus/lib/tracing"
"github.com/filecoin-project/lotus/node/repo"
@@ -24,7 +25,7 @@ import (
var log = logging.Logger("main")
func SetupCloseHandler() {
func setupCloseHandler() {
c := make(chan os.Signal, 1)
signal.Notify(c, os.Interrupt, syscall.SIGTERM)
go func() {
@@ -36,7 +37,6 @@ func SetupCloseHandler() {
}
func main() {
SetupCloseHandler()
lotuslog.SetupLogLevels()
@@ -48,10 +48,12 @@ func main() {
configCmd,
testCmd,
webCmd,
guidedsetup.GuidedsetupCmd,
configMigrateCmd,
sealCmd,
}
jaeger := tracing.SetupJaegerTracing("lotus")
jaeger := tracing.SetupJaegerTracing("curio")
defer func() {
if jaeger != nil {
_ = jaeger.ForceFlush(context.Background())
@@ -65,7 +67,7 @@ func main() {
if jaeger != nil {
_ = jaeger.Shutdown(cctx.Context)
}
jaeger = tracing.SetupJaegerTracing("lotus/" + cmd.Name)
jaeger = tracing.SetupJaegerTracing("curio/" + cmd.Name)
if cctx.IsSet("color") {
color.NoColor = !cctx.Bool("color")
@@ -80,10 +82,14 @@ func main() {
}
app := &cli.App{
Name: "lotus-provider",
Name: "curio",
Usage: "Filecoin decentralized storage network provider",
Version: build.UserVersion(),
EnableBashCompletion: true,
Before: func(c *cli.Context) error {
setupCloseHandler()
return nil
},
Flags: []cli.Flag{
&cli.BoolFlag{
// examined in the Before above
@@ -93,48 +99,45 @@ func main() {
},
&cli.StringFlag{
Name: "panic-reports",
EnvVars: []string{"LOTUS_PANIC_REPORT_PATH"},
EnvVars: []string{"CURIO_PANIC_REPORT_PATH"},
Hidden: true,
Value: "~/.lotusprovider", // should follow --repo default
Value: "~/.curio", // should follow --repo default
},
&cli.StringFlag{
Name: "db-host",
EnvVars: []string{"LOTUS_DB_HOST"},
EnvVars: []string{"CURIO_DB_HOST", "CURIO_HARMONYDB_HOSTS"},
Usage: "Command separated list of hostnames for yugabyte cluster",
Value: "yugabyte",
},
&cli.StringFlag{
Name: "db-name",
EnvVars: []string{"LOTUS_DB_NAME", "LOTUS_HARMONYDB_HOSTS"},
EnvVars: []string{"CURIO_DB_NAME", "CURIO_HARMONYDB_NAME"},
Value: "yugabyte",
},
&cli.StringFlag{
Name: "db-user",
EnvVars: []string{"LOTUS_DB_USER", "LOTUS_HARMONYDB_USERNAME"},
EnvVars: []string{"CURIO_DB_USER", "CURIO_HARMONYDB_USERNAME"},
Value: "yugabyte",
},
&cli.StringFlag{
Name: "db-password",
EnvVars: []string{"LOTUS_DB_PASSWORD", "LOTUS_HARMONYDB_PASSWORD"},
EnvVars: []string{"CURIO_DB_PASSWORD", "CURIO_HARMONYDB_PASSWORD"},
Value: "yugabyte",
},
&cli.StringFlag{
Name: "db-port",
EnvVars: []string{"LOTUS_DB_PORT", "LOTUS_HARMONYDB_PORT"},
EnvVars: []string{"CURIO_DB_PORT", "CURIO_HARMONYDB_PORT"},
Hidden: true,
Value: "5433",
},
&cli.StringFlag{
Name: deps.FlagRepoPath,
EnvVars: []string{"LOTUS_REPO_PATH"},
Value: "~/.lotusprovider",
EnvVars: []string{"CURIO_REPO_PATH"},
Value: "~/.curio",
},
cliutil.FlagVeryVerbose,
},
Commands: append(local, lcli.CommonCommands...),
Before: func(c *cli.Context) error {
return nil
},
After: func(c *cli.Context) error {
if r := recover(); r != nil {
p, err := homedir.Expand(c.String(FlagMinerRepo))
@@ -143,7 +146,7 @@ func main() {
panic(r)
}
// Generate report in LOTUS_PATH and re-raise panic
// Generate report in CURIO_PATH and re-raise panic
build.GeneratePanicReport(c.String("panic-reports"), p, c.App.Name)
panic(r)
}
@@ -151,6 +154,6 @@ func main() {
},
}
app.Setup()
app.Metadata["repoType"] = repo.Provider
app.Metadata["repoType"] = repo.Curio
lcli.RunApp(app)
}
+71
View File
@@ -0,0 +1,71 @@
package main
import (
"fmt"
"github.com/urfave/cli/v2"
"golang.org/x/xerrors"
cliutil "github.com/filecoin-project/lotus/cli/util"
"github.com/filecoin-project/lotus/cmd/curio/guidedsetup"
"github.com/filecoin-project/lotus/node/repo"
)
var configMigrateCmd = &cli.Command{
Name: "from-miner",
Usage: "Express a database config (for curio) from an existing miner.",
Description: "Express a database config (for curio) from an existing miner.",
Flags: []cli.Flag{
&cli.StringFlag{
Name: FlagMinerRepo,
Aliases: []string{FlagMinerRepoDeprecation},
EnvVars: []string{"LOTUS_MINER_PATH", "LOTUS_STORAGE_PATH"},
Value: "~/.lotusminer",
Usage: fmt.Sprintf("Specify miner repo path. flag(%s) and env(LOTUS_STORAGE_PATH) are DEPRECATION, will REMOVE SOON", FlagMinerRepoDeprecation),
},
&cli.StringFlag{
Name: "repo",
EnvVars: []string{"LOTUS_PATH"},
Hidden: true,
Value: "~/.lotus",
},
&cli.StringFlag{
Name: "to-layer",
Aliases: []string{"t"},
Usage: "The layer name for this data push. 'base' is recommended for single-miner setup.",
},
&cli.BoolFlag{
Name: "overwrite",
Aliases: []string{"o"},
Usage: "Use this with --to-layer to replace an existing layer",
},
},
Action: fromMiner,
}
const (
FlagMinerRepo = "miner-repo"
)
const FlagMinerRepoDeprecation = "storagerepo"
func fromMiner(cctx *cli.Context) (err error) {
minerRepoPath := cctx.String(FlagMinerRepo)
layerName := cctx.String("to-layer")
overwrite := cctx.Bool("overwrite")
// Populate API Key
_, header, err := cliutil.GetRawAPI(cctx, repo.FullNode, "v0")
if err != nil {
return fmt.Errorf("cannot read API: %w", err)
}
ainfo, err := cliutil.GetAPIInfo(&cli.Context{}, repo.FullNode)
if err != nil {
return xerrors.Errorf(`could not get API info for FullNode: %w
Set the environment variable to the value of "lotus auth api-info --perm=admin"`, err)
}
chainApiInfo := header.Get("Authorization")[7:] + ":" + ainfo.Addr
_, err = guidedsetup.SaveConfigToLayer(minerRepoPath, layerName, overwrite, chainApiInfo)
return err
}
@@ -12,9 +12,9 @@ import (
"github.com/filecoin-project/lotus/chain/actors/builtin/miner"
"github.com/filecoin-project/lotus/chain/types"
lcli "github.com/filecoin-project/lotus/cli"
"github.com/filecoin-project/lotus/cmd/lotus-provider/deps"
"github.com/filecoin-project/lotus/cmd/curio/deps"
"github.com/filecoin-project/lotus/curiosrc/seal"
"github.com/filecoin-project/lotus/lib/harmony/harmonydb"
"github.com/filecoin-project/lotus/provider/lpseal"
)
var sealCmd = &cli.Command{
@@ -113,7 +113,7 @@ var sealStartCmd = &cli.Command{
return xerrors.Errorf("getting seal proof type: %w", err)
}
num, err := lpseal.AllocateSectorNumbers(ctx, dep.Full, dep.DB, act, cctx.Int("count"), func(tx *harmonydb.Tx, numbers []abi.SectorNumber) (bool, error) {
num, err := seal.AllocateSectorNumbers(ctx, dep.Full, dep.DB, act, cctx.Int("count"), func(tx *harmonydb.Tx, numbers []abi.SectorNumber) (bool, error) {
for _, n := range numbers {
_, err := tx.Exec("insert into sectors_sdr_pipeline (sp_id, sector_number, reg_seal_proof) values ($1, $2, $3)", mid, n, spt)
if err != nil {
@@ -15,9 +15,9 @@ import (
"github.com/filecoin-project/go-address"
"github.com/filecoin-project/go-state-types/dline"
"github.com/filecoin-project/lotus/cmd/lotus-provider/deps"
"github.com/filecoin-project/lotus/cmd/curio/deps"
curio "github.com/filecoin-project/lotus/curiosrc"
"github.com/filecoin-project/lotus/lib/harmony/harmonydb"
"github.com/filecoin-project/lotus/provider"
)
var testCmd = &cli.Command{
@@ -27,6 +27,9 @@ var testCmd = &cli.Command{
//provingInfoCmd,
wdPostCmd,
},
Before: func(cctx *cli.Context) error {
return nil
},
}
var wdPostCmd = &cli.Command{
@@ -47,7 +50,7 @@ var wdPostCmd = &cli.Command{
var wdPostTaskCmd = &cli.Command{
Name: "task",
Aliases: []string{"scheduled", "schedule", "async", "asynchronous"},
Usage: "Test the windowpost scheduler by running it on the next available lotus-provider. ",
Usage: "Test the windowpost scheduler by running it on the next available curio. ",
Flags: []cli.Flag{
&cli.Uint64Flag{
Name: "deadline",
@@ -148,7 +151,7 @@ It will not send any messages to the chain. Since it can compute any deadline, o
&cli.StringFlag{
Name: "storage-json",
Usage: "path to json file containing storage config",
Value: "~/.lotus-provider/storage.json",
Value: "~/.curio/storage.json",
},
&cli.Uint64Flag{
Name: "partition",
@@ -164,7 +167,8 @@ It will not send any messages to the chain. Since it can compute any deadline, o
return err
}
wdPostTask, wdPoStSubmitTask, derlareRecoverTask, err := provider.WindowPostScheduler(ctx, deps.Cfg.Fees, deps.Cfg.Proving, deps.Full, deps.Verif, deps.LW, nil, nil,
wdPostTask, wdPoStSubmitTask, derlareRecoverTask, err := curio.WindowPostScheduler(
ctx, deps.Cfg.Fees, deps.Cfg.Proving, deps.Full, deps.Verif, deps.LW, nil, nil,
deps.As, deps.Maddrs, deps.DB, deps.Stor, deps.Si, deps.Cfg.Subsystems.WindowPostMaxTasks)
if err != nil {
return err
@@ -27,34 +27,33 @@ import (
"github.com/filecoin-project/lotus/api"
"github.com/filecoin-project/lotus/api/client"
cliutil "github.com/filecoin-project/lotus/cli/util"
"github.com/filecoin-project/lotus/cmd/lotus-provider/deps"
"github.com/filecoin-project/lotus/cmd/curio/deps"
"github.com/filecoin-project/lotus/curiosrc/market"
"github.com/filecoin-project/lotus/curiosrc/web"
"github.com/filecoin-project/lotus/lib/rpcenc"
"github.com/filecoin-project/lotus/metrics"
"github.com/filecoin-project/lotus/metrics/proxy"
"github.com/filecoin-project/lotus/node/repo"
"github.com/filecoin-project/lotus/provider/lpmarket"
"github.com/filecoin-project/lotus/provider/lpweb"
"github.com/filecoin-project/lotus/storage/paths"
"github.com/filecoin-project/lotus/storage/sealer/fsutil"
"github.com/filecoin-project/lotus/storage/sealer/storiface"
)
var log = logging.Logger("lp/rpc")
var log = logging.Logger("curio/rpc")
var permissioned = os.Getenv("LOTUS_DISABLE_AUTH_PERMISSIONED") != "1"
func LotusProviderHandler(
func CurioHandler(
authv func(ctx context.Context, token string) ([]auth.Permission, error),
remote http.HandlerFunc,
a api.LotusProvider,
a api.Curio,
permissioned bool) http.Handler {
mux := mux.NewRouter()
readerHandler, readerServerOpt := rpcenc.ReaderParamDecoder()
rpcServer := jsonrpc.NewServer(jsonrpc.WithServerErrors(api.RPCErrors), readerServerOpt)
wapi := proxy.MetricedAPI[api.LotusProvider, api.LotusProviderStruct](a)
wapi := proxy.MetricedAPI[api.Curio, api.CurioStruct](a)
if permissioned {
wapi = api.PermissionedAPI[api.LotusProvider, api.LotusProviderStruct](wapi)
wapi = api.PermissionedAPI[api.Curio, api.CurioStruct](wapi)
}
rpcServer.Register("Filecoin", wapi)
@@ -76,13 +75,16 @@ func LotusProviderHandler(
return ah
}
type ProviderAPI struct {
type CurioAPI struct {
*deps.Deps
paths.SectorIndex
ShutdownChan chan struct{}
}
func (p *ProviderAPI) StorageDetachLocal(ctx context.Context, path string) error {
func (p *CurioAPI) Version(context.Context) (api.Version, error) {
return api.CurioAPIVersion0, nil
}
func (p *CurioAPI) StorageDetachLocal(ctx context.Context, path string) error {
path, err := homedir.Expand(path)
if err != nil {
return xerrors.Errorf("expanding local path: %w", err)
@@ -130,7 +132,7 @@ func (p *ProviderAPI) StorageDetachLocal(ctx context.Context, path string) error
return p.LocalStore.ClosePath(ctx, localPath.ID)
}
func (p *ProviderAPI) StorageLocal(ctx context.Context) (map[storiface.ID]string, error) {
func (p *CurioAPI) StorageLocal(ctx context.Context) (map[storiface.ID]string, error) {
ps, err := p.LocalStore.Local(ctx)
if err != nil {
return nil, err
@@ -144,27 +146,23 @@ func (p *ProviderAPI) StorageLocal(ctx context.Context) (map[storiface.ID]string
return out, nil
}
func (p *ProviderAPI) StorageStat(ctx context.Context, id storiface.ID) (fsutil.FsStat, error) {
func (p *CurioAPI) StorageStat(ctx context.Context, id storiface.ID) (fsutil.FsStat, error) {
return p.Stor.FsStat(ctx, id)
}
func (p *ProviderAPI) Version(context.Context) (api.Version, error) {
return api.ProviderAPIVersion0, nil
}
func (p *ProviderAPI) AllocatePieceToSector(ctx context.Context, maddr address.Address, piece api.PieceDealInfo, rawSize int64, source url.URL, header http.Header) (api.SectorOffset, error) {
di := lpmarket.NewPieceIngester(p.Deps.DB, p.Deps.Full)
func (p *CurioAPI) AllocatePieceToSector(ctx context.Context, maddr address.Address, piece api.PieceDealInfo, rawSize int64, source url.URL, header http.Header) (api.SectorOffset, error) {
di := market.NewPieceIngester(p.Deps.DB, p.Deps.Full)
return di.AllocatePieceToSector(ctx, maddr, piece, rawSize, source, header)
}
// Trigger shutdown
func (p *ProviderAPI) Shutdown(context.Context) error {
func (p *CurioAPI) Shutdown(context.Context) error {
close(p.ShutdownChan)
return nil
}
func (p *ProviderAPI) StorageAddLocal(ctx context.Context, path string) error {
func (p *CurioAPI) StorageAddLocal(ctx context.Context, path string) error {
path, err := homedir.Expand(path)
if err != nil {
return xerrors.Errorf("expanding local path: %w", err)
@@ -212,10 +210,10 @@ func ListenAndServe(ctx context.Context, dependencies *deps.Deps, shutdownChan c
}
// Serve the RPC.
srv := &http.Server{
Handler: LotusProviderHandler(
Handler: CurioHandler(
authVerify,
remoteHandler,
&ProviderAPI{dependencies, dependencies.Si, shutdownChan},
&CurioAPI{dependencies, dependencies.Si, shutdownChan},
permissioned),
ReadHeaderTimeout: time.Minute * 3,
BaseContext: func(listener net.Listener) context.Context {
@@ -230,7 +228,7 @@ func ListenAndServe(ctx context.Context, dependencies *deps.Deps, shutdownChan c
eg.Go(srv.ListenAndServe)
if dependencies.Cfg.Subsystems.EnableWebGui {
web, err := lpweb.GetSrv(ctx, dependencies)
web, err := web.GetSrv(ctx, dependencies)
if err != nil {
return err
}
@@ -252,8 +250,8 @@ func ListenAndServe(ctx context.Context, dependencies *deps.Deps, shutdownChan c
return eg.Wait()
}
func GetProviderAPI(ctx *cli.Context) (api.LotusProvider, jsonrpc.ClientCloser, error) {
addr, headers, err := cliutil.GetRawAPI(ctx, repo.Provider, "v0")
func GetCurioAPI(ctx *cli.Context) (api.Curio, jsonrpc.ClientCloser, error) {
addr, headers, err := cliutil.GetRawAPI(ctx, repo.Curio, "v0")
if err != nil {
return nil, nil, err
}
@@ -272,5 +270,5 @@ func GetProviderAPI(ctx *cli.Context) (api.LotusProvider, jsonrpc.ClientCloser,
addr = u.String()
return client.NewProviderRpc(ctx.Context, addr, headers)
return client.NewCurioRpc(ctx.Context, addr, headers)
}
+10 -10
View File
@@ -14,9 +14,9 @@ import (
"github.com/filecoin-project/lotus/build"
lcli "github.com/filecoin-project/lotus/cli"
"github.com/filecoin-project/lotus/cmd/lotus-provider/deps"
"github.com/filecoin-project/lotus/cmd/lotus-provider/rpc"
"github.com/filecoin-project/lotus/cmd/lotus-provider/tasks"
"github.com/filecoin-project/lotus/cmd/curio/deps"
"github.com/filecoin-project/lotus/cmd/curio/rpc"
"github.com/filecoin-project/lotus/cmd/curio/tasks"
"github.com/filecoin-project/lotus/lib/ulimit"
"github.com/filecoin-project/lotus/metrics"
"github.com/filecoin-project/lotus/node"
@@ -28,7 +28,7 @@ type stackTracer interface {
var runCmd = &cli.Command{
Name: "run",
Usage: "Start a lotus provider process",
Usage: "Start a Curio process",
Flags: []cli.Flag{
&cli.StringFlag{
Name: "listen",
@@ -53,12 +53,12 @@ var runCmd = &cli.Command{
&cli.StringFlag{
Name: "storage-json",
Usage: "path to json file containing storage config",
Value: "~/.lotus-provider/storage.json",
Value: "~/.curio/storage.json",
},
&cli.StringFlag{
Name: "journal",
Usage: "path to journal files",
Value: "~/.lotus-provider/",
Value: "~/.curio/",
},
&cli.StringSliceFlag{
Name: "layers",
@@ -89,7 +89,7 @@ var runCmd = &cli.Command{
ctx, _ := tag.New(lcli.DaemonContext(cctx),
tag.Insert(metrics.Version, build.BuildVersion),
tag.Insert(metrics.Commit, build.CurrentCommit),
tag.Insert(metrics.NodeType, "provider"),
tag.Insert(metrics.NodeType, "curio"),
)
shutdownChan := make(chan struct{})
{
@@ -135,7 +135,7 @@ var runCmd = &cli.Command{
return err
}
finishCh := node.MonitorShutdown(shutdownChan) //node.ShutdownHandler{Component: "rpc server", StopFunc: rpcStopper},
//node.ShutdownHandler{Component: "provider", StopFunc: stop},
//node.ShutdownHandler{Component: "curio", StopFunc: stop},
<-finishCh
return nil
@@ -144,8 +144,8 @@ var runCmd = &cli.Command{
var webCmd = &cli.Command{
Name: "web",
Usage: "Start lotus provider web interface",
Description: `Start an instance of lotus provider web interface.
Usage: "Start Curio web interface",
Description: `Start an instance of Curio web interface.
This creates the 'web' layer if it does not exist, then calls run with that layer.`,
Flags: []cli.Flag{
&cli.StringFlag{
@@ -10,7 +10,7 @@ import (
var stopCmd = &cli.Command{
Name: "stop",
Usage: "Stop a running lotus provider",
Usage: "Stop a running Curio process",
Flags: []cli.Flag{},
Action: func(cctx *cli.Context) error {
api, closer, err := lcli.GetAPI(cctx)
@@ -23,7 +23,7 @@ import (
"github.com/filecoin-project/lotus/chain/types"
lcli "github.com/filecoin-project/lotus/cli"
"github.com/filecoin-project/lotus/cmd/lotus-provider/rpc"
"github.com/filecoin-project/lotus/cmd/curio/rpc"
"github.com/filecoin-project/lotus/storage/sealer/fsutil"
"github.com/filecoin-project/lotus/storage/sealer/storiface"
)
@@ -104,7 +104,7 @@ over time
},
},
Action: func(cctx *cli.Context) error {
minerApi, closer, err := rpc.GetProviderAPI(cctx)
minerApi, closer, err := rpc.GetCurioAPI(cctx)
if err != nil {
return err
}
@@ -182,7 +182,7 @@ var storageDetachCmd = &cli.Command{
},
ArgsUsage: "[path]",
Action: func(cctx *cli.Context) error {
minerApi, closer, err := rpc.GetProviderAPI(cctx)
minerApi, closer, err := rpc.GetCurioAPI(cctx)
if err != nil {
return err
}
@@ -213,7 +213,7 @@ var storageListCmd = &cli.Command{
//storageListSectorsCmd,
},
Action: func(cctx *cli.Context) error {
minerApi, closer, err := rpc.GetProviderAPI(cctx)
minerApi, closer, err := rpc.GetCurioAPI(cctx)
if err != nil {
return err
}
@@ -412,7 +412,7 @@ var storageFindCmd = &cli.Command{
Usage: "find sector in the storage system",
ArgsUsage: "[miner address] [sector number]",
Action: func(cctx *cli.Context) error {
minerApi, closer, err := rpc.GetProviderAPI(cctx)
minerApi, closer, err := rpc.GetCurioAPI(cctx)
if err != nil {
return err
}
@@ -1,4 +1,4 @@
// Package tasks contains tasks that can be run by the lotus-provider command.
// Package tasks contains tasks that can be run by the curio command.
package tasks
import (
@@ -8,21 +8,21 @@ import (
"github.com/samber/lo"
"golang.org/x/xerrors"
"github.com/filecoin-project/lotus/cmd/lotus-provider/deps"
"github.com/filecoin-project/lotus/cmd/curio/deps"
curio "github.com/filecoin-project/lotus/curiosrc"
"github.com/filecoin-project/lotus/curiosrc/chainsched"
"github.com/filecoin-project/lotus/curiosrc/ffi"
"github.com/filecoin-project/lotus/curiosrc/message"
"github.com/filecoin-project/lotus/curiosrc/piece"
"github.com/filecoin-project/lotus/curiosrc/seal"
"github.com/filecoin-project/lotus/curiosrc/winning"
"github.com/filecoin-project/lotus/lib/harmony/harmonytask"
"github.com/filecoin-project/lotus/lib/lazy"
"github.com/filecoin-project/lotus/lib/must"
"github.com/filecoin-project/lotus/node/modules"
"github.com/filecoin-project/lotus/provider"
"github.com/filecoin-project/lotus/provider/chainsched"
"github.com/filecoin-project/lotus/provider/lpffi"
"github.com/filecoin-project/lotus/provider/lpmessage"
"github.com/filecoin-project/lotus/provider/lppiece"
"github.com/filecoin-project/lotus/provider/lpseal"
"github.com/filecoin-project/lotus/provider/lpwinning"
)
var log = logging.Logger("lotus-provider/deps")
var log = logging.Logger("curio/deps")
func StartTasks(ctx context.Context, dependencies *deps.Deps) (*harmonytask.TaskEngine, error) {
cfg := dependencies.Cfg
@@ -37,7 +37,7 @@ func StartTasks(ctx context.Context, dependencies *deps.Deps) (*harmonytask.Task
si := dependencies.Si
var activeTasks []harmonytask.TaskInterface
sender, sendTask := lpmessage.NewSender(full, full, db)
sender, sendTask := message.NewSender(full, full, db)
activeTasks = append(activeTasks, sendTask)
chainSched := chainsched.New(full)
@@ -51,8 +51,10 @@ func StartTasks(ctx context.Context, dependencies *deps.Deps) (*harmonytask.Task
// PoSt
if cfg.Subsystems.EnableWindowPost {
wdPostTask, wdPoStSubmitTask, derlareRecoverTask, err := provider.WindowPostScheduler(ctx, cfg.Fees, cfg.Proving, full, verif, lw, sender,
chainSched, as, maddrs, db, stor, si, cfg.Subsystems.WindowPostMaxTasks)
wdPostTask, wdPoStSubmitTask, derlareRecoverTask, err := curio.WindowPostScheduler(
ctx, cfg.Fees, cfg.Proving, full, verif, lw, sender, chainSched,
as, maddrs, db, stor, si, cfg.Subsystems.WindowPostMaxTasks)
if err != nil {
return nil, err
}
@@ -61,21 +63,21 @@ func StartTasks(ctx context.Context, dependencies *deps.Deps) (*harmonytask.Task
}
if cfg.Subsystems.EnableWinningPost {
winPoStTask := lpwinning.NewWinPostTask(cfg.Subsystems.WinningPostMaxTasks, db, lw, verif, full, maddrs)
winPoStTask := winning.NewWinPostTask(cfg.Subsystems.WinningPostMaxTasks, db, lw, verif, full, maddrs)
activeTasks = append(activeTasks, winPoStTask)
needProofParams = true
}
}
slrLazy := lazy.MakeLazy(func() (*lpffi.SealCalls, error) {
return lpffi.NewSealCalls(stor, lstor, si), nil
slrLazy := lazy.MakeLazy(func() (*ffi.SealCalls, error) {
return ffi.NewSealCalls(stor, lstor, si), nil
})
{
// Piece handling
if cfg.Subsystems.EnableParkPiece {
parkPieceTask := lppiece.NewParkPieceTask(db, must.One(slrLazy.Val()), cfg.Subsystems.ParkPieceMaxTasks)
cleanupPieceTask := lppiece.NewCleanupPieceTask(db, must.One(slrLazy.Val()), 0)
parkPieceTask := piece.NewParkPieceTask(db, must.One(slrLazy.Val()), cfg.Subsystems.ParkPieceMaxTasks)
cleanupPieceTask := piece.NewCleanupPieceTask(db, must.One(slrLazy.Val()), 0)
activeTasks = append(activeTasks, parkPieceTask, cleanupPieceTask)
}
}
@@ -89,10 +91,10 @@ func StartTasks(ctx context.Context, dependencies *deps.Deps) (*harmonytask.Task
{
// Sealing
var sp *lpseal.SealPoller
var slr *lpffi.SealCalls
var sp *seal.SealPoller
var slr *ffi.SealCalls
if hasAnySealingTask {
sp = lpseal.NewPoller(db, full)
sp = seal.NewPoller(db, full)
go sp.RunPoller(ctx)
slr = must.One(slrLazy.Val())
@@ -100,29 +102,29 @@ func StartTasks(ctx context.Context, dependencies *deps.Deps) (*harmonytask.Task
// NOTE: Tasks with the LEAST priority are at the top
if cfg.Subsystems.EnableSealSDR {
sdrTask := lpseal.NewSDRTask(full, db, sp, slr, cfg.Subsystems.SealSDRMaxTasks)
sdrTask := seal.NewSDRTask(full, db, sp, slr, cfg.Subsystems.SealSDRMaxTasks)
activeTasks = append(activeTasks, sdrTask)
}
if cfg.Subsystems.EnableSealSDRTrees {
treesTask := lpseal.NewTreesTask(sp, db, slr, cfg.Subsystems.SealSDRTreesMaxTasks)
finalizeTask := lpseal.NewFinalizeTask(cfg.Subsystems.FinalizeMaxTasks, sp, slr, db)
treesTask := seal.NewTreesTask(sp, db, slr, cfg.Subsystems.SealSDRTreesMaxTasks)
finalizeTask := seal.NewFinalizeTask(cfg.Subsystems.FinalizeMaxTasks, sp, slr, db)
activeTasks = append(activeTasks, treesTask, finalizeTask)
}
if cfg.Subsystems.EnableSendPrecommitMsg {
precommitTask := lpseal.NewSubmitPrecommitTask(sp, db, full, sender, as, cfg.Fees.MaxPreCommitGasFee)
precommitTask := seal.NewSubmitPrecommitTask(sp, db, full, sender, as, cfg.Fees.MaxPreCommitGasFee)
activeTasks = append(activeTasks, precommitTask)
}
if cfg.Subsystems.EnablePoRepProof {
porepTask := lpseal.NewPoRepTask(db, full, sp, slr, cfg.Subsystems.PoRepProofMaxTasks)
porepTask := seal.NewPoRepTask(db, full, sp, slr, cfg.Subsystems.PoRepProofMaxTasks)
activeTasks = append(activeTasks, porepTask)
needProofParams = true
}
if cfg.Subsystems.EnableMoveStorage {
moveStorageTask := lpseal.NewMoveStorageTask(sp, slr, db, cfg.Subsystems.MoveStorageMaxTasks)
moveStorageTask := seal.NewMoveStorageTask(sp, slr, db, cfg.Subsystems.MoveStorageMaxTasks)
activeTasks = append(activeTasks, moveStorageTask)
}
if cfg.Subsystems.EnableSendCommitMsg {
commitTask := lpseal.NewSubmitCommitTask(sp, db, full, sender, as, cfg.Fees.MaxCommitGasFee)
commitTask := seal.NewSubmitCommitTask(sp, db, full, sender, as, cfg.Fees.MaxCommitGasFee)
activeTasks = append(activeTasks, commitTask)
}
}
@@ -150,7 +152,7 @@ func StartTasks(ctx context.Context, dependencies *deps.Deps) (*harmonytask.Task
}
if hasAnySealingTask {
watcher, err := lpmessage.NewMessageWatcher(db, ht, chainSched, full)
watcher, err := message.NewMessageWatcher(db, ht, chainSched, full)
if err != nil {
return nil, err
}
-254
View File
@@ -1,254 +0,0 @@
package main
import (
"bytes"
"context"
"encoding/base64"
"errors"
"fmt"
"os"
"path"
"strings"
"github.com/BurntSushi/toml"
"github.com/fatih/color"
"github.com/ipfs/go-datastore"
"github.com/samber/lo"
"github.com/urfave/cli/v2"
"golang.org/x/xerrors"
"github.com/filecoin-project/go-address"
cliutil "github.com/filecoin-project/lotus/cli/util"
"github.com/filecoin-project/lotus/cmd/lotus-provider/deps"
"github.com/filecoin-project/lotus/lib/harmony/harmonydb"
"github.com/filecoin-project/lotus/node/config"
"github.com/filecoin-project/lotus/node/modules"
"github.com/filecoin-project/lotus/node/repo"
)
var configMigrateCmd = &cli.Command{
Name: "from-miner",
Usage: "Express a database config (for lotus-provider) from an existing miner.",
Description: "Express a database config (for lotus-provider) from an existing miner.",
Flags: []cli.Flag{
&cli.StringFlag{
Name: FlagMinerRepo,
Aliases: []string{FlagMinerRepoDeprecation},
EnvVars: []string{"LOTUS_MINER_PATH", "LOTUS_STORAGE_PATH"},
Value: "~/.lotusminer",
Usage: "Miner repo path",
},
&cli.StringFlag{
Name: "repo",
EnvVars: []string{"LOTUS_PATH"},
Hidden: true,
Value: "~/.lotus",
},
&cli.StringFlag{
Name: "to-layer",
Aliases: []string{"t"},
Usage: "The layer name for this data push. 'base' is recommended for single-miner setup.",
},
&cli.BoolFlag{
Name: "overwrite",
Aliases: []string{"o"},
Usage: "Use this with --to-layer to replace an existing layer",
},
},
Action: fromMiner,
}
const (
FlagMinerRepo = "miner-repo"
)
const FlagMinerRepoDeprecation = "storagerepo"
func fromMiner(cctx *cli.Context) (err error) {
ctx := context.Background()
cliCommandColor := color.New(color.FgHiBlue).SprintFunc()
configColor := color.New(color.FgHiGreen).SprintFunc()
r, err := repo.NewFS(cctx.String(FlagMinerRepo))
if err != nil {
return err
}
ok, err := r.Exists()
if err != nil {
return err
}
if !ok {
return fmt.Errorf("repo not initialized")
}
lr, err := r.LockRO(repo.StorageMiner)
if err != nil {
return fmt.Errorf("locking repo: %w", err)
}
defer func() { _ = lr.Close() }()
cfgNode, err := lr.Config()
if err != nil {
return fmt.Errorf("getting node config: %w", err)
}
smCfg := cfgNode.(*config.StorageMiner)
db, err := harmonydb.NewFromConfig(smCfg.HarmonyDB)
if err != nil {
return fmt.Errorf("could not reach the database. Ensure the Miner config toml's HarmonyDB entry"+
" is setup to reach Yugabyte correctly: %w", err)
}
var titles []string
err = db.Select(ctx, &titles, `SELECT title FROM harmony_config WHERE LENGTH(config) > 0`)
if err != nil {
return fmt.Errorf("miner cannot reach the db. Ensure the config toml's HarmonyDB entry"+
" is setup to reach Yugabyte correctly: %s", err.Error())
}
name := cctx.String("to-layer")
if name == "" {
name = fmt.Sprintf("mig%d", len(titles))
} else {
if lo.Contains(titles, name) && !cctx.Bool("overwrite") {
return errors.New("the overwrite flag is needed to replace existing layer: " + name)
}
}
msg := "Layer " + configColor(name) + ` created. `
// Copy over identical settings:
buf, err := os.ReadFile(path.Join(lr.Path(), "config.toml"))
if err != nil {
return fmt.Errorf("could not read config.toml: %w", err)
}
lpCfg := config.DefaultLotusProvider()
_, err = deps.LoadConfigWithUpgrades(string(buf), lpCfg)
if err != nil {
return fmt.Errorf("could not decode toml: %w", err)
}
// Populate Miner Address
mmeta, err := lr.Datastore(ctx, "/metadata")
if err != nil {
return xerrors.Errorf("opening miner metadata datastore: %w", err)
}
defer func() {
_ = mmeta.Close()
}()
maddrBytes, err := mmeta.Get(ctx, datastore.NewKey("miner-address"))
if err != nil {
return xerrors.Errorf("getting miner address datastore entry: %w", err)
}
addr, err := address.NewFromBytes(maddrBytes)
if err != nil {
return xerrors.Errorf("parsing miner actor address: %w", err)
}
lpCfg.Addresses = []config.LotusProviderAddresses{{
MinerAddresses: []string{addr.String()},
}}
ks, err := lr.KeyStore()
if err != nil {
return xerrors.Errorf("keystore err: %w", err)
}
js, err := ks.Get(modules.JWTSecretName)
if err != nil {
return xerrors.Errorf("error getting JWTSecretName: %w", err)
}
lpCfg.Apis.StorageRPCSecret = base64.StdEncoding.EncodeToString(js.PrivateKey)
// Populate API Key
_, header, err := cliutil.GetRawAPI(cctx, repo.FullNode, "v0")
if err != nil {
return fmt.Errorf("cannot read API: %w", err)
}
ainfo, err := cliutil.GetAPIInfo(&cli.Context{}, repo.FullNode)
if err != nil {
return xerrors.Errorf(`could not get API info for FullNode: %w
Set the environment variable to the value of "lotus auth api-info --perm=admin"`, err)
}
lpCfg.Apis.ChainApiInfo = []string{header.Get("Authorization")[7:] + ":" + ainfo.Addr}
// WindowPoSt message
msg += "\n!! Before running lotus-provider with Window PoSt enabled, ensure any miner/worker answering of WindowPost is disabled by " +
"(on Miner) " + configColor("DisableBuiltinWindowPoSt=true") + " and (on Workers) not enabling windowpost on CLI or via " +
"environment variable " + configColor("LOTUS_WORKER_WINDOWPOST") + "."
// WinningPoSt message
msg += "\n!! Before running lotus-provider with Winning PoSt enabled, ensure any miner/worker answering of WinningPost is disabled by " +
"(on Miner) " + configColor("DisableBuiltinWinningPoSt=true") + " and (on Workers) not enabling winningpost on CLI or via " +
"environment variable " + configColor("LOTUS_WORKER_WINNINGPOST") + "."
// Express as configTOML
configTOML := &bytes.Buffer{}
if err = toml.NewEncoder(configTOML).Encode(lpCfg); err != nil {
return err
}
if !lo.Contains(titles, "base") {
cfg, err := getDefaultConfig(true)
if err != nil {
return xerrors.Errorf("Cannot get default config: %w", err)
}
_, err = db.Exec(ctx, "INSERT INTO harmony_config (title, config) VALUES ('base', $1)", cfg)
if err != nil {
return err
}
}
if cctx.Bool("overwrite") {
i, err := db.Exec(ctx, "DELETE FROM harmony_config WHERE title=$1", name)
if i != 0 {
fmt.Println("Overwriting existing layer")
}
if err != nil {
fmt.Println("Got error while deleting existing layer: " + err.Error())
}
}
_, err = db.Exec(ctx, "INSERT INTO harmony_config (title, config) VALUES ($1, $2)", name, configTOML.String())
if err != nil {
return err
}
dbSettings := ""
def := config.DefaultStorageMiner().HarmonyDB
if def.Hosts[0] != smCfg.HarmonyDB.Hosts[0] {
dbSettings += ` --db-host="` + strings.Join(smCfg.HarmonyDB.Hosts, ",") + `"`
}
if def.Port != smCfg.HarmonyDB.Port {
dbSettings += " --db-port=" + smCfg.HarmonyDB.Port
}
if def.Username != smCfg.HarmonyDB.Username {
dbSettings += ` --db-user="` + smCfg.HarmonyDB.Username + `"`
}
if def.Password != smCfg.HarmonyDB.Password {
dbSettings += ` --db-password="` + smCfg.HarmonyDB.Password + `"`
}
if def.Database != smCfg.HarmonyDB.Database {
dbSettings += ` --db-name="` + smCfg.HarmonyDB.Database + `"`
}
var layerMaybe string
if name != "base" {
layerMaybe = "--layer=" + name
}
msg += `
To work with the config:
` + cliCommandColor(`lotus-provider `+dbSettings+` config help `)
msg += `
To run Lotus Provider: in its own machine or cgroup without other files, use the command:
` + cliCommandColor(`lotus-provider `+dbSettings+` run `+layerMaybe)
fmt.Println(msg)
return nil
}
@@ -35,14 +35,14 @@ import (
"github.com/filecoin-project/lotus/build"
"github.com/filecoin-project/lotus/chain/types"
lcli "github.com/filecoin-project/lotus/cli"
"github.com/filecoin-project/lotus/cmd/lotus-provider/deps"
"github.com/filecoin-project/lotus/cmd/curio/deps"
cumarket "github.com/filecoin-project/lotus/curiosrc/market"
"github.com/filecoin-project/lotus/curiosrc/market/fakelm"
"github.com/filecoin-project/lotus/lib/harmony/harmonydb"
"github.com/filecoin-project/lotus/lib/must"
"github.com/filecoin-project/lotus/lib/nullreader"
"github.com/filecoin-project/lotus/metrics/proxy"
"github.com/filecoin-project/lotus/node"
"github.com/filecoin-project/lotus/provider/lpmarket"
"github.com/filecoin-project/lotus/provider/lpmarket/fakelm"
"github.com/filecoin-project/lotus/storage/paths"
"github.com/filecoin-project/lotus/storage/sealer/storiface"
)
@@ -90,7 +90,7 @@ var lpUtilStartDealCmd = &cli.Command{
}
// open rpc
var rpc api.LotusProviderStruct
var rpc api.CurioStruct
closer2, err := jsonrpc.NewMergeClient(ctx, cctx.String("provider-rpc"), "Filecoin", []interface{}{&rpc.Internal}, nil)
if err != nil {
return xerrors.Errorf("open rpc: %w", err)
@@ -370,7 +370,7 @@ var lpBoostProxyCmd = &cli.Command{
defer closer()
pin := lpmarket.NewPieceIngester(db, full)
pin := cumarket.NewPieceIngester(db, full)
si := paths.NewDBIndex(nil, db)
+1 -1
View File
@@ -72,7 +72,7 @@ var backfillEventsCmd = &cli.Command{
}
if cctx.IsSet("from") {
// we need to fetch the tipset after the epoch being specified since we will need to advance currTs
currTs, err = api.ChainGetTipSetByHeight(ctx, abi.ChainEpoch(cctx.Int("from")+1), currTs.Key())
currTs, err = api.ChainGetTipSetAfterHeight(ctx, abi.ChainEpoch(cctx.Int("from")+1), currTs.Key())
if err != nil {
return err
}
+1 -1
View File
@@ -117,7 +117,7 @@ func (sim *Simulation) saveConfig() error {
var simulationPrefix = datastore.NewKey("/simulation")
// key returns the the key in the form /simulation/<subkey>/<simulation-name>. For example,
// key returns the key in the form /simulation/<subkey>/<simulation-name>. For example,
// /simulation/head/default.
func (sim *Simulation) key(subkey string) datastore.Key {
return simulationPrefix.ChildString(subkey).ChildString(sim.name)