2020-08-04 06:40:06 +00:00
package util
import (
2023-04-11 15:45:50 +00:00
"encoding/base64"
"encoding/hex"
2020-08-04 06:40:06 +00:00
"fmt"
2023-04-11 15:45:50 +00:00
"os"
2020-08-04 06:40:06 +00:00
2024-10-15 12:27:28 +00:00
"github.com/nspcc-dev/neo-go/cli/cmdargs"
2023-11-27 11:20:18 +00:00
"github.com/nspcc-dev/neo-go/cli/flags"
2021-09-14 12:02:54 +00:00
"github.com/nspcc-dev/neo-go/cli/options"
2023-11-27 11:20:18 +00:00
"github.com/nspcc-dev/neo-go/cli/txctx"
2022-10-05 09:30:54 +00:00
vmcli "github.com/nspcc-dev/neo-go/cli/vm"
2024-12-12 15:46:42 +00:00
"github.com/nspcc-dev/neo-go/pkg/services/helpers/neofs"
2023-04-11 15:45:50 +00:00
"github.com/nspcc-dev/neo-go/pkg/vm"
2024-07-09 18:24:39 +00:00
"github.com/urfave/cli/v2"
2020-08-04 06:40:06 +00:00
)
2020-08-05 10:17:23 +00:00
// NewCommands returns util commands for neo-go CLI.
2024-07-09 18:24:39 +00:00
func NewCommands ( ) [ ] * cli . Command {
2024-07-04 22:34:40 +00:00
// By default, RPC flag is required. sendtx and txdump may be called without provided rpc-endpoint.
rpcFlagOriginal , _ := options . RPC [ 0 ] . ( * cli . StringFlag )
rpcFlag := * rpcFlagOriginal
rpcFlag . Required = false
txDumpFlags := append ( [ ] cli . Flag { & rpcFlag } , options . RPC [ 1 : ] ... )
2023-12-28 11:58:38 +00:00
txSendFlags := append ( txDumpFlags , txctx . AwaitFlag )
2023-11-27 11:20:18 +00:00
txCancelFlags := append ( [ ] cli . Flag {
2024-07-09 18:24:39 +00:00
& flags . AddressFlag {
Name : "address" ,
Aliases : [ ] string { "a" } ,
Usage : "Address to use as conflicting transaction signee (and gas source)" ,
2023-11-27 11:20:18 +00:00
} ,
txctx . GasFlag ,
2023-12-28 11:58:38 +00:00
txctx . AwaitFlag ,
2023-11-27 11:20:18 +00:00
} , options . RPC ... )
txCancelFlags = append ( txCancelFlags , options . Wallet ... )
2024-10-15 12:27:28 +00:00
uploadBinFlags := append ( [ ] cli . Flag {
& cli . StringSliceFlag {
Name : "fs-rpc-endpoint" ,
Aliases : [ ] string { "fsr" } ,
Usage : "List of NeoFS storage node RPC addresses (comma-separated or multiple --fs-rpc-endpoint flags)" ,
Required : true ,
Action : func ( ctx * cli . Context , fsRpcEndpoints [ ] string ) error {
for _ , endpoint := range fsRpcEndpoints {
if endpoint == "" {
return cli . Exit ( "NeoFS RPC endpoint cannot contain empty values" , 1 )
}
}
return nil
} ,
} ,
& cli . StringFlag {
Name : "container" ,
Aliases : [ ] string { "cid" } ,
Usage : "NeoFS container ID to upload blocks to" ,
Required : true ,
Action : cmdargs . EnsureNotEmpty ( "container" ) ,
} ,
& cli . StringFlag {
Name : "block-attribute" ,
Usage : "Attribute key of the block object" ,
Required : true ,
Action : cmdargs . EnsureNotEmpty ( "block-attribute" ) ,
} ,
& cli . StringFlag {
Name : "index-attribute" ,
Usage : "Attribute key of the index file object" ,
Required : true ,
Action : cmdargs . EnsureNotEmpty ( "index-attribute" ) ,
} ,
& flags . AddressFlag {
Name : "address" ,
Usage : "Address to use for signing the uploading and searching transactions in NeoFS" ,
} ,
& cli . UintFlag {
Name : "index-file-size" ,
Usage : "Size of index file" ,
2024-12-12 15:46:42 +00:00
Value : neofs . DefaultIndexFileSize ,
2024-10-15 12:27:28 +00:00
} ,
2024-10-23 18:41:41 +00:00
& cli . UintFlag {
Name : "workers" ,
Usage : "Number of workers to fetch and upload blocks concurrently" ,
Value : 50 ,
} ,
& cli . UintFlag {
Name : "searchers" ,
Usage : "Number of concurrent searches for blocks" ,
Value : 20 ,
} ,
2024-11-02 18:56:06 +00:00
& cli . UintFlag {
Name : "retries" ,
Usage : "Maximum number of Neo/NeoFS node request retries" ,
2024-12-12 15:46:42 +00:00
Value : neofs . MaxRetries ,
2024-11-02 18:56:06 +00:00
Action : func ( context * cli . Context , u uint ) error {
if u < 1 {
return cli . Exit ( "retries should be greater than 0" , 1 )
}
return nil
} ,
} ,
2024-11-15 12:35:37 +00:00
options . Debug ,
2024-10-15 12:27:28 +00:00
} , options . RPC ... )
uploadBinFlags = append ( uploadBinFlags , options . Wallet ... )
2024-07-09 18:24:39 +00:00
return [ ] * cli . Command {
2020-08-04 06:40:06 +00:00
{
Name : "util" ,
Usage : "Various helper commands" ,
2024-07-09 18:24:39 +00:00
Subcommands : [ ] * cli . Command {
2020-08-04 06:40:06 +00:00
{
Name : "convert" ,
Usage : "Convert provided argument into other possible formats" ,
UsageText : ` convert < arg >
< arg > is an argument which is tried to be interpreted as an item of different types
and converted to other formats . Strings are escaped and output in quotes . ` ,
Action : handleParse ,
} ,
2022-08-31 19:38:35 +00:00
{
Name : "sendtx" ,
Usage : "Send complete transaction stored in a context file" ,
2024-07-09 18:24:39 +00:00
UsageText : "sendtx [-r <endpoint>] [--await] <file.in>" ,
2022-08-31 19:38:35 +00:00
Description : ` Sends the transaction from the given context file to the given RPC node if it ' s
completely signed and ready . This command expects a ContractParametersContext
JSON file for input , it can ' t handle binary ( or hex - or base64 - encoded )
2023-12-28 11:58:38 +00:00
transactions . If the -- await flag is included , the command waits for the
transaction to be included in a block before exiting .
2022-08-31 19:38:35 +00:00
` ,
Action : sendTx ,
2023-12-28 11:58:38 +00:00
Flags : txSendFlags ,
2022-08-31 19:38:35 +00:00
} ,
2023-11-27 11:20:18 +00:00
{
Name : "canceltx" ,
Usage : "Cancel transaction by sending conflicting transaction" ,
2024-07-12 09:16:24 +00:00
UsageText : "canceltx -r <endpoint> --wallet <wallet> [--address <account>] [--wallet-config <path>] [--gas <gas>] [--await] <txid>" ,
2023-11-27 11:20:18 +00:00
Description : ` Aims to prevent a transaction from being added to the blockchain by dispatching a more
2023-12-27 09:26:02 +00:00
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 ) , the ValidUntilBlock value of the conflicting transaction is set to the
target transaction ' s ValidUntilBlock value . 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
2023-12-28 11:58:38 +00:00
in both scenarios . When the -- await flag is included , the command waits for one of the conflicting
2024-04-10 16:18:54 +00:00
or target transactions to be included in a block .
` ,
2023-11-27 11:20:18 +00:00
Action : cancelTx ,
Flags : txCancelFlags ,
} ,
2021-09-14 12:02:54 +00:00
{
Name : "txdump" ,
Usage : "Dump transaction stored in file" ,
UsageText : "txdump [-r <endpoint>] <file.in>" ,
Action : txDump ,
Flags : txDumpFlags ,
2023-12-28 11:58:38 +00:00
Description : ` Dumps the transaction from the given parameter context file to
the output . This command expects a ContractParametersContext JSON file for input , it can ' t handle
binary ( or hex - or base64 - encoded ) transactions . If -- rpc - endpoint flag is specified the result
of the given script after running it true the VM will be printed . Otherwise only transaction will
2024-04-10 16:18:54 +00:00
be printed .
` ,
2021-09-14 12:02:54 +00:00
} ,
2023-04-11 15:45:50 +00:00
{
Name : "ops" ,
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." ,
2024-07-09 18:24:39 +00:00
UsageText : "ops [-i path-to-file] [--hex] <base64/hex-encoded script>" ,
2023-04-11 15:45:50 +00:00
Action : handleOps ,
Flags : [ ] cli . Flag {
2024-07-09 18:24:39 +00:00
& cli . StringFlag {
Name : "in" ,
Aliases : [ ] string { "i" } ,
Usage : "Input file containing base64- or hex- encoded script representation" ,
2023-04-11 15:45:50 +00:00
} ,
2024-07-09 18:24:39 +00:00
& cli . BoolFlag {
2023-04-11 15:45:50 +00:00
Name : "hex" ,
2024-07-03 12:35:18 +00:00
Usage : "Use hex encoding and do not check base64" ,
2023-04-11 15:45:50 +00:00
} ,
} ,
} ,
2024-10-15 12:27:28 +00:00
{
Name : "upload-bin" ,
Usage : "Fetch blocks from RPC node and upload them to the NeoFS container" ,
2024-12-07 14:59:05 +00:00
UsageText : "neo-go util upload-bin --fs-rpc-endpoint <address1>[,<address2>[...]] --container <cid> --block-attribute block --index-attribute index --rpc-endpoint <node> [--timeout <time>] --wallet <wallet> [--wallet-config <config>] [--address <address>] [--workers <num>] [--searchers <num>] [--index-file-size <size>] [--retries <num>] [--debug]" ,
2024-10-15 12:27:28 +00:00
Action : uploadBin ,
Flags : uploadBinFlags ,
} ,
2020-08-04 06:40:06 +00:00
} ,
} ,
}
}
func handleParse ( ctx * cli . Context ) error {
2024-07-09 18:24:39 +00:00
res , err := vmcli . Parse ( ctx . Args ( ) . Slice ( ) )
2020-08-04 06:40:06 +00:00
if err != nil {
2024-07-09 18:24:39 +00:00
return cli . Exit ( err , 1 )
2020-08-04 06:40:06 +00:00
}
2020-08-28 09:11:19 +00:00
fmt . Fprint ( ctx . App . Writer , res )
2020-08-04 06:40:06 +00:00
return nil
}
2023-04-11 15:45:50 +00:00
func handleOps ( ctx * cli . Context ) error {
var (
s string
err error
b [ ] byte
)
in := ctx . String ( "in" )
if len ( in ) != 0 {
b , err := os . ReadFile ( in )
if err != nil {
2024-07-09 18:24:39 +00:00
return cli . Exit ( fmt . Errorf ( "failed to read file: %w" , err ) , 1 )
2023-04-11 15:45:50 +00:00
}
s = string ( b )
} else {
if ! ctx . Args ( ) . Present ( ) {
2024-07-09 18:24:39 +00:00
return cli . Exit ( "missing script" , 1 )
2023-04-11 15:45:50 +00:00
}
2024-07-09 18:24:39 +00:00
s = ctx . Args ( ) . Slice ( ) [ 0 ]
2023-04-11 15:45:50 +00:00
}
b , err = base64 . StdEncoding . DecodeString ( s )
if err != nil || ctx . Bool ( "hex" ) {
b , err = hex . DecodeString ( s )
}
if err != nil {
2024-07-09 18:24:39 +00:00
return cli . Exit ( "unknown encoding: base64 or hex are supported" , 1 )
2023-04-11 15:45:50 +00:00
}
v := vm . New ( )
v . LoadScript ( b )
v . PrintOps ( ctx . App . Writer )
return nil
}