github.com/nspcc-dev/neo-go@v0.105.2-0.20240517133400-6be757af3eba/cli/util/convert.go (about)

     1  package util
     2  
     3  import (
     4  	"encoding/base64"
     5  	"encoding/hex"
     6  	"fmt"
     7  	"os"
     8  
     9  	"github.com/nspcc-dev/neo-go/cli/flags"
    10  	"github.com/nspcc-dev/neo-go/cli/options"
    11  	"github.com/nspcc-dev/neo-go/cli/txctx"
    12  	vmcli "github.com/nspcc-dev/neo-go/cli/vm"
    13  	"github.com/nspcc-dev/neo-go/pkg/vm"
    14  	"github.com/urfave/cli"
    15  )
    16  
    17  // NewCommands returns util commands for neo-go CLI.
    18  func NewCommands() []cli.Command {
    19  	txDumpFlags := append([]cli.Flag{}, options.RPC...)
    20  	txSendFlags := append(txDumpFlags, txctx.AwaitFlag)
    21  	txCancelFlags := append([]cli.Flag{
    22  		flags.AddressFlag{
    23  			Name:  "address, a",
    24  			Usage: "address to use as conflicting transaction signee (and gas source)",
    25  		},
    26  		txctx.GasFlag,
    27  		txctx.AwaitFlag,
    28  	}, options.RPC...)
    29  	txCancelFlags = append(txCancelFlags, options.Wallet...)
    30  	return []cli.Command{
    31  		{
    32  			Name:  "util",
    33  			Usage: "Various helper commands",
    34  			Subcommands: []cli.Command{
    35  				{
    36  					Name:  "convert",
    37  					Usage: "Convert provided argument into other possible formats",
    38  					UsageText: `convert <arg>
    39  
    40  <arg> is an argument which is tried to be interpreted as an item of different types
    41          and converted to other formats. Strings are escaped and output in quotes.`,
    42  					Action: handleParse,
    43  				},
    44  				{
    45  					Name:      "sendtx",
    46  					Usage:     "Send complete transaction stored in a context file",
    47  					UsageText: "sendtx [-r <endpoint>] <file.in> [--await]",
    48  					Description: `Sends the transaction from the given context file to the given RPC node if it's
    49     completely signed and ready. This command expects a ContractParametersContext
    50     JSON file for input, it can't handle binary (or hex- or base64-encoded)
    51     transactions. If the --await flag is included, the command waits for the
    52     transaction to be included in a block before exiting.
    53  `,
    54  					Action: sendTx,
    55  					Flags:  txSendFlags,
    56  				},
    57  				{
    58  					Name:      "canceltx",
    59  					Usage:     "Cancel transaction by sending conflicting transaction",
    60  					UsageText: "canceltx <txid> -r <endpoint> --wallet <wallet> [--account <account>] [--wallet-config <path>] [--gas <gas>] [--await]",
    61  					Description: `Aims to prevent a transaction from being added to the blockchain by dispatching a more 
    62     prioritized conflicting transaction to the specified RPC node. The input for this command should 
    63     be the transaction hash. If another account is not specified, the conflicting transaction is 
    64     automatically generated and signed by the default account in the wallet. If the target transaction 
    65     is in the memory pool of the provided RPC node, the NetworkFee value of the conflicting transaction 
    66     is set to the target transaction's NetworkFee value plus one (if it's sufficient for the 
    67     conflicting transaction itself), the ValidUntilBlock value of the conflicting transaction is set to the
    68     target transaction's ValidUntilBlock value. If the target transaction is not in the memory pool, standard 
    69     NetworkFee calculations are performed based on the calculatenetworkfee RPC request. If the --gas 
    70     flag is included, the specified value is added to the resulting conflicting transaction network fee 
    71     in both scenarios. When the --await flag is included, the command waits for one of the conflicting 
    72     or target transactions to be included in a block.
    73  `,
    74  					Action: cancelTx,
    75  					Flags:  txCancelFlags,
    76  				},
    77  				{
    78  					Name:      "txdump",
    79  					Usage:     "Dump transaction stored in file",
    80  					UsageText: "txdump [-r <endpoint>] <file.in>",
    81  					Action:    txDump,
    82  					Flags:     txDumpFlags,
    83  					Description: `Dumps the transaction from the given parameter context file to 
    84     the output. This command expects a ContractParametersContext JSON file for input, it can't handle
    85     binary (or hex- or base64-encoded) transactions. If --rpc-endpoint flag is specified the result 
    86     of the given script after running it true the VM will be printed. Otherwise only transaction will
    87     be printed.
    88  `,
    89  				},
    90  				{
    91  					Name:      "ops",
    92  					Usage:     "Pretty-print VM opcodes of the given base64- or hex- encoded script (base64 is checked first). If the input file is specified, then the script is taken from the file.",
    93  					UsageText: "ops <base64/hex-encoded script> [-i path-to-file] [--hex]",
    94  					Action:    handleOps,
    95  					Flags: []cli.Flag{
    96  						cli.StringFlag{
    97  							Name:  "in, i",
    98  							Usage: "input file containing base64- or hex- encoded script representation",
    99  						},
   100  						cli.BoolFlag{
   101  							Name:  "hex",
   102  							Usage: "use hex encoding and do not check base64",
   103  						},
   104  					},
   105  				},
   106  			},
   107  		},
   108  	}
   109  }
   110  
   111  func handleParse(ctx *cli.Context) error {
   112  	res, err := vmcli.Parse(ctx.Args())
   113  	if err != nil {
   114  		return cli.NewExitError(err, 1)
   115  	}
   116  	fmt.Fprint(ctx.App.Writer, res)
   117  	return nil
   118  }
   119  
   120  func handleOps(ctx *cli.Context) error {
   121  	var (
   122  		s   string
   123  		err error
   124  		b   []byte
   125  	)
   126  	in := ctx.String("in")
   127  	if len(in) != 0 {
   128  		b, err := os.ReadFile(in)
   129  		if err != nil {
   130  			return cli.NewExitError(fmt.Errorf("failed to read file: %w", err), 1)
   131  		}
   132  		s = string(b)
   133  	} else {
   134  		if !ctx.Args().Present() {
   135  			return cli.NewExitError("missing script", 1)
   136  		}
   137  		s = ctx.Args()[0]
   138  	}
   139  	b, err = base64.StdEncoding.DecodeString(s)
   140  	if err != nil || ctx.Bool("hex") {
   141  		b, err = hex.DecodeString(s)
   142  	}
   143  	if err != nil {
   144  		return cli.NewExitError("unknown encoding: base64 or hex are supported", 1)
   145  	}
   146  	v := vm.New()
   147  	v.LoadScript(b)
   148  	v.PrintOps(ctx.App.Writer)
   149  	return nil
   150  }