From 9f9dc979fb4a234a024d5d85a0ac430541e72426 Mon Sep 17 00:00:00 2001 From: LexLuthr <88259624+LexLuthr@users.noreply.github.com> Date: Thu, 4 Apr 2024 00:00:14 +0400 Subject: [PATCH] feat: curio: add miner init (#11775) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * sptool: Initial structure * sptool: Port lotus-miner actor withdraw * sptool: Make cli docsgen happy * actors are done * info * proving * sptool the rest * fixed gitignore * lints * oops * 2 * terminate * fixes * curio new-miner setup * reword doc section * fix curio flags * fix gen * change repetitive prompt * add miner to base * add config test * fix config compare, add tests * go mod tidy * fix itest in GA * fix comparer function * fix compare value match --------- Co-authored-by: Łukasz Magiera Co-authored-by: Andrew Jackson (Ajax) --- .circleci/config.yml | 6 + .github/workflows/test.yml | 2 +- cli/spcli/actor.go | 197 ++- cmd/curio/config.go | 9 - cmd/curio/config_new.go | 112 +- cmd/curio/config_test.go | 416 +++++++ cmd/curio/deps/deps.go | 97 ++ cmd/curio/guidedsetup/guidedsetup.go | 433 +++++-- cmd/curio/internal/translations/catalog.go | 688 ++++++----- .../translations/locales/en/out.gotext.json | 1068 ++++++++++++----- .../locales/ko/messages.gotext.json | 432 ++++++- .../translations/locales/ko/out.gotext.json | 87 +- .../locales/zh/messages.gotext.json | 348 ++++++ .../translations/locales/zh/out.gotext.json | 87 +- cmd/curio/internal/translations/updateLang.sh | 2 +- cmd/curio/main.go | 3 +- cmd/sptool/actor.go | 1 + cmd/sptool/sector.go | 1 - documentation/en/cli-curio.md | 7 +- documentation/en/cli-sptool.md | 17 + go.mod | 2 +- itests/curio_test.go | 67 ++ node/config/load.go | 22 +- 23 files changed, 3160 insertions(+), 944 deletions(-) create mode 100644 cmd/curio/config_test.go create mode 100644 itests/curio_test.go diff --git a/.circleci/config.yml b/.circleci/config.yml index 30ebaf5d9..be70019a3 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -554,6 +554,12 @@ workflows: - build suite: itest-cli target: "./itests/cli_test.go" + - test: + name: test-itest-curio + requires: + - build + suite: itest-curio + target: "./itests/curio_test.go" - test: name: test-itest-deadlines requires: diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index 127dd58d3..ad274dfa5 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -124,7 +124,7 @@ jobs: # A list of test groups that require YugabyteDB to be running # In CircleCI, all jobs had yugabytedb running as a sidecar. yugabytedb: | - ["itest-harmonydb", "itest-harmonytask"] + ["itest-harmonydb", "itest-harmonytask", "itest-curio"] # A list of test groups that require Proof Parameters to be fetched # In CircleCI, only the following jobs had get-params set: # - unit-cli (✅) diff --git a/cli/spcli/actor.go b/cli/spcli/actor.go index 296d5ffb1..33590de50 100644 --- a/cli/spcli/actor.go +++ b/cli/spcli/actor.go @@ -2,9 +2,11 @@ package spcli import ( "bytes" + "context" "fmt" "strconv" + "github.com/docker/go-units" cbor "github.com/ipfs/go-ipld-cbor" "github.com/libp2p/go-libp2p/core/peer" ma "github.com/multiformats/go-multiaddr" @@ -19,16 +21,20 @@ import ( "github.com/filecoin-project/go-state-types/builtin" "github.com/filecoin-project/go-state-types/builtin/v9/miner" "github.com/filecoin-project/go-state-types/network" + power2 "github.com/filecoin-project/specs-actors/v2/actors/builtin/power" + power6 "github.com/filecoin-project/specs-actors/v6/actors/builtin/power" - "github.com/filecoin-project/lotus/api" lapi "github.com/filecoin-project/lotus/api" + "github.com/filecoin-project/lotus/api/v1api" "github.com/filecoin-project/lotus/blockstore" "github.com/filecoin-project/lotus/build" "github.com/filecoin-project/lotus/chain/actors" "github.com/filecoin-project/lotus/chain/actors/adt" lminer "github.com/filecoin-project/lotus/chain/actors/builtin/miner" + "github.com/filecoin-project/lotus/chain/actors/builtin/power" "github.com/filecoin-project/lotus/chain/types" lcli "github.com/filecoin-project/lotus/cli" + cliutil "github.com/filecoin-project/lotus/cli/util" "github.com/filecoin-project/lotus/node/impl" ) @@ -1225,7 +1231,7 @@ func ActorCompactAllocatedCmd(getActor ActorAddressGetter) *cli.Command { } } -func isController(mi api.MinerInfo, addr address.Address) bool { +func isController(mi lapi.MinerInfo, addr address.Address) bool { if addr == mi.Owner || addr == mi.Worker { return true } @@ -1238,3 +1244,190 @@ func isController(mi api.MinerInfo, addr address.Address) bool { return false } + +var ActorNewMinerCmd = &cli.Command{ + Name: "new-miner", + Usage: "Initializes a new miner actor", + Flags: []cli.Flag{ + &cli.StringFlag{ + Name: "worker", + Aliases: []string{"w"}, + Usage: "worker key to use for new miner initialisation", + }, + &cli.StringFlag{ + Name: "owner", + Aliases: []string{"o"}, + Usage: "owner key to use for new miner initialisation", + }, + &cli.StringFlag{ + Name: "from", + Aliases: []string{"f"}, + Usage: "address to send actor(miner) creation message from", + }, + &cli.StringFlag{ + Name: "sector-size", + Usage: "specify sector size to use for new miner initialisation", + }, + }, + Action: func(cctx *cli.Context) error { + ctx := cctx.Context + + full, closer, err := cliutil.GetFullNodeAPIV1(cctx) + if err != nil { + return xerrors.Errorf("connecting to full node: %w", err) + } + defer closer() + + var owner address.Address + if cctx.String("owner") == "" { + return xerrors.Errorf("must provide a owner address") + } + owner, err = address.NewFromString(cctx.String("owner")) + + if err != nil { + return err + } + + worker := owner + if cctx.String("worker") != "" { + worker, err = address.NewFromString(cctx.String("worker")) + if err != nil { + return xerrors.Errorf("could not parse worker address: %w", err) + } + } + + sender := owner + if fromstr := cctx.String("from"); fromstr != "" { + faddr, err := address.NewFromString(fromstr) + if err != nil { + return xerrors.Errorf("could not parse from address: %w", err) + } + sender = faddr + } + + if !cctx.IsSet("sector-size") { + return xerrors.Errorf("must define sector size") + } + + sectorSizeInt, err := units.RAMInBytes(cctx.String("sector-size")) + if err != nil { + return err + } + ssize := abi.SectorSize(sectorSizeInt) + + _, err = CreateStorageMiner(ctx, full, owner, worker, sender, ssize, cctx.Uint64("confidence")) + if err != nil { + return err + } + return nil + }, +} + +func CreateStorageMiner(ctx context.Context, fullNode v1api.FullNode, owner, worker, sender address.Address, ssize abi.SectorSize, confidence uint64) (address.Address, error) { + // make sure the sender account exists on chain + _, err := fullNode.StateLookupID(ctx, owner, types.EmptyTSK) + if err != nil { + return address.Undef, xerrors.Errorf("sender must exist on chain: %w", err) + } + + // make sure the worker account exists on chain + _, err = fullNode.StateLookupID(ctx, worker, types.EmptyTSK) + if err != nil { + signed, err := fullNode.MpoolPushMessage(ctx, &types.Message{ + From: sender, + To: worker, + Value: types.NewInt(0), + }, nil) + if err != nil { + return address.Undef, xerrors.Errorf("push worker init: %w", err) + } + + fmt.Printf("Initializing worker account %s, message: %s\n", worker, signed.Cid()) + fmt.Println("Waiting for confirmation") + + mw, err := fullNode.StateWaitMsg(ctx, signed.Cid(), confidence, 2000, true) + if err != nil { + return address.Undef, xerrors.Errorf("waiting for worker init: %w", err) + } + if mw.Receipt.ExitCode != 0 { + return address.Undef, xerrors.Errorf("initializing worker account failed: exit code %d", mw.Receipt.ExitCode) + } + } + + // make sure the owner account exists on chain + _, err = fullNode.StateLookupID(ctx, owner, types.EmptyTSK) + if err != nil { + signed, err := fullNode.MpoolPushMessage(ctx, &types.Message{ + From: sender, + To: owner, + Value: types.NewInt(0), + }, nil) + if err != nil { + return address.Undef, xerrors.Errorf("push owner init: %w", err) + } + + fmt.Printf("Initializing owner account %s, message: %s\n", worker, signed.Cid()) + fmt.Println("Waiting for confirmation") + + mw, err := fullNode.StateWaitMsg(ctx, signed.Cid(), confidence, 2000, true) + if err != nil { + return address.Undef, xerrors.Errorf("waiting for owner init: %w", err) + } + if mw.Receipt.ExitCode != 0 { + return address.Undef, xerrors.Errorf("initializing owner account failed: exit code %d", mw.Receipt.ExitCode) + } + } + + // Note: the correct thing to do would be to call SealProofTypeFromSectorSize if actors version is v3 or later, but this still works + nv, err := fullNode.StateNetworkVersion(ctx, types.EmptyTSK) + if err != nil { + return address.Undef, xerrors.Errorf("failed to get network version: %w", err) + } + spt, err := lminer.WindowPoStProofTypeFromSectorSize(ssize, nv) + if err != nil { + return address.Undef, xerrors.Errorf("getting post proof type: %w", err) + } + + params, err := actors.SerializeParams(&power6.CreateMinerParams{ + Owner: owner, + Worker: worker, + WindowPoStProofType: spt, + }) + if err != nil { + return address.Undef, err + } + + createStorageMinerMsg := &types.Message{ + To: power.Address, + From: sender, + Value: big.Zero(), + + Method: power.Methods.CreateMiner, + Params: params, + } + + signed, err := fullNode.MpoolPushMessage(ctx, createStorageMinerMsg, nil) + if err != nil { + return address.Undef, xerrors.Errorf("pushing createMiner message: %w", err) + } + + fmt.Printf("Pushed CreateMiner message: %s\n", signed.Cid()) + fmt.Println("Waiting for confirmation") + + mw, err := fullNode.StateWaitMsg(ctx, signed.Cid(), confidence, 2000, true) + if err != nil { + return address.Undef, xerrors.Errorf("waiting for createMiner message: %w", err) + } + + if mw.Receipt.ExitCode != 0 { + return address.Undef, xerrors.Errorf("create miner failed: exit code %d", mw.Receipt.ExitCode) + } + + var retval power2.CreateMinerReturn + if err := retval.UnmarshalCBOR(bytes.NewReader(mw.Receipt.Return)); err != nil { + return address.Undef, err + } + + fmt.Printf("New miners address is: %s (%s)\n", retval.IDAddress, retval.RobustAddress) + return retval.IDAddress, nil +} diff --git a/cmd/curio/config.go b/cmd/curio/config.go index 2938118ad..66bb2e8b4 100644 --- a/cmd/curio/config.go +++ b/cmd/curio/config.go @@ -352,15 +352,6 @@ 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.DefaultCurioConfig() lpNew := config.DefaultCurioConfig() diff --git a/cmd/curio/config_new.go b/cmd/curio/config_new.go index 38ca44597..65549bd69 100644 --- a/cmd/curio/config_new.go +++ b/cmd/curio/config_new.go @@ -1,25 +1,14 @@ package main import ( - "bytes" - "crypto/rand" - "encoding/base64" "fmt" - "io" - "github.com/BurntSushi/toml" - "github.com/fatih/color" - "github.com/samber/lo" "github.com/urfave/cli/v2" "golang.org/x/xerrors" - "github.com/filecoin-project/go-address" - "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/curio/deps" - "github.com/filecoin-project/lotus/node/config" "github.com/filecoin-project/lotus/node/repo" ) @@ -36,10 +25,8 @@ var configNewCmd = &cli.Command{ }, }, Action: func(cctx *cli.Context) error { - configColor := color.New(color.FgHiGreen).SprintFunc() - if cctx.Args().Len() < 1 { - return xerrors.New("must specify at least one SP actor address. Use 'lotus-shed miner create'") + return xerrors.New("must specify at least one SP actor address. Use 'lotus-shed miner create' or use 'curio guided-setup'") } ctx := cctx.Context @@ -55,105 +42,16 @@ var configNewCmd = &cli.Command{ } defer closer() - var titles []string - err = db.Select(ctx, &titles, `SELECT title FROM harmony_config WHERE LENGTH(config) > 0`) + ainfo, err := cliutil.GetAPIInfo(cctx, repo.FullNode) 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()) + return xerrors.Errorf("could not get API info for FullNode: %w", err) } - name := cctx.String("to-layer") - if name == "" { - name = fmt.Sprintf("cluster%d", len(titles)) - } else { - if lo.Contains(titles, name) && !cctx.Bool("overwrite") { - return xerrors.New("the overwrite flag is needed to replace existing layer: " + name) - } - } - msg := "Layer " + configColor(name) + ` created. ` - - // setup config - lpCfg := config.DefaultCurioConfig() - - for _, addr := range cctx.Args().Slice() { - maddr, err := address.NewFromString(addr) - if err != nil { - return xerrors.Errorf("Invalid address: %s", addr) - } - - _, err = full.StateMinerInfo(ctx, maddr, types.EmptyTSK) - if err != nil { - return xerrors.Errorf("Failed to get miner info: %w", err) - } - - lpCfg.Addresses = append(lpCfg.Addresses, config.CurioAddresses{ - PreCommitControl: nil, - CommitControl: nil, - TerminateControl: nil, - DisableOwnerFallback: false, - DisableWorkerFallback: false, - MinerAddresses: []string{addr}, - }) - } - - { - sk, err := io.ReadAll(io.LimitReader(rand.Reader, 32)) - if err != nil { - return err - } - - lpCfg.Apis.StorageRPCSecret = base64.StdEncoding.EncodeToString(sk) - } - - { - ainfo, err := cliutil.GetAPIInfo(cctx, repo.FullNode) - if err != nil { - return xerrors.Errorf("could not get API info for FullNode: %w", err) - } - - token, err := full.AuthNew(ctx, api.AllPermissions) - if err != nil { - return err - } - - lpCfg.Apis.ChainApiInfo = append(lpCfg.Apis.ChainApiInfo, fmt.Sprintf("%s:%s", string(token), ainfo.Addr)) - } - - // write config - - 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()) + token, err := full.AuthNew(ctx, api.AllPermissions) if err != nil { return err } - fmt.Println(msg) - return nil + return deps.CreateMinerConfig(ctx, full, db, cctx.Args().Slice(), fmt.Sprintf("%s:%s", string(token), ainfo.Addr)) }, } diff --git a/cmd/curio/config_test.go b/cmd/curio/config_test.go new file mode 100644 index 000000000..31c4b4bd0 --- /dev/null +++ b/cmd/curio/config_test.go @@ -0,0 +1,416 @@ +package main + +import ( + "testing" + + "github.com/samber/lo" + "github.com/stretchr/testify/require" + + "github.com/filecoin-project/lotus/cmd/curio/deps" + "github.com/filecoin-project/lotus/node/config" +) + +var baseText string = ` +[Subsystems] + # EnableWindowPost enables window post to be executed on this lotus-provider instance. Each machine in the cluster + # with WindowPoSt enabled will also participate in the window post scheduler. It is possible to have multiple + # machines with WindowPoSt enabled which will provide redundancy, and in case of multiple partitions per deadline, + # will allow for parallel processing of partitions. + # + # It is possible to have instances handling both WindowPoSt and WinningPoSt, which can provide redundancy without + # the need for additional machines. In setups like this it is generally recommended to run + # partitionsPerDeadline+1 machines. + # + # type: bool + #EnableWindowPost = false + + # type: int + #WindowPostMaxTasks = 0 + + # EnableWinningPost enables winning post to be executed on this lotus-provider instance. + # Each machine in the cluster with WinningPoSt enabled will also participate in the winning post scheduler. + # It is possible to mix machines with WindowPoSt and WinningPoSt enabled, for details see the EnableWindowPost + # documentation. + # + # type: bool + #EnableWinningPost = false + + # type: int + #WinningPostMaxTasks = 0 + + # EnableParkPiece enables the "piece parking" task to run on this node. This task is responsible for fetching + # pieces from the network and storing them in the storage subsystem until sectors are sealed. This task is + # only applicable when integrating with boost, and should be enabled on nodes which will hold deal data + # from boost until sectors containing the related pieces have the TreeD/TreeR constructed. + # Note that future Curio implementations will have a separate task type for fetching pieces from the internet. + # + # type: bool + #EnableParkPiece = false + + # type: int + #ParkPieceMaxTasks = 0 + + # EnableSealSDR enables SDR tasks to run. SDR is the long sequential computation + # creating 11 layer files in sector cache directory. + # + # SDR is the first task in the sealing pipeline. It's inputs are just the hash of the + # unsealed data (CommD), sector number, miner id, and the seal proof type. + # It's outputs are the 11 layer files in the sector cache directory. + # + # In lotus-miner this was run as part of PreCommit1. + # + # type: bool + #EnableSealSDR = false + + # The maximum amount of SDR tasks that can run simultaneously. Note that the maximum number of tasks will + # also be bounded by resources available on the machine. + # + # type: int + #SealSDRMaxTasks = 0 + + # EnableSealSDRTrees enables the SDR pipeline tree-building task to run. + # This task handles encoding of unsealed data into last sdr layer and building + # of TreeR, TreeC and TreeD. + # + # This task runs after SDR + # TreeD is first computed with optional input of unsealed data + # TreeR is computed from replica, which is first computed as field + # addition of the last SDR layer and the bottom layer of TreeD (which is the unsealed data) + # TreeC is computed from the 11 SDR layers + # The 3 trees will later be used to compute the PoRep proof. + # + # In case of SyntheticPoRep challenges for PoRep will be pre-generated at this step, and trees and layers + # will be dropped. SyntheticPoRep works by pre-generating a very large set of challenges (~30GiB on disk) + # then using a small subset of them for the actual PoRep computation. This allows for significant scratch space + # saving between PreCommit and PoRep generation at the expense of more computation (generating challenges in this step) + # + # In lotus-miner this was run as part of PreCommit2 (TreeD was run in PreCommit1). + # Note that nodes with SDRTrees enabled will also answer to Finalize tasks, + # which just remove unneeded tree data after PoRep is computed. + # + # type: bool + #EnableSealSDRTrees = false + + # The maximum amount of SealSDRTrees tasks that can run simultaneously. Note that the maximum number of tasks will + # also be bounded by resources available on the machine. + # + # type: int + #SealSDRTreesMaxTasks = 0 + + # FinalizeMaxTasks is the maximum amount of finalize tasks that can run simultaneously. + # The finalize task is enabled on all machines which also handle SDRTrees tasks. Finalize ALWAYS runs on whichever + # machine holds sector cache files, as it removes unneeded tree data after PoRep is computed. + # Finalize will run in parallel with the SubmitCommitMsg task. + # + # type: int + #FinalizeMaxTasks = 0 + + # EnableSendPrecommitMsg enables the sending of precommit messages to the chain + # from this lotus-provider instance. + # This runs after SDRTrees and uses the output CommD / CommR (roots of TreeD / TreeR) for the message + # + # type: bool + #EnableSendPrecommitMsg = false + + # EnablePoRepProof enables the computation of the porep proof + # + # This task runs after interactive-porep seed becomes available, which happens 150 epochs (75min) after the + # precommit message lands on chain. This task should run on a machine with a GPU. Vanilla PoRep proofs are + # requested from the machine which holds sector cache files which most likely is the machine which ran the SDRTrees + # task. + # + # In lotus-miner this was Commit1 / Commit2 + # + # type: bool + #EnablePoRepProof = false + + # The maximum amount of PoRepProof tasks that can run simultaneously. Note that the maximum number of tasks will + # also be bounded by resources available on the machine. + # + # type: int + #PoRepProofMaxTasks = 0 + + # EnableSendCommitMsg enables the sending of commit messages to the chain + # from this lotus-provider instance. + # + # type: bool + #EnableSendCommitMsg = false + + # EnableMoveStorage enables the move-into-long-term-storage task to run on this lotus-provider instance. + # This tasks should only be enabled on nodes with long-term storage. + # + # The MoveStorage task is the last task in the sealing pipeline. It moves the sealed sector data from the + # SDRTrees machine into long-term storage. This task runs after the Finalize task. + # + # type: bool + #EnableMoveStorage = false + + # The maximum amount of MoveStorage tasks that can run simultaneously. Note that the maximum number of tasks will + # also be bounded by resources available on the machine. It is recommended that this value is set to a number which + # uses all available network (or disk) bandwidth on the machine without causing bottlenecks. + # + # type: int + #MoveStorageMaxTasks = 0 + + # EnableWebGui enables the web GUI on this lotus-provider instance. The UI has minimal local overhead, but it should + # only need to be run on a single machine in the cluster. + # + # type: bool + #EnableWebGui = false + + # The address that should listen for Web GUI requests. + # + # type: string + #GuiAddress = ":4701" + + +[Fees] + # type: types.FIL + #DefaultMaxFee = "0.07 FIL" + + # type: types.FIL + #MaxPreCommitGasFee = "0.025 FIL" + + # type: types.FIL + #MaxCommitGasFee = "0.05 FIL" + + # type: types.FIL + #MaxTerminateGasFee = "0.5 FIL" + + # WindowPoSt is a high-value operation, so the default fee should be high. + # + # type: types.FIL + #MaxWindowPoStGasFee = "5 FIL" + + # type: types.FIL + #MaxPublishDealsFee = "0.05 FIL" + + [Fees.MaxPreCommitBatchGasFee] + # type: types.FIL + #Base = "0 FIL" + + # type: types.FIL + #PerSector = "0.02 FIL" + + [Fees.MaxCommitBatchGasFee] + # type: types.FIL + #Base = "0 FIL" + + # type: types.FIL + #PerSector = "0.03 FIL" + +[[Addresses]] + #PreCommitControl = [] + + #CommitControl = [] + + #TerminateControl = [] + + #DisableOwnerFallback = false + + #DisableWorkerFallback = false + + MinerAddresses = ["t01013"] + + +[[Addresses]] + #PreCommitControl = [] + + #CommitControl = [] + + #TerminateControl = [] + + #DisableOwnerFallback = false + + #DisableWorkerFallback = false + + #MinerAddresses = [] + + +[[Addresses]] + #PreCommitControl = [] + + #CommitControl = [] + + #TerminateControl = [] + + #DisableOwnerFallback = false + + #DisableWorkerFallback = false + + MinerAddresses = ["t01006"] + + +[Proving] + # Maximum number of sector checks to run in parallel. (0 = unlimited) + # + # WARNING: Setting this value too high may make the node crash by running out of stack + # WARNING: Setting this value too low may make sector challenge reading much slower, resulting in failed PoSt due + # to late submission. + # + # After changing this option, confirm that the new value works in your setup by invoking + # 'lotus-miner proving compute window-post 0' + # + # type: int + #ParallelCheckLimit = 32 + + # Maximum amount of time a proving pre-check can take for a sector. If the check times out the sector will be skipped + # + # WARNING: Setting this value too low risks in sectors being skipped even though they are accessible, just reading the + # test challenge took longer than this timeout + # WARNING: Setting this value too high risks missing PoSt deadline in case IO operations related to this sector are + # blocked (e.g. in case of disconnected NFS mount) + # + # type: Duration + #SingleCheckTimeout = "10m0s" + + # Maximum amount of time a proving pre-check can take for an entire partition. If the check times out, sectors in + # the partition which didn't get checked on time will be skipped + # + # WARNING: Setting this value too low risks in sectors being skipped even though they are accessible, just reading the + # test challenge took longer than this timeout + # WARNING: Setting this value too high risks missing PoSt deadline in case IO operations related to this partition are + # blocked or slow + # + # type: Duration + #PartitionCheckTimeout = "20m0s" + + # Disable Window PoSt computation on the lotus-miner process even if no window PoSt workers are present. + # + # WARNING: If no windowPoSt workers are connected, window PoSt WILL FAIL resulting in faulty sectors which will need + # to be recovered. Before enabling this option, make sure your PoSt workers work correctly. + # + # After changing this option, confirm that the new value works in your setup by invoking + # 'lotus-miner proving compute window-post 0' + # + # type: bool + #DisableBuiltinWindowPoSt = false + + # Disable Winning PoSt computation on the lotus-miner process even if no winning PoSt workers are present. + # + # WARNING: If no WinningPoSt workers are connected, Winning PoSt WILL FAIL resulting in lost block rewards. + # Before enabling this option, make sure your PoSt workers work correctly. + # + # type: bool + #DisableBuiltinWinningPoSt = false + + # Disable WindowPoSt provable sector readability checks. + # + # In normal operation, when preparing to compute WindowPoSt, lotus-miner will perform a round of reading challenges + # from all sectors to confirm that those sectors can be proven. Challenges read in this process are discarded, as + # we're only interested in checking that sector data can be read. + # + # When using builtin proof computation (no PoSt workers, and DisableBuiltinWindowPoSt is set to false), this process + # can save a lot of time and compute resources in the case that some sectors are not readable - this is caused by + # the builtin logic not skipping snark computation when some sectors need to be skipped. + # + # When using PoSt workers, this process is mostly redundant, with PoSt workers challenges will be read once, and + # if challenges for some sectors aren't readable, those sectors will just get skipped. + # + # Disabling sector pre-checks will slightly reduce IO load when proving sectors, possibly resulting in shorter + # time to produce window PoSt. In setups with good IO capabilities the effect of this option on proving time should + # be negligible. + # + # NOTE: It likely is a bad idea to disable sector pre-checks in setups with no PoSt workers. + # + # NOTE: Even when this option is enabled, recovering sectors will be checked before recovery declaration message is + # sent to the chain + # + # After changing this option, confirm that the new value works in your setup by invoking + # 'lotus-miner proving compute window-post 0' + # + # type: bool + #DisableWDPoStPreChecks = false + + # Maximum number of partitions to prove in a single SubmitWindowPoSt messace. 0 = network limit (3 in nv21) + # + # A single partition may contain up to 2349 32GiB sectors, or 2300 64GiB sectors. + # // + # Note that setting this value lower may result in less efficient gas use - more messages will be sent, + # to prove each deadline, resulting in more total gas use (but each message will have lower gas limit) + # + # Setting this value above the network limit has no effect + # + # type: int + #MaxPartitionsPerPoStMessage = 0 + + # In some cases when submitting DeclareFaultsRecovered messages, + # there may be too many recoveries to fit in a BlockGasLimit. + # In those cases it may be necessary to set this value to something low (eg 1); + # Note that setting this value lower may result in less efficient gas use - more messages will be sent than needed, + # resulting in more total gas use (but each message will have lower gas limit) + # + # type: int + #MaxPartitionsPerRecoveryMessage = 0 + + # Enable single partition per PoSt Message for partitions containing recovery sectors + # + # In cases when submitting PoSt messages which contain recovering sectors, the default network limit may still be + # too high to fit in the block gas limit. In those cases, it becomes useful to only house the single partition + # with recovering sectors in the post message + # + # Note that setting this value lower may result in less efficient gas use - more messages will be sent, + # to prove each deadline, resulting in more total gas use (but each message will have lower gas limit) + # + # type: bool + #SingleRecoveringPartitionPerPostMessage = false + + +[Journal] + # Events of the form: "system1:event1,system1:event2[,...]" + # + # type: string + #DisabledEvents = "" + + +[Apis] + # ChainApiInfo is the API endpoint for the Lotus daemon. + # + # type: []string + ChainApiInfo = ["eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJBbGxvdyI6WyJyZWFkIiwid3JpdGUiLCJzaWduIiwiYWRtaW4iXX0.T_jmG4DTs9Zjd7rr78862lT7D2U63uz-zqcUKHwcqaU:/dns/localhost/tcp/1234/http"] + + # RPC Secret for the storage subsystem. + # If integrating with lotus-miner this must match the value from + # cat ~/.lotusminer/keystore/MF2XI2BNNJ3XILLQOJUXMYLUMU | jq -r .PrivateKey + # + # type: string + StorageRPCSecret = "HxHe8YLHiY0LjHVw/WT/4XQkPGgRyCEYk+xiFi0Ob0o=" + +` + +func TestConfig(t *testing.T) { + baseCfg := config.DefaultCurioConfig() + + addr1 := config.CurioAddresses{ + PreCommitControl: []string{}, + CommitControl: []string{}, + TerminateControl: []string{"t3qroiebizgkz7pvj26reg5r5mqiftrt5hjdske2jzjmlacqr2qj7ytjncreih2mvujxoypwpfusmwpipvxncq"}, + DisableOwnerFallback: false, + DisableWorkerFallback: false, + MinerAddresses: []string{"t01000"}, + } + + addr2 := config.CurioAddresses{ + MinerAddresses: []string{"t01001"}, + } + + _, err := deps.LoadConfigWithUpgrades(baseText, baseCfg) + require.NoError(t, err) + + baseCfg.Addresses = append(baseCfg.Addresses, addr1) + baseCfg.Addresses = lo.Filter(baseCfg.Addresses, func(a config.CurioAddresses, _ int) bool { + return len(a.MinerAddresses) > 0 + }) + + _, err = config.ConfigUpdate(baseCfg, config.DefaultCurioConfig(), config.Commented(true), config.DefaultKeepUncommented(), config.NoEnv()) + require.NoError(t, err) + + baseCfg.Addresses = append(baseCfg.Addresses, addr2) + baseCfg.Addresses = lo.Filter(baseCfg.Addresses, func(a config.CurioAddresses, _ int) bool { + return len(a.MinerAddresses) > 0 + }) + + _, err = config.ConfigUpdate(baseCfg, config.DefaultCurioConfig(), config.Commented(true), config.DefaultKeepUncommented(), config.NoEnv()) + require.NoError(t, err) + +} diff --git a/cmd/curio/deps/deps.go b/cmd/curio/deps/deps.go index c25741cbc..79881ebb8 100644 --- a/cmd/curio/deps/deps.go +++ b/cmd/curio/deps/deps.go @@ -3,10 +3,12 @@ package deps import ( "context" + "crypto/rand" "database/sql" "encoding/base64" "errors" "fmt" + "io" "net" "net/http" "net/url" @@ -29,6 +31,8 @@ import ( "github.com/filecoin-project/go-statestore" "github.com/filecoin-project/lotus/api" + "github.com/filecoin-project/lotus/api/v1api" + "github.com/filecoin-project/lotus/chain/types" curio "github.com/filecoin-project/lotus/curiosrc" "github.com/filecoin-project/lotus/curiosrc/multictladdr" "github.com/filecoin-project/lotus/journal" @@ -434,3 +438,96 @@ func GetDepsCLI(ctx context.Context, cctx *cli.Context) (*Deps, error) { Full: full, }, nil } + +func CreateMinerConfig(ctx context.Context, full v1api.FullNode, db *harmonydb.DB, miners []string, info string) error { + var titles []string + err := db.Select(ctx, &titles, `SELECT title FROM harmony_config WHERE LENGTH(config) > 0`) + if err != nil { + return fmt.Errorf("cannot reach the db. Ensure that Yugabyte flags are set correctly to"+ + " reach Yugabyte: %s", err.Error()) + } + + // setup config + curioConfig := config.DefaultCurioConfig() + + for _, addr := range miners { + maddr, err := address.NewFromString(addr) + if err != nil { + return xerrors.Errorf("Invalid address: %s", addr) + } + + _, err = full.StateMinerInfo(ctx, maddr, types.EmptyTSK) + if err != nil { + return xerrors.Errorf("Failed to get miner info: %w", err) + } + + curioConfig.Addresses = append(curioConfig.Addresses, config.CurioAddresses{ + PreCommitControl: []string{}, + CommitControl: []string{}, + TerminateControl: []string{}, + DisableOwnerFallback: false, + DisableWorkerFallback: false, + MinerAddresses: []string{addr}, + }) + } + + { + sk, err := io.ReadAll(io.LimitReader(rand.Reader, 32)) + if err != nil { + return err + } + + curioConfig.Apis.StorageRPCSecret = base64.StdEncoding.EncodeToString(sk) + } + + { + curioConfig.Apis.ChainApiInfo = append(curioConfig.Apis.ChainApiInfo, info) + } + + curioConfig.Addresses = lo.Filter(curioConfig.Addresses, func(a config.CurioAddresses, _ int) bool { + return len(a.MinerAddresses) > 0 + }) + + // If no base layer is present + if !lo.Contains(titles, "base") { + cb, err := config.ConfigUpdate(curioConfig, config.DefaultCurioConfig(), config.Commented(true), config.DefaultKeepUncommented(), config.NoEnv()) + if err != nil { + return xerrors.Errorf("Failed to generate default config: %w", err) + } + cfg := string(cb) + _, err = db.Exec(ctx, "INSERT INTO harmony_config (title, config) VALUES ('base', $1)", cfg) + if err != nil { + return xerrors.Errorf("failed to insert the 'base' into the database: %w", err) + } + fmt.Printf("The base layer has been updated with miner[s] %s\n", miners) + return nil + } + + // if base layer is present + baseCfg := config.DefaultCurioConfig() + var baseText string + err = db.QueryRow(ctx, "SELECT config FROM harmony_config WHERE title='base'").Scan(&baseText) + if err != nil { + return xerrors.Errorf("Cannot load base config from database: %w", err) + } + _, err = LoadConfigWithUpgrades(baseText, baseCfg) + if err != nil { + return xerrors.Errorf("Cannot parse base config: %w", err) + } + + baseCfg.Addresses = append(baseCfg.Addresses, curioConfig.Addresses...) + 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 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 xerrors.Errorf("cannot update base config: %w", err) + } + fmt.Printf("The base layer has been updated with miner[s] %s\n", miners) + return nil +} diff --git a/cmd/curio/guidedsetup/guidedsetup.go b/cmd/curio/guidedsetup/guidedsetup.go index 038b07e3f..1af49d868 100644 --- a/cmd/curio/guidedsetup/guidedsetup.go +++ b/cmd/curio/guidedsetup/guidedsetup.go @@ -8,6 +8,7 @@ package guidedsetup import ( "bytes" "context" + "crypto/rand" "encoding/base64" "encoding/json" "fmt" @@ -18,12 +19,14 @@ import ( "os/signal" "path" "reflect" + "strconv" "strings" "syscall" "time" "github.com/BurntSushi/toml" "github.com/charmbracelet/lipgloss" + "github.com/docker/go-units" "github.com/manifoldco/promptui" "github.com/mitchellh/go-homedir" "github.com/samber/lo" @@ -33,12 +36,15 @@ import ( "github.com/filecoin-project/go-address" "github.com/filecoin-project/go-jsonrpc" + "github.com/filecoin-project/go-state-types/abi" "github.com/filecoin-project/lotus/api" - "github.com/filecoin-project/lotus/api/v0api" + "github.com/filecoin-project/lotus/api/v1api" "github.com/filecoin-project/lotus/build" "github.com/filecoin-project/lotus/chain/types" + "github.com/filecoin-project/lotus/cli/spcli" cliutil "github.com/filecoin-project/lotus/cli/util" + "github.com/filecoin-project/lotus/cmd/curio/deps" _ "github.com/filecoin-project/lotus/cmd/curio/internal/translations" "github.com/filecoin-project/lotus/lib/harmony/harmonydb" "github.com/filecoin-project/lotus/node/config" @@ -50,7 +56,7 @@ 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", + Usage: "Run the guided setup for migrating from lotus-miner to Curio or Creating a new Curio miner", Flags: []cli.Flag{ &cli.StringFlag{ // for cliutil.GetFullNodeAPI Name: "repo", @@ -63,9 +69,6 @@ var GuidedsetupCmd = &cli.Command{ 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, @@ -74,10 +77,25 @@ var GuidedsetupCmd = &cli.Command{ Help: T("Use the arrow keys to navigate: ↓ ↑ → ← "), }, cctx: cctx, + ctx: cctx.Context, } - for _, step := range migrationSteps { - step(&migrationData) + + newOrMigrate(&migrationData) + if migrationData.init { + say(header, "This interactive tool creates a new miner actor and creates the basic configuration layer for it.") + say(notice, "This process is partially idempotent. Once a new miner actor has been created and subsequent steps fail, the user need to run 'curio config new-cluster < miner ID >' to finish the configuration.") + for _, step := range newMinerSteps { + step(&migrationData) + } + } else { + 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.") + + for _, step := range migrationSteps { + step(&migrationData) + } } + for _, closer := range migrationData.closers { closer() } @@ -164,6 +182,23 @@ func SetupLanguage() (func(key message.Reference, a ...interface{}) string, func } } +func newOrMigrate(d *MigrationData) { + i, _, err := (&promptui.Select{ + Label: d.T("I want to:"), + Items: []string{ + d.T("Migrate from existing Lotus-Miner"), + d.T("Create a new miner")}, + Templates: d.selectTemplates, + }).Run() + if err != nil { + d.say(notice, "Aborting remaining steps.", err.Error()) + os.Exit(1) + } + if i == 1 { + d.init = true + } +} + type migrationStep func(*MigrationData) var migrationSteps = []migrationStep{ @@ -176,6 +211,17 @@ var migrationSteps = []migrationStep{ complete, } +type newMinerStep func(data *MigrationData) + +var newMinerSteps = []newMinerStep{ + stepPresteps, + stepCreateActor, + stepNewMinerConfig, + doc, + oneLastThing, + completeInit, +} + type MigrationData struct { T func(key message.Reference, a ...interface{}) string say func(style lipgloss.Style, key message.Reference, a ...interface{}) @@ -184,9 +230,16 @@ type MigrationData struct { MinerConfig *config.StorageMiner DB *harmonydb.DB MinerID address.Address - full v0api.FullNode + full v1api.FullNode cctx *cli.Context closers []jsonrpc.ClientCloser + ctx context.Context + owner address.Address + worker address.Address + sender address.Address + ssize abi.SectorSize + confidence uint64 + init bool } func complete(d *MigrationData) { @@ -194,13 +247,19 @@ func complete(d *MigrationData) { 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 completeInit(d *MigrationData) { + stepCompleted(d, d.T("New Miner initialization complete.")) + d.say(plain, "Try the web interface with %s for further guided improvements.", "--layers=gui") +} + 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.full, closer, err = cliutil.GetFullNodeAPIV1(d.cctx) d.closers = append(d.closers, closer) if err != nil { d.say(notice, "Error getting API: %s", err.Error()) @@ -329,7 +388,7 @@ func doc(d *MigrationData) { 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, "Increase reliability using redundancy: start multiple machines with at-least the post layer: 'curio run --layers=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.") } @@ -381,69 +440,11 @@ func yugabyteConnect(d *MigrationData) { } 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 - } + if err != nil { + hcfg := getDBDetails(d) + harmonyCfg = *hcfg } -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 @@ -588,3 +589,293 @@ func stepCompleted(d *MigrationData, step string) { fmt.Print(green.Render("✔ ")) d.say(plain, "Step Complete: %s\n", step) } + +func stepCreateActor(d *MigrationData) { + d.say(plain, "Initializing a new miner actor.") + + for { + i, _, err := (&promptui.Select{ + Label: d.T("Enter the info to create a new miner"), + Items: []string{ + d.T("Owner Address: %s", d.owner.String()), + d.T("Worker Address: %s", d.worker.String()), + d.T("Sender Address: %s", d.sender.String()), + d.T("Sector Size: %d", d.ssize), + d.T("Confidence epochs: %d", d.confidence), + d.T("Continue to verify the addresses and create a new miner actor.")}, + Size: 6, + Templates: d.selectTemplates, + }).Run() + if err != nil { + d.say(notice, "Miner creation error occurred: %s ", err.Error()) + os.Exit(1) + } + switch i { + case 0: + owner, err := (&promptui.Prompt{ + Label: d.T("Enter the owner address"), + }).Run() + if err != nil { + d.say(notice, "No address provided") + continue + } + ownerAddr, err := address.NewFromString(owner) + if err != nil { + d.say(notice, "Failed to parse the address: %s", err.Error()) + } + d.owner = ownerAddr + case 1, 2: + val, err := (&promptui.Prompt{ + Label: d.T("Enter %s address", []string{"worker", "sender"}[i-1]), + Default: d.owner.String(), + }).Run() + if err != nil { + d.say(notice, err.Error()) + continue + } + addr, err := address.NewFromString(val) + if err != nil { + d.say(notice, "Failed to parse the address: %s", err.Error()) + } + switch i { + case 1: + d.worker = addr + case 2: + d.sender = addr + } + continue + case 3: + val, err := (&promptui.Prompt{ + Label: d.T("Enter the sector size"), + }).Run() + if err != nil { + d.say(notice, "No value provided") + continue + } + sectorSize, err := units.RAMInBytes(val) + if err != nil { + d.say(notice, "Failed to parse sector size: %s", err.Error()) + continue + } + d.ssize = abi.SectorSize(sectorSize) + continue + case 4: + confidenceStr, err := (&promptui.Prompt{ + Label: d.T("Confidence epochs"), + Default: strconv.Itoa(5), + }).Run() + if err != nil { + d.say(notice, err.Error()) + continue + } + confidence, err := strconv.ParseUint(confidenceStr, 10, 64) + if err != nil { + d.say(notice, "Failed to parse confidence: %s", err.Error()) + continue + } + d.confidence = confidence + goto minerInit // break out of the for loop once we have all the values + } + } + +minerInit: + miner, err := spcli.CreateStorageMiner(d.ctx, d.full, d.owner, d.worker, d.sender, d.ssize, d.confidence) + if err != nil { + d.say(notice, "Failed to create the miner actor: %s", err.Error()) + os.Exit(1) + } + + d.MinerID = miner + stepCompleted(d, d.T("Miner %s created successfully", miner.String())) +} + +func stepPresteps(d *MigrationData) { + + // Setup and connect to YugabyteDB + _ = getDBDetails(d) + + // Verify HarmonyDB connection + var titles []string + err := d.DB.Select(d.ctx, &titles, `SELECT title FROM harmony_config WHERE LENGTH(config) > 0`) + if err != nil { + d.say(notice, "Cannot reach the DB: %s", err.Error()) + os.Exit(1) + } + + // Get full node API + full, closer, err := cliutil.GetFullNodeAPIV1(d.cctx) + if err != nil { + d.say(notice, "Error connecting to full node API: %s", err.Error()) + os.Exit(1) + } + d.full = full + d.closers = append(d.closers, closer) + stepCompleted(d, d.T("Pre-initialization steps complete")) +} + +func stepNewMinerConfig(d *MigrationData) { + curioCfg := config.DefaultCurioConfig() + curioCfg.Addresses = append(curioCfg.Addresses, config.CurioAddresses{ + PreCommitControl: []string{}, + CommitControl: []string{}, + TerminateControl: []string{}, + DisableOwnerFallback: false, + DisableWorkerFallback: false, + MinerAddresses: []string{d.MinerID.String()}, + }) + + sk, err := io.ReadAll(io.LimitReader(rand.Reader, 32)) + if err != nil { + d.say(notice, "Failed to generate random bytes for secret: %s", err.Error()) + d.say(notice, "Please do not run guided-setup again as miner creation is not idempotent. You need to run 'curio config new-cluster %s' to finish the configuration", d.MinerID.String()) + os.Exit(1) + } + + curioCfg.Apis.StorageRPCSecret = base64.StdEncoding.EncodeToString(sk) + + ainfo, err := cliutil.GetAPIInfo(d.cctx, repo.FullNode) + if err != nil { + d.say(notice, "Failed to get API info for FullNode: %w", err) + d.say(notice, "Please do not run guided-setup again as miner creation is not idempotent. You need to run 'curio config new-cluster %s' to finish the configuration", d.MinerID.String()) + os.Exit(1) + } + + token, err := d.full.AuthNew(d.ctx, api.AllPermissions) + if err != nil { + d.say(notice, "Failed to verify the auth token from daemon node: %s", err.Error()) + d.say(notice, "Please do not run guided-setup again as miner creation is not idempotent. You need to run 'curio config new-cluster %s' to finish the configuration", d.MinerID.String()) + os.Exit(1) + } + + curioCfg.Apis.ChainApiInfo = append(curioCfg.Apis.ChainApiInfo, fmt.Sprintf("%s:%s", string(token), ainfo.Addr)) + + // write config + var titles []string + err = d.DB.Select(d.ctx, &titles, `SELECT title FROM harmony_config WHERE LENGTH(config) > 0`) + if err != nil { + d.say(notice, "Cannot reach the DB: %s", err.Error()) + d.say(notice, "Please do not run guided-setup again as miner creation is not idempotent. You need to run 'curio config new-cluster %s' to finish the configuration", d.MinerID.String()) + os.Exit(1) + } + + // If 'base' layer is not present + if !lo.Contains(titles, "base") { + curioCfg.Addresses = lo.Filter(curioCfg.Addresses, func(a config.CurioAddresses, _ int) bool { + return len(a.MinerAddresses) > 0 + }) + cb, err := config.ConfigUpdate(curioCfg, config.DefaultCurioConfig(), config.Commented(true), config.DefaultKeepUncommented(), config.NoEnv()) + if err != nil { + d.say(notice, "Failed to generate default config: %s", err.Error()) + d.say(notice, "Please do not run guided-setup again as miner creation is not idempotent. You need to run 'curio config new-cluster %s' to finish the configuration", d.MinerID.String()) + os.Exit(1) + } + _, err = d.DB.Exec(d.ctx, "INSERT INTO harmony_config (title, config) VALUES ('base', $1)", string(cb)) + if err != nil { + d.say(notice, "Failed to insert 'base' config layer in database: %s", err.Error()) + d.say(notice, "Please do not run guided-setup again as miner creation is not idempotent. You need to run 'curio config new-cluster %s' to finish the configuration", d.MinerID.String()) + os.Exit(1) + } + stepCompleted(d, d.T("Configuration 'base' was updated to include this miner's address")) + return + } + + // If base layer is already present + baseCfg := config.DefaultCurioConfig() + var baseText string + + err = d.DB.QueryRow(d.ctx, "SELECT config FROM harmony_config WHERE title='base'").Scan(&baseText) + if err != nil { + d.say(notice, "Failed to load base config from database: %s", err.Error()) + d.say(notice, "Please do not run guided-setup again as miner creation is not idempotent. You need to run 'curio config new-cluster %s' to finish the configuration", d.MinerID.String()) + os.Exit(1) + } + _, err = deps.LoadConfigWithUpgrades(baseText, baseCfg) + if err != nil { + d.say(notice, "Failed to parse base config: %s", err.Error()) + d.say(notice, "Please do not run guided-setup again as miner creation is not idempotent. You need to run 'curio config new-cluster %s' to finish the configuration", d.MinerID.String()) + os.Exit(1) + } + + baseCfg.Addresses = append(baseCfg.Addresses, curioCfg.Addresses...) + 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 { + d.say(notice, "Failed to regenerate base config: %s", err.Error()) + d.say(notice, "Please do not run guided-setup again as miner creation is not idempotent. You need to run 'curio config new-cluster %s' to finish the configuration", d.MinerID.String()) + os.Exit(1) + } + _, err = d.DB.Exec(d.ctx, "UPDATE harmony_config SET config=$1 WHERE title='base'", string(cb)) + if err != nil { + d.say(notice, "Failed to insert 'base' config layer in database: %s", err.Error()) + d.say(notice, "Please do not run guided-setup again as miner creation is not idempotent. You need to run 'curio config new-cluster %s' to finish the configuration", d.MinerID.String()) + os.Exit(1) + } + + stepCompleted(d, d.T("Configuration 'base' was updated to include this miner's address")) +} + +func getDBDetails(d *MigrationData) *config.HarmonyDB { + harmonyCfg := config.DefaultStorageMiner().HarmonyDB + 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: + 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 + } + d.DB = db + return &harmonyCfg + } + } +} diff --git a/cmd/curio/internal/translations/catalog.go b/cmd/curio/internal/translations/catalog.go index 1aca33033..44c97dfac 100644 --- a/cmd/curio/internal/translations/catalog.go +++ b/cmd/curio/internal/translations/catalog.go @@ -40,292 +40,436 @@ func init() { } 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, + "Aborting migration.": 45, + "Aborting remaining steps.": 9, + "Aggregate-Anonymous: version, chain, and Miner power (bucketed).": 22, + "Cannot reach the DB: %s": 90, + "Cannot read the config.toml file in the provided directory, Error: %s": 65, + "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.": 116, + "Confidence epochs": 86, + "Confidence epochs: %d": 76, + "Configuration 'base' was created to include this miner's address and its wallet setup.": 117, + "Configuration 'base' was updated to include this miner's address": 99, + "Configuration 'base' was updated to include this miner's address and its wallet setup.": 115, + "Connected to Yugabyte": 59, + "Connected to Yugabyte. Schema is current.": 47, + "Continue to connect and update schema.": 109, + "Continue to verify the addresses and create a new miner actor.": 77, + "Could not create repo from directory: %s. Aborting migration": 66, + "Could not lock miner repo. Your miner must be stopped: %s\n Aborting migration": 67, + "Create a new miner": 8, + "Ctrl+C pressed in Terminal": 5, + "Database config error occurred, abandoning migration: %s ": 110, + "Database: %s": 108, + "Documentation: ": 32, + "Each step needs your confirmation and can be reversed. Press Ctrl+C to exit at any time.": 4, + "Enabling Sector Indexing in the database.": 48, + "Enter %s address": 82, + "Enter the Yugabyte database %s": 113, + "Enter the Yugabyte database host(s)": 111, + "Enter the info to connect to your Yugabyte database installation (https://download.yugabyte.com/)": 103, + "Enter the info to create a new miner": 71, + "Enter the owner address": 79, + "Enter the path to the configuration directory used by %s": 63, + "Enter the sector size": 83, + "Error closing backup file: %s": 56, + "Error connecting to Yugabyte database: %s": 114, + "Error connecting to full node API: %s": 91, + "Error creating backup file: %s": 53, + "Error encoding config.toml: %s": 49, + "Error expanding path: %s": 51, + "Error getting API: %s": 15, + "Error getting miner info: %s": 27, + "Error getting miner power: %s": 25, + "Error getting token: %s": 17, + "Error interpreting miner ID: %s: ID: %s": 40, + "Error marshalling message: %s": 26, + "Error reading config.toml: %s": 54, + "Error reading filemode of config.toml: %s": 52, + "Error saving config to layer: %s. Aborting Migration": 18, + "Error sending message: %s": 29, + "Error sending message: Status %s, Message: ": 30, + "Error signing message: %s": 28, + "Error verifying sectors: %s": 41, + "Error writing backup file: %s": 55, + "Error writing config.toml: %s": 57, + "Failed to create the miner actor: %s": 88, + "Failed to generate default config: %s": 97, + "Failed to generate random bytes for secret: %s": 93, + "Failed to get API info for FullNode: %w": 95, + "Failed to insert 'base' config layer in database: %s": 98, + "Failed to load base config from database: %s": 100, + "Failed to parse base config: %s": 101, + "Failed to parse confidence: %s": 87, + "Failed to parse sector size: %s": 85, + "Failed to parse the address: %s": 81, + "Failed to regenerate base config: %s": 102, + "Failed to verify the auth token from daemon node: %s": 96, + "Filecoin %s channels: %s and %s": 35, + "Hint: I am someone running Curio on whichever chain.": 23, + "Host: %s": 104, + "I want to:": 6, + "Increase reliability using redundancy: start multiple machines with at-least the post layer: 'curio run --layers=post'": 36, + "Individual Data: Miner ID, Curio version, chain (%s or %s). Signed.": 21, + "Initializing a new miner actor.": 70, + "Layer %s created. ": 118, + "Lotus-Miner to Curio Migration.": 10, + "Message sent.": 31, + "Migrate from existing Lotus-Miner": 7, + "Migrating lotus-miner config.toml to Curio in-database configuration.": 14, + "Miner %s created successfully": 89, + "Miner creation error occurred: %s ": 78, + "New Miner initialization complete.": 13, + "No address provided": 80, + "No host provided": 112, + "No path provided, abandoning migration ": 64, + "No value provided": 84, + "Nothing.": 24, + "Now shut down lotus-miner and move the systems to %s.": 43, + "One database can serve multiple miner IDs: Run a migration for each lotus-miner.": 37, + "Other": 62, + "Owner Address: %s": 72, + "Password: %s": 107, + "Please do not run guided-setup again as miner creation is not idempotent. You need to run 'curio config new-cluster %s' to finish the configuration": 94, + "Please start (or restart) %s now that database credentials are in %s.": 38, + "Port: %s": 105, + "Pre-initialization steps complete": 92, + "Press return to continue": 44, + "Press return to update %s with Yugabyte info. A Backup file will be written to that folder before changes are made.": 50, + "Read Miner Config": 68, + "Restart Lotus Miner. ": 58, + "Sector Size: %d": 75, + "Sectors verified. %d sector locations found.": 46, + "Select the location of your lotus-miner config directory?": 61, + "Select what you want to share with the Curio team.": 20, + "Sender Address: %s": 74, + "Step Complete: %s\n": 69, + "The '%s' layer stores common configuration. All curio instances can include it in their %s argument.": 33, + "The Curio team wants to improve the software you use. Tell the team you're using `%s`.": 19, + "The sectors are in the database. The database is ready for %s.": 42, + "This interactive tool creates a new miner actor and creates the basic configuration layer for it.": 1, + "This interactive tool migrates lotus-miner to Curio in 5 minutes.": 3, + "This process is partially idempotent. Once a new miner actor has been created and subsequent steps fail, the user need to run 'curio config new-cluster < miner ID >' to finish the configuration.": 2, + "To run Curio: With machine or cgroup isolation, use the command (with example layer selection):": 120, + "To start, ensure your sealing pipeline is drained and shut-down lotus-miner.": 60, + "To work with the config: ": 119, + "Try the web interface with %s for further guided improvements.": 11, + "Use the arrow keys to navigate: ↓ ↑ → ← ": 0, + "Username: %s": 106, + "Waiting for %s to write sectors into Yugabyte.": 39, + "Worker Address: %s": 73, + "You can add other layers for per-machine configuration changes.": 34, + "You can now migrate your market node (%s), if applicable.": 12, + "could not get API info for FullNode: %w": 16, } -var enIndex = []uint32{ // 82 elements +var enIndex = []uint32{ // 122 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, + 0x00000000, 0x00000035, 0x00000097, 0x0000015a, + 0x0000019c, 0x000001f5, 0x00000210, 0x0000021b, + 0x0000023d, 0x00000250, 0x0000026a, 0x0000028a, + 0x000002cc, 0x00000309, 0x0000032c, 0x00000372, + 0x0000038b, 0x000003b6, 0x000003d1, 0x00000409, + 0x00000463, 0x00000496, 0x000004e0, 0x00000521, + 0x00000556, 0x0000055f, 0x00000580, 0x000005a1, + 0x000005c1, 0x000005de, 0x000005fb, 0x0000062e, // 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, + 0x0000063c, 0x00000650, 0x000006bb, 0x000006fb, + 0x00000724, 0x0000079b, 0x000007ec, 0x00000838, + 0x0000086a, 0x00000898, 0x000008b7, 0x000008f9, + 0x00000932, 0x0000094b, 0x0000095f, 0x0000098f, + 0x000009b9, 0x000009e3, 0x00000a05, 0x00000a7c, + 0x00000a98, 0x00000ac5, 0x00000ae7, 0x00000b08, + 0x00000b29, 0x00000b4a, 0x00000b6b, 0x00000b85, + 0x00000b9b, 0x00000be8, 0x00000c22, 0x00000c28, // Entry 40 - 5F - 0x00000b28, 0x00000b3e, 0x00000b8b, 0x00000bc5, - 0x00000bcb, 0x00000c07, 0x00000c33, 0x00000c7c, - 0x00000cbc, 0x00000d0d, 0x00000d1f, 0x00000d39, - 0x00000d90, 0x00000e2d, 0x00000e84, 0x00000e9e, - 0x00000ebc, 0x00000f1c, -} // Size: 352 bytes + 0x00000c64, 0x00000c90, 0x00000cd9, 0x00000d19, + 0x00000d6a, 0x00000d7c, 0x00000d96, 0x00000db6, + 0x00000ddb, 0x00000df0, 0x00000e06, 0x00000e1c, + 0x00000e2f, 0x00000e48, 0x00000e87, 0x00000eb1, + 0x00000ec9, 0x00000edd, 0x00000f00, 0x00000f14, + 0x00000f2a, 0x00000f3c, 0x00000f5f, 0x00000f71, + 0x00000f93, 0x00000fbb, 0x00000fdc, 0x00000ff7, + 0x00001020, 0x00001042, 0x00001074, 0x0000110b, + // Entry 60 - 7F + 0x00001136, 0x0000116e, 0x00001197, 0x000011cf, + 0x00001210, 0x00001240, 0x00001263, 0x0000128b, + 0x000012ed, 0x000012f9, 0x00001305, 0x00001315, + 0x00001325, 0x00001335, 0x0000135c, 0x0000139d, + 0x000013c1, 0x000013d2, 0x000013f4, 0x00001421, + 0x00001478, 0x00001515, 0x0000156c, 0x00001586, + 0x000015a4, 0x00001604, +} // Size: 512 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):" +const enData string = "" + // Size: 5636 bytes + "\x04\x00\x01 0\x02Use the arrow keys to navigate: ↓ ↑ → ←\x02This intera" + + "ctive tool creates a new miner actor and creates the basic configuration" + + " layer for it.\x02This process is partially idempotent. Once a new miner" + + " actor has been created and subsequent steps fail, the user need to run " + + "'curio config new-cluster < miner ID >' to finish the configuration.\x02" + + "This interactive tool migrates lotus-miner to Curio in 5 minutes.\x02Eac" + + "h step needs your confirmation and can be reversed. Press Ctrl+C to exit" + + " at any time.\x02Ctrl+C pressed in Terminal\x02I want to:\x02Migrate fro" + + "m existing Lotus-Miner\x02Create a new miner\x02Aborting remaining steps" + + ".\x02Lotus-Miner to Curio Migration.\x02Try the web interface with %[1]s" + + " for further guided improvements.\x02You can now migrate your market nod" + + "e (%[1]s), if applicable.\x02New Miner initialization complete.\x02Migra" + + "ting lotus-miner config.toml to Curio in-database configuration.\x02Erro" + + "r getting API: %[1]s\x02could not get API info for FullNode: %[1]w\x02Er" + + "ror getting token: %[1]s\x02Error saving config to layer: %[1]s. Abortin" + + "g Migration\x02The Curio team wants to improve the software you use. Tel" + + "l the team you're using `%[1]s`.\x02Select what you want to share with t" + + "he Curio team.\x02Individual Data: Miner ID, Curio version, chain (%[1]s" + + " or %[2]s). Signed.\x02Aggregate-Anonymous: version, chain, and Miner po" + + "wer (bucketed).\x02Hint: I am someone running Curio on whichever chain." + + "\x02Nothing.\x02Error getting miner power: %[1]s\x02Error marshalling me" + + "ssage: %[1]s\x02Error getting miner info: %[1]s\x02Error signing message" + + ": %[1]s\x02Error sending message: %[1]s\x04\x00\x01 .\x02Error sending m" + + "essage: Status %[1]s, Message:\x02Message sent.\x04\x00\x01 \x0f\x02Docu" + + "mentation:\x02The '%[1]s' layer stores common configuration. All curio i" + + "nstances can include it in their %[2]s argument.\x02You can add other la" + + "yers for per-machine configuration changes.\x02Filecoin %[1]s channels: " + + "%[2]s and %[3]s\x02Increase reliability using redundancy: start multiple" + + " machines with at-least the post layer: 'curio run --layers=post'\x02One" + + " database can serve multiple miner IDs: Run a migration for each lotus-m" + + "iner.\x02Please start (or restart) %[1]s now that database credentials a" + + "re in %[2]s.\x02Waiting for %[1]s to write sectors into Yugabyte.\x02Err" + + "or interpreting miner ID: %[1]s: ID: %[2]s\x02Error verifying sectors: %" + + "[1]s\x02The sectors are in the database. The database is ready for %[1]s" + + ".\x02Now shut down lotus-miner and move the systems to %[1]s.\x02Press r" + + "eturn to continue\x02Aborting migration.\x02Sectors verified. %[1]d sect" + + "or locations found.\x02Connected to Yugabyte. Schema is current.\x02Enab" + + "ling Sector Indexing in the database.\x02Error encoding config.toml: %[1" + + "]s\x02Press return to update %[1]s with Yugabyte info. A Backup file wil" + + "l be written to that folder before changes are made.\x02Error expanding " + + "path: %[1]s\x02Error reading filemode of config.toml: %[1]s\x02Error cre" + + "ating backup file: %[1]s\x02Error reading config.toml: %[1]s\x02Error wr" + + "iting backup file: %[1]s\x02Error closing backup file: %[1]s\x02Error wr" + + "iting config.toml: %[1]s\x04\x00\x01 \x15\x02Restart Lotus Miner.\x02Con" + + "nected to Yugabyte\x02To start, ensure your sealing pipeline is drained " + + "and shut-down lotus-miner.\x02Select the location of your lotus-miner co" + + "nfig directory?\x02Other\x02Enter the path to the configuration director" + + "y used by %[1]s\x04\x00\x01 '\x02No path provided, abandoning migration" + + "\x02Cannot read the config.toml file in the provided directory, 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 Abo" + + "rting migration\x02Read Miner Config\x04\x00\x01\x0a\x15\x02Step Complet" + + "e: %[1]s\x02Initializing a new miner actor.\x02Enter the info to create " + + "a new miner\x02Owner Address: %[1]s\x02Worker Address: %[1]s\x02Sender A" + + "ddress: %[1]s\x02Sector Size: %[1]d\x02Confidence epochs: %[1]d\x02Conti" + + "nue to verify the addresses and create a new miner actor.\x04\x00\x01 %" + + "\x02Miner creation error occurred: %[1]s\x02Enter the owner address\x02N" + + "o address provided\x02Failed to parse the address: %[1]s\x02Enter %[1]s " + + "address\x02Enter the sector size\x02No value provided\x02Failed to parse" + + " sector size: %[1]s\x02Confidence epochs\x02Failed to parse confidence: " + + "%[1]s\x02Failed to create the miner actor: %[1]s\x02Miner %[1]s created " + + "successfully\x02Cannot reach the DB: %[1]s\x02Error connecting to full n" + + "ode API: %[1]s\x02Pre-initialization steps complete\x02Failed to generat" + + "e random bytes for secret: %[1]s\x02Please do not run guided-setup again" + + " as miner creation is not idempotent. You need to run 'curio config new-" + + "cluster %[1]s' to finish the configuration\x02Failed to get API info for" + + " FullNode: %[1]w\x02Failed to verify the auth token from daemon node: %[" + + "1]s\x02Failed to generate default config: %[1]s\x02Failed to insert 'bas" + + "e' config layer in database: %[1]s\x02Configuration 'base' was updated t" + + "o include this miner's address\x02Failed to load base config from databa" + + "se: %[1]s\x02Failed to parse base config: %[1]s\x02Failed to regenerate " + + "base config: %[1]s\x02Enter the info to connect to your Yugabyte databas" + + "e installation (https://download.yugabyte.com/)\x02Host: %[1]s\x02Port: " + + "%[1]s\x02Username: %[1]s\x02Password: %[1]s\x02Database: %[1]s\x02Contin" + + "ue to connect and update schema.\x04\x00\x01 <\x02Database config error " + + "occurred, abandoning migration: %[1]s\x02Enter the Yugabyte database hos" + + "t(s)\x02No host provided\x02Enter the Yugabyte database %[1]s\x02Error c" + + "onnecting to Yugabyte database: %[1]s\x02Configuration 'base' was update" + + "d to include this miner's address and its wallet setup.\x02Compare the c" + + "onfigurations %[1]s to %[2]s. Changes between the miner IDs other than w" + + "allet addreses should be a new, minimal layer for runners that need it." + + "\x02Configuration 'base' 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 with the config:\x02To run Curio: With machine or cgroup" + + " isolation, use the command (with example layer selection):" -var koIndex = []uint32{ // 82 elements +var koIndex = []uint32{ // 122 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, + 0x00000000, 0x00000044, 0x000000c1, 0x000001c1, + 0x0000020e, 0x00000289, 0x000002aa, 0x000002bc, + 0x000002e5, 0x00000300, 0x00000325, 0x00000348, + 0x000003a2, 0x000003f2, 0x00000418, 0x00000471, + 0x00000490, 0x000004cc, 0x000004fc, 0x00000554, + 0x000005e0, 0x00000619, 0x0000066f, 0x000006ad, + 0x000006fb, 0x00000716, 0x00000750, 0x00000783, + 0x000007bd, 0x000007e7, 0x00000811, 0x00000853, // 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, + 0x00000877, 0x00000884, 0x0000090a, 0x0000095c, + 0x00000983, 0x00000a1f, 0x00000ab1, 0x00000b2c, + 0x00000b70, 0x00000bae, 0x00000bd5, 0x00000c40, + 0x00000c8a, 0x00000cb1, 0x00000ccc, 0x00000d1b, + 0x00000d5c, 0x00000d9c, 0x00000de3, 0x00000e89, + 0x00000eb9, 0x00000f08, 0x00000f2b, 0x00000f4c, + 0x00000f6f, 0x00000f92, 0x00000fd0, 0x00000ff4, + 0x0000100a, 0x00001075, 0x000010c4, 0x000010cb, // Entry 40 - 5F - 0x00000cea, 0x00000d00, 0x00000d6b, 0x00000dba, - 0x00000dc1, 0x00000e09, 0x00000e5b, 0x00000eb5, - 0x00000eb5, 0x00000eb5, 0x00000ecd, 0x00000ee7, - 0x00000f51, 0x0000100b, 0x0000106f, 0x0000109e, - 0x0000109e, 0x0000112a, -} // Size: 352 bytes + 0x00001113, 0x00001165, 0x000011bf, 0x00001229, + 0x000012ba, 0x000012d2, 0x000012ec, 0x00001310, + 0x00001343, 0x0000135b, 0x00001373, 0x0000138b, + 0x000013a0, 0x000013b8, 0x0000140f, 0x0000143a, + 0x00001452, 0x00001479, 0x0000149c, 0x000014b0, + 0x000014c5, 0x000014e9, 0x00001513, 0x00001524, + 0x0000154a, 0x00001570, 0x000015a9, 0x000015e1, + 0x00001619, 0x00001638, 0x00001684, 0x00001742, + // Entry 60 - 7F + 0x0000178e, 0x000017dc, 0x000017ff, 0x0000185b, + 0x000018ab, 0x00001900, 0x00001943, 0x00001982, + 0x000019f0, 0x00001a01, 0x00001a0f, 0x00001a27, + 0x00001a3b, 0x00001a55, 0x00001a7f, 0x00001ae2, + 0x00001b1e, 0x00001b48, 0x00001b80, 0x00001bd4, + 0x00001c3e, 0x00001cf8, 0x00001d5c, 0x00001d8b, + 0x00001db2, 0x00001e3e, +} // Size: 512 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 격리를 사용하여 다음 명령을 사용" + - "하세요 (예제 레이어 선택과 함께):" +const koData string = "" + // Size: 7742 bytes + "\x04\x00\x01 ?\x02화살표 키를 사용하여 이동하세요: ↓ ↑ → ←\x02이 대화형 도구는 새로운 채굴자 액터를 생성" + + "하고 그에 대한 기본 구성 레이어를 생성합니다.\x02이 프로세스는 부분적으로 항등원적입니다. 새로운 채굴자 액터가 생성되었고" + + " 후속 단계가 실패하는 경우 사용자는 구성을 완료하기 위해 'curio config new-cluster < 채굴자 ID >'를 " + + "실행해야 합니다.\x02이 대화형 도구는 5분 안에 lotus-miner를 Curio로 이주합니다.\x02각 단계는 확인이 필" + + "요하며 되돌릴 수 있습니다. 언제든지 Ctrl+C를 눌러 종료할 수 있습니다.\x02터미널에서 Ctrl+C가 눌림\x02나는 " + + "원한다:\x02기존의 Lotus-Miner에서 이전하기\x02새로운 채굴자 생성\x02나머지 단계를 중단합니다.\x02Lotu" + + "s-Miner에서 Curio로 이주.\x02더 많은 안내를 위해 %[1]s를 사용하여 웹 인터페이스를 시도하세요.\x02해당하는 " + + "경우 이제 시장 노드를 이주할 수 있습니다 (%[1]s).\x02새로운 채굴자 초기화 완료.\x02lotus-miner con" + + "fig.toml을 Curio의 데이터베이스 구성으로 이전 중입니다.\x02API 가져오기 오류: %[1]s\x02FullNode의" + + " API 정보를 가져올 수 없습니다: %[1]w\x02토큰을 가져오는 중 오류 발생: %[1]s\x02레이어에 구성을 저장하는 중" + + " 오류 발생: %[1]s. 마이그레이션 중단\x02Curio 팀은 당신이 사용하는 소프트웨어를 개선하고자 합니다. 팀에게 `%[1" + + "]s`를 사용 중이라고 알려주세요.\x02Curio 팀과 공유하고 싶은 것을 선택하세요.\x02개별 데이터: 채굴자 ID, Cur" + + "io 버전, 체인 (%[1]s 또는 %[2]s). 서명됨.\x02집계-익명: 버전, 체인, 및 채굴자 파워 (버킷).\x02힌트:" + + " 나는 어떤 체인에서든 Curio를 실행 중인 사람입니다.\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기계별 구성 변" + + "경을 위해 다른 레이어를 추가할 수 있습니다.\x02Filecoin %[1]s 채널: %[2]s 및 %[3]s\x02신뢰성 향" + + "상을 위한 중복성 사용: 적어도 post 레이어를 사용하여 여러 대의 기계를 시작하십시오: 'curio run --layers" + + "=post'\x02한 개의 데이터베이스는 여러 광부 ID를 제공할 수 있습니다: 각 lotus-miner에 대해 마이그레이션을 실" + + "행하세요.\x02데이터베이스 자격 증명이 %[2]s에 입력되었으므로 지금 %[1]s을 시작하거나 다시 시작하세요.\x02%[1" + + "]s가 Yugabyte에 섹터를 기록하도록 대기 중입니다.\x02광부 ID를 해석하는 중 오류 발생: %[1]s: ID: %[2]" + + "s\x02섹터 확인 중 오류 발생: %[1]s\x02섹터가 데이터베이스에 있습니다. 데이터베이스가 %[1]s를 위해 준비되었습니다" + + ".\x02이제 lotus-miner를 종료하고 시스템을 %[1]s로 이동하세요.\x02계속하려면 리턴을 누르세요\x02마이그레이션" + + " 중단.\x02섹터가 확인되었습니다. %[1]d개의 섹터 위치를 찾았습니다.\x02Yugabyte에 연결되었습니다. 스키마가 현재" + + "입니다.\x02데이터베이스에서 Sector Indexing을 활성화합니다.\x02config.toml을 인코딩하는 중 오류가 " + + "발생했습니다: %[1]s\x02%[1]s을 Yugabyte 정보로 업데이트하려면 리턴 키를 누르세요. 변경 사항을 적용하기 전" + + "에 해당 폴더에 백업 파일이 작성됩니다.\x02경로를 확장하는 중 오류 발생: %[1]s\x02config.toml의 파일 모" + + "드를 읽는 중 오류가 발생했습니다: %[1]s\x02백업 파일 생성 오류: %[1]s\x02config.toml 읽기 오류: " + + "%[1]s\x02백업 파일 쓰기 오류: %[1]s\x02백업 파일 닫기 오류: %[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디렉토리에서 저장소를 생성할 수 없습니다: %[1]s. 마이그레이션을 중단합니다.\x02광부 저장소를 " + + "잠금 해제할 수 없습니다. 귀하의 광부를 중지해야 합니다: %[1]s\x0a 마이그레이션을 중단합니다.\x02마이너 구성 읽기" + + "\x04\x00\x01\x0a\x15\x02단계 완료: %[1]s\x02새 채굴자 액터 초기화 중.\x02새 채굴자를 생성하기 위" + + "한 정보 입력\x02소유자 주소: %[1]s\x02작업자 주소: %[1]s\x02송신자 주소: %[1]s\x02섹터 크기: %" + + "[1]d\x02신뢰 에포크: %[1]d\x02주소를 확인하고 새 채굴자 액터를 생성하려면 계속 진행하세요.\x04\x00\x01 " + + "&\x02채굴자 생성 오류 발생: %[1]s\x02소유자 주소 입력\x02주소가 제공되지 않았습니다\x02주소 구문 분석 실패: " + + "%[1]s\x02%[1]s 주소 입력\x02섹터 크기 입력\x02값이 제공되지 않았습니다\x02섹터 크기 구문 분석 실패: %[1" + + "]s\x02신뢰 에포크\x02신뢰도 구문 분석 실패: %[1]s\x02채굴자 액터 생성 실패: %[1]s\x02%[1]s 채굴자가" + + " 성공적으로 생성되었습니다\x02데이터베이스에 연결할 수 없습니다: %[1]s\x02풀 노드 API에 연결하는 중 오류 발생: %" + + "[1]s\x02사전 초기화 단계 완료\x02비밀번호를 위한 랜덤 바이트 생성에 실패했습니다: %[1]s\x02마이너 생성은 ide" + + "mpotent하지 않으므로 가이드 설정을 다시 실행하지 마십시오. 구성을 완료하려면 'curio config new-cluster" + + " %[1]s'를 실행해야 합니다.\x02FullNode에 대한 API 정보를 가져오는 데 실패했습니다: %[1]w\x02데몬 노드" + + "로부터 인증 토큰을 확인하는 중 오류 발생: %[1]s\x02기본 구성 생성 실패: %[1]s\x02데이터베이스에 'base'" + + " 구성 레이어를 삽입하는 데 실패했습니다: %[1]s\x02이 마이너 주소를 포함한 구성 'base'가 업데이트되었습니다.\x02" + + "데이터베이스에서 기본 구성을 로드하는 데 실패했습니다: %[1]s\x02기본 구성을 구문 분석하는 데 실패했습니다: %[1]s" + + "\x02기본 구성을 재생성하는 데 실패했습니다: %[1]s\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을 입력하십시오\x02Yugabyte 데이터" + + "베이스에 연결하는 중 오류가 발생했습니다: %[1]s\x02이 마이너의 주소와 지갑 설정을 포함하도록 구성 'base'가 업데" + + "이트되었습니다.\x02구성 %[1]s를 %[2]s과 비교하세요. 지갑 주소 이외의 마이너 ID 사이의 변경 사항은 필요한 실행" + + "자를 위한 새로운 최소한의 레이어여야 합니다.\x02이 마이너의 주소와 지갑 설정을 포함하도록 구성 'base'가 생성되었습니" + + "다.\x04\x00\x01 *\x02레이어 %[1]s가 생성되었습니다.\x04\x00\x01 \x22\x02구성 파일을 사용하" + + "려면:\x02Curio를 실행하려면: 기계 또는 cgroup 격리를 사용하여 다음 명령을 사용하세요 (예제 레이어 선택과 함께" + + "):" -var zhIndex = []uint32{ // 82 elements +var zhIndex = []uint32{ // 122 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, + 0x00000000, 0x00000033, 0x0000008b, 0x00000134, + 0x0000017c, 0x000001cb, 0x000001e4, 0x000001f1, + 0x00000211, 0x0000022a, 0x00000240, 0x0000025d, + 0x0000029c, 0x000002dd, 0x000002f9, 0x0000033e, + 0x0000035b, 0x00000384, 0x000003a2, 0x000003db, + 0x0000042f, 0x0000045c, 0x000004ab, 0x000004e6, + 0x0000051b, 0x00000525, 0x00000549, 0x00000567, + 0x0000058b, 0x000005a9, 0x000005c7, 0x000005fc, // 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, + 0x0000060f, 0x0000061e, 0x00000678, 0x000006b5, + 0x000006dd, 0x0000073c, 0x0000078c, 0x000007df, + 0x00000805, 0x00000832, 0x00000850, 0x0000088c, + 0x000008be, 0x000008ce, 0x000008de, 0x00000911, + 0x0000093e, 0x00000963, 0x00000986, 0x000009fe, + 0x00000a1c, 0x00000a4b, 0x00000a6f, 0x00000a94, + 0x00000ab8, 0x00000adc, 0x00000aff, 0x00000b1f, + 0x00000b34, 0x00000b7f, 0x00000baf, 0x00000bb6, // Entry 40 - 5F - 0x000008b7, 0x000008cc, 0x00000917, 0x00000947, - 0x0000094e, 0x00000978, 0x0000099c, 0x000009e0, - 0x000009e0, 0x000009e0, 0x000009f3, 0x00000a0d, - 0x00000a59, 0x00000adb, 0x00000b27, 0x00000b41, - 0x00000b41, 0x00000b98, -} // Size: 352 bytes + 0x00000be0, 0x00000c04, 0x00000c48, 0x00000c7a, + 0x00000cc3, 0x00000cd6, 0x00000cf0, 0x00000d0f, + 0x00000d34, 0x00000d4c, 0x00000d61, 0x00000d79, + 0x00000d8d, 0x00000da4, 0x00000dd5, 0x00000dfa, + 0x00000e10, 0x00000e20, 0x00000e3a, 0x00000e4e, + 0x00000e61, 0x00000e6e, 0x00000e8e, 0x00000e9e, + 0x00000ebb, 0x00000edb, 0x00000ef5, 0x00000f12, + 0x00000f43, 0x00000f5c, 0x00000f85, 0x00001012, + // Entry 60 - 7F + 0x0000103e, 0x00001079, 0x00001099, 0x000010ca, + 0x000010fd, 0x0000112a, 0x0000114b, 0x00001171, + 0x000011cb, 0x000011da, 0x000011e9, 0x000011fb, + 0x0000120a, 0x0000121c, 0x0000123b, 0x00001273, + 0x00001298, 0x000012a8, 0x000012c6, 0x000012f2, + 0x0000133e, 0x000013c0, 0x0000140c, 0x00001426, + 0x0000143e, 0x00001495, +} // Size: 512 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隔离,使用命令(附带示例层选择):" +const zhData string = "" + // Size: 5269 bytes + "\x04\x00\x01 .\x02使用箭头键进行导航:↓ ↑ → ←\x02此交互式工具将创建一个新的矿工角色,并为其创建基本配置层。\x02" + + "该过程部分幂等。一旦创建了新的矿工角色,并且随后的步骤失败,用户需要运行 'curio config new-cluster < 矿工 ID" + + " >' 来完成配置。\x02这个交互式工具可以在5分钟内将lotus-miner迁移到Curio。\x02每一步都需要您的确认,并且可以撤销。随" + + "时按Ctrl+C退出。\x02在终端中按下Ctrl+C\x02我想要:\x02从现有的 Lotus-Miner 迁移\x02创建一个新的矿工" + + "\x02中止剩余步骤。\x02Lotus-Miner到Curio迁移。\x02尝试使用%[1]s的Web界面进行进一步引导式改进。\x02如果适" + + "用,您现在可以迁移您的市场节点(%[1]s)。\x02新矿工初始化完成。\x02将 lotus-miner config.toml 迁移到 " + + "Curio 的数据库配置中。\x02获取 API 时出错:%[1]s\x02无法获取FullNode的API信息:%[1]w\x02获取令牌时出" + + "错:%[1]s\x02保存配置到层时出错:%[1]s。正在中止迁移\x02Curio 团队希望改进您使用的软件。告诉团队您正在使用 `%[1" + + "]s`。\x02选择您想与Curio团队分享的内容。\x02个人数据:矿工 ID,Curio 版本,链(%[1]s 或 %[2]s)。签名。" + + "\x02聚合-匿名:版本,链和矿工算力(分桶)。\x02提示:我是在任何链上运行 Curio 的人。\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您可以添加其他层进行每台机器的配置更改。" + + "\x02Filecoin %[1]s 频道:%[2]s 和 %[3]s\x02通过冗余增加可靠性:使用至少后层启动多台机器:'curio run" + + " --layers=post'\x02一个数据库可以服务多个矿工ID:为每个lotus-miner运行迁移。\x02请立即启动(或重新启动)%[" + + "1]s,因为数据库凭据已在%[2]s中。\x02等待%[1]s将扇区写入Yugabyte。\x02解释矿工ID时出错:%[1]s:ID:%[2]" + + "s\x02验证扇区时出错:%[1]s\x02扇区在数据库中。数据库已准备好用于%[1]s。\x02现在关闭lotus-miner并将系统移至%[" + + "1]s。\x02按回车继续\x02中止迁移。\x02扇区已验证。发现了%[1]d个扇区位置。\x02已连接到Yugabyte。模式是当前的。" + + "\x02在数据库中启用扇区索引。\x02编码config.toml时出错:%[1]s\x02按回车键更新 %[1]s 以包含 Yugabyte " + + "信息。在进行更改之前,将在该文件夹中写入备份文件。\x02扩展路径时出错:%[1]s\x02读取config.toml文件模式时出错:%[1" + + "]s\x02创建备份文件时出错:%[1]s\x02读取 config.toml 时出错:%[1]s\x02写入备份文件时出错:%[1]s\x02" + + "关闭备份文件时出错:%[1]s\x02写入config.toml时出错:%[1]s\x04\x00\x01 \x1b\x02重新启动Lotu" + + "s Miner。\x02已连接到Yugabyte\x02开始之前,请确保您的密封管道已排空并关闭lotus-miner。\x02选择您的lotu" + + "s-miner配置目录的位置?\x02其他\x02输入%[1]s使用的配置目录的路径\x04\x00\x01 \x1f\x02未提供路径,放弃迁" + + "移\x02无法读取提供的目录中的config.toml文件,错误:%[1]s\x02无法从目录创建repo:%[1]s。 中止迁移\x02无" + + "法锁定矿工repo。 您的矿工必须停止:%[1]s\x0a 中止迁移\x02读取矿工配置\x04\x00\x01\x0a\x15\x02步骤" + + "完成:%[1]s\x02初始化新的矿工角色。\x02输入创建新矿工所需的信息\x02所有者地址:%[1]s\x02工作地址:%[1]s" + + "\x02发送者地址:%[1]s\x02扇区大小: %[1]d\x02置信度时期: %[1]d\x02继续验证地址并创建新的矿工角色。\x04" + + "\x00\x01 \x02矿工创建错误发生: %[1]s\x02输入所有者地址\x02未提供地址\x02解析地址失败: %[1]s\x02输入" + + " %[1]s 地址\x02输入扇区大小\x02未提供值\x02解析扇区大小失败: %[1]s\x02置信度时期\x02解析置信度失败: %[1]" + + "s\x02创建矿工角色失败: %[1]s\x02矿工 %[1]s 创建成功\x02无法访问数据库: %[1]s\x02连接到完整节点 API 时" + + "发生错误: %[1]s\x02预初始化步骤完成\x02生成密码的随机字节失败: %[1]s\x02请不要再次运行引导设置,因为矿工创建不是幂" + + "等的。 您需要运行 'curio config new-cluster %[1]s' 来完成配置。\x02无法获取 FullNode 的 A" + + "PI 信息: %[1]w\x02无法验证来自守护进程节点的授权令牌: %[1]s\x02无法生成默认配置: %[1]s\x02无法将 'base" + + "' 配置层插入数据库: %[1]s\x02配置 'base' 已更新以包含此矿工的地址\x02从数据库加载基本配置失败:%[1]s\x02解析基" + + "本配置失败:%[1]s\x02重新生成基本配置失败: %[1]s\x02输入连接到您的Yugabyte数据库安装的信息(https://do" + + "wnload.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输入Y" + + "ugabyte数据库主机(S)\x02未提供主机\x02输入Yugabyte数据库 %[1]s\x02连接到Yugabyte数据库时出错:%[1" + + "]s\x02配置'base'已更新,包含了这个矿工的地址和其钱包设置。\x02比较配置%[1]s和%[2]s。矿工ID之间除了钱包地址的变化应该" + + "是需要的运行者的一个新的、最小的层。\x02配置'base'已创建,包括了这个矿工的地址和其钱包设置。\x04\x00\x01 \x15" + + "\x02层%[1]s已创建。\x04\x00\x01 \x13\x02要使用配置:\x02运行Curio:使用机器或cgroup隔离,使用命令(" + + "附带示例层选择):" - // Total table size 12286 bytes (11KiB); checksum: 15B16994 + // Total table size 20183 bytes (19KiB); checksum: 4FD3E25A diff --git a/cmd/curio/internal/translations/locales/en/out.gotext.json b/cmd/curio/internal/translations/locales/en/out.gotext.json index 1cd3957d4..db8a264ee 100644 --- a/cmd/curio/internal/translations/locales/en/out.gotext.json +++ b/cmd/curio/internal/translations/locales/en/out.gotext.json @@ -1,6 +1,27 @@ { "language": "en", "messages": [ + { + "id": "Use the arrow keys to navigate: ↓ ↑ → ←", + "message": "Use the arrow keys to navigate: ↓ ↑ → ←", + "translation": "Use the arrow keys to navigate: ↓ ↑ → ←", + "translatorComment": "Copied from source.", + "fuzzy": true + }, + { + "id": "This interactive tool creates a new miner actor and creates the basic configuration layer for it.", + "message": "This interactive tool creates a new miner actor and creates the basic configuration layer for it.", + "translation": "This interactive tool creates a new miner actor and creates the basic configuration layer for it.", + "translatorComment": "Copied from source.", + "fuzzy": true + }, + { + "id": "This process is partially idempotent. Once a new miner actor has been created and subsequent steps fail, the user need to run 'curio config new-cluster \u003c miner ID \u003e' to finish the configuration.", + "message": "This process is partially idempotent. Once a new miner actor has been created and subsequent steps fail, the user need to run 'curio config new-cluster \u003c miner ID \u003e' to finish the configuration.", + "translation": "This process is partially idempotent. Once a new miner actor has been created and subsequent steps fail, the user need to run 'curio config new-cluster \u003c miner ID \u003e' to finish the configuration.", + "translatorComment": "Copied from source.", + "fuzzy": true + }, { "id": "This interactive tool migrates lotus-miner to Curio in 5 minutes.", "message": "This interactive tool migrates lotus-miner to Curio in 5 minutes.", @@ -15,13 +36,6 @@ "translatorComment": "Copied from source.", "fuzzy": true }, - { - "id": "Use the arrow keys to navigate: ↓ ↑ → ←", - "message": "Use the arrow keys to navigate: ↓ ↑ → ←", - "translation": "Use the arrow keys to navigate: ↓ ↑ → ←", - "translatorComment": "Copied from source.", - "fuzzy": true - }, { "id": "Ctrl+C pressed in Terminal", "message": "Ctrl+C pressed in Terminal", @@ -29,6 +43,44 @@ "translatorComment": "Copied from source.", "fuzzy": true }, + { + "id": "I want to:", + "message": "I want to:", + "translation": "I want to:", + "translatorComment": "Copied from source.", + "fuzzy": true + }, + { + "id": "Migrate from existing Lotus-Miner", + "message": "Migrate from existing Lotus-Miner", + "translation": "Migrate from existing Lotus-Miner", + "translatorComment": "Copied from source.", + "fuzzy": true + }, + { + "id": "Create a new miner", + "message": "Create a new miner", + "translation": "Create a new miner", + "translatorComment": "Copied from source.", + "fuzzy": true + }, + { + "id": "Aborting remaining steps.", + "message": "Aborting remaining steps.", + "translation": "Aborting remaining steps.", + "translatorComment": "Copied from source.", + "placeholders": [ + { + "id": "Error", + "string": "%[1]v", + "type": "string", + "underlyingType": "string", + "argNum": 1, + "expr": "err.Error()" + } + ], + "fuzzy": true + }, { "id": "Lotus-Miner to Curio Migration.", "message": "Lotus-Miner to Curio Migration.", @@ -71,16 +123,23 @@ "fuzzy": true }, { - "id": "Migrating config.toml to database.", - "message": "Migrating config.toml to database.", - "translation": "Migrating config.toml to database.", + "id": "New Miner initialization complete.", + "message": "New Miner initialization complete.", + "translation": "New Miner initialization complete.", "translatorComment": "Copied from source.", "fuzzy": true }, { - "id": "Error reading from database: {Error}. Aborting Migration.", - "message": "Error reading from database: {Error}. Aborting Migration.", - "translation": "Error reading from database: {Error}. Aborting Migration.", + "id": "Migrating lotus-miner config.toml to Curio in-database configuration.", + "message": "Migrating lotus-miner config.toml to Curio in-database configuration.", + "translation": "Migrating lotus-miner config.toml to Curio in-database configuration.", + "translatorComment": "Copied from source.", + "fuzzy": true + }, + { + "id": "Error getting API: {Error}", + "message": "Error getting API: {Error}", + "translation": "Error getting API: {Error}", "translatorComment": "Copied from source.", "placeholders": [ { @@ -94,31 +153,6 @@ ], "fuzzy": true }, - { - "id": "Error connecting to lotus node: {Error} {Error_1}", - "message": "Error connecting to lotus node: {Error} {Error_1}", - "translation": "Error connecting to lotus node: {Error} {Error_1}", - "translatorComment": "Copied from source.", - "placeholders": [ - { - "id": "Error", - "string": "%[1]s", - "type": "string", - "underlyingType": "string", - "argNum": 1, - "expr": "err.Error()" - }, - { - "id": "Error_1", - "string": "%[2]s", - "type": "string", - "underlyingType": "string", - "argNum": 2, - "expr": "err2.Error()" - } - ], - "fuzzy": true - }, { "id": "could not get API info for FullNode: {Err}", "message": "could not get API info for FullNode: {Err}", @@ -171,10 +205,20 @@ "fuzzy": true }, { - "id": "Protocol Labs wants to improve the software you use. Tell the team you're using Curio.", - "message": "Protocol Labs wants to improve the software you use. Tell the team you're using Curio.", - "translation": "Protocol Labs wants to improve the software you use. Tell the team you're using Curio.", + "id": "The Curio team wants to improve the software you use. Tell the team you're using `{Curio}`.", + "message": "The Curio team wants to improve the software you use. Tell the team you're using `{Curio}`.", + "translation": "The Curio team wants to improve the software you use. Tell the team you're using `{Curio}`.", "translatorComment": "Copied from source.", + "placeholders": [ + { + "id": "Curio", + "string": "%[1]s", + "type": "string", + "underlyingType": "string", + "argNum": 1, + "expr": "\"curio\"" + } + ], "fuzzy": true }, { @@ -185,9 +229,9 @@ "fuzzy": true }, { - "id": "Individual Data: Miner ID, Curio version, net ({Mainnet} or {Testnet}). Signed.", - "message": "Individual Data: Miner ID, Curio version, net ({Mainnet} or {Testnet}). Signed.", - "translation": "Individual Data: Miner ID, Curio version, net ({Mainnet} or {Testnet}). Signed.", + "id": "Individual Data: Miner ID, Curio version, chain ({Mainnet} or {Calibration}). Signed.", + "message": "Individual Data: Miner ID, Curio version, chain ({Mainnet} or {Calibration}). Signed.", + "translation": "Individual Data: Miner ID, Curio version, chain ({Mainnet} or {Calibration}). Signed.", "translatorComment": "Copied from source.", "placeholders": [ { @@ -199,27 +243,27 @@ "expr": "\"mainnet\"" }, { - "id": "Testnet", + "id": "Calibration", "string": "%[2]s", "type": "string", "underlyingType": "string", "argNum": 2, - "expr": "\"testnet\"" + "expr": "\"calibration\"" } ], "fuzzy": true }, { - "id": "Aggregate-Anonymous: version, net, and Miner power (bucketed).", - "message": "Aggregate-Anonymous: version, net, and Miner power (bucketed).", - "translation": "Aggregate-Anonymous: version, net, and Miner power (bucketed).", + "id": "Aggregate-Anonymous: version, chain, and Miner power (bucketed).", + "message": "Aggregate-Anonymous: version, chain, and Miner power (bucketed).", + "translation": "Aggregate-Anonymous: version, chain, and Miner power (bucketed).", "translatorComment": "Copied from source.", "fuzzy": true }, { - "id": "Hint: I am someone running Curio on net.", - "message": "Hint: I am someone running Curio on net.", - "translation": "Hint: I am someone running Curio on net.", + "id": "Hint: I am someone running Curio on whichever chain.", + "message": "Hint: I am someone running Curio on whichever chain.", + "translation": "Hint: I am someone running Curio on whichever chain.", "translatorComment": "Copied from source.", "fuzzy": true }, @@ -230,23 +274,6 @@ "translatorComment": "Copied from source.", "fuzzy": true }, - { - "id": "Aborting remaining steps.", - "message": "Aborting remaining steps.", - "translation": "Aborting remaining steps.", - "translatorComment": "Copied from source.", - "placeholders": [ - { - "id": "Error", - "string": "%[1]v", - "type": "string", - "underlyingType": "string", - "argNum": 1, - "expr": "err.Error()" - } - ], - "fuzzy": true - }, { "id": "Error getting miner power: {Error}", "message": "Error getting miner power: {Error}", @@ -437,37 +464,10 @@ "fuzzy": true }, { - "id": "Start multiple Curio instances with the '{Post}' layer to redundancy.", - "message": "Start multiple Curio instances with the '{Post}' layer to redundancy.", - "translation": "Start multiple Curio instances with the '{Post}' layer to redundancy.", + "id": "Increase reliability using redundancy: start multiple machines with at-least the post layer: 'curio run --layers=post'", + "message": "Increase reliability using redundancy: start multiple machines with at-least the post layer: 'curio run --layers=post'", + "translation": "Increase reliability using redundancy: start multiple machines with at-least the post layer: 'curio run --layers=post'", "translatorComment": "Copied from source.", - "placeholders": [ - { - "id": "Post", - "string": "%[1]s", - "type": "string", - "underlyingType": "string", - "argNum": 1, - "expr": "\"post\"" - } - ], - "fuzzy": true - }, - { - "id": "Point your browser to your web GUI to complete setup with {Boost} and advanced featues.", - "message": "Point your browser to your web GUI to complete setup with {Boost} and advanced featues.", - "translation": "Point your browser to your web GUI to complete setup with {Boost} and advanced featues.", - "translatorComment": "Copied from source.", - "placeholders": [ - { - "id": "Boost", - "string": "%[1]s", - "type": "string", - "underlyingType": "string", - "argNum": 1, - "expr": "\"Boost\"" - } - ], "fuzzy": true }, { @@ -626,177 +626,6 @@ ], "fuzzy": true }, - { - "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": "Enter the info to connect to your Yugabyte database installation (https://download.yugabyte.com/)", - "translatorComment": "Copied from source.", - "fuzzy": true - }, - { - "id": "Host: {Hosts_}", - "message": "Host: {Hosts_}", - "translation": "Host: {Hosts_}", - "translatorComment": "Copied from source.", - "placeholders": [ - { - "id": "Hosts_", - "string": "%[1]s", - "type": "string", - "underlyingType": "string", - "argNum": 1, - "expr": "strings.Join(harmonyCfg.Hosts, \",\")" - } - ], - "fuzzy": true - }, - { - "id": "Port: {Port}", - "message": "Port: {Port}", - "translation": "Port: {Port}", - "translatorComment": "Copied from source.", - "placeholders": [ - { - "id": "Port", - "string": "%[1]s", - "type": "string", - "underlyingType": "string", - "argNum": 1, - "expr": "harmonyCfg.Port" - } - ], - "fuzzy": true - }, - { - "id": "Username: {Username}", - "message": "Username: {Username}", - "translation": "Username: {Username}", - "translatorComment": "Copied from source.", - "placeholders": [ - { - "id": "Username", - "string": "%[1]s", - "type": "string", - "underlyingType": "string", - "argNum": 1, - "expr": "harmonyCfg.Username" - } - ], - "fuzzy": true - }, - { - "id": "Password: {Password}", - "message": "Password: {Password}", - "translation": "Password: {Password}", - "translatorComment": "Copied from source.", - "placeholders": [ - { - "id": "Password", - "string": "%[1]s", - "type": "string", - "underlyingType": "string", - "argNum": 1, - "expr": "harmonyCfg.Password" - } - ], - "fuzzy": true - }, - { - "id": "Database: {Database}", - "message": "Database: {Database}", - "translation": "Database: {Database}", - "translatorComment": "Copied from source.", - "placeholders": [ - { - "id": "Database", - "string": "%[1]s", - "type": "string", - "underlyingType": "string", - "argNum": 1, - "expr": "harmonyCfg.Database" - } - ], - "fuzzy": true - }, - { - "id": "Continue to connect and update schema.", - "message": "Continue to connect and update schema.", - "translation": "Continue to connect and update schema.", - "translatorComment": "Copied from source.", - "fuzzy": true - }, - { - "id": "Database config error occurred, abandoning migration: {Error}", - "message": "Database config error occurred, abandoning migration: {Error}", - "translation": "Database config error occurred, abandoning migration: {Error}", - "translatorComment": "Copied from source.", - "placeholders": [ - { - "id": "Error", - "string": "%[1]s", - "type": "string", - "underlyingType": "string", - "argNum": 1, - "expr": "err.Error()" - } - ], - "fuzzy": true - }, - { - "id": "Enter the Yugabyte database host(s)", - "message": "Enter the Yugabyte database host(s)", - "translation": "Enter the Yugabyte database host(s)", - "translatorComment": "Copied from source.", - "fuzzy": true - }, - { - "id": "No host provided", - "message": "No host provided", - "translation": "No host provided", - "translatorComment": "Copied from source.", - "fuzzy": true - }, - { - "id": "Enter the Yugabyte database {Stringport_username_password_databasei_1}", - "message": "Enter the Yugabyte database {Stringport_username_password_databasei_1}", - "translation": "Enter the Yugabyte database {Stringport_username_password_databasei_1}", - "translatorComment": "Copied from source.", - "placeholders": [ - { - "id": "Stringport_username_password_databasei_1", - "string": "%[1]s", - "type": "string", - "underlyingType": "string", - "argNum": 1, - "expr": "[]string{\"port\", \"username\", \"password\", \"database\"}[i-1]" - } - ], - "fuzzy": true - }, - { - "id": "No value provided", - "message": "No value provided", - "translation": "No value provided", - "translatorComment": "Copied from source.", - "fuzzy": true - }, - { - "id": "Error connecting to Yugabyte database: {Error}", - "message": "Error connecting to Yugabyte database: {Error}", - "translation": "Error connecting to Yugabyte database: {Error}", - "translatorComment": "Copied from source.", - "placeholders": [ - { - "id": "Error", - "string": "%[1]s", - "type": "string", - "underlyingType": "string", - "argNum": 1, - "expr": "err.Error()" - } - ], - "fuzzy": true - }, { "id": "Connected to Yugabyte. Schema is current.", "message": "Connected to Yugabyte. Schema is current.", @@ -829,9 +658,9 @@ "fuzzy": true }, { - "id": "Press return to update {Toml} with Yugabyte info. Backup the file now.", - "message": "Press return to update {Toml} with Yugabyte info. Backup the file now.", - "translation": "Press return to update {Toml} with Yugabyte info. Backup the file now.", + "id": "Press return to update {Toml} with Yugabyte info. A Backup file will be written to that folder before changes are made.", + "message": "Press return to update {Toml} with Yugabyte info. A Backup file will be written to that folder before changes are made.", + "translation": "Press return to update {Toml} with Yugabyte info. A Backup file will be written to that folder before changes are made.", "translatorComment": "Copied from source.", "placeholders": [ { @@ -879,6 +708,74 @@ ], "fuzzy": true }, + { + "id": "Error creating backup file: {Error}", + "message": "Error creating backup file: {Error}", + "translation": "Error creating backup file: {Error}", + "translatorComment": "Copied from source.", + "placeholders": [ + { + "id": "Error", + "string": "%[1]s", + "type": "string", + "underlyingType": "string", + "argNum": 1, + "expr": "err.Error()" + } + ], + "fuzzy": true + }, + { + "id": "Error reading config.toml: {Error}", + "message": "Error reading config.toml: {Error}", + "translation": "Error reading config.toml: {Error}", + "translatorComment": "Copied from source.", + "placeholders": [ + { + "id": "Error", + "string": "%[1]s", + "type": "string", + "underlyingType": "string", + "argNum": 1, + "expr": "err.Error()" + } + ], + "fuzzy": true + }, + { + "id": "Error writing backup file: {Error}", + "message": "Error writing backup file: {Error}", + "translation": "Error writing backup file: {Error}", + "translatorComment": "Copied from source.", + "placeholders": [ + { + "id": "Error", + "string": "%[1]s", + "type": "string", + "underlyingType": "string", + "argNum": 1, + "expr": "err.Error()" + } + ], + "fuzzy": true + }, + { + "id": "Error closing backup file: {Error}", + "message": "Error closing backup file: {Error}", + "translation": "Error closing backup file: {Error}", + "translatorComment": "Copied from source.", + "placeholders": [ + { + "id": "Error", + "string": "%[1]s", + "type": "string", + "underlyingType": "string", + "argNum": 1, + "expr": "err.Error()" + } + ], + "fuzzy": true + }, { "id": "Error writing config.toml: {Error}", "message": "Error writing config.toml: {Error}", @@ -1030,6 +927,631 @@ ], "fuzzy": true }, + { + "id": "Initializing a new miner actor.", + "message": "Initializing a new miner actor.", + "translation": "Initializing a new miner actor.", + "translatorComment": "Copied from source.", + "fuzzy": true + }, + { + "id": "Enter the info to create a new miner", + "message": "Enter the info to create a new miner", + "translation": "Enter the info to create a new miner", + "translatorComment": "Copied from source.", + "fuzzy": true + }, + { + "id": "Owner Address: {String}", + "message": "Owner Address: {String}", + "translation": "Owner Address: {String}", + "translatorComment": "Copied from source.", + "placeholders": [ + { + "id": "String", + "string": "%[1]s", + "type": "string", + "underlyingType": "string", + "argNum": 1, + "expr": "d.owner.String()" + } + ], + "fuzzy": true + }, + { + "id": "Worker Address: {String}", + "message": "Worker Address: {String}", + "translation": "Worker Address: {String}", + "translatorComment": "Copied from source.", + "placeholders": [ + { + "id": "String", + "string": "%[1]s", + "type": "string", + "underlyingType": "string", + "argNum": 1, + "expr": "d.worker.String()" + } + ], + "fuzzy": true + }, + { + "id": "Sender Address: {String}", + "message": "Sender Address: {String}", + "translation": "Sender Address: {String}", + "translatorComment": "Copied from source.", + "placeholders": [ + { + "id": "String", + "string": "%[1]s", + "type": "string", + "underlyingType": "string", + "argNum": 1, + "expr": "d.sender.String()" + } + ], + "fuzzy": true + }, + { + "id": "Sector Size: {Ssize}", + "message": "Sector Size: {Ssize}", + "translation": "Sector Size: {Ssize}", + "translatorComment": "Copied from source.", + "placeholders": [ + { + "id": "Ssize", + "string": "%[1]d", + "type": "github.com/filecoin-project/go-state-types/abi.SectorSize", + "underlyingType": "uint64", + "argNum": 1, + "expr": "d.ssize" + } + ], + "fuzzy": true + }, + { + "id": "Confidence epochs: {Confidence}", + "message": "Confidence epochs: {Confidence}", + "translation": "Confidence epochs: {Confidence}", + "translatorComment": "Copied from source.", + "placeholders": [ + { + "id": "Confidence", + "string": "%[1]d", + "type": "uint64", + "underlyingType": "uint64", + "argNum": 1, + "expr": "d.confidence" + } + ], + "fuzzy": true + }, + { + "id": "Continue to verify the addresses and create a new miner actor.", + "message": "Continue to verify the addresses and create a new miner actor.", + "translation": "Continue to verify the addresses and create a new miner actor.", + "translatorComment": "Copied from source.", + "fuzzy": true + }, + { + "id": "Miner creation error occurred: {Error}", + "message": "Miner creation error occurred: {Error}", + "translation": "Miner creation error occurred: {Error}", + "translatorComment": "Copied from source.", + "placeholders": [ + { + "id": "Error", + "string": "%[1]s", + "type": "string", + "underlyingType": "string", + "argNum": 1, + "expr": "err.Error()" + } + ], + "fuzzy": true + }, + { + "id": "Enter the owner address", + "message": "Enter the owner address", + "translation": "Enter the owner address", + "translatorComment": "Copied from source.", + "fuzzy": true + }, + { + "id": "No address provided", + "message": "No address provided", + "translation": "No address provided", + "translatorComment": "Copied from source.", + "fuzzy": true + }, + { + "id": "Failed to parse the address: {Error}", + "message": "Failed to parse the address: {Error}", + "translation": "Failed to parse the address: {Error}", + "translatorComment": "Copied from source.", + "placeholders": [ + { + "id": "Error", + "string": "%[1]s", + "type": "string", + "underlyingType": "string", + "argNum": 1, + "expr": "err.Error()" + } + ], + "fuzzy": true + }, + { + "id": "Enter {Stringworker_senderi_1} address", + "message": "Enter {Stringworker_senderi_1} address", + "translation": "Enter {Stringworker_senderi_1} address", + "translatorComment": "Copied from source.", + "placeholders": [ + { + "id": "Stringworker_senderi_1", + "string": "%[1]s", + "type": "string", + "underlyingType": "string", + "argNum": 1, + "expr": "[]string{\"worker\", \"sender\"}[i-1]" + } + ], + "fuzzy": true + }, + { + "id": "Enter the sector size", + "message": "Enter the sector size", + "translation": "Enter the sector size", + "translatorComment": "Copied from source.", + "fuzzy": true + }, + { + "id": "No value provided", + "message": "No value provided", + "translation": "No value provided", + "translatorComment": "Copied from source.", + "fuzzy": true + }, + { + "id": "Failed to parse sector size: {Error}", + "message": "Failed to parse sector size: {Error}", + "translation": "Failed to parse sector size: {Error}", + "translatorComment": "Copied from source.", + "placeholders": [ + { + "id": "Error", + "string": "%[1]s", + "type": "string", + "underlyingType": "string", + "argNum": 1, + "expr": "err.Error()" + } + ], + "fuzzy": true + }, + { + "id": "Confidence epochs", + "message": "Confidence epochs", + "translation": "Confidence epochs", + "translatorComment": "Copied from source.", + "fuzzy": true + }, + { + "id": "Failed to parse confidence: {Error}", + "message": "Failed to parse confidence: {Error}", + "translation": "Failed to parse confidence: {Error}", + "translatorComment": "Copied from source.", + "placeholders": [ + { + "id": "Error", + "string": "%[1]s", + "type": "string", + "underlyingType": "string", + "argNum": 1, + "expr": "err.Error()" + } + ], + "fuzzy": true + }, + { + "id": "Failed to create the miner actor: {Error}", + "message": "Failed to create the miner actor: {Error}", + "translation": "Failed to create the miner actor: {Error}", + "translatorComment": "Copied from source.", + "placeholders": [ + { + "id": "Error", + "string": "%[1]s", + "type": "string", + "underlyingType": "string", + "argNum": 1, + "expr": "err.Error()" + } + ], + "fuzzy": true + }, + { + "id": "Miner {String} created successfully", + "message": "Miner {String} created successfully", + "translation": "Miner {String} created successfully", + "translatorComment": "Copied from source.", + "placeholders": [ + { + "id": "String", + "string": "%[1]s", + "type": "string", + "underlyingType": "string", + "argNum": 1, + "expr": "miner.String()" + } + ], + "fuzzy": true + }, + { + "id": "Cannot reach the DB: {Error}", + "message": "Cannot reach the DB: {Error}", + "translation": "Cannot reach the DB: {Error}", + "translatorComment": "Copied from source.", + "placeholders": [ + { + "id": "Error", + "string": "%[1]s", + "type": "string", + "underlyingType": "string", + "argNum": 1, + "expr": "err.Error()" + } + ], + "fuzzy": true + }, + { + "id": "Error connecting to full node API: {Error}", + "message": "Error connecting to full node API: {Error}", + "translation": "Error connecting to full node API: {Error}", + "translatorComment": "Copied from source.", + "placeholders": [ + { + "id": "Error", + "string": "%[1]s", + "type": "string", + "underlyingType": "string", + "argNum": 1, + "expr": "err.Error()" + } + ], + "fuzzy": true + }, + { + "id": "Pre-initialization steps complete", + "message": "Pre-initialization steps complete", + "translation": "Pre-initialization steps complete", + "translatorComment": "Copied from source.", + "fuzzy": true + }, + { + "id": "Failed to generate random bytes for secret: {Error}", + "message": "Failed to generate random bytes for secret: {Error}", + "translation": "Failed to generate random bytes for secret: {Error}", + "translatorComment": "Copied from source.", + "placeholders": [ + { + "id": "Error", + "string": "%[1]s", + "type": "string", + "underlyingType": "string", + "argNum": 1, + "expr": "err.Error()" + } + ], + "fuzzy": true + }, + { + "id": "Please do not run guided-setup again as miner creation is not idempotent. You need to run 'curio config new-cluster {String}' to finish the configuration", + "message": "Please do not run guided-setup again as miner creation is not idempotent. You need to run 'curio config new-cluster {String}' to finish the configuration", + "translation": "Please do not run guided-setup again as miner creation is not idempotent. You need to run 'curio config new-cluster {String}' to finish the configuration", + "translatorComment": "Copied from source.", + "placeholders": [ + { + "id": "String", + "string": "%[1]s", + "type": "string", + "underlyingType": "string", + "argNum": 1, + "expr": "d.MinerID.String()" + } + ], + "fuzzy": true + }, + { + "id": "Failed to get API info for FullNode: {Err}", + "message": "Failed to get API info for FullNode: {Err}", + "translation": "Failed to get API info for FullNode: {Err}", + "translatorComment": "Copied from source.", + "placeholders": [ + { + "id": "Err", + "string": "%[1]w", + "type": "error", + "underlyingType": "interface{Error() string}", + "argNum": 1, + "expr": "err" + } + ], + "fuzzy": true + }, + { + "id": "Failed to verify the auth token from daemon node: {Error}", + "message": "Failed to verify the auth token from daemon node: {Error}", + "translation": "Failed to verify the auth token from daemon node: {Error}", + "translatorComment": "Copied from source.", + "placeholders": [ + { + "id": "Error", + "string": "%[1]s", + "type": "string", + "underlyingType": "string", + "argNum": 1, + "expr": "err.Error()" + } + ], + "fuzzy": true + }, + { + "id": "Failed to generate default config: {Error}", + "message": "Failed to generate default config: {Error}", + "translation": "Failed to generate default config: {Error}", + "translatorComment": "Copied from source.", + "placeholders": [ + { + "id": "Error", + "string": "%[1]s", + "type": "string", + "underlyingType": "string", + "argNum": 1, + "expr": "err.Error()" + } + ], + "fuzzy": true + }, + { + "id": "Failed to insert 'base' config layer in database: {Error}", + "message": "Failed to insert 'base' config layer in database: {Error}", + "translation": "Failed to insert 'base' config layer in database: {Error}", + "translatorComment": "Copied from source.", + "placeholders": [ + { + "id": "Error", + "string": "%[1]s", + "type": "string", + "underlyingType": "string", + "argNum": 1, + "expr": "err.Error()" + } + ], + "fuzzy": true + }, + { + "id": "Configuration 'base' was updated to include this miner's address", + "message": "Configuration 'base' was updated to include this miner's address", + "translation": "Configuration 'base' was updated to include this miner's address", + "translatorComment": "Copied from source.", + "fuzzy": true + }, + { + "id": "Failed to load base config from database: {Error}", + "message": "Failed to load base config from database: {Error}", + "translation": "Failed to load base config from database: {Error}", + "translatorComment": "Copied from source.", + "placeholders": [ + { + "id": "Error", + "string": "%[1]s", + "type": "string", + "underlyingType": "string", + "argNum": 1, + "expr": "err.Error()" + } + ], + "fuzzy": true + }, + { + "id": "Failed to parse base config: {Error}", + "message": "Failed to parse base config: {Error}", + "translation": "Failed to parse base config: {Error}", + "translatorComment": "Copied from source.", + "placeholders": [ + { + "id": "Error", + "string": "%[1]s", + "type": "string", + "underlyingType": "string", + "argNum": 1, + "expr": "err.Error()" + } + ], + "fuzzy": true + }, + { + "id": "Failed to regenerate base config: {Error}", + "message": "Failed to regenerate base config: {Error}", + "translation": "Failed to regenerate base config: {Error}", + "translatorComment": "Copied from source.", + "placeholders": [ + { + "id": "Error", + "string": "%[1]s", + "type": "string", + "underlyingType": "string", + "argNum": 1, + "expr": "err.Error()" + } + ], + "fuzzy": true + }, + { + "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": "Enter the info to connect to your Yugabyte database installation (https://download.yugabyte.com/)", + "translatorComment": "Copied from source.", + "fuzzy": true + }, + { + "id": "Host: {Hosts_}", + "message": "Host: {Hosts_}", + "translation": "Host: {Hosts_}", + "translatorComment": "Copied from source.", + "placeholders": [ + { + "id": "Hosts_", + "string": "%[1]s", + "type": "string", + "underlyingType": "string", + "argNum": 1, + "expr": "strings.Join(harmonyCfg.Hosts, \",\")" + } + ], + "fuzzy": true + }, + { + "id": "Port: {Port}", + "message": "Port: {Port}", + "translation": "Port: {Port}", + "translatorComment": "Copied from source.", + "placeholders": [ + { + "id": "Port", + "string": "%[1]s", + "type": "string", + "underlyingType": "string", + "argNum": 1, + "expr": "harmonyCfg.Port" + } + ], + "fuzzy": true + }, + { + "id": "Username: {Username}", + "message": "Username: {Username}", + "translation": "Username: {Username}", + "translatorComment": "Copied from source.", + "placeholders": [ + { + "id": "Username", + "string": "%[1]s", + "type": "string", + "underlyingType": "string", + "argNum": 1, + "expr": "harmonyCfg.Username" + } + ], + "fuzzy": true + }, + { + "id": "Password: {Password}", + "message": "Password: {Password}", + "translation": "Password: {Password}", + "translatorComment": "Copied from source.", + "placeholders": [ + { + "id": "Password", + "string": "%[1]s", + "type": "string", + "underlyingType": "string", + "argNum": 1, + "expr": "harmonyCfg.Password" + } + ], + "fuzzy": true + }, + { + "id": "Database: {Database}", + "message": "Database: {Database}", + "translation": "Database: {Database}", + "translatorComment": "Copied from source.", + "placeholders": [ + { + "id": "Database", + "string": "%[1]s", + "type": "string", + "underlyingType": "string", + "argNum": 1, + "expr": "harmonyCfg.Database" + } + ], + "fuzzy": true + }, + { + "id": "Continue to connect and update schema.", + "message": "Continue to connect and update schema.", + "translation": "Continue to connect and update schema.", + "translatorComment": "Copied from source.", + "fuzzy": true + }, + { + "id": "Database config error occurred, abandoning migration: {Error}", + "message": "Database config error occurred, abandoning migration: {Error}", + "translation": "Database config error occurred, abandoning migration: {Error}", + "translatorComment": "Copied from source.", + "placeholders": [ + { + "id": "Error", + "string": "%[1]s", + "type": "string", + "underlyingType": "string", + "argNum": 1, + "expr": "err.Error()" + } + ], + "fuzzy": true + }, + { + "id": "Enter the Yugabyte database host(s)", + "message": "Enter the Yugabyte database host(s)", + "translation": "Enter the Yugabyte database host(s)", + "translatorComment": "Copied from source.", + "fuzzy": true + }, + { + "id": "No host provided", + "message": "No host provided", + "translation": "No host provided", + "translatorComment": "Copied from source.", + "fuzzy": true + }, + { + "id": "Enter the Yugabyte database {Stringport_username_password_databasei_1}", + "message": "Enter the Yugabyte database {Stringport_username_password_databasei_1}", + "translation": "Enter the Yugabyte database {Stringport_username_password_databasei_1}", + "translatorComment": "Copied from source.", + "placeholders": [ + { + "id": "Stringport_username_password_databasei_1", + "string": "%[1]s", + "type": "string", + "underlyingType": "string", + "argNum": 1, + "expr": "[]string{\"port\", \"username\", \"password\", \"database\"}[i-1]" + } + ], + "fuzzy": true + }, + { + "id": "Error connecting to Yugabyte database: {Error}", + "message": "Error connecting to Yugabyte database: {Error}", + "translation": "Error connecting to Yugabyte database: {Error}", + "translatorComment": "Copied from source.", + "placeholders": [ + { + "id": "Error", + "string": "%[1]s", + "type": "string", + "underlyingType": "string", + "argNum": 1, + "expr": "err.Error()" + } + ], + "fuzzy": true + }, { "id": "Configuration 'base' was updated to include this miner's address and its wallet setup.", "message": "Configuration 'base' was updated to include this miner's address and its wallet setup.", diff --git a/cmd/curio/internal/translations/locales/ko/messages.gotext.json b/cmd/curio/internal/translations/locales/ko/messages.gotext.json index ab0f8c6af..61107880c 100644 --- a/cmd/curio/internal/translations/locales/ko/messages.gotext.json +++ b/cmd/curio/internal/translations/locales/ko/messages.gotext.json @@ -621,84 +621,462 @@ "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 - } + }, + { + "id": "This interactive tool creates a new miner actor and creates the basic configuration layer for it.", + "translation": "이 대화형 도구는 새로운 채굴자 액터를 생성하고 그에 대한 기본 구성 레이어를 생성합니다.", + "message": "This interactive tool creates a new miner actor and creates the basic configuration layer for it.", + "placeholder": null + }, + { + "id": "This process is partially idempotent. Once a new miner actor has been created and subsequent steps fail, the user need to run 'curio config new-cluster {Arg_1}' to finish the configuration.", + "translation": "이 프로세스는 부분적으로 idempotent합니다. 새로운 채굴자 액터가 생성되었고 후속 단계가 실패하면 사용자는 구성을 완료하기 위해 'curio config new-cluster {Arg_1}'를 실행해야 합니다.", + "message": "This process is partially idempotent. Once a new miner actor has been created and subsequent steps fail, the user need to run 'curio config new-cluster {Arg_1}' to finish the configuration.", + "placeholder": null + }, + { + "id": "Choose if you with to create a new miner or migrate from existing Lotus-Miner", + "translation": "새 채굴자를 생성할지 기존의 Lotus-Miner에서 이전할지 선택하세요.", + "message": "Choose if you with to create a new miner or migrate from existing Lotus-Miner", + "placeholder": null + }, + { + "id": "Migrate from existing Lotus-Miner", + "translation": "기존의 Lotus-Miner에서 이전하기", + "message": "Migrate from existing Lotus-Miner", + "placeholder": null + }, + { + "id": "Create a new miner", + "translation": "새로운 채굴자 생성", + "message": "Create a new miner", + "placeholder": null + }, + { + "id": "New Miner initialization complete.", + "translation": "새로운 채굴자 초기화 완료.", + "message": "New Miner initialization complete.", + "placeholder": null + }, + { + "id": "Migrating lotus-miner config.toml to Curio in-database configuration.", + "translation": "lotus-miner config.toml을 Curio의 데이터베이스 구성으로 이전 중입니다.", + "message": "Migrating lotus-miner config.toml to Curio in-database configuration.", + "placeholder": null + }, + { + "id": "Error getting API: {Error}", + "translation": "API 가져오기 오류: {Error}", + "message": "Error getting API: {Error}", + "placeholder": null + }, + { + "id": "The Curio team wants to improve the software you use. Tell the team you're using {Curio}.", + "translation": "Curio 팀은 당신이 사용하는 소프트웨어를 개선하고자 합니다. 팀에게 {Curio}를 사용 중이라고 알려주세요.", + "message": "The Curio team wants to improve the software you use. Tell the team you're using {Curio}.", + "placeholder": null + }, + { + "id": "Individual Data: Miner ID, Curio version, chain ({Mainnet} or {Calibration}). Signed.", + "translation": "개별 데이터: 채굴자 ID, Curio 버전, 체인 ({Mainnet} 또는 {Calibration}). 서명됨.", + "message": "Individual Data: Miner ID, Curio version, chain ({Mainnet} or {Calibration}). Signed.", + "placeholder": null + }, + { + "id": "Aggregate-Anonymous: version, chain, and Miner power (bucketed).", + "translation": "집계-익명: 버전, 체인, 및 채굴자 파워 (버킷).", + "message": "Aggregate-Anonymous: version, chain, and Miner power (bucketed).", + "placeholder": null + }, + { + "id": "Hint: I am someone running Curio on whichever chain.", + "translation": "힌트: 나는 어떤 체인에서든 Curio를 실행 중인 사람입니다.", + "message": "Hint: I am someone running Curio on whichever chain.", + "placeholder": null + }, + { + "id": "Press return to update {Toml} with Yugabyte info. A Backup file will be written to that folder before changes are made.", + "translation": "{Toml}을 Yugabyte 정보로 업데이트하려면 리턴 키를 누르세요. 변경 사항을 적용하기 전에 해당 폴더에 백업 파일이 작성됩니다.", + "message": "Press return to update {Toml} with Yugabyte info. A Backup file will be written to that folder before changes are made.", + "placeholder": null + }, + { + "id": "Error creating backup file: {Error}", + "translation": "백업 파일 생성 오류: {Error}", + "message": "Error creating backup file: {Error}", + "placeholder": null + }, + { + "id": "Error reading config.toml: {Error}", + "translation": "config.toml 읽기 오류: {Error}", + "message": "Error reading config.toml: {Error}", + "placeholder": null + }, + { + "id": "Error writing backup file: {Error}", + "translation": "백업 파일 쓰기 오류: {Error}", + "message": "Error writing backup file: {Error}", + "placeholder": null + }, + { + "id": "Error closing backup file: {Error}", + "translation": "백업 파일 닫기 오류: {Error}", + "message": "Error closing backup file: {Error}", + "placeholder": null + }, + { + "id": "Initializing a new miner actor.", + "translation": "새 채굴자 액터 초기화 중.", + "message": "Initializing a new miner actor.", + "placeholder": null + }, + { + "id": "Enter the info to create a new miner", + "translation": "새 채굴자를 생성하기 위한 정보 입력", + "message": "Enter the info to create a new miner", + "placeholder": null + }, + { + "id": "Owner Address: {String}", + "translation": "소유자 주소: {String}", + "message": "Owner Address: {String}", + "placeholder": null + }, + { + "id": "Worker Address: {String}", + "translation": "작업자 주소: {String}", + "message": "Worker Address: {String}", + "placeholder": null + }, + { + "id": "Sender Address: {String}", + "translation": "송신자 주소: {String}", + "message": "Sender Address: {String}", + "placeholder": null + }, + { + "id": "Sector Size: {Ssize}", + "translation": "섹터 크기: {Ssize}", + "message": "Sector Size: {Ssize}", + "placeholder": null + }, + { + "id": "Confidence: {Confidence}", + "translation": "신뢰도: {Confidence}", + "message": "Confidence: {Confidence}", + "placeholder": null + }, + { + "id": "Continue to verify the addresses and create a new miner actor.", + "translation": "주소를 확인하고 새 채굴자 액터를 생성하려면 계속 진행하세요.", + "message": "Continue to verify the addresses and create a new miner actor.", + "placeholder": null + }, + { + "id": "Miner creation error occurred: {Error}", + "translation": "채굴자 생성 오류 발생: {Error}", + "message": "Miner creation error occurred: {Error}", + "placeholder": null + }, + { + "id": "Enter the owner address", + "translation": "소유자 주소 입력", + "message": "Enter the owner address", + "placeholder": null + }, + { + "id": "No address provided", + "translation": "주소가 제공되지 않았습니다", + "message": "No address provided", + "placeholder": null + }, + { + "id": "Failed to parse the address: {Error}", + "translation": "주소 구문 분석 실패: {Error}", + "message": "Failed to parse the address: {Error}", + "placeholder": null + }, + { + "id": "Enter {Stringworker_senderi_1} address", + "translation": "{Stringworker_senderi_1} 주소 입력", + "message": "Enter {Stringworker_senderi_1} address", + "placeholder": null + }, + { + "id": "Enter the sector size", + "translation": "섹터 크기 입력", + "message": "Enter the sector size", + "placeholder": null + }, + { + "id": "Failed to parse sector size: {Error}", + "translation": "섹터 크기 구문 분석 실패: {Error}", + "message": "Failed to parse sector size: {Error}", + "placeholder": null + }, + { + "id": "Enter the confidence", + "translation": "신뢰도 입력", + "message": "Enter the confidence", + "placeholder": null + }, + { + "id": "Failed to parse confidence: {Error}", + "translation": "신뢰도 구문 분석 실패: {Error}", + "message": "Failed to parse confidence: {Error}", + "placeholder": null + }, + { + "id": "Failed to create the miner actor: {Error}", + "translation": "채굴자 액터 생성 실패: {Error}", + "message": "Failed to create the miner actor: {Error}", + "placeholder": null + }, + { + "id": "Miner {String} created successfully", + "translation": "{String} 채굴자가 성공적으로 생성되었습니다", + "message": "Miner {String} created successfully", + "placeholder": null + }, + { + "id": "Cannot reach the DB: {Error}", + "translation": "데이터베이스에 연결할 수 없습니다: {Error}", + "message": "Cannot reach the DB: {Error}", + "placeholder": null + }, + { + "id": "Error connecting to full node API: {Error}", + "translation": "풀 노드 API에 연결하는 중 오류 발생: {Error}", + "message": "Error connecting to full node API: {Error}", + "placeholder": null + }, + { + "id": "Pre-initialization steps complete", + "translation": "사전 초기화 단계 완료", + "message": "Pre-initialization steps complete", + "placeholder": null + }, + { + "id": "Failed to random bytes for secret: {Error}", + "translation": "비밀을 위한 랜덤 바이트 생성 실패: {Error}", + "message": "Failed to random bytes for secret: {Error}", + "placeholder": null + }, + { + "id": "Please do not run guided-setup again as miner creation is not idempotent. You need to run 'curio config new-cluster {String}' to finish the configuration", + "translation": "마이너 생성은 idempotent하지 않으므로 가이드 설정을 다시 실행하지 마십시오. 구성을 완료하려면 'curio config new-cluster {String}'를 실행해야 합니다.", + "message": "Please do not run guided-setup again as miner creation is not idempotent. You need to run 'curio config new-cluster {String}' to finish the configuration", + "placeholder": null + }, + { + "id": "Failed to verify the auth token from daemon node: {Error}", + "translation": "데몬 노드로부터 인증 토큰을 확인하는 중 오류 발생: {Error}", + "message": "Failed to verify the auth token from daemon node: {Error}", + "placeholder": null + }, + { + "id": "Failed to encode the config: {Error}", + "translation": "구성을 인코딩하는 중 오류 발생: {Error}", + "message": "Failed to encode the config: {Error}", + "placeholder": null + }, + { + "id": "Failed to generate default config: {Error}", + "translation": "기본 구성 생성 실패: {Error}", + "message": "Failed to generate default config: {Error}", + "placeholder": null + }, + { + "id": "Failed to inset 'base' config layer in database: {Error}", + "translation": "데이터베이스에 'base' 구성 레이어 삽입 실패: {Error}", + "message": "Failed to inset 'base' config layer in database: {Error}", + "placeholder": null + }, + { + "id": "Failed to inset '{String}' config layer in database: {Error}", + "translation": "데이터베이스에 '{String}' 구성 레이어 삽입 실패: {Error}", + "message": "Failed to inset '{String}' config layer in database: {Error}", + "placeholder": null + }, + { + "id": "New Curio configuration layer '{String}' created", + "translation": "새로운 Curio 구성 레이어 '{String}'가 생성되었습니다", + "message": "New Curio configuration layer '{String}' created", + "placeholder": null + }, + { + "id": "The Curio team wants to improve the software you use. Tell the team you're using `{Curio}`.", + "translation": "Curio 팀은 당신이 사용하는 소프트웨어를 개선하고자 합니다. 팀에게 `{Curio}`를 사용 중이라고 알려주세요.", + "message": "The Curio team wants to improve the software you use. Tell the team you're using `{Curio}`.", + "placeholder": null + }, + { + "id": "Confidence epochs: {Confidence}", + "translation": "신뢰 에포크: {Confidence}", + "message": "Confidence epochs: {Confidence}", + "placeholder": null + }, + { + "id": "Failed to generate random bytes for secret: {Error}", + "translation": "비밀번호를 위한 랜덤 바이트 생성에 실패했습니다: {Error}", + "message": "Failed to generate random bytes for secret: {Error}", + "placeholder": null + }, + { + "id": "Failed to get API info for FullNode: {Err}", + "translation": "FullNode에 대한 API 정보를 가져오는 데 실패했습니다: {Err}", + "message": "Failed to get API info for FullNode: {Err}", + "placeholder": null + }, + { + "id": "Failed to insert 'base' config layer in database: {Error}", + "translation": "데이터베이스에 'base' 구성 레이어를 삽입하는 데 실패했습니다: {Error}", + "message": "Failed to insert 'base' config layer in database: {Error}", + "placeholder": null + }, + { + "id": "Failed to insert '{String}' config layer in database: {Error}", + "translation": "데이터베이스에 '{String}' 구성 레이어를 삽입하는 데 실패했습니다: {Error}", + "message": "Failed to insert '{String}' config layer in database: {Error}", + "placeholder": null + }, + { + "id": "This process is partially idempotent. Once a new miner actor has been created and subsequent steps fail, the user need to run 'curio config new-cluster \u003c miner ID \u003e' to finish the configuration.", + "translation": "이 프로세스는 부분적으로 항등원적입니다. 새로운 채굴자 액터가 생성되었고 후속 단계가 실패하는 경우 사용자는 구성을 완료하기 위해 'curio config new-cluster \u003c 채굴자 ID \u003e'를 실행해야 합니다.", + "message": "This process is partially idempotent. Once a new miner actor has been created and subsequent steps fail, the user need to run 'curio config new-cluster \u003c miner ID \u003e' to finish the configuration.", + "placeholder": null + }, + { + "id": "Confidence epochs", + "translation": "신뢰 에포크", + "message": "Confidence epochs", + "placeholder": null + }, + { + "id": "Increase reliability using redundancy: start multiple machines with at-least the post layer: 'curio run --layers=post'", + "translation": "신뢰성 향상을 위한 중복성 사용: 적어도 post 레이어를 사용하여 여러 대의 기계를 시작하십시오: 'curio run --layers=post'", + "message": "Increase reliability using redundancy: start multiple machines with at-least the post layer: 'curio run --layers=post'", + "placeholder": null + }, + { + "id": "I want to:", + "translation": "나는 원한다:", + "message": "I want to:", + "placeholder": null + }, + { + "id": "Configuration 'base' was updated to include this miner's address", + "translation": "이 마이너 주소를 포함한 구성 'base'가 업데이트되었습니다.", + "message": "Configuration 'base' was updated to include this miner's address", + "placeholder": null + }, + { + "id": "Cannot load base config: {Error}", + "translation": "기본 구성을 불러올 수 없습니다: {Error}", + "message": "Cannot load base config: {Error}", + "placeholder": null + }, + { + "id": "Failed to load base config: {Error}", + "translation": "기본 구성을 로드하는 데 실패했습니다: {Error}", + "message": "Failed to load base config: {Error}", + "placeholder": null + }, + { + "id": "Failed to regenerate base config: {Error}", + "translation": "기본 구성을 재생성하는 데 실패했습니다: {Error}", + "message": "Failed to regenerate base config: {Error}", + "placeholder": null + }, + { + "id": "Failed to load base config from database: {Error}", + "translation": "데이터베이스에서 기본 구성을 로드하는 데 실패했습니다: {Error}", + "message": "Failed to load base config from database: {Error}", + "placeholder": null + }, + { + "id": "Failed to parse base config: {Error}", + "translation": "기본 구성을 구문 분석하는 데 실패했습니다: {Error}", + "message": "Failed to parse base config: {Error}", + "placeholder": null + } ] } \ No newline at end of file diff --git a/cmd/curio/internal/translations/locales/ko/out.gotext.json b/cmd/curio/internal/translations/locales/ko/out.gotext.json index 9eb8915c0..8e0014cd4 100644 --- a/cmd/curio/internal/translations/locales/ko/out.gotext.json +++ b/cmd/curio/internal/translations/locales/ko/out.gotext.json @@ -1,89 +1,4 @@ { "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 - } - ] + "messages": [] } diff --git a/cmd/curio/internal/translations/locales/zh/messages.gotext.json b/cmd/curio/internal/translations/locales/zh/messages.gotext.json index ffb5f3bde..fc9a0f313 100644 --- a/cmd/curio/internal/translations/locales/zh/messages.gotext.json +++ b/cmd/curio/internal/translations/locales/zh/messages.gotext.json @@ -699,6 +699,354 @@ "translation": "要使用配置:", "message": "To work with the config:", "placeholder": null + }, + { + "id": "This interactive tool creates a new miner actor and creates the basic configuration layer for it.", + "translation": "此交互式工具将创建一个新的矿工角色,并为其创建基本配置层。", + "message": "This interactive tool creates a new miner actor and creates the basic configuration layer for it.", + "placeholder": null + }, + { + "id": "This process is partially idempotent. Once a new miner actor has been created and subsequent steps fail, the user need to run 'curio config new-cluster {Arg_1}' to finish the configuration.", + "translation": "此过程在某种程度上是幂等的。一旦创建了新的矿工角色,并且后续步骤失败,用户需要运行'curio config new-cluster {Arg_1}'来完成配置。", + "message": "This process is partially idempotent. Once a new miner actor has been created and subsequent steps fail, the user need to run 'curio config new-cluster {Arg_1}' to finish the configuration.", + "placeholder": null + }, + { + "id": "Choose if you with to create a new miner or migrate from existing Lotus-Miner", + "translation": "选择您是否要创建新矿工或从现有的 Lotus-Miner 迁移", + "message": "Choose if you with to create a new miner or migrate from existing Lotus-Miner", + "placeholder": null + }, + { + "id": "Migrate from existing Lotus-Miner", + "translation": "从现有的 Lotus-Miner 迁移", + "message": "Migrate from existing Lotus-Miner", + "placeholder": null + }, + { + "id": "Create a new miner", + "translation": "创建一个新的矿工", + "message": "Create a new miner", + "placeholder": null + }, + { + "id": "New Miner initialization complete.", + "translation": "新矿工初始化完成。", + "message": "New Miner initialization complete.", + "placeholder": null + }, + { + "id": "Migrating lotus-miner config.toml to Curio in-database configuration.", + "translation": "将 lotus-miner config.toml 迁移到 Curio 的数据库配置中。", + "message": "Migrating lotus-miner config.toml to Curio in-database configuration.", + "placeholder": null + }, + { + "id": "Error getting API: {Error}", + "translation": "获取 API 时出错:{Error}", + "message": "Error getting API: {Error}", + "placeholder": null + }, + { + "id": "The Curio team wants to improve the software you use. Tell the team you're using `{Curio}`.", + "translation": "Curio 团队希望改进您使用的软件。告诉团队您正在使用 `{Curio}`。", + "message": "The Curio team wants to improve the software you use. Tell the team you're using `{Curio}`.", + "placeholder": null + }, + { + "id": "Individual Data: Miner ID, Curio version, chain ({Mainnet} or {Calibration}). Signed.", + "translation": "个人数据:矿工 ID,Curio 版本,链({Mainnet} 或 {Calibration})。签名。", + "message": "Individual Data: Miner ID, Curio version, chain ({Mainnet} or {Calibration}). Signed.", + "placeholder": null + }, + { + "id": "Aggregate-Anonymous: version, chain, and Miner power (bucketed).", + "translation": "聚合-匿名:版本,链和矿工算力(分桶)。", + "message": "Aggregate-Anonymous: version, chain, and Miner power (bucketed).", + "placeholder": null + }, + { + "id": "Hint: I am someone running Curio on whichever chain.", + "translation": "提示:我是在任何链上运行 Curio 的人。", + "message": "Hint: I am someone running Curio on whichever chain.", + "placeholder": null + }, + { + "id": "Press return to update {Toml} with Yugabyte info. A Backup file will be written to that folder before changes are made.", + "translation": "按回车键更新 {Toml} 以包含 Yugabyte 信息。在进行更改之前,将在该文件夹中写入备份文件。", + "message": "Press return to update {Toml} with Yugabyte info. A Backup file will be written to that folder before changes are made.", + "placeholder": null + }, + { + "id": "Error creating backup file: {Error}", + "translation": "创建备份文件时出错:{Error}", + "message": "Error creating backup file: {Error}", + "placeholder": null + }, + { + "id": "Error reading config.toml: {Error}", + "translation": "读取 config.toml 时出错:{Error}", + "message": "Error reading config.toml: {Error}", + "placeholder": null + }, + { + "id": "Error writing backup file: {Error}", + "translation": "写入备份文件时出错:{Error}", + "message": "Error writing backup file: {Error}", + "placeholder": null + }, + { + "id": "Error closing backup file: {Error}", + "translation": "关闭备份文件时出错:{Error}", + "message": "Error closing backup file: {Error}", + "placeholder": null + }, + { + "id": "Initializing a new miner actor.", + "translation": "初始化新的矿工角色。", + "message": "Initializing a new miner actor.", + "placeholder": null + }, + { + "id": "Enter the info to create a new miner", + "translation": "输入创建新矿工所需的信息", + "message": "Enter the info to create a new miner", + "placeholder": null + }, + { + "id": "Owner Address: {String}", + "translation": "所有者地址:{String}", + "message": "Owner Address: {String}", + "placeholder": null + }, + { + "id": "Worker Address: {String}", + "translation": "工作地址:{String}", + "message": "Worker Address: {String}", + "placeholder": null + }, + { + "id": "Sender Address: {String}", + "translation": "发送者地址:{String}", + "message": "Sender Address: {String}", + "placeholder": null + }, + { + "id": "Sector Size: {Ssize}", + "translation": "扇区大小: {Ssize}", + "message": "Sector Size: {Ssize}", + "placeholder": null + }, + { + "id": "Confidence epochs: {Confidence}", + "translation": "置信度时期: {Confidence}", + "message": "Confidence epochs: {Confidence}", + "placeholder": null + }, + { + "id": "Continue to verify the addresses and create a new miner actor.", + "translation": "继续验证地址并创建新的矿工角色。", + "message": "Continue to verify the addresses and create a new miner actor.", + "placeholder": null + }, + { + "id": "Miner creation error occurred: {Error}", + "translation": "矿工创建错误发生: {Error}", + "message": "Miner creation error occurred: {Error}", + "placeholder": null + }, + { + "id": "Enter the owner address", + "translation": "输入所有者地址", + "message": "Enter the owner address", + "placeholder": null + }, + { + "id": "No address provided", + "translation": "未提供地址", + "message": "No address provided", + "placeholder": null + }, + { + "id": "Failed to parse the address: {Error}", + "translation": "解析地址失败: {Error}", + "message": "Failed to parse the address: {Error}", + "placeholder": null + }, + { + "id": "Enter {Stringworker_senderi_1} address", + "translation": "输入 {Stringworker_senderi_1} 地址", + "message": "Enter {Stringworker_senderi_1} address", + "placeholder": null + }, + { + "id": "Enter the sector size", + "translation": "输入扇区大小", + "message": "Enter the sector size", + "placeholder": null + }, + { + "id": "Failed to parse sector size: {Error}", + "translation": "解析扇区大小失败: {Error}", + "message": "Failed to parse sector size: {Error}", + "placeholder": null + }, + { + "id": "Enter the confidence", + "translation": "输入置信度", + "message": "Enter the confidence", + "placeholder": null + }, + { + "id": "Failed to parse confidence: {Error}", + "translation": "解析置信度失败: {Error}", + "message": "Failed to parse confidence: {Error}", + "placeholder": null + }, + { + "id": "Failed to create the miner actor: {Error}", + "translation": "创建矿工角色失败: {Error}", + "message": "Failed to create the miner actor: {Error}", + "placeholder": null + }, + { + "id": "Miner {String} created successfully", + "translation": "矿工 {String} 创建成功", + "message": "Miner {String} created successfully", + "placeholder": null + }, + { + "id": "Cannot reach the DB: {Error}", + "translation": "无法访问数据库: {Error}", + "message": "Cannot reach the DB: {Error}", + "placeholder": null + }, + { + "id": "Error connecting to full node API: {Error}", + "translation": "连接到完整节点 API 时发生错误: {Error}", + "message": "Error connecting to full node API: {Error}", + "placeholder": null + }, + { + "id": "Pre-initialization steps complete", + "translation": "预初始化步骤完成", + "message": "Pre-initialization steps complete", + "placeholder": null + }, + { + "id": "Failed to generate random bytes for secret: {Error}", + "translation": "生成密码的随机字节失败: {Error}", + "message": "Failed to generate random bytes for secret: {Error}", + "placeholder": null + }, + { + "id": "Please do not run guided-setup again as miner creation is not idempotent. You need to run 'curio config new-cluster {String}' to finish the configuration", + "translation": "请不要再次运行引导设置,因为矿工创建不是幂等的。 您需要运行 'curio config new-cluster {String}' 来完成配置。", + "message": "Please do not run guided-setup again as miner creation is not idempotent. You need to run 'curio config new-cluster {String}' to finish the configuration", + "placeholder": null + }, + { + "id": "Failed to get API info for FullNode: {Err}", + "translation": "无法获取 FullNode 的 API 信息: {Err}", + "message": "Failed to get API info for FullNode: {Err}", + "placeholder": null + }, + { + "id": "Failed to verify the auth token from daemon node: {Error}", + "translation": "无法验证来自守护进程节点的授权令牌: {Error}", + "message": "Failed to verify the auth token from daemon node: {Error}", + "placeholder": null + }, + { + "id": "Failed to encode the config: {Error}", + "translation": "无法编码配置: {Error}", + "message": "Failed to encode the config: {Error}", + "placeholder": null + }, + { + "id": "Failed to generate default config: {Error}", + "translation": "无法生成默认配置: {Error}", + "message": "Failed to generate default config: {Error}", + "placeholder": null + }, + { + "id": "Failed to insert 'base' config layer in database: {Error}", + "translation": "无法将 'base' 配置层插入数据库: {Error}", + "message": "Failed to insert 'base' config layer in database: {Error}", + "placeholder": null + }, + { + "id": "Failed to insert '{String}' config layer in database: {Error}", + "translation": "无法将 '{String}' 配置层插入数据库: {Error}", + "message": "Failed to insert '{String}' config layer in database: {Error}", + "placeholder": null + }, + { + "id": "New Curio configuration layer '{String}' created", + "translation": "新的 Curio 配置层 '{String}' 已创建", + "message": "New Curio configuration layer '{String}' created", + "placeholder": null + }, + { + "id": "This process is partially idempotent. Once a new miner actor has been created and subsequent steps fail, the user need to run 'curio config new-cluster \u003c miner ID \u003e' to finish the configuration.", + "translation": "该过程部分幂等。一旦创建了新的矿工角色,并且随后的步骤失败,用户需要运行 'curio config new-cluster \u003c 矿工 ID \u003e' 来完成配置。", + "message": "This process is partially idempotent. Once a new miner actor has been created and subsequent steps fail, the user need to run 'curio config new-cluster \u003c miner ID \u003e' to finish the configuration.", + "placeholder": null + }, + { + "id": "Confidence epochs", + "translation": "置信度时期", + "message": "Confidence epochs", + "placeholder": null + }, + { + "id": "Increase reliability using redundancy: start multiple machines with at-least the post layer: 'curio run --layers=post'", + "translation": "通过冗余增加可靠性:使用至少后层启动多台机器:'curio run --layers=post'", + "message": "Increase reliability using redundancy: start multiple machines with at-least the post layer: 'curio run --layers=post'", + "placeholder": null + }, + { + "id": "I want to:", + "translation": "我想要:", + "message": "I want to:", + "placeholder": null + }, + { + "id": "Configuration 'base' was updated to include this miner's address", + "translation": "配置 'base' 已更新以包含此矿工的地址", + "message": "Configuration 'base' was updated to include this miner's address", + "placeholder": null + }, + { + "id": "Cannot load base config: {Error}", + "translation": "无法加载基本配置: {Error}", + "message": "Cannot load base config: {Error}", + "placeholder": null + }, + { + "id": "Failed to load base config: {Error}", + "translation": "加载基本配置失败: {Error}", + "message": "Failed to load base config: {Error}", + "placeholder": null + }, + { + "id": "Failed to regenerate base config: {Error}", + "translation": "重新生成基本配置失败: {Error}", + "message": "Failed to regenerate base config: {Error}", + "placeholder": null + }, + { + "id": "Failed to load base config from database: {Error}", + "translation": "从数据库加载基本配置失败:{Error}", + "message": "Failed to load base config from database: {Error}", + "placeholder": null + }, + { + "id": "Failed to parse base config: {Error}", + "translation": "解析基本配置失败:{Error}", + "message": "Failed to parse base config: {Error}", + "placeholder": null } ] } \ No newline at end of file diff --git a/cmd/curio/internal/translations/locales/zh/out.gotext.json b/cmd/curio/internal/translations/locales/zh/out.gotext.json index 37ac5f933..bb9d25e4c 100644 --- a/cmd/curio/internal/translations/locales/zh/out.gotext.json +++ b/cmd/curio/internal/translations/locales/zh/out.gotext.json @@ -1,89 +1,4 @@ { "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 - } - ] + "messages": [] } diff --git a/cmd/curio/internal/translations/updateLang.sh b/cmd/curio/internal/translations/updateLang.sh index 6325ab146..984f63fd5 100755 --- a/cmd/curio/internal/translations/updateLang.sh +++ b/cmd/curio/internal/translations/updateLang.sh @@ -2,7 +2,7 @@ #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 +if [ "$(find ../../guidedsetup/* -newer catalog.go)" ] || [ "$(find locales/* -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 diff --git a/cmd/curio/main.go b/cmd/curio/main.go index 9a58768f3..bb506f190 100644 --- a/cmd/curio/main.go +++ b/cmd/curio/main.go @@ -111,7 +111,7 @@ func main() { Name: "db-host", EnvVars: []string{"CURIO_DB_HOST", "CURIO_HARMONYDB_HOSTS"}, Usage: "Command separated list of hostnames for yugabyte cluster", - Value: "yugabyte", + Value: "127.0.0.1", }, &cli.StringFlag{ Name: "db-name", @@ -131,7 +131,6 @@ func main() { &cli.StringFlag{ Name: "db-port", EnvVars: []string{"CURIO_DB_PORT", "CURIO_HARMONYDB_PORT"}, - Hidden: true, Value: "5433", }, &cli.StringFlag{ diff --git a/cmd/sptool/actor.go b/cmd/sptool/actor.go index fb0d5e966..f17568a31 100644 --- a/cmd/sptool/actor.go +++ b/cmd/sptool/actor.go @@ -32,6 +32,7 @@ var actorCmd = &cli.Command{ spcli.ActorCompactAllocatedCmd(SPTActorGetter), spcli.ActorProposeChangeBeneficiaryCmd(SPTActorGetter), spcli.ActorConfirmChangeBeneficiaryCmd(SPTActorGetter), + spcli.ActorNewMinerCmd, }, } diff --git a/cmd/sptool/sector.go b/cmd/sptool/sector.go index 8f33053d3..b8e003c99 100644 --- a/cmd/sptool/sector.go +++ b/cmd/sptool/sector.go @@ -280,7 +280,6 @@ var sectorsListCmd = &cli.Command{ for _, st := range sset { s := st.SectorNumber - _, inSSet := commitedIDs[s] _, inASet := activeIDs[s] diff --git a/documentation/en/cli-curio.md b/documentation/en/cli-curio.md index f7c4f2d0c..88e8c1cce 100644 --- a/documentation/en/cli-curio.md +++ b/documentation/en/cli-curio.md @@ -16,7 +16,7 @@ COMMANDS: config Manage node config by layers. The layer 'base' will always be applied at Curio start-up. test Utility functions for testing web Start Curio web interface - guided-setup Run the guided setup for migrating from lotus-miner to Curio + guided-setup Run the guided setup for migrating from lotus-miner to Curio or Creating a new Curio miner seal Manage the sealing pipeline market auth Manage RPC permissions @@ -28,10 +28,11 @@ COMMANDS: GLOBAL OPTIONS: --color use color in display output (default: depends on output being a TTY) - --db-host value Command separated list of hostnames for yugabyte cluster (default: "yugabyte") [$CURIO_DB_HOST, $CURIO_HARMONYDB_HOSTS] + --db-host value Command separated list of hostnames for yugabyte cluster (default: "127.0.0.1") [$CURIO_DB_HOST, $CURIO_HARMONYDB_HOSTS] --db-name value (default: "yugabyte") [$CURIO_DB_NAME, $CURIO_HARMONYDB_NAME] --db-user value (default: "yugabyte") [$CURIO_DB_USER, $CURIO_HARMONYDB_USERNAME] --db-password value (default: "yugabyte") [$CURIO_DB_PASSWORD, $CURIO_HARMONYDB_PASSWORD] + --db-port value (default: "5433") [$CURIO_DB_PORT, $CURIO_HARMONYDB_PORT] --repo-path value (default: "~/.curio") [$CURIO_REPO_PATH] --vv enables very verbose mode, useful for debugging the CLI (default: false) --help, -h show help @@ -305,7 +306,7 @@ OPTIONS: ## curio guided-setup ``` NAME: - curio guided-setup - Run the guided setup for migrating from lotus-miner to Curio + curio guided-setup - Run the guided setup for migrating from lotus-miner to Curio or Creating a new Curio miner USAGE: curio guided-setup [command options] [arguments...] diff --git a/documentation/en/cli-sptool.md b/documentation/en/cli-sptool.md index 7b888a884..a9bd90897 100644 --- a/documentation/en/cli-sptool.md +++ b/documentation/en/cli-sptool.md @@ -43,6 +43,7 @@ COMMANDS: compact-allocated compact allocated sectors bitfield propose-change-beneficiary Propose a beneficiary address change confirm-change-beneficiary Confirm a beneficiary address change + new-miner Initializes a new miner actor help, h Shows a list of commands or help for one command OPTIONS: @@ -231,6 +232,22 @@ OPTIONS: --help, -h show help ``` +### sptool actor new-miner +``` +NAME: + sptool actor new-miner - Initializes a new miner actor + +USAGE: + sptool actor new-miner [command options] [arguments...] + +OPTIONS: + --worker value, -w value worker key to use for new miner initialisation + --owner value, -o value owner key to use for new miner initialisation + --from value, -f value address to send actor(miner) creation message from + --sector-size value specify sector size to use for new miner initialisation + --help, -h show help +``` + ## sptool info ``` NAME: diff --git a/go.mod b/go.mod index 82f1838bb..7787753c3 100644 --- a/go.mod +++ b/go.mod @@ -69,6 +69,7 @@ require ( github.com/georgysavva/scany/v2 v2.0.0 github.com/go-openapi/spec v0.19.11 github.com/golang/mock v1.6.0 + github.com/google/go-cmp v0.6.0 github.com/google/uuid v1.5.0 github.com/gorilla/mux v1.8.1 github.com/gorilla/websocket v1.5.1 @@ -222,7 +223,6 @@ require ( github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da // indirect github.com/golang/protobuf v1.5.3 // indirect github.com/golang/snappy v0.0.4 // indirect - github.com/google/go-cmp v0.6.0 // indirect github.com/google/gopacket v1.1.19 // indirect github.com/google/pprof v0.0.0-20240207164012-fb44976bdcd5 // indirect github.com/hannahhoward/cbor-gen-for v0.0.0-20230214144701-5d17c9d5243c // indirect diff --git a/itests/curio_test.go b/itests/curio_test.go new file mode 100644 index 000000000..997352dd3 --- /dev/null +++ b/itests/curio_test.go @@ -0,0 +1,67 @@ +package itests + +import ( + "context" + "testing" + "time" + + "github.com/docker/go-units" + "github.com/stretchr/testify/require" + + "github.com/filecoin-project/go-state-types/abi" + + "github.com/filecoin-project/lotus/cli/spcli" + "github.com/filecoin-project/lotus/cmd/curio/deps" + "github.com/filecoin-project/lotus/itests/kit" + "github.com/filecoin-project/lotus/node/config" + "github.com/filecoin-project/lotus/node/impl" +) + +func TestCurioNewActor(t *testing.T) { + ctx, cancel := context.WithCancel(context.Background()) + defer cancel() + + full, miner, esemble := kit.EnsembleMinimal(t, + kit.LatestActorsAt(-1), + kit.MockProofs(), + kit.WithSectorIndexDB(), + ) + + esemble.Start() + blockTime := 100 * time.Millisecond + esemble.BeginMining(blockTime) + + db := miner.BaseAPI.(*impl.StorageMinerAPI).HarmonyDB + + var titles []string + err := db.Select(ctx, &titles, `SELECT title FROM harmony_config WHERE LENGTH(config) > 0`) + require.NoError(t, err) + require.NotEmpty(t, titles) + require.NotContains(t, titles, "base") + + addr := miner.OwnerKey.Address + sectorSizeInt, err := units.RAMInBytes("8MiB") + require.NoError(t, err) + + maddr, err := spcli.CreateStorageMiner(ctx, full, addr, addr, addr, abi.SectorSize(sectorSizeInt), 0) + require.NoError(t, err) + + err = deps.CreateMinerConfig(ctx, full, db, []string{maddr.String()}, "FULL NODE API STRING") + require.NoError(t, err) + + err = db.Select(ctx, &titles, `SELECT title FROM harmony_config WHERE LENGTH(config) > 0`) + require.NoError(t, err) + require.Contains(t, titles, "base") + baseCfg := config.DefaultCurioConfig() + var baseText string + + err = db.QueryRow(ctx, "SELECT config FROM harmony_config WHERE title='base'").Scan(&baseText) + require.NoError(t, err) + _, err = deps.LoadConfigWithUpgrades(baseText, baseCfg) + require.NoError(t, err) + + require.NotNil(t, baseCfg.Addresses) + require.GreaterOrEqual(t, len(baseCfg.Addresses), 1) + + require.Contains(t, baseCfg.Addresses[0].MinerAddresses, maddr.String()) +} diff --git a/node/config/load.go b/node/config/load.go index 1b8df1696..1d5a87458 100644 --- a/node/config/load.go +++ b/node/config/load.go @@ -4,13 +4,17 @@ import ( "bytes" "fmt" "io" + "math/big" "os" "reflect" "regexp" + "sort" "strings" "unicode" "github.com/BurntSushi/toml" + "github.com/google/go-cmp/cmp" + "github.com/google/go-cmp/cmp/cmpopts" "github.com/kelseyhightower/envconfig" "golang.org/x/xerrors" ) @@ -395,8 +399,22 @@ func ConfigUpdate(cfgCur, cfgDef interface{}, opts ...UpdateCfgOpt) ([]byte, err return nil, xerrors.Errorf("parsing updated config: %w", err) } - if !reflect.DeepEqual(cfgCur, cfgUpdated) { - return nil, xerrors.Errorf("updated config didn't match current config:") + opts := []cmp.Option{ + // This equality function compares big.Int + cmpopts.IgnoreUnexported(big.Int{}), + cmp.Comparer(func(x, y []string) bool { + tx, ty := reflect.TypeOf(x), reflect.TypeOf(y) + if tx.Kind() == reflect.Slice && ty.Kind() == reflect.Slice && tx.Elem().Kind() == reflect.String && ty.Elem().Kind() == reflect.String { + sort.Strings(x) + sort.Strings(y) + return strings.Join(x, "\n") == strings.Join(y, "\n") + } + return false + }), + } + + if !cmp.Equal(cfgUpdated, cfgCur, opts...) { + return nil, xerrors.Errorf("updated config didn't match current config") } }