Merge pull request #2731 from nspcc-dev/cli-tx-outs
Add ability to save any tx in the CLI
This commit is contained in:
commit
5c94ffab37
8 changed files with 148 additions and 193 deletions
|
@ -8,19 +8,17 @@ import (
|
||||||
"os"
|
"os"
|
||||||
"path/filepath"
|
"path/filepath"
|
||||||
"strings"
|
"strings"
|
||||||
"time"
|
|
||||||
|
|
||||||
"github.com/nspcc-dev/neo-go/cli/cmdargs"
|
"github.com/nspcc-dev/neo-go/cli/cmdargs"
|
||||||
"github.com/nspcc-dev/neo-go/cli/flags"
|
"github.com/nspcc-dev/neo-go/cli/flags"
|
||||||
"github.com/nspcc-dev/neo-go/cli/input"
|
"github.com/nspcc-dev/neo-go/cli/input"
|
||||||
"github.com/nspcc-dev/neo-go/cli/options"
|
"github.com/nspcc-dev/neo-go/cli/options"
|
||||||
"github.com/nspcc-dev/neo-go/cli/paramcontext"
|
"github.com/nspcc-dev/neo-go/cli/txctx"
|
||||||
cliwallet "github.com/nspcc-dev/neo-go/cli/wallet"
|
cliwallet "github.com/nspcc-dev/neo-go/cli/wallet"
|
||||||
"github.com/nspcc-dev/neo-go/pkg/compiler"
|
"github.com/nspcc-dev/neo-go/pkg/compiler"
|
||||||
"github.com/nspcc-dev/neo-go/pkg/core/state"
|
"github.com/nspcc-dev/neo-go/pkg/core/state"
|
||||||
"github.com/nspcc-dev/neo-go/pkg/core/transaction"
|
"github.com/nspcc-dev/neo-go/pkg/core/transaction"
|
||||||
"github.com/nspcc-dev/neo-go/pkg/encoding/address"
|
"github.com/nspcc-dev/neo-go/pkg/encoding/address"
|
||||||
"github.com/nspcc-dev/neo-go/pkg/encoding/fixedn"
|
|
||||||
"github.com/nspcc-dev/neo-go/pkg/neorpc/result"
|
"github.com/nspcc-dev/neo-go/pkg/neorpc/result"
|
||||||
"github.com/nspcc-dev/neo-go/pkg/rpcclient/actor"
|
"github.com/nspcc-dev/neo-go/pkg/rpcclient/actor"
|
||||||
"github.com/nspcc-dev/neo-go/pkg/rpcclient/invoker"
|
"github.com/nspcc-dev/neo-go/pkg/rpcclient/invoker"
|
||||||
|
@ -62,22 +60,6 @@ var (
|
||||||
Name: addressFlagName,
|
Name: addressFlagName,
|
||||||
Usage: "address to use as transaction signee (and gas source)",
|
Usage: "address to use as transaction signee (and gas source)",
|
||||||
}
|
}
|
||||||
gasFlag = flags.Fixed8Flag{
|
|
||||||
Name: "gas, g",
|
|
||||||
Usage: "network fee to add to the transaction (prioritizing it)",
|
|
||||||
}
|
|
||||||
sysGasFlag = flags.Fixed8Flag{
|
|
||||||
Name: "sysgas, e",
|
|
||||||
Usage: "system fee to add to transaction (compensating for execution)",
|
|
||||||
}
|
|
||||||
outFlag = cli.StringFlag{
|
|
||||||
Name: "out",
|
|
||||||
Usage: "file to put JSON transaction to",
|
|
||||||
}
|
|
||||||
forceFlag = cli.BoolFlag{
|
|
||||||
Name: "force",
|
|
||||||
Usage: "force-push the transaction in case of bad VM state after test script invocation",
|
|
||||||
}
|
|
||||||
)
|
)
|
||||||
|
|
||||||
// ModVersion contains `pkg/interop` module version
|
// ModVersion contains `pkg/interop` module version
|
||||||
|
@ -120,10 +102,10 @@ func NewCommands() []cli.Command {
|
||||||
walletFlag,
|
walletFlag,
|
||||||
walletConfigFlag,
|
walletConfigFlag,
|
||||||
addressFlag,
|
addressFlag,
|
||||||
gasFlag,
|
txctx.GasFlag,
|
||||||
sysGasFlag,
|
txctx.SysGasFlag,
|
||||||
outFlag,
|
txctx.OutFlag,
|
||||||
forceFlag,
|
txctx.ForceFlag,
|
||||||
}
|
}
|
||||||
invokeFunctionFlags = append(invokeFunctionFlags, options.RPC...)
|
invokeFunctionFlags = append(invokeFunctionFlags, options.RPC...)
|
||||||
deployFlags := append(invokeFunctionFlags, []cli.Flag{
|
deployFlags := append(invokeFunctionFlags, []cli.Flag{
|
||||||
|
@ -668,7 +650,6 @@ func invokeInternal(ctx *cli.Context, signAndPush bool) error {
|
||||||
func invokeWithArgs(ctx *cli.Context, acc *wallet.Account, wall *wallet.Wallet, script util.Uint160, operation string, params []interface{}, cosigners []transaction.Signer) error {
|
func invokeWithArgs(ctx *cli.Context, acc *wallet.Account, wall *wallet.Wallet, script util.Uint160, operation string, params []interface{}, cosigners []transaction.Signer) error {
|
||||||
var (
|
var (
|
||||||
err error
|
err error
|
||||||
gas, sysgas fixedn.Fixed8
|
|
||||||
signersAccounts []actor.SignerAccount
|
signersAccounts []actor.SignerAccount
|
||||||
resp *result.Invoke
|
resp *result.Invoke
|
||||||
signAndPush = acc != nil
|
signAndPush = acc != nil
|
||||||
|
@ -676,8 +657,6 @@ func invokeWithArgs(ctx *cli.Context, acc *wallet.Account, wall *wallet.Wallet,
|
||||||
act *actor.Actor
|
act *actor.Actor
|
||||||
)
|
)
|
||||||
if signAndPush {
|
if signAndPush {
|
||||||
gas = flags.Fixed8FromContext(ctx, "gas")
|
|
||||||
sysgas = flags.Fixed8FromContext(ctx, "sysgas")
|
|
||||||
signersAccounts, err = cmdargs.GetSignersAccounts(acc, wall, cosigners, transaction.None)
|
signersAccounts, err = cmdargs.GetSignersAccounts(acc, wall, cosigners, transaction.None)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return cli.NewExitError(fmt.Errorf("invalid signers: %w", err), 1)
|
return cli.NewExitError(fmt.Errorf("invalid signers: %w", err), 1)
|
||||||
|
@ -731,44 +710,16 @@ func invokeWithArgs(ctx *cli.Context, acc *wallet.Account, wall *wallet.Wallet,
|
||||||
}
|
}
|
||||||
|
|
||||||
fmt.Fprintln(ctx.App.Writer, string(b))
|
fmt.Fprintln(ctx.App.Writer, string(b))
|
||||||
} else {
|
return nil
|
||||||
|
}
|
||||||
if len(resp.Script) == 0 {
|
if len(resp.Script) == 0 {
|
||||||
return cli.NewExitError(errors.New("no script returned from the RPC node"), 1)
|
return cli.NewExitError(errors.New("no script returned from the RPC node"), 1)
|
||||||
}
|
}
|
||||||
ver := act.GetVersion()
|
tx, err := act.MakeUnsignedUncheckedRun(resp.Script, resp.GasConsumed, nil)
|
||||||
tx, err := act.MakeUnsignedUncheckedRun(resp.Script, resp.GasConsumed+int64(sysgas), nil)
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return cli.NewExitError(fmt.Errorf("failed to create tx: %w", err), 1)
|
return cli.NewExitError(fmt.Errorf("failed to create tx: %w", err), 1)
|
||||||
}
|
}
|
||||||
tx.NetworkFee += int64(gas)
|
return txctx.SignAndSend(ctx, act, acc, tx)
|
||||||
if out != "" {
|
|
||||||
// Make a long-lived transaction, it's to be signed manually.
|
|
||||||
tx.ValidUntilBlock += (ver.Protocol.MaxValidUntilBlockIncrement - uint32(ver.Protocol.ValidatorsCount)) - 2
|
|
||||||
m := act.GetNetwork()
|
|
||||||
if err := paramcontext.InitAndSave(m, tx, acc, out); err != nil {
|
|
||||||
return cli.NewExitError(err, 1)
|
|
||||||
}
|
|
||||||
fmt.Fprintln(ctx.App.Writer, tx.Hash().StringLE())
|
|
||||||
} else {
|
|
||||||
if !ctx.Bool("force") {
|
|
||||||
promptTime := time.Now()
|
|
||||||
err := input.ConfirmTx(ctx.App.Writer, tx)
|
|
||||||
if err != nil {
|
|
||||||
return cli.NewExitError(err, 1)
|
|
||||||
}
|
|
||||||
waitTime := time.Since(promptTime)
|
|
||||||
// Compensate for confirmation waiting.
|
|
||||||
tx.ValidUntilBlock += uint32((waitTime.Milliseconds() / int64(ver.Protocol.MillisecondsPerBlock))) + 1
|
|
||||||
}
|
|
||||||
txHash, _, err := act.SignAndSend(tx)
|
|
||||||
if err != nil {
|
|
||||||
return cli.NewExitError(fmt.Errorf("failed to push invocation tx: %w", err), 1)
|
|
||||||
}
|
|
||||||
fmt.Fprintf(ctx.App.Writer, "Sent invocation transaction %s\n", txHash.StringLE())
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return nil
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func testInvokeScript(ctx *cli.Context) error {
|
func testInvokeScript(ctx *cli.Context) error {
|
||||||
|
|
79
cli/txctx/tx.go
Normal file
79
cli/txctx/tx.go
Normal file
|
@ -0,0 +1,79 @@
|
||||||
|
/*
|
||||||
|
Package txctx contains helper functions that deal with transactions in CLI context.
|
||||||
|
*/
|
||||||
|
package txctx
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"time"
|
||||||
|
|
||||||
|
"github.com/nspcc-dev/neo-go/cli/flags"
|
||||||
|
"github.com/nspcc-dev/neo-go/cli/input"
|
||||||
|
"github.com/nspcc-dev/neo-go/cli/paramcontext"
|
||||||
|
"github.com/nspcc-dev/neo-go/pkg/core/transaction"
|
||||||
|
"github.com/nspcc-dev/neo-go/pkg/rpcclient/actor"
|
||||||
|
"github.com/nspcc-dev/neo-go/pkg/wallet"
|
||||||
|
"github.com/urfave/cli"
|
||||||
|
)
|
||||||
|
|
||||||
|
var (
|
||||||
|
// GasFlag is a flag used for the additional network fee.
|
||||||
|
GasFlag = flags.Fixed8Flag{
|
||||||
|
Name: "gas, g",
|
||||||
|
Usage: "network fee to add to the transaction (prioritizing it)",
|
||||||
|
}
|
||||||
|
// SysGasFlag is a flag used for the additional system fee.
|
||||||
|
SysGasFlag = flags.Fixed8Flag{
|
||||||
|
Name: "sysgas, e",
|
||||||
|
Usage: "system fee to add to the transaction (compensating for execution)",
|
||||||
|
}
|
||||||
|
// OutFlag is a flag used for file output.
|
||||||
|
OutFlag = cli.StringFlag{
|
||||||
|
Name: "out",
|
||||||
|
Usage: "file (JSON) to put signature context with a transaction to",
|
||||||
|
}
|
||||||
|
// ForceFlag is a flag used to force transaction send.
|
||||||
|
ForceFlag = cli.BoolFlag{
|
||||||
|
Name: "force",
|
||||||
|
Usage: "Do not ask for a confirmation (and ignore errors)",
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
|
// SignAndSend adds network and system fees to the provided transaction and
|
||||||
|
// either sends it to the network (with a confirmation or --force flag) or saves
|
||||||
|
// it into a file (given in the --out flag).
|
||||||
|
func SignAndSend(ctx *cli.Context, act *actor.Actor, acc *wallet.Account, tx *transaction.Transaction) error {
|
||||||
|
var (
|
||||||
|
err error
|
||||||
|
gas = flags.Fixed8FromContext(ctx, "gas")
|
||||||
|
sysgas = flags.Fixed8FromContext(ctx, "sysgas")
|
||||||
|
ver = act.GetVersion()
|
||||||
|
)
|
||||||
|
|
||||||
|
tx.SystemFee += int64(sysgas)
|
||||||
|
tx.NetworkFee += int64(gas)
|
||||||
|
|
||||||
|
if outFile := ctx.String("out"); outFile != "" {
|
||||||
|
// Make a long-lived transaction, it's to be signed manually.
|
||||||
|
tx.ValidUntilBlock += (ver.Protocol.MaxValidUntilBlockIncrement - uint32(ver.Protocol.ValidatorsCount)) - 2
|
||||||
|
err = paramcontext.InitAndSave(ver.Protocol.Network, tx, acc, outFile)
|
||||||
|
} else {
|
||||||
|
if !ctx.Bool("force") {
|
||||||
|
promptTime := time.Now()
|
||||||
|
err := input.ConfirmTx(ctx.App.Writer, tx)
|
||||||
|
if err != nil {
|
||||||
|
return cli.NewExitError(err, 1)
|
||||||
|
}
|
||||||
|
waitTime := time.Since(promptTime)
|
||||||
|
// Compensate for confirmation waiting.
|
||||||
|
tx.ValidUntilBlock += uint32((waitTime.Milliseconds() / int64(ver.Protocol.MillisecondsPerBlock))) + 1
|
||||||
|
}
|
||||||
|
_, _, err = act.SignAndSend(tx)
|
||||||
|
}
|
||||||
|
if err != nil {
|
||||||
|
return cli.NewExitError(err, 1)
|
||||||
|
}
|
||||||
|
|
||||||
|
fmt.Fprintln(ctx.App.Writer, tx.Hash().StringLE())
|
||||||
|
return nil
|
||||||
|
}
|
|
@ -55,7 +55,8 @@ func TestRegisterCandidate(t *testing.T) {
|
||||||
e.Run(t, "neo-go", "wallet", "candidate", "register",
|
e.Run(t, "neo-go", "wallet", "candidate", "register",
|
||||||
"--rpc-endpoint", "http://"+e.RPC.Addr,
|
"--rpc-endpoint", "http://"+e.RPC.Addr,
|
||||||
"--wallet", testcli.ValidatorWallet,
|
"--wallet", testcli.ValidatorWallet,
|
||||||
"--address", validatorAddress)
|
"--address", validatorAddress,
|
||||||
|
"--force")
|
||||||
e.CheckTxPersisted(t)
|
e.CheckTxPersisted(t)
|
||||||
|
|
||||||
vs, err := e.Chain.GetEnrollments()
|
vs, err := e.Chain.GetEnrollments()
|
||||||
|
@ -77,7 +78,8 @@ func TestRegisterCandidate(t *testing.T) {
|
||||||
"--rpc-endpoint", "http://"+e.RPC.Addr,
|
"--rpc-endpoint", "http://"+e.RPC.Addr,
|
||||||
"--wallet", testcli.ValidatorWallet,
|
"--wallet", testcli.ValidatorWallet,
|
||||||
"--address", validatorAddress,
|
"--address", validatorAddress,
|
||||||
"--candidate", validatorHex)
|
"--candidate", validatorHex,
|
||||||
|
"--force")
|
||||||
_, index := e.CheckTxPersisted(t)
|
_, index := e.CheckTxPersisted(t)
|
||||||
|
|
||||||
vs, err = e.Chain.GetEnrollments()
|
vs, err = e.Chain.GetEnrollments()
|
||||||
|
@ -110,7 +112,8 @@ func TestRegisterCandidate(t *testing.T) {
|
||||||
e.Run(t, "neo-go", "wallet", "candidate", "vote",
|
e.Run(t, "neo-go", "wallet", "candidate", "vote",
|
||||||
"--rpc-endpoint", "http://"+e.RPC.Addr,
|
"--rpc-endpoint", "http://"+e.RPC.Addr,
|
||||||
"--wallet", testcli.ValidatorWallet,
|
"--wallet", testcli.ValidatorWallet,
|
||||||
"--address", validatorAddress)
|
"--address", validatorAddress,
|
||||||
|
"--force")
|
||||||
_, index = e.CheckTxPersisted(t)
|
_, index = e.CheckTxPersisted(t)
|
||||||
|
|
||||||
vs, err = e.Chain.GetEnrollments()
|
vs, err = e.Chain.GetEnrollments()
|
||||||
|
@ -143,7 +146,8 @@ func TestRegisterCandidate(t *testing.T) {
|
||||||
e.Run(t, "neo-go", "wallet", "candidate", "unregister",
|
e.Run(t, "neo-go", "wallet", "candidate", "unregister",
|
||||||
"--rpc-endpoint", "http://"+e.RPC.Addr,
|
"--rpc-endpoint", "http://"+e.RPC.Addr,
|
||||||
"--wallet", testcli.ValidatorWallet,
|
"--wallet", testcli.ValidatorWallet,
|
||||||
"--address", validatorAddress)
|
"--address", validatorAddress,
|
||||||
|
"--force")
|
||||||
e.CheckTxPersisted(t)
|
e.CheckTxPersisted(t)
|
||||||
|
|
||||||
vs, err = e.Chain.GetEnrollments()
|
vs, err = e.Chain.GetEnrollments()
|
||||||
|
|
|
@ -9,6 +9,7 @@ import (
|
||||||
"github.com/nspcc-dev/neo-go/cli/cmdargs"
|
"github.com/nspcc-dev/neo-go/cli/cmdargs"
|
||||||
"github.com/nspcc-dev/neo-go/cli/flags"
|
"github.com/nspcc-dev/neo-go/cli/flags"
|
||||||
"github.com/nspcc-dev/neo-go/cli/options"
|
"github.com/nspcc-dev/neo-go/cli/options"
|
||||||
|
"github.com/nspcc-dev/neo-go/cli/txctx"
|
||||||
"github.com/nspcc-dev/neo-go/pkg/config"
|
"github.com/nspcc-dev/neo-go/pkg/config"
|
||||||
"github.com/nspcc-dev/neo-go/pkg/encoding/address"
|
"github.com/nspcc-dev/neo-go/pkg/encoding/address"
|
||||||
"github.com/nspcc-dev/neo-go/pkg/neorpc/result"
|
"github.com/nspcc-dev/neo-go/pkg/neorpc/result"
|
||||||
|
@ -94,7 +95,7 @@ func newNEP11Commands() []cli.Command {
|
||||||
walletPathFlag,
|
walletPathFlag,
|
||||||
walletConfigFlag,
|
walletConfigFlag,
|
||||||
tokenFlag,
|
tokenFlag,
|
||||||
forceFlag,
|
txctx.ForceFlag,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
|
|
@ -6,13 +6,11 @@ import (
|
||||||
"fmt"
|
"fmt"
|
||||||
"math/big"
|
"math/big"
|
||||||
"strings"
|
"strings"
|
||||||
"time"
|
|
||||||
|
|
||||||
"github.com/nspcc-dev/neo-go/cli/cmdargs"
|
"github.com/nspcc-dev/neo-go/cli/cmdargs"
|
||||||
"github.com/nspcc-dev/neo-go/cli/flags"
|
"github.com/nspcc-dev/neo-go/cli/flags"
|
||||||
"github.com/nspcc-dev/neo-go/cli/input"
|
|
||||||
"github.com/nspcc-dev/neo-go/cli/options"
|
"github.com/nspcc-dev/neo-go/cli/options"
|
||||||
"github.com/nspcc-dev/neo-go/cli/paramcontext"
|
"github.com/nspcc-dev/neo-go/cli/txctx"
|
||||||
"github.com/nspcc-dev/neo-go/pkg/core/native/nativenames"
|
"github.com/nspcc-dev/neo-go/pkg/core/native/nativenames"
|
||||||
"github.com/nspcc-dev/neo-go/pkg/core/transaction"
|
"github.com/nspcc-dev/neo-go/pkg/core/transaction"
|
||||||
"github.com/nspcc-dev/neo-go/pkg/encoding/address"
|
"github.com/nspcc-dev/neo-go/pkg/encoding/address"
|
||||||
|
@ -37,14 +35,6 @@ var (
|
||||||
Name: "token",
|
Name: "token",
|
||||||
Usage: "Token to use (hash or name (for NEO/GAS or imported tokens))",
|
Usage: "Token to use (hash or name (for NEO/GAS or imported tokens))",
|
||||||
}
|
}
|
||||||
gasFlag = flags.Fixed8Flag{
|
|
||||||
Name: "gas, g",
|
|
||||||
Usage: "network fee to add to the transaction (prioritizing it)",
|
|
||||||
}
|
|
||||||
sysGasFlag = flags.Fixed8Flag{
|
|
||||||
Name: "sysgas, e",
|
|
||||||
Usage: "system fee to add to transaction (compensating for execution)",
|
|
||||||
}
|
|
||||||
baseBalanceFlags = []cli.Flag{
|
baseBalanceFlags = []cli.Flag{
|
||||||
walletPathFlag,
|
walletPathFlag,
|
||||||
walletConfigFlag,
|
walletConfigFlag,
|
||||||
|
@ -65,13 +55,13 @@ var (
|
||||||
baseTransferFlags = []cli.Flag{
|
baseTransferFlags = []cli.Flag{
|
||||||
walletPathFlag,
|
walletPathFlag,
|
||||||
walletConfigFlag,
|
walletConfigFlag,
|
||||||
outFlag,
|
txctx.OutFlag,
|
||||||
fromAddrFlag,
|
fromAddrFlag,
|
||||||
toAddrFlag,
|
toAddrFlag,
|
||||||
tokenFlag,
|
tokenFlag,
|
||||||
gasFlag,
|
txctx.GasFlag,
|
||||||
sysGasFlag,
|
txctx.SysGasFlag,
|
||||||
forceFlag,
|
txctx.ForceFlag,
|
||||||
cli.StringFlag{
|
cli.StringFlag{
|
||||||
Name: "amount",
|
Name: "amount",
|
||||||
Usage: "Amount of asset to send",
|
Usage: "Amount of asset to send",
|
||||||
|
@ -80,11 +70,11 @@ var (
|
||||||
multiTransferFlags = append([]cli.Flag{
|
multiTransferFlags = append([]cli.Flag{
|
||||||
walletPathFlag,
|
walletPathFlag,
|
||||||
walletConfigFlag,
|
walletConfigFlag,
|
||||||
outFlag,
|
txctx.OutFlag,
|
||||||
fromAddrFlag,
|
fromAddrFlag,
|
||||||
gasFlag,
|
txctx.GasFlag,
|
||||||
sysGasFlag,
|
txctx.SysGasFlag,
|
||||||
forceFlag,
|
txctx.ForceFlag,
|
||||||
}, options.RPC...)
|
}, options.RPC...)
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -143,7 +133,7 @@ func newNEP17Commands() []cli.Command {
|
||||||
walletPathFlag,
|
walletPathFlag,
|
||||||
walletConfigFlag,
|
walletConfigFlag,
|
||||||
tokenFlag,
|
tokenFlag,
|
||||||
forceFlag,
|
txctx.ForceFlag,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
@ -599,7 +589,7 @@ func multiTransferNEP17(ctx *cli.Context) error {
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return cli.NewExitError(fmt.Errorf("can't make transaction: %w", err), 1)
|
return cli.NewExitError(fmt.Errorf("can't make transaction: %w", err), 1)
|
||||||
}
|
}
|
||||||
return signAndSendSomeTransaction(ctx, act, acc, tx)
|
return txctx.SignAndSend(ctx, act, acc, tx)
|
||||||
}
|
}
|
||||||
|
|
||||||
func transferNEP17(ctx *cli.Context) error {
|
func transferNEP17(ctx *cli.Context) error {
|
||||||
|
@ -697,7 +687,7 @@ func transferNEP(ctx *cli.Context, standard string) error {
|
||||||
return cli.NewExitError(fmt.Errorf("can't make transaction: %w", err), 1)
|
return cli.NewExitError(fmt.Errorf("can't make transaction: %w", err), 1)
|
||||||
}
|
}
|
||||||
|
|
||||||
return signAndSendSomeTransaction(ctx, act, acc, tx)
|
return txctx.SignAndSend(ctx, act, acc, tx)
|
||||||
}
|
}
|
||||||
|
|
||||||
func makeMultiTransferNEP17(act *actor.Actor, recipients []rpcclient.TransferTarget) (*transaction.Transaction, error) {
|
func makeMultiTransferNEP17(act *actor.Actor, recipients []rpcclient.TransferTarget) (*transaction.Transaction, error) {
|
||||||
|
@ -713,42 +703,6 @@ func makeMultiTransferNEP17(act *actor.Actor, recipients []rpcclient.TransferTar
|
||||||
return act.MakeUnsignedRun(script, nil)
|
return act.MakeUnsignedRun(script, nil)
|
||||||
}
|
}
|
||||||
|
|
||||||
func signAndSendSomeTransaction(ctx *cli.Context, act *actor.Actor, acc *wallet.Account, tx *transaction.Transaction) error {
|
|
||||||
var (
|
|
||||||
err error
|
|
||||||
gas = flags.Fixed8FromContext(ctx, "gas")
|
|
||||||
sysgas = flags.Fixed8FromContext(ctx, "sysgas")
|
|
||||||
)
|
|
||||||
|
|
||||||
tx.SystemFee += int64(sysgas)
|
|
||||||
tx.NetworkFee += int64(gas)
|
|
||||||
|
|
||||||
ver := act.GetVersion()
|
|
||||||
if outFile := ctx.String("out"); outFile != "" {
|
|
||||||
// Make a long-lived transaction, it's to be signed manually.
|
|
||||||
tx.ValidUntilBlock += (ver.Protocol.MaxValidUntilBlockIncrement - uint32(ver.Protocol.ValidatorsCount)) - 2
|
|
||||||
err = paramcontext.InitAndSave(ver.Protocol.Network, tx, acc, outFile)
|
|
||||||
} else {
|
|
||||||
if !ctx.Bool("force") {
|
|
||||||
promptTime := time.Now()
|
|
||||||
err := input.ConfirmTx(ctx.App.Writer, tx)
|
|
||||||
if err != nil {
|
|
||||||
return cli.NewExitError(err, 1)
|
|
||||||
}
|
|
||||||
waitTime := time.Since(promptTime)
|
|
||||||
// Compensate for confirmation waiting.
|
|
||||||
tx.ValidUntilBlock += uint32((waitTime.Milliseconds() / int64(ver.Protocol.MillisecondsPerBlock))) + 1
|
|
||||||
}
|
|
||||||
_, _, err = act.SignAndSend(tx)
|
|
||||||
}
|
|
||||||
if err != nil {
|
|
||||||
return cli.NewExitError(err, 1)
|
|
||||||
}
|
|
||||||
|
|
||||||
fmt.Fprintln(ctx.App.Writer, tx.Hash().StringLE())
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func getDefaultAddress(fromFlag *flags.Address, w *wallet.Wallet) (util.Uint160, error) {
|
func getDefaultAddress(fromFlag *flags.Address, w *wallet.Wallet) (util.Uint160, error) {
|
||||||
if fromFlag.IsSet {
|
if fromFlag.IsSet {
|
||||||
return fromFlag.Uint160(), nil
|
return fromFlag.Uint160(), nil
|
||||||
|
|
|
@ -7,6 +7,7 @@ import (
|
||||||
"github.com/nspcc-dev/neo-go/cli/flags"
|
"github.com/nspcc-dev/neo-go/cli/flags"
|
||||||
"github.com/nspcc-dev/neo-go/cli/input"
|
"github.com/nspcc-dev/neo-go/cli/input"
|
||||||
"github.com/nspcc-dev/neo-go/cli/options"
|
"github.com/nspcc-dev/neo-go/cli/options"
|
||||||
|
"github.com/nspcc-dev/neo-go/cli/txctx"
|
||||||
"github.com/nspcc-dev/neo-go/pkg/core/transaction"
|
"github.com/nspcc-dev/neo-go/pkg/core/transaction"
|
||||||
"github.com/nspcc-dev/neo-go/pkg/crypto/keys"
|
"github.com/nspcc-dev/neo-go/pkg/crypto/keys"
|
||||||
"github.com/nspcc-dev/neo-go/pkg/encoding/address"
|
"github.com/nspcc-dev/neo-go/pkg/encoding/address"
|
||||||
|
@ -22,12 +23,15 @@ func newValidatorCommands() []cli.Command {
|
||||||
{
|
{
|
||||||
Name: "register",
|
Name: "register",
|
||||||
Usage: "register as a new candidate",
|
Usage: "register as a new candidate",
|
||||||
UsageText: "register -w <path> -r <rpc> -a <addr>",
|
UsageText: "register -w <path> -r <rpc> -a <addr> [-g gas] [-e sysgas] [--out file] [--force]",
|
||||||
Action: handleRegister,
|
Action: handleRegister,
|
||||||
Flags: append([]cli.Flag{
|
Flags: append([]cli.Flag{
|
||||||
walletPathFlag,
|
walletPathFlag,
|
||||||
walletConfigFlag,
|
walletConfigFlag,
|
||||||
gasFlag,
|
txctx.GasFlag,
|
||||||
|
txctx.SysGasFlag,
|
||||||
|
txctx.OutFlag,
|
||||||
|
txctx.ForceFlag,
|
||||||
flags.AddressFlag{
|
flags.AddressFlag{
|
||||||
Name: "address, a",
|
Name: "address, a",
|
||||||
Usage: "Address to register",
|
Usage: "Address to register",
|
||||||
|
@ -37,12 +41,15 @@ func newValidatorCommands() []cli.Command {
|
||||||
{
|
{
|
||||||
Name: "unregister",
|
Name: "unregister",
|
||||||
Usage: "unregister self as a candidate",
|
Usage: "unregister self as a candidate",
|
||||||
UsageText: "unregister -w <path> -r <rpc> -a <addr>",
|
UsageText: "unregister -w <path> -r <rpc> -a <addr> [-g gas] [-e sysgas] [--out file] [--force]",
|
||||||
Action: handleUnregister,
|
Action: handleUnregister,
|
||||||
Flags: append([]cli.Flag{
|
Flags: append([]cli.Flag{
|
||||||
walletPathFlag,
|
walletPathFlag,
|
||||||
walletConfigFlag,
|
walletConfigFlag,
|
||||||
gasFlag,
|
txctx.GasFlag,
|
||||||
|
txctx.SysGasFlag,
|
||||||
|
txctx.OutFlag,
|
||||||
|
txctx.ForceFlag,
|
||||||
flags.AddressFlag{
|
flags.AddressFlag{
|
||||||
Name: "address, a",
|
Name: "address, a",
|
||||||
Usage: "Address to unregister",
|
Usage: "Address to unregister",
|
||||||
|
@ -52,7 +59,7 @@ func newValidatorCommands() []cli.Command {
|
||||||
{
|
{
|
||||||
Name: "vote",
|
Name: "vote",
|
||||||
Usage: "vote for a validator",
|
Usage: "vote for a validator",
|
||||||
UsageText: "vote -w <path> -r <rpc> [-s <timeout>] [-g gas] -a <addr> [-c <public key>]",
|
UsageText: "vote -w <path> -r <rpc> [-s <timeout>] [-g gas] [-e sysgas] -a <addr> [-c <public key>] [--out file] [--force]",
|
||||||
Description: `Votes for a validator by calling "vote" method of a NEO native
|
Description: `Votes for a validator by calling "vote" method of a NEO native
|
||||||
contract. Do not provide candidate argument to perform unvoting.
|
contract. Do not provide candidate argument to perform unvoting.
|
||||||
`,
|
`,
|
||||||
|
@ -60,7 +67,10 @@ func newValidatorCommands() []cli.Command {
|
||||||
Flags: append([]cli.Flag{
|
Flags: append([]cli.Flag{
|
||||||
walletPathFlag,
|
walletPathFlag,
|
||||||
walletConfigFlag,
|
walletConfigFlag,
|
||||||
gasFlag,
|
txctx.GasFlag,
|
||||||
|
txctx.SysGasFlag,
|
||||||
|
txctx.OutFlag,
|
||||||
|
txctx.ForceFlag,
|
||||||
flags.AddressFlag{
|
flags.AddressFlag{
|
||||||
Name: "address, a",
|
Name: "address, a",
|
||||||
Usage: "Address to vote from",
|
Usage: "Address to vote from",
|
||||||
|
@ -118,19 +128,12 @@ func handleNeoAction(ctx *cli.Context, mkTx func(*neo.Contract, util.Uint160, *w
|
||||||
return cli.NewExitError(fmt.Errorf("RPC actor issue: %w", err), 1)
|
return cli.NewExitError(fmt.Errorf("RPC actor issue: %w", err), 1)
|
||||||
}
|
}
|
||||||
|
|
||||||
gas := flags.Fixed8FromContext(ctx, "gas")
|
|
||||||
contract := neo.New(act)
|
contract := neo.New(act)
|
||||||
tx, err := mkTx(contract, addr, acc)
|
tx, err := mkTx(contract, addr, acc)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return cli.NewExitError(err, 1)
|
return cli.NewExitError(err, 1)
|
||||||
}
|
}
|
||||||
tx.NetworkFee += int64(gas)
|
return txctx.SignAndSend(ctx, act, acc, tx)
|
||||||
res, _, err := act.SignAndSend(tx)
|
|
||||||
if err != nil {
|
|
||||||
return cli.NewExitError(fmt.Errorf("failed to sign/send transaction: %w", err), 1)
|
|
||||||
}
|
|
||||||
fmt.Fprintln(ctx.App.Writer, res.StringLE())
|
|
||||||
return nil
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func handleVote(ctx *cli.Context) error {
|
func handleVote(ctx *cli.Context) error {
|
||||||
|
|
|
@ -14,13 +14,15 @@ import (
|
||||||
"github.com/nspcc-dev/neo-go/cli/flags"
|
"github.com/nspcc-dev/neo-go/cli/flags"
|
||||||
"github.com/nspcc-dev/neo-go/cli/input"
|
"github.com/nspcc-dev/neo-go/cli/input"
|
||||||
"github.com/nspcc-dev/neo-go/cli/options"
|
"github.com/nspcc-dev/neo-go/cli/options"
|
||||||
|
"github.com/nspcc-dev/neo-go/cli/txctx"
|
||||||
"github.com/nspcc-dev/neo-go/pkg/config"
|
"github.com/nspcc-dev/neo-go/pkg/config"
|
||||||
|
"github.com/nspcc-dev/neo-go/pkg/core/transaction"
|
||||||
"github.com/nspcc-dev/neo-go/pkg/crypto/keys"
|
"github.com/nspcc-dev/neo-go/pkg/crypto/keys"
|
||||||
"github.com/nspcc-dev/neo-go/pkg/encoding/address"
|
"github.com/nspcc-dev/neo-go/pkg/encoding/address"
|
||||||
"github.com/nspcc-dev/neo-go/pkg/rpcclient/actor"
|
|
||||||
"github.com/nspcc-dev/neo-go/pkg/rpcclient/neo"
|
"github.com/nspcc-dev/neo-go/pkg/rpcclient/neo"
|
||||||
"github.com/nspcc-dev/neo-go/pkg/smartcontract"
|
"github.com/nspcc-dev/neo-go/pkg/smartcontract"
|
||||||
"github.com/nspcc-dev/neo-go/pkg/smartcontract/manifest"
|
"github.com/nspcc-dev/neo-go/pkg/smartcontract/manifest"
|
||||||
|
"github.com/nspcc-dev/neo-go/pkg/util"
|
||||||
"github.com/nspcc-dev/neo-go/pkg/vm"
|
"github.com/nspcc-dev/neo-go/pkg/vm"
|
||||||
"github.com/nspcc-dev/neo-go/pkg/wallet"
|
"github.com/nspcc-dev/neo-go/pkg/wallet"
|
||||||
"github.com/urfave/cli"
|
"github.com/urfave/cli"
|
||||||
|
@ -63,10 +65,6 @@ var (
|
||||||
Name: "decrypt, d",
|
Name: "decrypt, d",
|
||||||
Usage: "Decrypt encrypted keys.",
|
Usage: "Decrypt encrypted keys.",
|
||||||
}
|
}
|
||||||
outFlag = cli.StringFlag{
|
|
||||||
Name: "out",
|
|
||||||
Usage: "file to put JSON transaction to",
|
|
||||||
}
|
|
||||||
inFlag = cli.StringFlag{
|
inFlag = cli.StringFlag{
|
||||||
Name: "in",
|
Name: "in",
|
||||||
Usage: "file with JSON transaction",
|
Usage: "file with JSON transaction",
|
||||||
|
@ -79,10 +77,6 @@ var (
|
||||||
Name: "to",
|
Name: "to",
|
||||||
Usage: "Address to send an asset to",
|
Usage: "Address to send an asset to",
|
||||||
}
|
}
|
||||||
forceFlag = cli.BoolFlag{
|
|
||||||
Name: "force",
|
|
||||||
Usage: "Do not ask for a confirmation",
|
|
||||||
}
|
|
||||||
)
|
)
|
||||||
|
|
||||||
// NewCommands returns 'wallet' command.
|
// NewCommands returns 'wallet' command.
|
||||||
|
@ -90,6 +84,10 @@ func NewCommands() []cli.Command {
|
||||||
claimFlags := []cli.Flag{
|
claimFlags := []cli.Flag{
|
||||||
walletPathFlag,
|
walletPathFlag,
|
||||||
walletConfigFlag,
|
walletConfigFlag,
|
||||||
|
txctx.GasFlag,
|
||||||
|
txctx.SysGasFlag,
|
||||||
|
txctx.OutFlag,
|
||||||
|
txctx.ForceFlag,
|
||||||
flags.AddressFlag{
|
flags.AddressFlag{
|
||||||
Name: "address, a",
|
Name: "address, a",
|
||||||
Usage: "Address to claim GAS for",
|
Usage: "Address to claim GAS for",
|
||||||
|
@ -99,7 +97,7 @@ func NewCommands() []cli.Command {
|
||||||
signFlags := []cli.Flag{
|
signFlags := []cli.Flag{
|
||||||
walletPathFlag,
|
walletPathFlag,
|
||||||
walletConfigFlag,
|
walletConfigFlag,
|
||||||
outFlag,
|
txctx.OutFlag,
|
||||||
inFlag,
|
inFlag,
|
||||||
flags.AddressFlag{
|
flags.AddressFlag{
|
||||||
Name: "address, a",
|
Name: "address, a",
|
||||||
|
@ -114,7 +112,7 @@ func NewCommands() []cli.Command {
|
||||||
{
|
{
|
||||||
Name: "claim",
|
Name: "claim",
|
||||||
Usage: "claim GAS",
|
Usage: "claim GAS",
|
||||||
UsageText: "neo-go wallet claim -w wallet [--wallet-config path] -a address -r endpoint [-s timeout]",
|
UsageText: "neo-go wallet claim -w wallet [--wallet-config path] [-g gas] [-e sysgas] -a address -r endpoint [-s timeout] [--out file] [--force]",
|
||||||
Action: claimGas,
|
Action: claimGas,
|
||||||
Flags: claimFlags,
|
Flags: claimFlags,
|
||||||
},
|
},
|
||||||
|
@ -282,7 +280,7 @@ func NewCommands() []cli.Command {
|
||||||
Flags: []cli.Flag{
|
Flags: []cli.Flag{
|
||||||
walletPathFlag,
|
walletPathFlag,
|
||||||
walletConfigFlag,
|
walletConfigFlag,
|
||||||
forceFlag,
|
txctx.ForceFlag,
|
||||||
flags.AddressFlag{
|
flags.AddressFlag{
|
||||||
Name: "address, a",
|
Name: "address, a",
|
||||||
Usage: "Account address or hash in LE form to be removed",
|
Usage: "Account address or hash in LE form to be removed",
|
||||||
|
@ -317,7 +315,7 @@ func NewCommands() []cli.Command {
|
||||||
Flags: []cli.Flag{
|
Flags: []cli.Flag{
|
||||||
walletPathFlag,
|
walletPathFlag,
|
||||||
walletConfigFlag,
|
walletConfigFlag,
|
||||||
forceFlag,
|
txctx.ForceFlag,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
@ -340,45 +338,9 @@ func NewCommands() []cli.Command {
|
||||||
}
|
}
|
||||||
|
|
||||||
func claimGas(ctx *cli.Context) error {
|
func claimGas(ctx *cli.Context) error {
|
||||||
if err := cmdargs.EnsureNone(ctx); err != nil {
|
return handleNeoAction(ctx, func(contract *neo.Contract, shash util.Uint160, _ *wallet.Account) (*transaction.Transaction, error) {
|
||||||
return err
|
return contract.TransferUnsigned(shash, shash, big.NewInt(0), nil)
|
||||||
}
|
})
|
||||||
wall, pass, err := readWallet(ctx)
|
|
||||||
if err != nil {
|
|
||||||
return cli.NewExitError(err, 1)
|
|
||||||
}
|
|
||||||
defer wall.Close()
|
|
||||||
|
|
||||||
addrFlag := ctx.Generic("address").(*flags.Address)
|
|
||||||
if !addrFlag.IsSet {
|
|
||||||
return cli.NewExitError("address was not provided", 1)
|
|
||||||
}
|
|
||||||
scriptHash := addrFlag.Uint160()
|
|
||||||
acc, err := getDecryptedAccount(wall, scriptHash, pass)
|
|
||||||
if err != nil {
|
|
||||||
return cli.NewExitError(err, 1)
|
|
||||||
}
|
|
||||||
|
|
||||||
gctx, cancel := options.GetTimeoutContext(ctx)
|
|
||||||
defer cancel()
|
|
||||||
|
|
||||||
c, err := options.GetRPCClient(gctx, ctx)
|
|
||||||
if err != nil {
|
|
||||||
return cli.NewExitError(err, 1)
|
|
||||||
}
|
|
||||||
|
|
||||||
act, err := actor.NewSimple(c, acc)
|
|
||||||
if err != nil {
|
|
||||||
return cli.NewExitError(err, 1)
|
|
||||||
}
|
|
||||||
neoToken := neo.New(act)
|
|
||||||
hash, _, err := neoToken.Transfer(scriptHash, scriptHash, big.NewInt(0), nil)
|
|
||||||
if err != nil {
|
|
||||||
return cli.NewExitError(err, 1)
|
|
||||||
}
|
|
||||||
|
|
||||||
fmt.Fprintln(ctx.App.Writer, hash.StringLE())
|
|
||||||
return nil
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func changePassword(ctx *cli.Context) error {
|
func changePassword(ctx *cli.Context) error {
|
||||||
|
|
|
@ -524,7 +524,8 @@ func TestWalletClaimGas(t *testing.T) {
|
||||||
e.Run(t, "neo-go", "wallet", "claim",
|
e.Run(t, "neo-go", "wallet", "claim",
|
||||||
"--rpc-endpoint", "http://"+e.RPC.Addr,
|
"--rpc-endpoint", "http://"+e.RPC.Addr,
|
||||||
"--wallet", testcli.TestWalletPath,
|
"--wallet", testcli.TestWalletPath,
|
||||||
"--address", testcli.TestWalletAccount)
|
"--address", testcli.TestWalletAccount,
|
||||||
|
"--force")
|
||||||
tx, height := e.CheckTxPersisted(t)
|
tx, height := e.CheckTxPersisted(t)
|
||||||
balanceBefore.Sub(balanceBefore, big.NewInt(tx.NetworkFee+tx.SystemFee))
|
balanceBefore.Sub(balanceBefore, big.NewInt(tx.NetworkFee+tx.SystemFee))
|
||||||
balanceBefore.Add(balanceBefore, cl)
|
balanceBefore.Add(balanceBefore, cl)
|
||||||
|
|
Loading…
Reference in a new issue