v1.27.0-a #10

Closed
jonathanface wants to merge 473 commits from v1.27.0-a into master
23 changed files with 3160 additions and 944 deletions
Showing only changes of commit 9f9dc979fb - Show all commits

View File

@ -554,6 +554,12 @@ workflows:
- build - build
suite: itest-cli suite: itest-cli
target: "./itests/cli_test.go" target: "./itests/cli_test.go"
- test:
name: test-itest-curio
requires:
- build
suite: itest-curio
target: "./itests/curio_test.go"
- test: - test:
name: test-itest-deadlines name: test-itest-deadlines
requires: requires:

View File

@ -124,7 +124,7 @@ jobs:
# A list of test groups that require YugabyteDB to be running # A list of test groups that require YugabyteDB to be running
# In CircleCI, all jobs had yugabytedb running as a sidecar. # In CircleCI, all jobs had yugabytedb running as a sidecar.
yugabytedb: | yugabytedb: |
["itest-harmonydb", "itest-harmonytask"] ["itest-harmonydb", "itest-harmonytask", "itest-curio"]
# A list of test groups that require Proof Parameters to be fetched # A list of test groups that require Proof Parameters to be fetched
# In CircleCI, only the following jobs had get-params set: # In CircleCI, only the following jobs had get-params set:
# - unit-cli (✅) # - unit-cli (✅)

View File

@ -2,9 +2,11 @@ package spcli
import ( import (
"bytes" "bytes"
"context"
"fmt" "fmt"
"strconv" "strconv"
"github.com/docker/go-units"
cbor "github.com/ipfs/go-ipld-cbor" cbor "github.com/ipfs/go-ipld-cbor"
"github.com/libp2p/go-libp2p/core/peer" "github.com/libp2p/go-libp2p/core/peer"
ma "github.com/multiformats/go-multiaddr" 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"
"github.com/filecoin-project/go-state-types/builtin/v9/miner" "github.com/filecoin-project/go-state-types/builtin/v9/miner"
"github.com/filecoin-project/go-state-types/network" "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" 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/blockstore"
"github.com/filecoin-project/lotus/build" "github.com/filecoin-project/lotus/build"
"github.com/filecoin-project/lotus/chain/actors" "github.com/filecoin-project/lotus/chain/actors"
"github.com/filecoin-project/lotus/chain/actors/adt" "github.com/filecoin-project/lotus/chain/actors/adt"
lminer "github.com/filecoin-project/lotus/chain/actors/builtin/miner" 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" "github.com/filecoin-project/lotus/chain/types"
lcli "github.com/filecoin-project/lotus/cli" lcli "github.com/filecoin-project/lotus/cli"
cliutil "github.com/filecoin-project/lotus/cli/util"
"github.com/filecoin-project/lotus/node/impl" "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 { if addr == mi.Owner || addr == mi.Worker {
return true return true
} }
@ -1238,3 +1244,190 @@ func isController(mi api.MinerInfo, addr address.Address) bool {
return false 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
}

View File

@ -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) { func diff(sourceConf, newConf string) (string, error) {
lpSrc := config.DefaultCurioConfig() lpSrc := config.DefaultCurioConfig()
lpNew := config.DefaultCurioConfig() lpNew := config.DefaultCurioConfig()

View File

@ -1,25 +1,14 @@
package main package main
import ( import (
"bytes"
"crypto/rand"
"encoding/base64"
"fmt" "fmt"
"io"
"github.com/BurntSushi/toml"
"github.com/fatih/color"
"github.com/samber/lo"
"github.com/urfave/cli/v2" "github.com/urfave/cli/v2"
"golang.org/x/xerrors" "golang.org/x/xerrors"
"github.com/filecoin-project/go-address"
"github.com/filecoin-project/lotus/api" "github.com/filecoin-project/lotus/api"
"github.com/filecoin-project/lotus/chain/types"
cliutil "github.com/filecoin-project/lotus/cli/util" cliutil "github.com/filecoin-project/lotus/cli/util"
"github.com/filecoin-project/lotus/cmd/curio/deps" "github.com/filecoin-project/lotus/cmd/curio/deps"
"github.com/filecoin-project/lotus/node/config"
"github.com/filecoin-project/lotus/node/repo" "github.com/filecoin-project/lotus/node/repo"
) )
@ -36,10 +25,8 @@ var configNewCmd = &cli.Command{
}, },
}, },
Action: func(cctx *cli.Context) error { Action: func(cctx *cli.Context) error {
configColor := color.New(color.FgHiGreen).SprintFunc()
if cctx.Args().Len() < 1 { 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 ctx := cctx.Context
@ -55,105 +42,16 @@ var configNewCmd = &cli.Command{
} }
defer closer() defer closer()
var titles []string ainfo, err := cliutil.GetAPIInfo(cctx, repo.FullNode)
err = db.Select(ctx, &titles, `SELECT title FROM harmony_config WHERE LENGTH(config) > 0`)
if err != nil { if err != nil {
return fmt.Errorf("miner cannot reach the db. Ensure the config toml's HarmonyDB entry"+ return xerrors.Errorf("could not get API info for FullNode: %w", err)
" is setup to reach Yugabyte correctly: %s", err.Error())
} }
name := cctx.String("to-layer") token, err := full.AuthNew(ctx, api.AllPermissions)
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())
if err != nil { if err != nil {
return err return err
} }
fmt.Println(msg) return deps.CreateMinerConfig(ctx, full, db, cctx.Args().Slice(), fmt.Sprintf("%s:%s", string(token), ainfo.Addr))
return nil
}, },
} }

416
cmd/curio/config_test.go Normal file
View File

@ -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)
}

View File

