Merge pull request #3223 from nspcc-dev/cancel_command
cli: cancel transaction command
This commit is contained in:
commit
7179efec35
7 changed files with 215 additions and 39 deletions
|
@ -32,6 +32,15 @@ const DefaultTimeout = 10 * time.Second
|
||||||
// check for flag presence in the context.
|
// check for flag presence in the context.
|
||||||
const RPCEndpointFlag = "rpc-endpoint"
|
const RPCEndpointFlag = "rpc-endpoint"
|
||||||
|
|
||||||
|
// Wallet is a set of flags used for wallet operations.
|
||||||
|
var Wallet = []cli.Flag{cli.StringFlag{
|
||||||
|
Name: "wallet, w",
|
||||||
|
Usage: "wallet to use to get the key for transaction signing; conflicts with --wallet-config flag",
|
||||||
|
}, cli.StringFlag{
|
||||||
|
Name: "wallet-config",
|
||||||
|
Usage: "path to wallet config to use to get the key for transaction signing; conflicts with --wallet flag"},
|
||||||
|
}
|
||||||
|
|
||||||
// Network is a set of flags for choosing the network to operate on
|
// Network is a set of flags for choosing the network to operate on
|
||||||
// (privnet/mainnet/testnet).
|
// (privnet/mainnet/testnet).
|
||||||
var Network = []cli.Flag{
|
var Network = []cli.Flag{
|
||||||
|
|
|
@ -37,7 +37,7 @@ func manifestAddGroup(ctx *cli.Context) error {
|
||||||
|
|
||||||
h := state.CreateContractHash(sender, nf.Checksum, m.Name)
|
h := state.CreateContractHash(sender, nf.Checksum, m.Name)
|
||||||
|
|
||||||
gAcc, w, err := getAccFromContext(ctx)
|
gAcc, w, err := GetAccFromContext(ctx)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return cli.NewExitError(fmt.Errorf("can't get account to sign group with: %w", err), 1)
|
return cli.NewExitError(fmt.Errorf("can't get account to sign group with: %w", err), 1)
|
||||||
}
|
}
|
||||||
|
|
|
@ -48,16 +48,7 @@ var (
|
||||||
errNoScriptHash = errors.New("no smart contract hash was provided, specify one as the first argument")
|
errNoScriptHash = errors.New("no smart contract hash was provided, specify one as the first argument")
|
||||||
errNoSmartContractName = errors.New("no name was provided, specify the '--name or -n' flag")
|
errNoSmartContractName = errors.New("no name was provided, specify the '--name or -n' flag")
|
||||||
errFileExist = errors.New("A file with given smart-contract name already exists")
|
errFileExist = errors.New("A file with given smart-contract name already exists")
|
||||||
|
addressFlag = flags.AddressFlag{
|
||||||
walletFlag = cli.StringFlag{
|
|
||||||
Name: "wallet, w",
|
|
||||||
Usage: "wallet to use to get the key for transaction signing; conflicts with --wallet-config flag",
|
|
||||||
}
|
|
||||||
walletConfigFlag = cli.StringFlag{
|
|
||||||
Name: "wallet-config",
|
|
||||||
Usage: "path to wallet config to use to get the key for transaction signing; conflicts with --wallet flag",
|
|
||||||
}
|
|
||||||
addressFlag = flags.AddressFlag{
|
|
||||||
Name: addressFlagName,
|
Name: addressFlagName,
|
||||||
Usage: "address to use as transaction signee (and gas source)",
|
Usage: "address to use as transaction signee (and gas source)",
|
||||||
}
|
}
|
||||||
|
@ -100,14 +91,13 @@ func NewCommands() []cli.Command {
|
||||||
testInvokeFunctionFlags := []cli.Flag{options.Historic}
|
testInvokeFunctionFlags := []cli.Flag{options.Historic}
|
||||||
testInvokeFunctionFlags = append(testInvokeFunctionFlags, options.RPC...)
|
testInvokeFunctionFlags = append(testInvokeFunctionFlags, options.RPC...)
|
||||||
invokeFunctionFlags := []cli.Flag{
|
invokeFunctionFlags := []cli.Flag{
|
||||||
walletFlag,
|
|
||||||
walletConfigFlag,
|
|
||||||
addressFlag,
|
addressFlag,
|
||||||
txctx.GasFlag,
|
txctx.GasFlag,
|
||||||
txctx.SysGasFlag,
|
txctx.SysGasFlag,
|
||||||
txctx.OutFlag,
|
txctx.OutFlag,
|
||||||
txctx.ForceFlag,
|
txctx.ForceFlag,
|
||||||
}
|
}
|
||||||
|
invokeFunctionFlags = append(invokeFunctionFlags, options.Wallet...)
|
||||||
invokeFunctionFlags = append(invokeFunctionFlags, options.RPC...)
|
invokeFunctionFlags = append(invokeFunctionFlags, options.RPC...)
|
||||||
deployFlags := append(invokeFunctionFlags, []cli.Flag{
|
deployFlags := append(invokeFunctionFlags, []cli.Flag{
|
||||||
cli.StringFlag{
|
cli.StringFlag{
|
||||||
|
@ -119,6 +109,24 @@ func NewCommands() []cli.Command {
|
||||||
Usage: "Manifest input file (*.manifest.json)",
|
Usage: "Manifest input file (*.manifest.json)",
|
||||||
},
|
},
|
||||||
}...)
|
}...)
|
||||||
|
manifestAddGroupFlags := append([]cli.Flag{
|
||||||
|
cli.StringFlag{
|
||||||
|
Name: "sender, s",
|
||||||
|
Usage: "deploy transaction sender",
|
||||||
|
},
|
||||||
|
flags.AddressFlag{
|
||||||
|
Name: addressFlagName, // use the same name for handler code unification.
|
||||||
|
Usage: "account to sign group with",
|
||||||
|
},
|
||||||
|
cli.StringFlag{
|
||||||
|
Name: "nef, n",
|
||||||
|
Usage: "path to the NEF file",
|
||||||
|
},
|
||||||
|
cli.StringFlag{
|
||||||
|
Name: "manifest, m",
|
||||||
|
Usage: "path to the manifest",
|
||||||
|
},
|
||||||
|
}, options.Wallet...)
|
||||||
return []cli.Command{{
|
return []cli.Command{{
|
||||||
Name: "contract",
|
Name: "contract",
|
||||||
Usage: "compile - debug - deploy smart contracts",
|
Usage: "compile - debug - deploy smart contracts",
|
||||||
|
@ -301,26 +309,7 @@ func NewCommands() []cli.Command {
|
||||||
Usage: "adds group to the manifest",
|
Usage: "adds group to the manifest",
|
||||||
UsageText: "neo-go contract manifest add-group -w wallet [--wallet-config path] -n nef -m manifest -a address -s address",
|
UsageText: "neo-go contract manifest add-group -w wallet [--wallet-config path] -n nef -m manifest -a address -s address",
|
||||||
Action: manifestAddGroup,
|
Action: manifestAddGroup,
|
||||||
Flags: []cli.Flag{
|
Flags: manifestAddGroupFlags,
|
||||||
walletFlag,
|
|
||||||
walletConfigFlag,
|
|
||||||
cli.StringFlag{
|
|
||||||
Name: "sender, s",
|
|
||||||
Usage: "deploy transaction sender",
|
|
||||||
},
|
|
||||||
flags.AddressFlag{
|
|
||||||
Name: addressFlagName, // use the same name for handler code unification.
|
|
||||||
Usage: "account to sign group with",
|
|
||||||
},
|
|
||||||
cli.StringFlag{
|
|
||||||
Name: "nef, n",
|
|
||||||
Usage: "path to the NEF file",
|
|
||||||
},
|
|
||||||
cli.StringFlag{
|
|
||||||
Name: "manifest, m",
|
|
||||||
Usage: "path to the manifest",
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
@ -581,7 +570,7 @@ func invokeInternal(ctx *cli.Context, signAndPush bool) error {
|
||||||
w *wallet.Wallet
|
w *wallet.Wallet
|
||||||
)
|
)
|
||||||
if signAndPush {
|
if signAndPush {
|
||||||
acc, w, err = getAccFromContext(ctx)
|
acc, w, err = GetAccFromContext(ctx)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return cli.NewExitError(err, 1)
|
return cli.NewExitError(err, 1)
|
||||||
}
|
}
|
||||||
|
@ -757,7 +746,8 @@ func inspect(ctx *cli.Context) error {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func getAccFromContext(ctx *cli.Context) (*wallet.Account, *wallet.Wallet, error) {
|
// GetAccFromContext returns account and wallet from context. If address is not set, default address is used.
|
||||||
|
func GetAccFromContext(ctx *cli.Context) (*wallet.Account, *wallet.Wallet, error) {
|
||||||
var addr util.Uint160
|
var addr util.Uint160
|
||||||
|
|
||||||
wPath := ctx.String("wallet")
|
wPath := ctx.String("wallet")
|
||||||
|
@ -789,11 +779,13 @@ func getAccFromContext(ctx *cli.Context) (*wallet.Account, *wallet.Wallet, error
|
||||||
addr = wall.GetChangeAddress()
|
addr = wall.GetChangeAddress()
|
||||||
}
|
}
|
||||||
|
|
||||||
acc, err := getUnlockedAccount(wall, addr, pass)
|
acc, err := GetUnlockedAccount(wall, addr, pass)
|
||||||
return acc, wall, err
|
return acc, wall, err
|
||||||
}
|
}
|
||||||
|
|
||||||
func getUnlockedAccount(wall *wallet.Wallet, addr util.Uint160, pass *string) (*wallet.Account, error) {
|
// GetUnlockedAccount returns account from wallet, address and uses pass to unlock specified account if given.
|
||||||
|
// If the password is not given, then it is requested from user.
|
||||||
|
func GetUnlockedAccount(wall *wallet.Wallet, addr util.Uint160, pass *string) (*wallet.Account, error) {
|
||||||
acc := wall.GetAccount(addr)
|
acc := wall.GetAccount(addr)
|
||||||
if acc == nil {
|
if acc == nil {
|
||||||
return nil, fmt.Errorf("wallet contains no account for '%s'", address.Uint160ToString(addr))
|
return nil, fmt.Errorf("wallet contains no account for '%s'", address.Uint160ToString(addr))
|
||||||
|
@ -844,7 +836,7 @@ func contractDeploy(ctx *cli.Context) error {
|
||||||
appCallParams = append(appCallParams, data[0])
|
appCallParams = append(appCallParams, data[0])
|
||||||
}
|
}
|
||||||
|
|
||||||
acc, w, err := getAccFromContext(ctx)
|
acc, w, err := GetAccFromContext(ctx)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return cli.NewExitError(fmt.Errorf("can't get sender address: %w", err), 1)
|
return cli.NewExitError(fmt.Errorf("can't get sender address: %w", err), 1)
|
||||||
}
|
}
|
||||||
|
|
74
cli/util/cancel.go
Normal file
74
cli/util/cancel.go
Normal file
|
@ -0,0 +1,74 @@
|
||||||
|
package util
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"strings"
|
||||||
|
|
||||||
|
"github.com/nspcc-dev/neo-go/cli/flags"
|
||||||
|
"github.com/nspcc-dev/neo-go/cli/options"
|
||||||
|
"github.com/nspcc-dev/neo-go/cli/smartcontract"
|
||||||
|
"github.com/nspcc-dev/neo-go/pkg/core/transaction"
|
||||||
|
"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/util"
|
||||||
|
"github.com/nspcc-dev/neo-go/pkg/vm/opcode"
|
||||||
|
"github.com/urfave/cli"
|
||||||
|
)
|
||||||
|
|
||||||
|
func cancelTx(ctx *cli.Context) error {
|
||||||
|
args := ctx.Args()
|
||||||
|
if len(args) == 0 {
|
||||||
|
return cli.NewExitError("transaction hash is missing", 1)
|
||||||
|
} else if len(args) > 1 {
|
||||||
|
return cli.NewExitError("only one transaction hash is accepted", 1)
|
||||||
|
}
|
||||||
|
|
||||||
|
txHash, err := util.Uint256DecodeStringLE(strings.TrimPrefix(args[0], "0x"))
|
||||||
|
if err != nil {
|
||||||
|
return cli.NewExitError(fmt.Sprintf("invalid tx hash: %s", args[0]), 1)
|
||||||
|
}
|
||||||
|
|
||||||
|
gctx, cancel := options.GetTimeoutContext(ctx)
|
||||||
|
defer cancel()
|
||||||
|
|
||||||
|
c, err := options.GetRPCClient(gctx, ctx)
|
||||||
|
if err != nil {
|
||||||
|
return cli.NewExitError(fmt.Errorf("failed to create RPC client: %w", err), 1)
|
||||||
|
}
|
||||||
|
|
||||||
|
mainTx, _ := c.GetRawTransactionVerbose(txHash)
|
||||||
|
if mainTx != nil && !mainTx.Blockhash.Equals(util.Uint256{}) {
|
||||||
|
return cli.NewExitError(fmt.Errorf("transaction %s is already accepted at block %s", txHash, mainTx.Blockhash.StringLE()), 1)
|
||||||
|
}
|
||||||
|
acc, w, err := smartcontract.GetAccFromContext(ctx)
|
||||||
|
if err != nil {
|
||||||
|
return cli.NewExitError(fmt.Errorf("failed to get account from context to sign the conflicting transaction: %w", err), 1)
|
||||||
|
}
|
||||||
|
defer w.Close()
|
||||||
|
|
||||||
|
if mainTx != nil && !mainTx.HasSigner(acc.ScriptHash()) {
|
||||||
|
return cli.NewExitError(fmt.Errorf("account %s is not a signer of the conflicting transaction", acc.Address), 1)
|
||||||
|
}
|
||||||
|
|
||||||
|
a, err := actor.NewSimple(c, acc)
|
||||||
|
if err != nil {
|
||||||
|
return cli.NewExitError(fmt.Errorf("failed to create Actor: %w", err), 1)
|
||||||
|
}
|
||||||
|
|
||||||
|
resHash, _, err := a.SendTunedRun([]byte{byte(opcode.RET)}, []transaction.Attribute{{Type: transaction.ConflictsT, Value: &transaction.Conflicts{Hash: txHash}}}, func(r *result.Invoke, t *transaction.Transaction) error {
|
||||||
|
err := actor.DefaultCheckerModifier(r, t)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
if mainTx != nil && t.NetworkFee < mainTx.NetworkFee+1 {
|
||||||
|
t.NetworkFee = mainTx.NetworkFee + 1
|
||||||
|
}
|
||||||
|
t.NetworkFee += int64(flags.Fixed8FromContext(ctx, "gas"))
|
||||||
|
return nil
|
||||||
|
})
|
||||||
|
if err != nil {
|
||||||
|
return cli.NewExitError(fmt.Errorf("failed to send conflicting transaction: %w", err), 1)
|
||||||
|
}
|
||||||
|
fmt.Fprintln(ctx.App.Writer, resHash.StringLE())
|
||||||
|
return nil
|
||||||
|
}
|
|
@ -6,7 +6,9 @@ import (
|
||||||
"fmt"
|
"fmt"
|
||||||
"os"
|
"os"
|
||||||
|
|
||||||
|
"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"
|
||||||
vmcli "github.com/nspcc-dev/neo-go/cli/vm"
|
vmcli "github.com/nspcc-dev/neo-go/cli/vm"
|
||||||
"github.com/nspcc-dev/neo-go/pkg/vm"
|
"github.com/nspcc-dev/neo-go/pkg/vm"
|
||||||
"github.com/urfave/cli"
|
"github.com/urfave/cli"
|
||||||
|
@ -15,6 +17,14 @@ import (
|
||||||
// NewCommands returns util commands for neo-go CLI.
|
// NewCommands returns util commands for neo-go CLI.
|
||||||
func NewCommands() []cli.Command {
|
func NewCommands() []cli.Command {
|
||||||
txDumpFlags := append([]cli.Flag{}, options.RPC...)
|
txDumpFlags := append([]cli.Flag{}, options.RPC...)
|
||||||
|
txCancelFlags := append([]cli.Flag{
|
||||||
|
flags.AddressFlag{
|
||||||
|
Name: "address, a",
|
||||||
|
Usage: "address to use as conflicting transaction signee (and gas source)",
|
||||||
|
},
|
||||||
|
txctx.GasFlag,
|
||||||
|
}, options.RPC...)
|
||||||
|
txCancelFlags = append(txCancelFlags, options.Wallet...)
|
||||||
return []cli.Command{
|
return []cli.Command{
|
||||||
{
|
{
|
||||||
Name: "util",
|
Name: "util",
|
||||||
|
@ -41,6 +51,24 @@ func NewCommands() []cli.Command {
|
||||||
Action: sendTx,
|
Action: sendTx,
|
||||||
Flags: txDumpFlags,
|
Flags: txDumpFlags,
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
Name: "canceltx",
|
||||||
|
Usage: "Cancel transaction by sending conflicting transaction",
|
||||||
|
UsageText: "canceltx <txid> -r <endpoint> --wallet <wallet> [--account <account>] [--wallet-config <path>] [--gas <gas>]",
|
||||||
|
Description: `Aims to prevent a transaction from being added to the blockchain by dispatching a more
|
||||||
|
prioritized conflicting transaction to the specified RPC node. The input for this command should
|
||||||
|
be the transaction hash. If another account is not specified, the conflicting transaction is
|
||||||
|
automatically generated and signed by the default account in the wallet. If the target transaction
|
||||||
|
is in the memory pool of the provided RPC node, the NetworkFee value of the conflicting transaction
|
||||||
|
is set to the target transaction's NetworkFee value plus one (if it's sufficient for the
|
||||||
|
conflicting transaction itself). If the target transaction is not in the memory pool, standard
|
||||||
|
NetworkFee calculations are performed based on the calculatenetworkfee RPC request. If the --gas
|
||||||
|
flag is included, the specified value is added to the resulting conflicting transaction network fee
|
||||||
|
in both scenarios.
|
||||||
|
`,
|
||||||
|
Action: cancelTx,
|
||||||
|
Flags: txCancelFlags,
|
||||||
|
},
|
||||||
{
|
{
|
||||||
Name: "txdump",
|
Name: "txdump",
|
||||||
Usage: "Dump transaction stored in file",
|
Usage: "Dump transaction stored in file",
|
||||||
|
|
|
@ -4,9 +4,12 @@ import (
|
||||||
"os"
|
"os"
|
||||||
"path/filepath"
|
"path/filepath"
|
||||||
"testing"
|
"testing"
|
||||||
|
"time"
|
||||||
|
|
||||||
"github.com/nspcc-dev/neo-go/internal/testcli"
|
"github.com/nspcc-dev/neo-go/internal/testcli"
|
||||||
|
"github.com/nspcc-dev/neo-go/pkg/smartcontract/trigger"
|
||||||
"github.com/nspcc-dev/neo-go/pkg/util"
|
"github.com/nspcc-dev/neo-go/pkg/util"
|
||||||
|
"github.com/nspcc-dev/neo-go/pkg/wallet"
|
||||||
"github.com/stretchr/testify/require"
|
"github.com/stretchr/testify/require"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -63,3 +66,73 @@ func TestUtilOps(t *testing.T) {
|
||||||
e.Run(t, "neo-go", "util", "ops", "--hex", "--in", tmp) // hex from file
|
e.Run(t, "neo-go", "util", "ops", "--hex", "--in", tmp) // hex from file
|
||||||
check(t)
|
check(t)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestUtilCancelTx(t *testing.T) {
|
||||||
|
e := testcli.NewExecutorSuspended(t)
|
||||||
|
|
||||||
|
w, err := wallet.NewWalletFromFile("../testdata/testwallet.json")
|
||||||
|
require.NoError(t, err)
|
||||||
|
|
||||||
|
transferArgs := []string{
|
||||||
|
"neo-go", "wallet", "nep17", "transfer",
|
||||||
|
"--rpc-endpoint", "http://" + e.RPC.Addresses()[0],
|
||||||
|
"--wallet", testcli.ValidatorWallet,
|
||||||
|
"--to", w.Accounts[0].Address,
|
||||||
|
"--token", "NEO",
|
||||||
|
"--from", testcli.ValidatorAddr,
|
||||||
|
"--force",
|
||||||
|
}
|
||||||
|
args := []string{"neo-go", "util", "canceltx",
|
||||||
|
"-r", "http://" + e.RPC.Addresses()[0],
|
||||||
|
"--wallet", testcli.ValidatorWallet,
|
||||||
|
"--address", testcli.ValidatorAddr}
|
||||||
|
|
||||||
|
e.In.WriteString("one\r")
|
||||||
|
e.Run(t, append(transferArgs, "--amount", "1")...)
|
||||||
|
line := e.GetNextLine(t)
|
||||||
|
txHash, err := util.Uint256DecodeStringLE(line)
|
||||||
|
require.NoError(t, err)
|
||||||
|
|
||||||
|
_, ok := e.Chain.GetMemPool().TryGetValue(txHash)
|
||||||
|
require.True(t, ok)
|
||||||
|
|
||||||
|
t.Run("invalid", func(t *testing.T) {
|
||||||
|
t.Run("missing tx argument", func(t *testing.T) {
|
||||||
|
e.RunWithError(t, args...)
|
||||||
|
})
|
||||||
|
t.Run("excessive arguments", func(t *testing.T) {
|
||||||
|
e.RunWithError(t, append(args, txHash.StringLE(), txHash.StringLE())...)
|
||||||
|
})
|
||||||
|
t.Run("invalid hash", func(t *testing.T) {
|
||||||
|
e.RunWithError(t, append(args, "notahash")...)
|
||||||
|
})
|
||||||
|
t.Run("not signed by main signer", func(t *testing.T) {
|
||||||
|
e.In.WriteString("one\r")
|
||||||
|
e.RunWithError(t, "neo-go", "util", "canceltx",
|
||||||
|
"-r", "http://"+e.RPC.Addresses()[0],
|
||||||
|
"--wallet", testcli.ValidatorWallet,
|
||||||
|
"--address", testcli.MultisigAddr, txHash.StringLE())
|
||||||
|
})
|
||||||
|
t.Run("wrong rpc endpoint", func(t *testing.T) {
|
||||||
|
e.In.WriteString("one\r")
|
||||||
|
e.RunWithError(t, "neo-go", "util", "canceltx",
|
||||||
|
"-r", "http://localhost:20331",
|
||||||
|
"--wallet", testcli.ValidatorWallet, txHash.StringLE())
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
|
e.In.WriteString("one\r")
|
||||||
|
e.Run(t, append(args, txHash.StringLE())...)
|
||||||
|
resHash, err := util.Uint256DecodeStringLE(e.GetNextLine(t))
|
||||||
|
require.NoError(t, err)
|
||||||
|
|
||||||
|
_, _, err = e.Chain.GetTransaction(resHash)
|
||||||
|
require.NoError(t, err)
|
||||||
|
e.CheckEOF(t)
|
||||||
|
go e.Chain.Run()
|
||||||
|
|
||||||
|
require.Eventually(t, func() bool {
|
||||||
|
_, aerErr := e.Chain.GetAppExecResults(resHash, trigger.Application)
|
||||||
|
return aerErr == nil
|
||||||
|
}, time.Second*2, time.Millisecond*50)
|
||||||
|
}
|
||||||
|
|
|
@ -214,7 +214,7 @@ and we're not accepting issues related to them.
|
||||||
|
|
||||||
| Method | Reason |
|
| Method | Reason |
|
||||||
| ------- | ------------|
|
| ------- | ------------|
|
||||||
| `canceltransaction` | Doesn't fit neo-go wallet model |
|
| `canceltransaction` | Doesn't fit neo-go wallet model, use CLI to do that (`neo-go util canceltx`) |
|
||||||
| `closewallet` | Doesn't fit neo-go wallet model |
|
| `closewallet` | Doesn't fit neo-go wallet model |
|
||||||
| `dumpprivkey` | Shouldn't exist for security reasons, see `closewallet` comment also |
|
| `dumpprivkey` | Shouldn't exist for security reasons, see `closewallet` comment also |
|
||||||
| `getnewaddress` | See `closewallet` comment, use CLI to do that |
|
| `getnewaddress` | See `closewallet` comment, use CLI to do that |
|
||||||
|
|
Loading…
Reference in a new issue