diff --git a/cli/server/server.go b/cli/server/server.go index 3f7170a8b..ed5840d72 100644 --- a/cli/server/server.go +++ b/cli/server/server.go @@ -357,9 +357,9 @@ func startServer(ctx *cli.Context) error { go serv.Start(errChan) go rpcServer.Start(errChan) - fmt.Println(logo()) - fmt.Println(serv.UserAgent) - fmt.Println() + fmt.Fprintln(ctx.App.Writer, logo()) + fmt.Fprintln(ctx.App.Writer, serv.UserAgent) + fmt.Fprintln(ctx.App.Writer) var shutdownErr error Main: diff --git a/cli/smartcontract/smart_contract.go b/cli/smartcontract/smart_contract.go index c4cca1cc5..0410e87d7 100644 --- a/cli/smartcontract/smart_contract.go +++ b/cli/smartcontract/smart_contract.go @@ -366,7 +366,7 @@ func initSmartContract(ctx *cli.Context) error { return cli.NewExitError(err, 1) } - fmt.Printf("Successfully initialized smart contract [%s]\n", contractName) + fmt.Fprintf(ctx.App.Writer, "Successfully initialized smart contract [%s]\n", contractName) return nil } @@ -405,7 +405,7 @@ func contractCompile(ctx *cli.Context) error { return cli.NewExitError(err, 1) } if ctx.Bool("verbose") { - fmt.Println(hex.EncodeToString(result)) + fmt.Fprintln(ctx.App.Writer, hex.EncodeToString(result)) } return nil @@ -495,14 +495,14 @@ func invokeInternal(ctx *cli.Context, signAndPush bool) error { if err != nil { return cli.NewExitError(fmt.Errorf("failed to push invocation tx: %w", err), 1) } - fmt.Printf("Sent invocation transaction %s\n", txHash.StringLE()) + fmt.Fprintf(ctx.App.Writer, "Sent invocation transaction %s\n", txHash.StringLE()) } else { b, err := json.MarshalIndent(resp, "", " ") if err != nil { return cli.NewExitError(err, 1) } - fmt.Println(string(b)) + fmt.Fprintln(ctx.App.Writer, string(b)) } return nil @@ -599,7 +599,7 @@ func testInvokeScript(ctx *cli.Context) error { return cli.NewExitError(err, 1) } - fmt.Println(string(b)) + fmt.Fprintln(ctx.App.Writer, string(b)) return nil } @@ -680,9 +680,9 @@ func getAccFromContext(ctx *cli.Context) (*wallet.Account, error) { return nil, cli.NewExitError(fmt.Errorf("wallet contains no account for '%s'", address.Uint160ToString(addr)), 1) } - fmt.Printf("Enter account %s password > ", address.Uint160ToString(addr)) + fmt.Fprintf(ctx.App.Writer, "Enter account %s password > ", address.Uint160ToString(addr)) rawPass, err := terminal.ReadPassword(syscall.Stdin) - fmt.Println() + fmt.Fprintln(ctx.App.Writer) if err != nil { return nil, cli.NewExitError(err, 1) } @@ -751,7 +751,7 @@ func contractDeploy(ctx *cli.Context) error { if err != nil { return cli.NewExitError(fmt.Errorf("failed to push invocation tx: %w", err), 1) } - fmt.Printf("Sent deployment transaction %s for contract %s\n", txHash.StringLE(), nefFile.Header.ScriptHash.StringLE()) + fmt.Fprintf(ctx.App.Writer, "Sent deployment transaction %s for contract %s\n", txHash.StringLE(), nefFile.Header.ScriptHash.StringLE()) return nil } diff --git a/cli/util/convert.go b/cli/util/convert.go index 731db8562..aecc98b43 100644 --- a/cli/util/convert.go +++ b/cli/util/convert.go @@ -33,6 +33,6 @@ func handleParse(ctx *cli.Context) error { if err != nil { return cli.NewExitError(err, 1) } - fmt.Print(res) + fmt.Fprint(ctx.App.Writer, res) return nil } diff --git a/cli/wallet/multisig.go b/cli/wallet/multisig.go index 3bcd47828..87bd2dffc 100644 --- a/cli/wallet/multisig.go +++ b/cli/wallet/multisig.go @@ -3,6 +3,7 @@ package wallet import ( "encoding/json" "fmt" + "io" "io/ioutil" "github.com/nspcc-dev/neo-go/cli/options" @@ -50,7 +51,7 @@ func signMultisig(ctx *cli.Context) error { if err != nil { return cli.NewExitError(fmt.Errorf("invalid address: %w", err), 1) } - acc, err := getDecryptedAccount(wall, sh) + acc, err := getDecryptedAccount(ctx, wall, sh) if err != nil { return cli.NewExitError(err, 1) } @@ -59,7 +60,7 @@ func signMultisig(ctx *cli.Context) error { if !ok { return cli.NewExitError("verifiable item is not a transaction", 1) } - printTxInfo(tx) + printTxInfo(ctx.App.Writer, tx) priv := acc.PrivateKey() sign := priv.Sign(tx.GetSignedPart()) @@ -86,11 +87,11 @@ func signMultisig(ctx *cli.Context) error { if err != nil { return cli.NewExitError(err, 1) } - fmt.Println(res.StringLE()) + fmt.Fprintln(ctx.App.Writer, res.StringLE()) return nil } - fmt.Println(tx.Hash().StringLE()) + fmt.Fprintln(ctx.App.Writer, tx.Hash().StringLE()) return nil } @@ -116,6 +117,6 @@ func writeParameterContext(c *context.ParameterContext, filename string) error { return nil } -func printTxInfo(t *transaction.Transaction) { - fmt.Printf("Hash: %s\n", t.Hash().StringLE()) +func printTxInfo(w io.Writer, t *transaction.Transaction) { + fmt.Fprintf(w, "Hash: %s\n", t.Hash().StringLE()) } diff --git a/cli/wallet/nep5.go b/cli/wallet/nep5.go index 641d13696..2f7397f2f 100644 --- a/cli/wallet/nep5.go +++ b/cli/wallet/nep5.go @@ -162,9 +162,9 @@ func getNEP5Balance(ctx *cli.Context) error { var token *wallet.Token name := ctx.String("token") if name != "" { - token, err = getMatchingToken(wall, name) + token, err = getMatchingToken(ctx, wall, name) if err != nil { - token, err = getMatchingTokenRPC(c, addrHash, name) + token, err = getMatchingTokenRPC(ctx, c, addrHash, name) if err != nil { return cli.NewExitError(err, 1) } @@ -181,26 +181,26 @@ func getNEP5Balance(ctx *cli.Context) error { if name != "" && !token.Hash.Equals(asset) { continue } - fmt.Printf("TokenHash: %s\n", asset.StringLE()) - fmt.Printf("\tAmount : %s\n", balances.Balances[i].Amount) - fmt.Printf("\tUpdated: %d\n", balances.Balances[i].LastUpdated) + fmt.Fprintf(ctx.App.Writer, "TokenHash: %s\n", asset.StringLE()) + fmt.Fprintf(ctx.App.Writer, "\tAmount : %s\n", balances.Balances[i].Amount) + fmt.Fprintf(ctx.App.Writer, "\tUpdated: %d\n", balances.Balances[i].LastUpdated) } return nil } -func getMatchingToken(w *wallet.Wallet, name string) (*wallet.Token, error) { +func getMatchingToken(ctx *cli.Context, w *wallet.Wallet, name string) (*wallet.Token, error) { switch strings.ToLower(name) { case "neo": return neoToken, nil case "gas": return gasToken, nil } - return getMatchingTokenAux(func(i int) *wallet.Token { + return getMatchingTokenAux(ctx, func(i int) *wallet.Token { return w.Extra.Tokens[i] }, len(w.Extra.Tokens), name) } -func getMatchingTokenRPC(c *client.Client, addr util.Uint160, name string) (*wallet.Token, error) { +func getMatchingTokenRPC(ctx *cli.Context, c *client.Client, addr util.Uint160, name string) (*wallet.Token, error) { bs, err := c.GetNEP5Balances(addr) if err != nil { return nil, err @@ -209,18 +209,18 @@ func getMatchingTokenRPC(c *client.Client, addr util.Uint160, name string) (*wal t, _ := c.NEP5TokenInfo(bs.Balances[i].Asset) return t } - return getMatchingTokenAux(get, len(bs.Balances), name) + return getMatchingTokenAux(ctx, get, len(bs.Balances), name) } -func getMatchingTokenAux(get func(i int) *wallet.Token, n int, name string) (*wallet.Token, error) { +func getMatchingTokenAux(ctx *cli.Context, get func(i int) *wallet.Token, n int, name string) (*wallet.Token, error) { var token *wallet.Token var count int for i := 0; i < n; i++ { t := get(i) if t != nil && (t.Name == name || t.Symbol == name || t.Address() == name || t.Hash.StringLE() == name) { if count == 1 { - printTokenInfo(token) - printTokenInfo(t) + printTokenInfo(ctx, token) + printTokenInfo(ctx, t) return nil, errors.New("multiple matching tokens found") } count++ @@ -247,7 +247,7 @@ func importNEP5Token(ctx *cli.Context) error { for _, t := range wall.Extra.Tokens { if t.Hash.Equals(tokenHash) { - printTokenInfo(t) + printTokenInfo(ctx, t) return cli.NewExitError("token already exists", 1) } } @@ -269,16 +269,17 @@ func importNEP5Token(ctx *cli.Context) error { if err := wall.Save(); err != nil { return cli.NewExitError(err, 1) } - printTokenInfo(tok) + printTokenInfo(ctx, tok) return nil } -func printTokenInfo(tok *wallet.Token) { - fmt.Printf("Name:\t%s\n", tok.Name) - fmt.Printf("Symbol:\t%s\n", tok.Symbol) - fmt.Printf("Hash:\t%s\n", tok.Hash.StringLE()) - fmt.Printf("Decimals: %d\n", tok.Decimals) - fmt.Printf("Address: %s\n", tok.Address()) +func printTokenInfo(ctx *cli.Context, tok *wallet.Token) { + w := ctx.App.Writer + fmt.Fprintf(w, "Name:\t%s\n", tok.Name) + fmt.Fprintf(w, "Symbol:\t%s\n", tok.Symbol) + fmt.Fprintf(w, "Hash:\t%s\n", tok.Hash.StringLE()) + fmt.Fprintf(w, "Decimals: %d\n", tok.Decimals) + fmt.Fprintf(w, "Address: %s\n", tok.Address()) } func printNEP5Info(ctx *cli.Context) error { @@ -289,19 +290,19 @@ func printNEP5Info(ctx *cli.Context) error { defer wall.Close() if name := ctx.String("token"); name != "" { - token, err := getMatchingToken(wall, name) + token, err := getMatchingToken(ctx, wall, name) if err != nil { return cli.NewExitError(err, 1) } - printTokenInfo(token) + printTokenInfo(ctx, token) return nil } for i, t := range wall.Extra.Tokens { if i > 0 { - fmt.Println() + fmt.Fprintln(ctx.App.Writer) } - printTokenInfo(t) + printTokenInfo(ctx, t) } return nil } @@ -317,12 +318,12 @@ func removeNEP5Token(ctx *cli.Context) error { if name == "" { return cli.NewExitError("token must be specified", 1) } - token, err := getMatchingToken(wall, name) + token, err := getMatchingToken(ctx, wall, name) if err != nil { return cli.NewExitError(err, 1) } if !ctx.Bool("force") { - if ok := askForConsent(); !ok { + if ok := askForConsent(ctx.App.Writer); !ok { return nil } } @@ -343,7 +344,7 @@ func multiTransferNEP5(ctx *cli.Context) error { fromFlag := ctx.Generic("from").(*flags.Address) from := fromFlag.Uint160() - acc, err := getDecryptedAccount(wall, from) + acc, err := getDecryptedAccount(ctx, wall, from) if err != nil { return cli.NewExitError(err, 1) } @@ -369,10 +370,10 @@ func multiTransferNEP5(ctx *cli.Context) error { } token, ok := cache[ss[0]] if !ok { - token, err = getMatchingToken(wall, ss[0]) + token, err = getMatchingToken(ctx, wall, ss[0]) if err != nil { - fmt.Println("Can't find matching token in the wallet. Querying RPC-node for balances.") - token, err = getMatchingTokenRPC(c, from, ctx.String("token")) + fmt.Fprintln(ctx.App.ErrWriter, "Can't find matching token in the wallet. Querying RPC-node for balances.") + token, err = getMatchingTokenRPC(ctx, c, from, ctx.String("token")) if err != nil { return cli.NewExitError(err, 1) } @@ -406,7 +407,7 @@ func transferNEP5(ctx *cli.Context) error { fromFlag := ctx.Generic("from").(*flags.Address) from := fromFlag.Uint160() - acc, err := getDecryptedAccount(wall, from) + acc, err := getDecryptedAccount(ctx, wall, from) if err != nil { return cli.NewExitError(err, 1) } @@ -421,10 +422,10 @@ func transferNEP5(ctx *cli.Context) error { toFlag := ctx.Generic("to").(*flags.Address) to := toFlag.Uint160() - token, err := getMatchingToken(wall, ctx.String("token")) + token, err := getMatchingToken(ctx, wall, ctx.String("token")) if err != nil { - fmt.Println("Can't find matching token in the wallet. Querying RPC-node for balances.") - token, err = getMatchingTokenRPC(c, from, ctx.String("token")) + fmt.Fprintln(ctx.App.ErrWriter, "Can't find matching token in the wallet. Querying RPC-node for balances.") + token, err = getMatchingTokenRPC(ctx, c, from, ctx.String("token")) if err != nil { return cli.NewExitError(err, 1) } @@ -470,10 +471,10 @@ func signAndSendTransfer(ctx *cli.Context, c *client.Client, acc *wallet.Account if err != nil { return cli.NewExitError(err, 1) } - fmt.Println(res.StringLE()) + fmt.Fprintln(ctx.App.Writer, res.StringLE()) return nil } - fmt.Println(tx.Hash().StringLE()) + fmt.Fprintln(ctx.App.Writer, tx.Hash().StringLE()) return nil } diff --git a/cli/wallet/validator.go b/cli/wallet/validator.go index fc03899cb..64c12d51c 100644 --- a/cli/wallet/validator.go +++ b/cli/wallet/validator.go @@ -83,7 +83,7 @@ func handleCandidate(ctx *cli.Context, method string) error { addrFlag := ctx.Generic("address").(*flags.Address) addr := addrFlag.Uint160() - acc, err := getDecryptedAccount(wall, addr) + acc, err := getDecryptedAccount(ctx, wall, addr) if err != nil { return cli.NewExitError(err, 1) } @@ -111,7 +111,7 @@ func handleCandidate(ctx *cli.Context, method string) error { if err != nil { return cli.NewExitError(err, 1) } - fmt.Println(res.StringLE()) + fmt.Fprintln(ctx.App.Writer, res.StringLE()) return nil } @@ -123,7 +123,7 @@ func handleVote(ctx *cli.Context) error { addrFlag := ctx.Generic("address").(*flags.Address) addr := addrFlag.Uint160() - acc, err := getDecryptedAccount(wall, addr) + acc, err := getDecryptedAccount(ctx, wall, addr) if err != nil { return cli.NewExitError(err, 1) } @@ -168,17 +168,17 @@ func handleVote(ctx *cli.Context) error { if err != nil { return cli.NewExitError(err, 1) } - fmt.Println(res.StringLE()) + fmt.Fprintln(ctx.App.Writer, res.StringLE()) return nil } -func getDecryptedAccount(wall *wallet.Wallet, addr util.Uint160) (*wallet.Account, error) { +func getDecryptedAccount(ctx *cli.Context, wall *wallet.Wallet, addr util.Uint160) (*wallet.Account, error) { acc := wall.GetAccount(addr) if acc == nil { return nil, fmt.Errorf("can't find account for the address: %s", address.Uint160ToString(addr)) } - if pass, err := readPassword("Password > "); err != nil { + if pass, err := readPassword(ctx.App.Writer, "Password > "); err != nil { return nil, err } else if err := acc.Decrypt(pass); err != nil { return nil, err diff --git a/cli/wallet/wallet.go b/cli/wallet/wallet.go index 54c5e4f69..30b742512 100644 --- a/cli/wallet/wallet.go +++ b/cli/wallet/wallet.go @@ -5,6 +5,7 @@ import ( "encoding/hex" "errors" "fmt" + "io" "os" "strings" "syscall" @@ -222,7 +223,7 @@ func claimGas(ctx *cli.Context) error { return cli.NewExitError("address was not provided", 1) } scriptHash := addrFlag.Uint160() - acc, err := getDecryptedAccount(wall, scriptHash) + acc, err := getDecryptedAccount(ctx, wall, scriptHash) if err != nil { return cli.NewExitError(err, 1) } @@ -245,7 +246,7 @@ func claimGas(ctx *cli.Context) error { return cli.NewExitError(err, 1) } - fmt.Println(hash.StringLE()) + fmt.Fprintln(ctx.App.Writer, hash.StringLE()) return nil } @@ -265,7 +266,7 @@ func convertWallet(ctx *cli.Context) error { for _, acc := range wall.Accounts { address.Prefix = address.NEO2Prefix - pass, err := readPassword(fmt.Sprintf("Enter passphrase for account %s (label '%s') > ", acc.Address, acc.Label)) + pass, err := readPassword(ctx.App.Writer, fmt.Sprintf("Enter passphrase for account %s (label '%s') > ", acc.Address, acc.Label)) if err != nil { return cli.NewExitError(err, -1) } else if err := acc.Decrypt(pass); err != nil { @@ -347,7 +348,7 @@ loop: for _, wif := range wifs { if decrypt { - pass, err := readPassword("Enter password > ") + pass, err := readPassword(ctx.App.Writer, "Enter password > ") if err != nil { return cli.NewExitError(err, 1) } @@ -360,7 +361,7 @@ loop: wif = pk.WIF() } - fmt.Println(wif) + fmt.Fprintln(ctx.App.Writer, wif) } return nil @@ -389,7 +390,7 @@ func importMultisig(ctx *cli.Context) error { } } - acc, err := newAccountFromWIF(ctx.String("wif")) + acc, err := newAccountFromWIF(ctx.App.Writer, ctx.String("wif")) if err != nil { return cli.NewExitError(err, 1) } @@ -419,7 +420,7 @@ func importDeployed(ctx *cli.Context) error { return cli.NewExitError(fmt.Errorf("invalid contract hash: %w", err), 1) } - acc, err := newAccountFromWIF(ctx.String("wif")) + acc, err := newAccountFromWIF(ctx.App.Writer, ctx.String("wif")) if err != nil { return cli.NewExitError(err, 1) } @@ -463,7 +464,7 @@ func importWallet(ctx *cli.Context) error { } defer wall.Close() - acc, err := newAccountFromWIF(ctx.String("wif")) + acc, err := newAccountFromWIF(ctx.App.Writer, ctx.String("wif")) if err != nil { return cli.NewExitError(err, 1) } @@ -502,8 +503,8 @@ func removeAccount(ctx *cli.Context) error { } if !ctx.Bool("force") { - fmt.Printf("Account %s will be removed. This action is irreversible.\n", addrArg) - if ok := askForConsent(); !ok { + fmt.Fprintf(ctx.App.Writer, "Account %s will be removed. This action is irreversible.\n", addrArg) + if ok := askForConsent(ctx.App.Writer); !ok { return nil } } @@ -516,8 +517,8 @@ func removeAccount(ctx *cli.Context) error { return nil } -func askForConsent() bool { - fmt.Print("Are you sure? [y/N]: ") +func askForConsent(w io.Writer) bool { + fmt.Fprintln(w, "Are you sure? [y/N]: ") reader := bufio.NewReader(os.Stdin) response, err := reader.ReadString('\n') if err == nil { @@ -526,7 +527,7 @@ func askForConsent() bool { return true } } - fmt.Println("Cancelled.") + fmt.Fprintln(w, "Cancelled.") return false } @@ -536,7 +537,7 @@ func dumpWallet(ctx *cli.Context) error { return cli.NewExitError(err, 1) } if ctx.Bool("decrypt") { - pass, err := readPassword("Enter wallet password > ") + pass, err := readPassword(ctx.App.Writer, "Enter wallet password > ") if err != nil { return cli.NewExitError(err, 1) } @@ -548,7 +549,7 @@ func dumpWallet(ctx *cli.Context) error { } } } - fmtPrintWallet(wall) + fmtPrintWallet(ctx.App.Writer, wall) return nil } @@ -571,20 +572,20 @@ func createWallet(ctx *cli.Context) error { } } - fmtPrintWallet(wall) - fmt.Printf("wallet successfully created, file location is %s\n", wall.Path()) + fmtPrintWallet(ctx.App.Writer, wall) + fmt.Fprintf(ctx.App.Writer, "wallet successfully created, file location is %s\n", wall.Path()) return nil } -func readAccountInfo() (string, string, error) { +func readAccountInfo(w io.Writer) (string, string, error) { buf := bufio.NewReader(os.Stdin) - fmt.Print("Enter the name of the account > ") + fmt.Fprint(w, "Enter the name of the account > ") rawName, _ := buf.ReadBytes('\n') - phrase, err := readPassword("Enter passphrase > ") + phrase, err := readPassword(w, "Enter passphrase > ") if err != nil { return "", "", err } - phraseCheck, err := readPassword("Confirm passphrase > ") + phraseCheck, err := readPassword(w, "Confirm passphrase > ") if err != nil { return "", "", err } @@ -598,7 +599,7 @@ func readAccountInfo() (string, string, error) { } func createAccount(ctx *cli.Context, wall *wallet.Wallet) error { - name, phrase, err := readAccountInfo() + name, phrase, err := readAccountInfo(ctx.App.Writer) if err != nil { return err } @@ -612,11 +613,11 @@ func openWallet(path string) (*wallet.Wallet, error) { return wallet.NewWalletFromFile(path) } -func newAccountFromWIF(wif string) (*wallet.Account, error) { +func newAccountFromWIF(w io.Writer, wif string) (*wallet.Account, error) { // note: NEP2 strings always have length of 58 even though // base58 strings can have different lengths even if slice lengths are equal if len(wif) == 58 { - pass, err := readPassword("Enter password > ") + pass, err := readPassword(w, "Enter password > ") if err != nil { return nil, err } @@ -629,8 +630,8 @@ func newAccountFromWIF(wif string) (*wallet.Account, error) { return nil, err } - fmt.Println("Provided WIF was unencrypted. Wallet can contain only encrypted keys.") - name, pass, err := readAccountInfo() + fmt.Fprintln(w, "Provided WIF was unencrypted. Wallet can contain only encrypted keys.") + name, pass, err := readAccountInfo(w) if err != nil { return nil, err } @@ -654,19 +655,19 @@ func addAccountAndSave(w *wallet.Wallet, acc *wallet.Account) error { return w.Save() } -func readPassword(prompt string) (string, error) { - fmt.Print(prompt) +func readPassword(w io.Writer, prompt string) (string, error) { + fmt.Fprint(w, prompt) rawPass, err := terminal.ReadPassword(syscall.Stdin) - fmt.Println() + fmt.Fprintln(w) if err != nil { return "", err } return strings.TrimRight(string(rawPass), "\n"), nil } -func fmtPrintWallet(wall *wallet.Wallet) { +func fmtPrintWallet(w io.Writer, wall *wallet.Wallet) { b, _ := wall.JSON() - fmt.Println("") - fmt.Println(string(b)) - fmt.Println("") + fmt.Fprintln(w, "") + fmt.Fprintln(w, string(b)) + fmt.Fprintln(w, "") }