@ -3,10 +3,12 @@ package deps
import ( import (
"context" "context"
"crypto/rand"
"database/sql" "database/sql"
"encoding/base64" "encoding/base64"
"errors" "errors"
"fmt" "fmt"
"io"
"net" "net"
"net/http" "net/http"
"net/url" "net/url"
@ -29,6 +31,8 @@ import (
"github.com/filecoin-project/go-statestore" "github.com/filecoin-project/go-statestore"
"github.com/filecoin-project/lotus/api" "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" curio "github.com/filecoin-project/lotus/curiosrc"
"github.com/filecoin-project/lotus/curiosrc/multictladdr" "github.com/filecoin-project/lotus/curiosrc/multictladdr"
"github.com/filecoin-project/lotus/journal" "github.com/filecoin-project/lotus/journal"
@ -434,3 +438,96 @@ func GetDepsCLI(ctx context.Context, cctx *cli.Context) (*Deps, error) {
Full: full, Full: full,
}, nil }, 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
}

View File

@ -8,6 +8,7 @@ package guidedsetup
import ( import (
"bytes" "bytes"
"context" "context"
"crypto/rand"
"encoding/base64" "encoding/base64"
"encoding/json" "encoding/json"
"fmt" "fmt"
@ -18,12 +19,14 @@ import (
"os/signal" "os/signal"
"path" "path"
"reflect" "reflect"
"strconv"
"strings" "strings"
"syscall" "syscall"
"time" "time"
"github.com/BurntSushi/toml" "github.com/BurntSushi/toml"
"github.com/charmbracelet/lipgloss" "github.com/charmbracelet/lipgloss"
"github.com/docker/go-units"
"github.com/manifoldco/promptui" "github.com/manifoldco/promptui"
"github.com/mitchellh/go-homedir" "github.com/mitchellh/go-homedir"
"github.com/samber/lo" "github.com/samber/lo"
@ -33,12 +36,15 @@ import (
"github.com/filecoin-project/go-address" "github.com/filecoin-project/go-address"
"github.com/filecoin-project/go-jsonrpc" "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"
"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/build"
"github.com/filecoin-project/lotus/chain/types" "github.com/filecoin-project/lotus/chain/types"
"github.com/filecoin-project/lotus/cli/spcli"
cliutil "github.com/filecoin-project/lotus/cli/util" 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/cmd/curio/internal/translations"
"github.com/filecoin-project/lotus/lib/harmony/harmonydb" "github.com/filecoin-project/lotus/lib/harmony/harmonydb"
"github.com/filecoin-project/lotus/node/config" "github.com/filecoin-project/lotus/node/config"
@ -50,7 +56,7 @@ const DeveloperFocusRequestURL = "https://curiostorage.org/cgi-bin/savedata.php"
var GuidedsetupCmd = &cli.Command{ var GuidedsetupCmd = &cli.Command{
Name: "guided-setup", 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{ Flags: []cli.Flag{
&cli.StringFlag{ // for cliutil.GetFullNodeAPI &cli.StringFlag{ // for cliutil.GetFullNodeAPI
Name: "repo", Name: "repo",
@ -63,9 +69,6 @@ var GuidedsetupCmd = &cli.Command{
T, say := SetupLanguage() T, say := SetupLanguage()
setupCtrlC(say) 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 // Run the migration steps
migrationData := MigrationData{ migrationData := MigrationData{
T: T, T: T,
@ -74,10 +77,25 @@ var GuidedsetupCmd = &cli.Command{
Help: T("Use the arrow keys to navigate: ↓ ↑ → ← "), Help: T("Use the arrow keys to navigate: ↓ ↑ → ← "),
}, },
cctx: cctx, 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 { for _, closer := range migrationData.closers {
closer() 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) type migrationStep func(*MigrationData)
var migrationSteps = []migrationStep{ var migrationSteps = []migrationStep{
@ -176,6 +211,17 @@ var migrationSteps = []migrationStep{
complete, complete,
} }
type newMinerStep func(data *MigrationData)
var newMinerSteps = []newMinerStep{
stepPresteps,
stepCreateActor,
stepNewMinerConfig,
doc,
oneLastThing,
completeInit,
}
type MigrationData struct { type MigrationData struct {
T func(key message.Reference, a ...interface{}) string T func(key message.Reference, a ...interface{}) string
say func(style lipgloss.Style, key message.Reference, a ...interface{}) say func(style lipgloss.Style, key message.Reference, a ...interface{})
@ -184,9 +230,16 @@ type MigrationData struct {
MinerConfig *config.StorageMiner MinerConfig *config.StorageMiner
DB *harmonydb.DB DB *harmonydb.DB
MinerID address.Address MinerID address.Address
full v0api.FullNode full v1api.FullNode
cctx *cli.Context cctx *cli.Context
closers []jsonrpc.ClientCloser 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) { 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, "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") 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) { func configToDB(d *MigrationData) {
d.say(section, "Migrating lotus-miner config.toml to Curio in-database configuration.") d.say(section, "Migrating lotus-miner config.toml to Curio in-database configuration.")
{ {
var closer jsonrpc.ClientCloser var closer jsonrpc.ClientCloser
var err error 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) d.closers = append(d.closers, closer)
if err != nil { if err != nil {
d.say(notice, "Error getting API: %s", err.Error()) 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, "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, "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.") 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 var err error
d.DB, err = harmonydb.NewFromConfig(harmonyCfg) d.DB, err = harmonydb.NewFromConfig(harmonyCfg)
if err == nil { if err != nil {
goto yugabyteConnected hcfg := getDBDetails(d)
} harmonyCfg = *hcfg
for {
i, _, err := (&promptui.Select{
Label: d.T("Enter the info to connect to your Yugabyte database installation (https://download.yugabyte.com/)"),
Items: []string{
d.T("Host: %s", strings.Join(harmonyCfg.Hosts, ",")),
d.T("Port: %s", harmonyCfg.Port),
d.T("Username: %s", harmonyCfg.Username),
d.T("Password: %s", harmonyCfg.Password),
d.T("Database: %s", harmonyCfg.Database),
d.T("Continue to connect and update schema.")},
Size: 6,
Templates: d.selectTemplates,
}).Run()
if err != nil {
d.say(notice, "Database config error occurred, abandoning migration: %s ", err.Error())
os.Exit(1)
}
switch i {
case 0:
host, err := (&promptui.Prompt{
Label: d.T("Enter the Yugabyte database host(s)"),
}).Run()
if err != nil {
d.say(notice, "No host provided")
continue
}
harmonyCfg.Hosts = strings.Split(host, ",")
case 1, 2, 3, 4:
val, err := (&promptui.Prompt{
Label: d.T("Enter the Yugabyte database %s", []string{"port", "username", "password", "database"}[i-1]),
}).Run()
if err != nil {
d.say(notice, "No value provided")
continue
}
switch i {
case 1:
harmonyCfg.Port = val
case 2:
harmonyCfg.Username = val
case 3:
harmonyCfg.Password = val
case 4:
harmonyCfg.Database = val
}
continue
case 5:
d.DB, err = harmonydb.NewFromConfig(harmonyCfg)
if err != nil {
if err.Error() == "^C" {
os.Exit(1)
}
d.say(notice, "Error connecting to Yugabyte database: %s", err.Error())
continue
}
goto yugabyteConnected
}
} }
yugabyteConnected:
d.say(plain, "Connected to Yugabyte. Schema is current.") d.say(plain, "Connected to Yugabyte. Schema is current.")
if !reflect.DeepEqual(harmonyCfg, d.MinerConfig.HarmonyDB) || !d.MinerConfig.Subsystems.EnableSectorIndexDB { if !reflect.DeepEqual(harmonyCfg, d.MinerConfig.HarmonyDB) || !d.MinerConfig.Subsystems.EnableSectorIndexDB {
d.MinerConfig.HarmonyDB = harmonyCfg d.MinerConfig.HarmonyDB = harmonyCfg
@ -588,3 +589,293 @@ func stepCompleted(d *MigrationData, step string) {
fmt.Print(green.Render("✔ ")) fmt.Print(green.Render("✔ "))
d.say(plain, "Step Complete: %s\n", step) 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
}
}
}

View File

@ -40,292 +40,436 @@ func init() {
} }
var messageKeyToIndex = map[string]int{ var messageKeyToIndex = map[string]int{
"Aborting migration.": 41, "Aborting migration.": 45,
"Aborting remaining steps.": 19, "Aborting remaining steps.": 9,
"Aggregate-Anonymous: version, net, and Miner power (bucketed).": 16, "Aggregate-Anonymous: version, chain, and Miner power (bucketed).": 22,
"Cannot read the config.toml file in the provided directory, Error: %s": 70, "Cannot reach the DB: %s": 90,
"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, "Cannot read the config.toml file in the provided directory, Error: %s": 65,
"Configuration 'base' was created to include this miner's address and its wallet setup.": 77, "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,
"Configuration 'base' was updated to include this miner's address and its wallet setup.": 75, "Confidence epochs": 86,
"Connected to Yugabyte": 64, "Confidence epochs: %d": 76,
"Connected to Yugabyte. Schema is current.": 56, "Configuration 'base' was created to include this miner's address and its wallet setup.": 117,
"Continue to connect and update schema.": 49, "Configuration 'base' was updated to include this miner's address": 99,
"Could not create repo from directory: %s. Aborting migration": 71, "Configuration 'base' was updated to include this miner's address and its wallet setup.": 115,
"Could not lock miner repo. Your miner must be stopped: %s\n Aborting migration": 72, "Connected to Yugabyte": 59,
"Ctrl+C pressed in Terminal": 3, "Connected to Yugabyte. Schema is current.": 47,
"Database config error occurred, abandoning migration: %s ": 50, "Continue to connect and update schema.": 109,
"Database: %s": 48, "Continue to verify the addresses and create a new miner actor.": 77,
"Documentation: ": 27, "Could not create repo from directory: %s. Aborting migration": 66,
"Each step needs your confirmation and can be reversed. Press Ctrl+C to exit at any time.": 1, "Could not lock miner repo. Your miner must be stopped: %s\n Aborting migration": 67,
"Enabling Sector Indexing in the database.": 57, "Create a new miner": 8,
"Enter the Yugabyte database %s": 53, "Ctrl+C pressed in Terminal": 5,
"Enter the Yugabyte database host(s)": 51, "Database config error occurred, abandoning migration: %s ": 110,
"Enter the info to connect to your Yugabyte database installation (https://download.yugabyte.com/)": 43, "Database: %s": 108,
"Enter the path to the configuration directory used by %s": 68, "Documentation: ": 32,
"Error connecting to Yugabyte database: %s": 55, "Each step needs your confirmation and can be reversed. Press Ctrl+C to exit at any time.": 4,
"Error connecting to lotus node: %s %s": 9, "Enabling Sector Indexing in the database.": 48,
"Error encoding config.toml: %s": 58, "Enter %s address": 82,
"Error expanding path: %s": 60, "Enter the Yugabyte database %s": 113,
"Error getting miner info: %s": 22, "Enter the Yugabyte database host(s)": 111,
"Error getting miner power: %s": 20, "Enter the info to connect to your Yugabyte database installation (https://download.yugabyte.com/)": 103,
"Error getting token: %s": 11, "Enter the info to create a new miner": 71,
"Error interpreting miner ID: %s: ID: %s": 36, "Enter the owner address": 79,
"Error marshalling message: %s": 21, "Enter the path to the configuration directory used by %s": 63,
"Error reading filemode of config.toml: %s": 61, "Enter the sector size": 83,
"Error reading from database: %s. Aborting Migration.": 8, "Error closing backup file: %s": 56,
"Error saving config to layer: %s. Aborting Migration": 12, "Error connecting to Yugabyte database: %s": 114,
"Error sending message: %s": 24, "Error connecting to full node API: %s": 91,
"Error sending message: Status %s, Message: ": 25, "Error creating backup file: %s": 53,
"Error signing message: %s": 23, "Error encoding config.toml: %s": 49,
"Error verifying sectors: %s": 37, "Error expanding path: %s": 51,
"Error writing config.toml: %s": 62, "Error getting API: %s": 15,
"Filecoin %s channels: %s and %s": 30, "Error getting miner info: %s": 27,
"Hint: I am someone running Curio on net.": 17, "Error getting miner power: %s": 25,
"Host: %s": 44, "Error getting token: %s": 17,
"Individual Data: Miner ID, Curio version, net (%s or %s). Signed.": 15, "Error interpreting miner ID: %s: ID: %s": 40,
"Layer %s created. ": 78, "Error marshalling message: %s": 26,
"Lotus-Miner to Curio Migration.": 4, "Error reading config.toml: %s": 54,
"Message sent.": 26, "Error reading filemode of config.toml: %s": 52,
"Migrating config.toml to database.": 7, "Error saving config to layer: %s. Aborting Migration": 18,
"No host provided": 52, "Error sending message: %s": 29,
"No path provided, abandoning migration ": 69, "Error sending message: Status %s, Message: ": 30,
"No value provided": 54, "Error signing message: %s": 28,
"Nothing.": 18, "Error verifying sectors: %s": 41,
"Now shut down lotus-miner and move the systems to %s.": 39, "Error writing backup file: %s": 55,
"One database can serve multiple miner IDs: Run a migration for each lotus-miner.": 33, "Error writing config.toml: %s": 57,
"Other": 67, "Failed to create the miner actor: %s": 88,
"Password: %s": 47, "Failed to generate default config: %s": 97,
"Please start (or restart) %s now that database credentials are in %s.": 34, "Failed to generate random bytes for secret: %s": 93,
"Point your browser to your web GUI to complete setup with %s and advanced featues.": 32, "Failed to get API info for FullNode: %w": 95,
"Port: %s": 45, "Failed to insert 'base' config layer in database: %s": 98,
"Press return to continue": 40, "Failed to load base config from database: %s": 100,
"Press return to update %s with Yugabyte info. Backup the file now.": 59, "Failed to parse base config: %s": 101,
"Protocol Labs wants to improve the software you use. Tell the team you're using Curio.": 13, "Failed to parse confidence: %s": 87,
"Read Miner Config": 73, "Failed to parse sector size: %s": 85,
"Restart Lotus Miner. ": 63, "Failed to parse the address: %s": 81,
"Sectors verified. %d sector locations found.": 42, "Failed to regenerate base config: %s": 102,
"Select the location of your lotus-miner config directory?": 66, "Failed to verify the auth token from daemon node: %s": 96,
"Select what you want to share with the Curio team.": 14, "Filecoin %s channels: %s and %s": 35,
"Start multiple Curio instances with the '%s' layer to redundancy.": 31, "Hint: I am someone running Curio on whichever chain.": 23,
"Step Complete: %s\n": 74, "Host: %s": 104,
"The '%s' layer stores common configuration. All curio instances can include it in their %s argument.": 28, "I want to:": 6,
"The sectors are in the database. The database is ready for %s.": 38, "Increase reliability using redundancy: start multiple machines with at-least the post layer: 'curio run --layers=post'": 36,
"This interactive tool migrates lotus-miner to Curio in 5 minutes.": 0, "Individual Data: Miner ID, Curio version, chain (%s or %s). Signed.": 21,
"To run Curio: With machine or cgroup isolation, use the command (with example layer selection):": 80, "Initializing a new miner actor.": 70,
"To start, ensure your sealing pipeline is drained and shut-down lotus-miner.": 65, "Layer %s created. ": 118,
"To work with the config: ": 79, "Lotus-Miner to Curio Migration.": 10,
"Try the web interface with %s for further guided improvements.": 5, "Message sent.": 31,
"Use the arrow keys to navigate: ↓ ↑ → ← ": 2, "Migrate from existing Lotus-Miner": 7,
"Username: %s": 46, "Migrating lotus-miner config.toml to Curio in-database configuration.": 14,
"Waiting for %s to write sectors into Yugabyte.": 35, "Miner %s created successfully": 89,
"You can add other layers for per-machine configuration changes.": 29, "Miner creation error occurred: %s ": 78,
"You can now migrate your market node (%s), if applicable.": 6, "New Miner initialization complete.": 13,
"could not get API info for FullNode: %w": 10, "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 // Entry 0 - 1F
0x00000000, 0x00000042, 0x0000009b, 0x000000d0, 0x00000000, 0x00000035, 0x00000097, 0x0000015a,
0x000000eb, 0x0000010b, 0x0000014d, 0x0000018a, 0x0000019c, 0x000001f5, 0x00000210, 0x0000021b,
0x000001ad, 0x000001e5, 0x00000211, 0x0000023c, 0x0000023d, 0x00000250, 0x0000026a, 0x0000028a,
0x00000257, 0x0000028f, 0x000002e6, 0x00000319, 0x000002cc, 0x00000309, 0x0000032c, 0x00000372,
0x00000361, 0x000003a0, 0x000003c9, 0x000003d2, 0x0000038b, 0x000003b6, 0x000003d1, 0x00000409,
0x000003ec, 0x0000040d, 0x0000042e, 0x0000044e, 0x00000463, 0x00000496, 0x000004e0, 0x00000521,
0x0000046b, 0x00000488, 0x000004bb, 0x000004c9, 0x00000556, 0x0000055f, 0x00000580, 0x000005a1,
0x000004dd, 0x00000548, 0x00000588, 0x000005b1, 0x000005c1, 0x000005de, 0x000005fb, 0x0000062e,
// Entry 20 - 3F // Entry 20 - 3F
0x000005f6, 0x0000064c, 0x0000069d, 0x000006e9, 0x0000063c, 0x00000650, 0x000006bb, 0x000006fb,
0x0000071b, 0x00000749, 0x00000768, 0x000007aa, 0x00000724, 0x0000079b, 0x000007ec, 0x00000838,
0x000007e3, 0x000007fc, 0x00000810, 0x00000840, 0x0000086a, 0x00000898, 0x000008b7, 0x000008f9,
0x000008a2, 0x000008ae, 0x000008ba, 0x000008ca, 0x00000932, 0x0000094b, 0x0000095f, 0x0000098f,
0x000008da, 0x000008ea, 0x00000911, 0x00000952, 0x000009b9, 0x000009e3, 0x00000a05, 0x00000a7c,
0x00000976, 0x00000987, 0x000009a9, 0x000009bb, 0x00000a98, 0x00000ac5, 0x00000ae7, 0x00000b08,
0x000009e8, 0x00000a12, 0x00000a3c, 0x00000a5e, 0x00000b29, 0x00000b4a, 0x00000b6b, 0x00000b85,
0x00000aa4, 0x00000ac0, 0x00000aed, 0x00000b0e, 0x00000b9b, 0x00000be8, 0x00000c22, 0x00000c28,
// Entry 40 - 5F // Entry 40 - 5F
0x00000b28, 0x00000b3e, 0x00000b8b, 0x00000bc5, 0x00000c64, 0x00000c90, 0x00000cd9, 0x00000d19,
0x00000bcb, 0x00000c07, 0x00000c33, 0x00000c7c, 0x00000d6a, 0x00000d7c, 0x00000d96, 0x00000db6,
0x00000cbc, 0x00000d0d, 0x00000d1f, 0x00000d39, 0x00000ddb, 0x00000df0, 0x00000e06, 0x00000e1c,
0x00000d90, 0x00000e2d, 0x00000e84, 0x00000e9e, 0x00000e2f, 0x00000e48, 0x00000e87, 0x00000eb1,
0x00000ebc, 0x00000f1c, 0x00000ec9, 0x00000edd, 0x00000f00, 0x00000f14,
} // Size: 352 bytes 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 const enData string = "" + // Size: 5636 bytes
"\x02This interactive tool migrates lotus-miner to Curio in 5 minutes." + "\x04\x00\x01 0\x02Use the arrow keys to navigate: ↓ ↑ → ←\x02This intera" +
"\x02Each step needs your confirmation and can be reversed. Press Ctrl+C " + "ctive tool creates a new miner actor and creates the basic configuration" +
"to exit at any time.\x04\x00\x01 0\x02Use the arrow keys to navigate: ↓ " + " layer for it.\x02This process is partially idempotent. Once a new miner" +
"↑ → ←\x02Ctrl+C pressed in Terminal\x02Lotus-Miner to Curio Migration." + " actor has been created and subsequent steps fail, the user need to run " +
"\x02Try the web interface with %[1]s for further guided improvements." + "'curio config new-cluster < miner ID >' to finish the configuration.\x02" +
"\x02You can now migrate your market node (%[1]s), if applicable.\x02Migr" + "This interactive tool migrates lotus-miner to Curio in 5 minutes.\x02Eac" +
"ating config.toml to database.\x02Error reading from database: %[1]s. Ab" + "h step needs your confirmation and can be reversed. Press Ctrl+C to exit" +
"orting Migration.\x02Error connecting to lotus node: %[1]s %[2]s\x02coul" + " at any time.\x02Ctrl+C pressed in Terminal\x02I want to:\x02Migrate fro" +
"d not get API info for FullNode: %[1]w\x02Error getting token: %[1]s\x02" + "m existing Lotus-Miner\x02Create a new miner\x02Aborting remaining steps" +
"Error saving config to layer: %[1]s. Aborting Migration\x02Protocol Labs" + ".\x02Lotus-Miner to Curio Migration.\x02Try the web interface with %[1]s" +
" wants to improve the software you use. Tell the team you're using Curio" + " for further guided improvements.\x02You can now migrate your market nod" +
".\x02Select what you want to share with the Curio team.\x02Individual Da" + "e (%[1]s), if applicable.\x02New Miner initialization complete.\x02Migra" +
"ta: Miner ID, Curio version, net (%[1]s or %[2]s). Signed.\x02Aggregate-" + "ting lotus-miner config.toml to Curio in-database configuration.\x02Erro" +
"Anonymous: version, net, and Miner power (bucketed).\x02Hint: I am someo" + "r getting API: %[1]s\x02could not get API info for FullNode: %[1]w\x02Er" +
"ne running Curio on net.\x02Nothing.\x02Aborting remaining steps.\x02Err" + "ror getting token: %[1]s\x02Error saving config to layer: %[1]s. Abortin" +
"or getting miner power: %[1]s\x02Error marshalling message: %[1]s\x02Err" + "g Migration\x02The Curio team wants to improve the software you use. Tel" +
"or getting miner info: %[1]s\x02Error signing message: %[1]s\x02Error se" + "l the team you're using `%[1]s`.\x02Select what you want to share with t" +
"nding message: %[1]s\x04\x00\x01 .\x02Error sending message: Status %[1]" + "he Curio team.\x02Individual Data: Miner ID, Curio version, chain (%[1]s" +
"s, Message:\x02Message sent.\x04\x00\x01 \x0f\x02Documentation:\x02The '" + " or %[2]s). Signed.\x02Aggregate-Anonymous: version, chain, and Miner po" +
"%[1]s' layer stores common configuration. All curio instances can includ" + "wer (bucketed).\x02Hint: I am someone running Curio on whichever chain." +
"e it in their %[2]s argument.\x02You can add other layers for per-machin" + "\x02Nothing.\x02Error getting miner power: %[1]s\x02Error marshalling me" +
"e configuration changes.\x02Filecoin %[1]s channels: %[2]s and %[3]s\x02" + "ssage: %[1]s\x02Error getting miner info: %[1]s\x02Error signing message" +
"Start multiple Curio instances with the '%[1]s' layer to redundancy.\x02" + ": %[1]s\x02Error sending message: %[1]s\x04\x00\x01 .\x02Error sending m" +
"Point your browser to your web GUI to complete setup with %[1]s and adva" + "essage: Status %[1]s, Message:\x02Message sent.\x04\x00\x01 \x0f\x02Docu" +
"nced featues.\x02One database can serve multiple miner IDs: Run a migrat" + "mentation:\x02The '%[1]s' layer stores common configuration. All curio i" +
"ion for each lotus-miner.\x02Please start (or restart) %[1]s now that da" + "nstances can include it in their %[2]s argument.\x02You can add other la" +
"tabase credentials are in %[2]s.\x02Waiting for %[1]s to write sectors i" + "yers for per-machine configuration changes.\x02Filecoin %[1]s channels: " +
"nto Yugabyte.\x02Error interpreting miner ID: %[1]s: ID: %[2]s\x02Error " + "%[2]s and %[3]s\x02Increase reliability using redundancy: start multiple" +
"verifying sectors: %[1]s\x02The sectors are in the database. The databas" + " machines with at-least the post layer: 'curio run --layers=post'\x02One" +
"e is ready for %[1]s.\x02Now shut down lotus-miner and move the systems " + " database can serve multiple miner IDs: Run a migration for each lotus-m" +
"to %[1]s.\x02Press return to continue\x02Aborting migration.\x02Sectors " + "iner.\x02Please start (or restart) %[1]s now that database credentials a" +
"verified. %[1]d sector locations found.\x02Enter the info to connect to " + "re in %[2]s.\x02Waiting for %[1]s to write sectors into Yugabyte.\x02Err" +
"your Yugabyte database installation (https://download.yugabyte.com/)\x02" + "or interpreting miner ID: %[1]s: ID: %[2]s\x02Error verifying sectors: %" +
"Host: %[1]s\x02Port: %[1]s\x02Username: %[1]s\x02Password: %[1]s\x02Data" + "[1]s\x02The sectors are in the database. The database is ready for %[1]s" +
"base: %[1]s\x02Continue to connect and update schema.\x04\x00\x01 <\x02D" + ".\x02Now shut down lotus-miner and move the systems to %[1]s.\x02Press r" +
"atabase config error occurred, abandoning migration: %[1]s\x02Enter the " + "eturn to continue\x02Aborting migration.\x02Sectors verified. %[1]d sect" +
"Yugabyte database host(s)\x02No host provided\x02Enter the Yugabyte data" + "or locations found.\x02Connected to Yugabyte. Schema is current.\x02Enab" +
"base %[1]s\x02No value provided\x02Error connecting to Yugabyte database" + "ling Sector Indexing in the database.\x02Error encoding config.toml: %[1" +
": %[1]s\x02Connected to Yugabyte. Schema is current.\x02Enabling Sector " + "]s\x02Press return to update %[1]s with Yugabyte info. A Backup file wil" +
"Indexing in the database.\x02Error encoding config.toml: %[1]s\x02Press " + "l be written to that folder before changes are made.\x02Error expanding " +
"return to update %[1]s with Yugabyte info. Backup the file now.\x02Error" + "path: %[1]s\x02Error reading filemode of config.toml: %[1]s\x02Error cre" +
" expanding path: %[1]s\x02Error reading filemode of config.toml: %[1]s" + "ating backup file: %[1]s\x02Error reading config.toml: %[1]s\x02Error wr" +
"\x02Error writing config.toml: %[1]s\x04\x00\x01 \x15\x02Restart Lotus M" + "iting backup file: %[1]s\x02Error closing backup file: %[1]s\x02Error wr" +
"iner.\x02Connected to Yugabyte\x02To start, ensure your sealing pipeline" + "iting config.toml: %[1]s\x04\x00\x01 \x15\x02Restart Lotus Miner.\x02Con" +
" is drained and shut-down lotus-miner.\x02Select the location of your lo" + "nected to Yugabyte\x02To start, ensure your sealing pipeline is drained " +
"tus-miner config directory?\x02Other\x02Enter the path to the configurat" + "and shut-down lotus-miner.\x02Select the location of your lotus-miner co" +
"ion directory used by %[1]s\x04\x00\x01 '\x02No path provided, abandonin" + "nfig directory?\x02Other\x02Enter the path to the configuration director" +
"g migration\x02Cannot read the config.toml file in the provided director" + "y used by %[1]s\x04\x00\x01 '\x02No path provided, abandoning migration" +
"y, Error: %[1]s\x02Could not create repo from directory: %[1]s. Aborting" + "\x02Cannot read the config.toml file in the provided directory, Error: %" +
" migration\x02Could not lock miner repo. Your miner must be stopped: %[1" + "[1]s\x02Could not create repo from directory: %[1]s. Aborting migration" +
"]s\x0a Aborting migration\x02Read Miner Config\x04\x00\x01\x0a\x15\x02St" + "\x02Could not lock miner repo. Your miner must be stopped: %[1]s\x0a Abo" +
"ep Complete: %[1]s\x02Configuration 'base' was updated to include this m" + "rting migration\x02Read Miner Config\x04\x00\x01\x0a\x15\x02Step Complet" +
"iner's address and its wallet setup.\x02Compare the configurations %[1]s" + "e: %[1]s\x02Initializing a new miner actor.\x02Enter the info to create " +
" to %[2]s. Changes between the miner IDs other than wallet addreses shou" + "a new miner\x02Owner Address: %[1]s\x02Worker Address: %[1]s\x02Sender A" +
"ld be a new, minimal layer for runners that need it.\x02Configuration 'b" + "ddress: %[1]s\x02Sector Size: %[1]d\x02Confidence epochs: %[1]d\x02Conti" +
"ase' was created to include this miner's address and its wallet setup." + "nue to verify the addresses and create a new miner actor.\x04\x00\x01 %" +
"\x04\x00\x01 \x15\x02Layer %[1]s created.\x04\x00\x01 \x19\x02To work wi" + "\x02Miner creation error occurred: %[1]s\x02Enter the owner address\x02N" +
"th the config:\x02To run Curio: With machine or cgroup isolation, use th" + "o address provided\x02Failed to parse the address: %[1]s\x02Enter %[1]s " +
"e command (with example layer selection):" "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 // Entry 0 - 1F
0x00000000, 0x0000004d, 0x000000c8, 0x0000010c, 0x00000000, 0x00000044, 0x000000c1, 0x000001c1,
0x0000012d, 0x00000150, 0x00000150, 0x000001a0, 0x0000020e, 0x00000289, 0x000002aa, 0x000002bc,
0x000001da, 0x0000022f, 0x0000022f, 0x0000022f, 0x000002e5, 0x00000300, 0x00000325, 0x00000348,
0x0000022f, 0x00000287, 0x00000315, 0x0000034e, 0x000003a2, 0x000003f2, 0x00000418, 0x00000471,
0x000003aa, 0x000003f4, 0x00000437, 0x00000452, 0x00000490, 0x000004cc, 0x000004fc, 0x00000554,
0x00000477, 0x000004b1, 0x000004e4, 0x0000051e, 0x000005e0, 0x00000619, 0x0000066f, 0x000006ad,
0x00000548, 0x00000572, 0x000005b4, 0x000005d8, 0x000006fb, 0x00000716, 0x00000750, 0x00000783,
0x000005e5, 0x0000066b, 0x000006bd, 0x000006bd, 0x000007bd, 0x000007e7, 0x00000811, 0x00000853,
// Entry 20 - 3F // Entry 20 - 3F
0x000006bd, 0x0000071e, 0x0000071e, 0x0000071e, 0x00000877, 0x00000884, 0x0000090a, 0x0000095c,
0x00000762, 0x00000762, 0x00000789, 0x000007f4, 0x00000983, 0x00000a1f, 0x00000ab1, 0x00000b2c,
0x0000083e, 0x00000865, 0x00000880, 0x000008cf, 0x00000b70, 0x00000bae, 0x00000bd5, 0x00000c40,
0x0000093d, 0x0000094e, 0x0000095c, 0x00000974, 0x00000c8a, 0x00000cb1, 0x00000ccc, 0x00000d1b,
0x00000988, 0x000009a2, 0x000009cc, 0x00000a2f, 0x00000d5c, 0x00000d9c, 0x00000de3, 0x00000e89,
0x00000a6b, 0x00000a95, 0x00000acd, 0x00000af1, 0x00000eb9, 0x00000f08, 0x00000f2b, 0x00000f4c,
0x00000b45, 0x00000b86, 0x00000b86, 0x00000bcd, 0x00000f6f, 0x00000f92, 0x00000fd0, 0x00000ff4,
0x00000c39, 0x00000c39, 0x00000c88, 0x00000cc6, 0x0000100a, 0x00001075, 0x000010c4, 0x000010cb,
// Entry 40 - 5F // Entry 40 - 5F
0x00000cea, 0x00000d00, 0x00000d6b, 0x00000dba, 0x00001113, 0x00001165, 0x000011bf, 0x00001229,
0x00000dc1, 0x00000e09, 0x00000e5b, 0x00000eb5, 0x000012ba, 0x000012d2, 0x000012ec, 0x00001310,
0x00000eb5, 0x00000eb5, 0x00000ecd, 0x00000ee7, 0x00001343, 0x0000135b, 0x00001373, 0x0000138b,
0x00000f51, 0x0000100b, 0x0000106f, 0x0000109e, 0x000013a0, 0x000013b8, 0x0000140f, 0x0000143a,
0x0000109e, 0x0000112a, 0x00001452, 0x00001479, 0x0000149c, 0x000014b0,
} // Size: 352 bytes 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 const koData string = "" + // Size: 7742 bytes
"\x02이 대화형 도구는 5분 안에 lotus-miner를 Curio로 이주합니다.\x02각 단계는 확인이 필요하며 되돌릴 수 있" + "\x04\x00\x01 ?\x02화살표 키를 사용하여 이동하세요: ↓ ↑ → ←\x02이 대화형 도구는 새로운 채굴자 액터를 생성" +
"습니다. 언제든지 Ctrl+C를 눌러 종료할 수 있습니다.\x04\x00\x01 ?\x02화살표 키를 사용하여 이동하세요: ↓" + "하고 그에 대한 기본 구성 레이어를 생성합니다.\x02이 프로세스는 부분적으로 항등원적입니다. 새로운 채굴자 액터가 생성되었고" +
" ↑ → ←\x02터미널에서 Ctrl+C가 눌림\x02Lotus-Miner에서 Curio로 이주.\x02해당하는 경우 이제 시장 " + " 후속 단계가 실패하는 경우 사용자는 구성을 완료하기 위해 'curio config new-cluster < 채굴자 ID >'를 " +
"노드를 이주할 수 있습니다 (%[1]s).\x02config.toml을 데이터베이스로 이주 중입니다.\x02데이터베이스에서 읽" + "실행해야 합니다.\x02이 대화형 도구는 5분 안에 lotus-miner를 Curio로 이주합니다.\x02각 단계는 확인이 필" +
"는 중 오류 발생: %[1]s. 마이그레이션 중단.\x02레이어에 구성을 저장하는 중 오류 발생: %[1]s. 마이그레이션 중" + "요하며 되돌릴 수 있습니다. 언제든지 Ctrl+C를 눌러 종료할 수 있습니다.\x02터미널에서 Ctrl+C가 눌림\x02나는 " +
"단\x02Protocol Labs는 당신이 사용하는 소프트웨어를 개선하고 싶어합니다. Curio를 사용 중이라고 팀에 알려주세" + "원한다:\x02기존의 Lotus-Miner에서 이전하기\x02새로운 채굴자 생성\x02나머지 단계를 중단합니다.\x02Lotu" +
"요.\x02Curio 팀과 공유하고 싶은 것을 선택하세요.\x02개별 데이터: 마이너 ID, Curio 버전, 네트워크 (%[" + "s-Miner에서 Curio로 이주.\x02더 많은 안내를 위해 %[1]s를 사용하여 웹 인터페이스를 시도하세요.\x02해당하는 " +
"1]s 또는 %[2]s). 서명됨.\x02집계-익명: 버전, 네트워크, 그리고 마이너 파워 (버킷).\x02힌트: 네트워크에서 C" + "경우 이제 시장 노드를 이주할 수 있습니다 (%[1]s).\x02새로운 채굴자 초기화 완료.\x02lotus-miner con" +
"urio를 실행 중인 사람입니다.\x02아무것도 없습니다.\x02나머지 단계를 중단합니다.\x02마이너 파워를 가져오는 중 오류 " + "fig.toml을 Curio의 데이터베이스 구성으로 이전 중입니다.\x02API 가져오기 오류: %[1]s\x02FullNode의" +
"발생: %[1]s\x02메시지를 마샬하는 중 오류 발생: %[1]s\x02마이너 정보를 가져오는 중 오류 발생: %[1]s" + " API 정보를 가져올 수 없습니다: %[1]w\x02토큰을 가져오는 중 오류 발생: %[1]s\x02레이어에 구성을 저장하는 중" +
"\x02메시지 서명 중 오류 발생: %[1]s\x02메시지 전송 중 오류 발생: %[1]s\x04\x00\x01 =\x02메시지 " + " 오류 발생: %[1]s. 마이그레이션 중단\x02Curio 팀은 당신이 사용하는 소프트웨어를 개선하고자 합니다. 팀에게 `%[1" +
"전송 중 오류 발생: 상태 %[1]s, 메시지:\x02메시지가 전송되었습니다.\x04\x00\x01 \x08\x02문서:" + "]s`를 사용 중이라고 알려주세요.\x02Curio 팀과 공유하고 싶은 것을 선택하세요.\x02개별 데이터: 채굴자 ID, Cur" +
"\x02'%[1]s' 레이어에는 공통 구성이 저장됩니다. 모든 Curio 인스턴스는 %[2]s 인수에 포함시킬 수 있습니다." + "io 버전, 체인 (%[1]s 또는 %[2]s). 서명됨.\x02집계-익명: 버전, 체인, 및 채굴자 파워 (버킷).\x02힌트:" +
"\x02기계별 구성 변경을 위해 다른 레이어를 추가할 수 있습니다.\x02브라우저를 웹 GUI로 이동하여 %[1]s 및 고급 기능" + " 나는 어떤 체인에서든 Curio를 실행 중인 사람입니다.\x02아무것도 없습니다.\x02마이너 파워를 가져오는 중 오류 발생: " +
"으로 설정을 완료하세요.\x02%[1]s가 Yugabyte에 섹터를 기록하도록 대기 중입니다.\x02섹터 확인 중 오류 발생:" + "%[1]s\x02메시지를 마샬하는 중 오류 발생: %[1]s\x02마이너 정보를 가져오는 중 오류 발생: %[1]s\x02메시지 " +
" %[1]s\x02섹터가 데이터베이스에 있습니다. 데이터베이스가 %[1]s를 위해 준비되었습니다.\x02이제 lotus-miner" + "서명 중 오류 발생: %[1]s\x02메시지 전송 중 오류 발생: %[1]s\x04\x00\x01 =\x02메시지 전송 중 오" +
"를 종료하고 시스템을 %[1]s로 이동하세요.\x02계속하려면 리턴을 누르세요\x02마이그레이션 중단.\x02섹터가 확인되었습" + "류 발생: 상태 %[1]s, 메시지:\x02메시지가 전송되었습니다.\x04\x00\x01 \x08\x02문서:\x02'%[1]" +
"니다. %[1]d개의 섹터 위치를 찾았습니다.\x02Yugabyte 데이터베이스 설치에 연결할 정보를 입력하십시오 (https" + "s' 레이어에는 공통 구성이 저장됩니다. 모든 Curio 인스턴스는 %[2]s 인수에 포함시킬 수 있습니다.\x02기계별 구성 변" +
"://download.yugabyte.com/)\x02호스트: %[1]s\x02포트: %[1]s\x02사용자 이름: %[1]s" + "경을 위해 다른 레이어를 추가할 수 있습니다.\x02Filecoin %[1]s 채널: %[2]s 및 %[3]s\x02신뢰성 향" +
"\x02비밀번호: %[1]s\x02데이터베이스: %[1]s\x02계속 연결 및 스키마 업데이트.\x04\x00\x01 ^\x02데" + "상을 위한 중복성 사용: 적어도 post 레이어를 사용하여 여러 대의 기계를 시작하십시오: 'curio run --layers" +
"이터베이스 구성 오류가 발생하여 마이그레이션을 포기합니다: %[1]s\x02Yugabyte 데이터베이스 호스트를 입력하십시오" + "=post'\x02한 개의 데이터베이스는 여러 광부 ID를 제공할 수 있습니다: 각 lotus-miner에 대해 마이그레이션을 실" +
"\x02호스트가 제공되지 않았습니다\x02Yugabyte 데이터베이스 %[1]s을 입력하십시오\x02값이 제공되지 않았습니다" + "행하세요.\x02데이터베이스 자격 증명이 %[2]s에 입력되었으므로 지금 %[1]s을 시작하거나 다시 시작하세요.\x02%[1" +
"\x02Yugabyte 데이터베이스에 연결하는 중 오류가 발생했습니다: %[1]s\x02Yugabyte에 연결되었습니다. 스키마가" + "]s가 Yugabyte에 섹터를 기록하도록 대기 중입니다.\x02광부 ID를 해석하는 중 오류 발생: %[1]s: ID: %[2]" +
" 현재입니다.\x02config.toml을 인코딩하는 중 오류가 발생했습니다: %[1]s\x02%[1]s을 Yugabyte 정보로" + "s\x02섹터 확인 중 오류 발생: %[1]s\x02섹터가 데이터베이스에 있습니다. 데이터베이스가 %[1]s를 위해 준비되었습니다" +
" 업데이트하려면 리턴을 누르세요. 지금 파일을 백업하세요.\x02config.toml의 파일 모드를 읽는 중 오류가 발생했습니다:" + ".\x02이제 lotus-miner를 종료하고 시스템을 %[1]s로 이동하세요.\x02계속하려면 리턴을 누르세요\x02마이그레이션" +
" %[1]s\x02config.toml을 쓰는 중 오류가 발생했습니다: %[1]s\x04\x00\x01 \x1f\x02로터스 마이" + " 중단.\x02섹터가 확인되었습니다. %[1]d개의 섹터 위치를 찾았습니다.\x02Yugabyte에 연결되었습니다. 스키마가 현재" +
"너 재시작.\x02Yugabyte에 연결됨\x02시작하려면 밀봉 파이프라인이 비어 있고 lotus-miner가 종료되었는지 확" + "입니다.\x02데이터베이스에서 Sector Indexing을 활성화합니다.\x02config.toml을 인코딩하는 중 오류가 " +
"인하세요.\x02로터스 마이너 구성 디렉토리의 위치를 선택하시겠습니까?\x02기타\x02%[1]s에서 사용하는 구성 디렉터리 " + "발생했습니다: %[1]s\x02%[1]s을 Yugabyte 정보로 업데이트하려면 리턴 키를 누르세요. 변경 사항을 적용하기 전" +
"경로를 입력하세요.\x04\x00\x01 M\x02경로가 제공되지 않았으므로 마이그레이션을 포기합니다\x02제공된 디렉토리에서" + "에 해당 폴더에 백업 파일이 작성됩니다.\x02경로를 확장하는 중 오류 발생: %[1]s\x02config.toml의 파일 모" +
" config.toml 파일을 읽을 수 없습니다. 오류: %[1]s\x02마이너 구성 읽기\x04\x00\x01\x0a\x15" + "드를 읽는 중 오류가 발생했습니다: %[1]s\x02백업 파일 생성 오류: %[1]s\x02config.toml 읽기 오류: " +
"\x02단계 완료: %[1]s\x02이 마이너의 주소와 지갑 설정을 포함하도록 구성 'base'가 업데이트되었습니다.\x02구성 " + "%[1]s\x02백업 파일 쓰기 오류: %[1]s\x02백업 파일 닫기 오류: %[1]s\x02config.toml을 쓰는 중 오" +
"%[1]s를 %[2]s과 비교하세요. 지갑 주소 이외의 마이너 ID 사이의 변경 사항은 필요한 실행자를 위한 새로운 최소한의 레이" + "류가 발생했습니다: %[1]s\x04\x00\x01 \x1f\x02로터스 마이너 재시작.\x02Yugabyte에 연결됨\x02" +
"어여야 합니다.\x02이 마이너의 주소와 지갑 설정을 포함하도록 구성 'base'가 생성되었습니다.\x04\x00\x01 *" + "시작하려면 밀봉 파이프라인이 비어 있고 lotus-miner가 종료되었는지 확인하세요.\x02로터스 마이너 구성 디렉토리의 위" +
"\x02레이어 %[1]s가 생성되었습니다.\x02Curio를 실행하려면: 기계 또는 cgroup 격리를 사용하여 다음 명령을 사용" + "치를 선택하시겠습니까?\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 // Entry 0 - 1F
0x00000000, 0x00000048, 0x00000097, 0x000000ca, 0x00000000, 0x00000033, 0x0000008b, 0x00000134,
0x000000e3, 0x00000100, 0x00000100, 0x00000141, 0x0000017c, 0x000001cb, 0x000001e4, 0x000001f1,
0x0000016b, 0x000001a4, 0x000001a4, 0x000001a4, 0x00000211, 0x0000022a, 0x00000240, 0x0000025d,
0x000001a4, 0x000001dd, 0x0000022f, 0x0000025c, 0x0000029c, 0x000002dd, 0x000002f9, 0x0000033e,
0x000002a9, 0x000002e7, 0x00000317, 0x00000321, 0x0000035b, 0x00000384, 0x000003a2, 0x000003db,
0x00000337, 0x0000035b, 0x00000379, 0x0000039d, 0x0000042f, 0x0000045c, 0x000004ab, 0x000004e6,
0x000003bb, 0x000003d9, 0x0000040e, 0x00000421, 0x0000051b, 0x00000525, 0x00000549, 0x00000567,
0x00000430, 0x0000048a, 0x000004c7, 0x000004c7, 0x0000058b, 0x000005a9, 0x000005c7, 0x000005fc,
// Entry 20 - 3F // Entry 20 - 3F
0x000004c7, 0x0000051e, 0x0000051e, 0x0000051e, 0x0000060f, 0x0000061e, 0x00000678, 0x000006b5,
0x00000544, 0x00000544, 0x00000562, 0x0000059e, 0x000006dd, 0x0000073c, 0x0000078c, 0x000007df,
0x000005d0, 0x000005e0, 0x000005f0, 0x00000623, 0x00000805, 0x00000832, 0x00000850, 0x0000088c,
0x0000067d, 0x0000068c, 0x0000069b, 0x000006ad, 0x000008be, 0x000008ce, 0x000008de, 0x00000911,
0x000006bc, 0x000006ce, 0x000006ed, 0x00000725, 0x0000093e, 0x00000963, 0x00000986, 0x000009fe,
0x0000074a, 0x0000075a, 0x00000778, 0x00000785, 0x00000a1c, 0x00000a4b, 0x00000a6f, 0x00000a94,
0x000007b1, 0x000007de, 0x000007de, 0x00000801, 0x00000ab8, 0x00000adc, 0x00000aff, 0x00000b1f,
0x00000845, 0x00000845, 0x00000874, 0x00000897, 0x00000b34, 0x00000b7f, 0x00000baf, 0x00000bb6,
// Entry 40 - 5F // Entry 40 - 5F
0x000008b7, 0x000008cc, 0x00000917, 0x00000947, 0x00000be0, 0x00000c04, 0x00000c48, 0x00000c7a,
0x0000094e, 0x00000978, 0x0000099c, 0x000009e0, 0x00000cc3, 0x00000cd6, 0x00000cf0, 0x00000d0f,
0x000009e0, 0x000009e0, 0x000009f3, 0x00000a0d, 0x00000d34, 0x00000d4c, 0x00000d61, 0x00000d79,
0x00000a59, 0x00000adb, 0x00000b27, 0x00000b41, 0x00000d8d, 0x00000da4, 0x00000dd5, 0x00000dfa,
0x00000b41, 0x00000b98, 0x00000e10, 0x00000e20, 0x00000e3a, 0x00000e4e,
} // Size: 352 bytes 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 const zhData string = "" + // Size: 5269 bytes
"\x02这个交互式工具可以在5分钟内将lotus-miner迁移到Curio。\x02每一步都需要您的确认并且可以撤销。随时按Ctrl+C退出" + "\x04\x00\x01 .\x02使用箭头键进行导航↓ ↑ → ←\x02此交互式工具将创建一个新的矿工角色并为其创建基本配置层。\x02" +
"。\x04\x00\x01 .\x02使用箭头键进行导航↓ ↑ → ←\x02在终端中按下Ctrl+C\x02Lotus-Miner到Cu" + "该过程部分幂等。一旦创建了新的矿工角色,并且随后的步骤失败,用户需要运行 'curio config new-cluster < 矿工 ID" +
"rio迁移。\x02如果适用您现在可以迁移您的市场节点(%[1]s)。\x02正在将config.toml迁移到数据库。\x02读取数据库时出" + " >' 来完成配置。\x02这个交互式工具可以在5分钟内将lotus-miner迁移到Curio。\x02每一步都需要您的确认并且可以撤销。随" +
"错:%[1]s。正在中止迁移。\x02保存配置到层时出错%[1]s。正在中止迁移\x02Protocol Labs希望改进您使用的软件。告" + "时按Ctrl+C退出。\x02在终端中按下Ctrl+C\x02我想要\x02从现有的 Lotus-Miner 迁移\x02创建一个新的矿工" +
"诉团队您正在使用Curio。\x02选择您想与Curio团队分享的内容。\x02个人数据矿工ID、Curio版本、网络(%[1]s或%[2" + "\x02中止剩余步骤。\x02Lotus-Miner到Curio迁移。\x02尝试使用%[1]s的Web界面进行进一步引导式改进。\x02如果适" +
"]s)。已签名。\x02聚合-匿名:版本、网络和矿工功率(分桶)。\x02提示我是在网络上运行Curio的人。\x02没有。\x02中止剩余步" + "用,您现在可以迁移您的市场节点(%[1]s)。\x02新矿工初始化完成。\x02将 lotus-miner config.toml 迁移到 " +
"骤。\x02获取矿工功率时出错%[1]s\x02整理消息时出错%[1]s\x02获取矿工信息时出错%[1]s\x02签署消息时出错%" + "Curio 的数据库配置中。\x02获取 API 时出错:%[1]s\x02无法获取FullNode的API信息%[1]w\x02获取令牌时出" +
"[1]s\x02发送消息时出错%[1]s\x04\x00\x01 0\x02发送消息时出错状态%[1]s消息\x02消息已发送。\x04" + "错:%[1]s\x02保存配置到层时出错%[1]s。正在中止迁移\x02Curio 团队希望改进您使用的软件。告诉团队您正在使用 `%[1" +
"\x00\x01 \x0a\x02文档\x02'%[1]s'层存储通用配置。所有Curio实例都可以在其%[2]s参数中包含它。\x02您可以" + "]s`。\x02选择您想与Curio团队分享的内容。\x02个人数据矿工 IDCurio 版本,链(%[1]s 或 %[2]s。签名。" +
"添加其他层进行每台机器的配置更改。\x02将您的浏览器指向您的网络GUI以使用%[1]s和高级功能完成设置。\x02等待%[1]s将扇区写" + "\x02聚合-匿名:版本,链和矿工算力(分桶)。\x02提示我是在任何链上运行 Curio 的人。\x02没有。\x02获取矿工功率时出错%" +
"入Yugabyte。\x02验证扇区时出错%[1]s\x02扇区在数据库中。数据库已准备好用于%[1]s。\x02现在关闭lotus-mi" + "[1]s\x02整理消息时出错%[1]s\x02获取矿工信息时出错%[1]s\x02签署消息时出错%[1]s\x02发送消息时出错%[1" +
"ner并将系统移至%[1]s。\x02按回车继续\x02中止迁移。\x02扇区已验证。发现了%[1]d个扇区位置。\x02输入连接到您的Yuga" + "]s\x04\x00\x01 0\x02发送消息时出错状态%[1]s消息\x02消息已发送。\x04\x00\x01 \x0a\x02文档" +
"byte数据库安装的信息https://download.yugabyte.com/\x02主机%[1]s\x02端口%[1]s\x02" + "\x02'%[1]s'层存储通用配置。所有Curio实例都可以在其%[2]s参数中包含它。\x02您可以添加其他层进行每台机器的配置更改。" +
"用户名:%[1]s\x02密码%[1]s\x02数据库%[1]s\x02继续连接和更新架构。\x04\x00\x01 3\x02发生数据" + "\x02Filecoin %[1]s 频道:%[2]s 和 %[3]s\x02通过冗余增加可靠性使用至少后层启动多台机器'curio run" +
"库配置错误,放弃迁移:%[1]s\x02输入Yugabyte数据库主机S\x02未提供主机\x02输入Yugabyte数据库 %[1]s" + " --layers=post'\x02一个数据库可以服务多个矿工ID为每个lotus-miner运行迁移。\x02请立即启动或重新启动%[" +
"\x02未提供值\x02连接到Yugabyte数据库时出错%[1]s\x02已连接到Yugabyte。模式是当前的。\x02编码config." + "1]s因为数据库凭据已在%[2]s中。\x02等待%[1]s将扇区写入Yugabyte。\x02解释矿工ID时出错%[1]sID%[2]" +
"toml时出错%[1]s\x02按回车更新%[1]s以获取Yugabyte信息。现在备份文件。\x02读取config.toml文件模式时出错" + "s\x02验证扇区时出错%[1]s\x02扇区在数据库中。数据库已准备好用于%[1]s。\x02现在关闭lotus-miner并将系统移至%[" +
"%[1]s\x02写入config.toml时出错%[1]s\x04\x00\x01 \x1b\x02重新启动Lotus Miner。" + "1]s。\x02按回车继续\x02中止迁移。\x02扇区已验证。发现了%[1]d个扇区位置。\x02已连接到Yugabyte。模式是当前的。" +
"\x02已连接到Yugabyte\x02开始之前请确保您的密封管道已排空并关闭lotus-miner。\x02选择您的lotus-miner配" + "\x02在数据库中启用扇区索引。\x02编码config.toml时出错%[1]s\x02按回车键更新 %[1]s 以包含 Yugabyte " +
"置目录的位置?\x02其他\x02输入%[1]s使用的配置目录的路径\x04\x00\x01 \x1f\x02未提供路径放弃迁移\x02无" + "信息。在进行更改之前,将在该文件夹中写入备份文件。\x02扩展路径时出错%[1]s\x02读取config.toml文件模式时出错%[1" +
"法读取提供的目录中的config.toml文件错误%[1]s\x02读取矿工配置\x04\x00\x01\x0a\x15\x02步骤完成" + "]s\x02创建备份文件时出错%[1]s\x02读取 config.toml 时出错:%[1]s\x02写入备份文件时出错%[1]s\x02" +
"%[1]s\x02配置'base'已更新,包含了这个矿工的地址和其钱包设置。\x02比较配置%[1]s和%[2]s。矿工ID之间除了钱包地" + "关闭备份文件时出错:%[1]s\x02写入config.toml时出错%[1]s\x04\x00\x01 \x1b\x02重新启动Lotu" +
"址的变化应该是需要的运行者的一个新的、最小的层。\x02配置'base'已创建,包括了这个矿工的地址和其钱包设置。\x04\x00\x01 " + "s Miner。\x02已连接到Yugabyte\x02开始之前请确保您的密封管道已排空并关闭lotus-miner。\x02选择您的lotu" +
"\x15\x02层%[1]s已创建。\x02运行Curio使用机器或cgroup隔离使用命令附带示例层选择" "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

File diff suppressed because it is too large Load Diff

View File

@ -621,84 +621,462 @@
"translation": "더 많은 안내를 위해 {__layersgui}를 사용하여 웹 인터페이스를 시도하세요.", "translation": "더 많은 안내를 위해 {__layersgui}를 사용하여 웹 인터페이스를 시도하세요.",
"message": "Try the web interface with {__layersgui} for further guided improvements.", "message": "Try the web interface with {__layersgui} for further guided improvements.",
"placeholder": null "placeholder": null
}, },
{ {
"id": "Error connecting to lotus node: {Error} {Error_1}", "id": "Error connecting to lotus node: {Error} {Error_1}",
"translation": "lotus 노드에 연결하는 중 오류 발생: {Error} {Error_1}", "translation": "lotus 노드에 연결하는 중 오류 발생: {Error} {Error_1}",
"message": "Error connecting to lotus node: {Error} {Error_1}", "message": "Error connecting to lotus node: {Error} {Error_1}",
"placeholder": null "placeholder": null
}, },
{ {
"id": "could not get API info for FullNode: {Err}", "id": "could not get API info for FullNode: {Err}",
"translation": "FullNode의 API 정보를 가져올 수 없습니다: {Err}", "translation": "FullNode의 API 정보를 가져올 수 없습니다: {Err}",
"message": "could not get API info for FullNode: {Err}", "message": "could not get API info for FullNode: {Err}",
"placeholder": null "placeholder": null
}, },
{ {
"id": "Error getting token: {Error}", "id": "Error getting token: {Error}",
"translation": "토큰을 가져오는 중 오류 발생: {Error}", "translation": "토큰을 가져오는 중 오류 발생: {Error}",
"message": "Error getting token: {Error}", "message": "Error getting token: {Error}",
"placeholder": null "placeholder": null
}, },
{ {
"id": "Filecoin {Slack} channels: {Fil_curio_help} and {Fil_curio_dev}", "id": "Filecoin {Slack} channels: {Fil_curio_help} and {Fil_curio_dev}",
"translation": "Filecoin {Slack} 채널: {Fil_curio_help} 및 {Fil_curio_dev}", "translation": "Filecoin {Slack} 채널: {Fil_curio_help} 및 {Fil_curio_dev}",
"message": "Filecoin {Slack} channels: {Fil_curio_help} and {Fil_curio_dev}", "message": "Filecoin {Slack} channels: {Fil_curio_help} and {Fil_curio_dev}",
"placeholder": null "placeholder": null
}, },
{ {
"id": "Start multiple Curio instances with the '{Post}' layer to redundancy.", "id": "Start multiple Curio instances with the '{Post}' layer to redundancy.",
"translation": "'{Post}' 레이어로 여러 Curio 인스턴스를 시작하여 중복성을 확보하세요.", "translation": "'{Post}' 레이어로 여러 Curio 인스턴스를 시작하여 중복성을 확보하세요.",
"message": "Start multiple Curio instances with the '{Post}' layer to redundancy.", "message": "Start multiple Curio instances with the '{Post}' layer to redundancy.",
"placeholder": null "placeholder": null
}, },
{ {
"id": "One database can serve multiple miner IDs: Run a migration for each lotus-miner.", "id": "One database can serve multiple miner IDs: Run a migration for each lotus-miner.",
"translation": "한 개의 데이터베이스는 여러 광부 ID를 제공할 수 있습니다: 각 lotus-miner에 대해 마이그레이션을 실행하세요.", "translation": "한 개의 데이터베이스는 여러 광부 ID를 제공할 수 있습니다: 각 lotus-miner에 대해 마이그레이션을 실행하세요.",
"message": "One database can serve multiple miner IDs: Run a migration for each lotus-miner.", "message": "One database can serve multiple miner IDs: Run a migration for each lotus-miner.",
"placeholder": null "placeholder": null
}, },
{ {
"id": "Please start (or restart) {Lotus_miner} now that database credentials are in {Toml}.", "id": "Please start (or restart) {Lotus_miner} now that database credentials are in {Toml}.",
"translation": "데이터베이스 자격 증명이 {Toml}에 입력되었으므로 지금 {Lotus_miner}을 시작하거나 다시 시작하세요.", "translation": "데이터베이스 자격 증명이 {Toml}에 입력되었으므로 지금 {Lotus_miner}을 시작하거나 다시 시작하세요.",
"message": "Please start (or restart) {Lotus_miner} now that database credentials are in {Toml}.", "message": "Please start (or restart) {Lotus_miner} now that database credentials are in {Toml}.",
"placeholder": null "placeholder": null
}, },
{ {
"id": "Error interpreting miner ID: {Error}: ID: {String}", "id": "Error interpreting miner ID: {Error}: ID: {String}",
"translation": "광부 ID를 해석하는 중 오류 발생: {Error}: ID: {String}", "translation": "광부 ID를 해석하는 중 오류 발생: {Error}: ID: {String}",
"message": "Error interpreting miner ID: {Error}: ID: {String}", "message": "Error interpreting miner ID: {Error}: ID: {String}",
"placeholder": null "placeholder": null
}, },
{ {
"id": "Enabling Sector Indexing in the database.", "id": "Enabling Sector Indexing in the database.",
"translation": "데이터베이스에서 Sector Indexing을 활성화합니다.", "translation": "데이터베이스에서 Sector Indexing을 활성화합니다.",
"message": "Enabling Sector Indexing in the database.", "message": "Enabling Sector Indexing in the database.",
"placeholder": null "placeholder": null
}, },
{ {
"id": "Error expanding path: {Error}", "id": "Error expanding path: {Error}",
"translation": "경로를 확장하는 중 오류 발생: {Error}", "translation": "경로를 확장하는 중 오류 발생: {Error}",
"message": "Error expanding path: {Error}", "message": "Error expanding path: {Error}",
"placeholder": null "placeholder": null
}, },
{ {
"id": "Could not create repo from directory: {Error}. Aborting migration", "id": "Could not create repo from directory: {Error}. Aborting migration",
"translation": "디렉토리에서 저장소를 생성할 수 없습니다: {Error}. 마이그레이션을 중단합니다.", "translation": "디렉토리에서 저장소를 생성할 수 없습니다: {Error}. 마이그레이션을 중단합니다.",
"message": "Could not create repo from directory: {Error}. Aborting migration", "message": "Could not create repo from directory: {Error}. Aborting migration",
"placeholder": null "placeholder": null
}, },
{ {
"id": "Could not lock miner repo. Your miner must be stopped: {Error}\n Aborting migration", "id": "Could not lock miner repo. Your miner must be stopped: {Error}\n Aborting migration",
"translation": "광부 저장소를 잠금 해제할 수 없습니다. 귀하의 광부를 중지해야 합니다: {Error}\n 마이그레이션을 중단합니다.", "translation": "광부 저장소를 잠금 해제할 수 없습니다. 귀하의 광부를 중지해야 합니다: {Error}\n 마이그레이션을 중단합니다.",
"message": "Could not lock miner repo. Your miner must be stopped: {Error}\n Aborting migration", "message": "Could not lock miner repo. Your miner must be stopped: {Error}\n Aborting migration",
"placeholder": null "placeholder": null
}, },
{ {
"id": "To work with the config:", "id": "To work with the config:",
"translation": "구성 파일을 사용하려면:", "translation": "구성 파일을 사용하려면:",
"message": "To work with the config:", "message": "To work with the config:",
"placeholder": null "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
}
] ]
} }

View File

@ -1,89 +1,4 @@
{ {
"language": "ko", "language": "ko",
"messages": [ "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
}
]
} }

View File

@ -699,6 +699,354 @@
"translation": "要使用配置:", "translation": "要使用配置:",
"message": "To work with the config:", "message": "To work with the config:",
"placeholder": null "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": "个人数据:矿工 IDCurio 版本,链({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
} }
] ]
} }

View File

@ -1,89 +1,4 @@
{ {
"language": "zh", "language": "zh",
"messages": [ "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
}
]
} }

View File

@ -2,7 +2,7 @@
#OP: Only run if some file in ../guidedsetup* is newer than catalog.go #OP: Only run if some file in ../guidedsetup* is newer than catalog.go
# Change this condition if using translations more widely. # 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 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 go run knowns/main.go locales/zh locales/ko
fi fi

View File

@ -111,7 +111,7 @@ func main() {
Name: "db-host", Name: "db-host",
EnvVars: []string{"CURIO_DB_HOST", "CURIO_HARMONYDB_HOSTS"}, EnvVars: []string{"CURIO_DB_HOST", "CURIO_HARMONYDB_HOSTS"},
Usage: "Command separated list of hostnames for yugabyte cluster", Usage: "Command separated list of hostnames for yugabyte cluster",
Value: "yugabyte", Value: "127.0.0.1",
}, },
&cli.StringFlag{ &cli.StringFlag{
Name: "db-name", Name: "db-name",
@ -131,7 +131,6 @@ func main() {
&cli.StringFlag{ &cli.StringFlag{
Name: "db-port", Name: "db-port",
EnvVars: []string{"CURIO_DB_PORT", "CURIO_HARMONYDB_PORT"}, EnvVars: []string{"CURIO_DB_PORT", "CURIO_HARMONYDB_PORT"},
Hidden: true,
Value: "5433", Value: "5433",
}, },
&cli.StringFlag{ &cli.StringFlag{

View File

@ -32,6 +32,7 @@ var actorCmd = &cli.Command{
spcli.ActorCompactAllocatedCmd(SPTActorGetter), spcli.ActorCompactAllocatedCmd(SPTActorGetter),
spcli.ActorProposeChangeBeneficiaryCmd(SPTActorGetter), spcli.ActorProposeChangeBeneficiaryCmd(SPTActorGetter),
spcli.ActorConfirmChangeBeneficiaryCmd(SPTActorGetter), spcli.ActorConfirmChangeBeneficiaryCmd(SPTActorGetter),
spcli.ActorNewMinerCmd,
}, },
} }

View File

@ -280,7 +280,6 @@ var sectorsListCmd = &cli.Command{
for _, st := range sset { for _, st := range sset {
s := st.SectorNumber s := st.SectorNumber
_, inSSet := commitedIDs[s] _, inSSet := commitedIDs[s]
_, inASet := activeIDs[s] _, inASet := activeIDs[s]

View File

@ -16,7 +16,7 @@ COMMANDS:
config Manage node config by layers. The layer 'base' will always be applied at Curio start-up. config Manage node config by layers. The layer 'base' will always be applied at Curio start-up.
test Utility functions for testing test Utility functions for testing
web Start Curio web interface 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 seal Manage the sealing pipeline
market market
auth Manage RPC permissions auth Manage RPC permissions
@ -28,10 +28,11 @@ COMMANDS:
GLOBAL OPTIONS: GLOBAL OPTIONS:
--color use color in display output (default: depends on output being a TTY) --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-name value (default: "yugabyte") [$CURIO_DB_NAME, $CURIO_HARMONYDB_NAME]
--db-user value (default: "yugabyte") [$CURIO_DB_USER, $CURIO_HARMONYDB_USERNAME] --db-user value (default: "yugabyte") [$CURIO_DB_USER, $CURIO_HARMONYDB_USERNAME]
--db-password value (default: "yugabyte") [$CURIO_DB_PASSWORD, $CURIO_HARMONYDB_PASSWORD] --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] --repo-path value (default: "~/.curio") [$CURIO_REPO_PATH]
--vv enables very verbose mode, useful for debugging the CLI (default: false) --vv enables very verbose mode, useful for debugging the CLI (default: false)
--help, -h show help --help, -h show help
@ -305,7 +306,7 @@ OPTIONS:
## curio guided-setup ## curio guided-setup
``` ```
NAME: 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: USAGE:
curio guided-setup [command options] [arguments...] curio guided-setup [command options] [arguments...]

View File

@ -43,6 +43,7 @@ COMMANDS:
compact-allocated compact allocated sectors bitfield compact-allocated compact allocated sectors bitfield
propose-change-beneficiary Propose a beneficiary address change propose-change-beneficiary Propose a beneficiary address change
confirm-change-beneficiary Confirm 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 help, h Shows a list of commands or help for one command
OPTIONS: OPTIONS:
@ -231,6 +232,22 @@ OPTIONS:
--help, -h show help --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 ## sptool info
``` ```
NAME: NAME:

2
go.mod
View File

@ -69,6 +69,7 @@ require (
github.com/georgysavva/scany/v2 v2.0.0 github.com/georgysavva/scany/v2 v2.0.0
github.com/go-openapi/spec v0.19.11 github.com/go-openapi/spec v0.19.11
github.com/golang/mock v1.6.0 github.com/golang/mock v1.6.0
github.com/google/go-cmp v0.6.0
github.com/google/uuid v1.5.0 github.com/google/uuid v1.5.0
github.com/gorilla/mux v1.8.1 github.com/gorilla/mux v1.8.1
github.com/gorilla/websocket v1.5.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/groupcache v0.0.0-20210331224755-41bb18bfe9da // indirect
github.com/golang/protobuf v1.5.3 // indirect github.com/golang/protobuf v1.5.3 // indirect
github.com/golang/snappy v0.0.4 // 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/gopacket v1.1.19 // indirect
github.com/google/pprof v0.0.0-20240207164012-fb44976bdcd5 // indirect github.com/google/pprof v0.0.0-20240207164012-fb44976bdcd5 // indirect
github.com/hannahhoward/cbor-gen-for v0.0.0-20230214144701-5d17c9d5243c // indirect github.com/hannahhoward/cbor-gen-for v0.0.0-20230214144701-5d17c9d5243c // indirect

67
itests/curio_test.go Normal file
View File

@ -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())
}

View File

@ -4,13 +4,17 @@ import (
"bytes" "bytes"
"fmt" "fmt"
"io" "io"
"math/big"
"os" "os"
"reflect" "reflect"
"regexp" "regexp"
"sort"
"strings" "strings"
"unicode" "unicode"
"github.com/BurntSushi/toml" "github.com/BurntSushi/toml"
"github.com/google/go-cmp/cmp"
"github.com/google/go-cmp/cmp/cmpopts"
"github.com/kelseyhightower/envconfig" "github.com/kelseyhightower/envconfig"
"golang.org/x/xerrors" "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) return nil, xerrors.Errorf("parsing updated config: %w", err)
} }
if !reflect.DeepEqual(cfgCur, cfgUpdated) { opts := []cmp.Option{
return nil, xerrors.Errorf("updated config didn't match current config:") // 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")
} }
} }