github.com/nspcc-dev/neo-go@v0.105.2-0.20240517133400-6be757af3eba/cli/txctx/tx.go (about) 1 /* 2 Package txctx contains helper functions that deal with transactions in CLI context. 3 */ 4 package txctx 5 6 import ( 7 "fmt" 8 "io" 9 "time" 10 11 "github.com/nspcc-dev/neo-go/cli/flags" 12 "github.com/nspcc-dev/neo-go/cli/input" 13 "github.com/nspcc-dev/neo-go/cli/paramcontext" 14 "github.com/nspcc-dev/neo-go/pkg/core/state" 15 "github.com/nspcc-dev/neo-go/pkg/core/transaction" 16 "github.com/nspcc-dev/neo-go/pkg/rpcclient/actor" 17 "github.com/nspcc-dev/neo-go/pkg/util" 18 "github.com/nspcc-dev/neo-go/pkg/wallet" 19 "github.com/urfave/cli" 20 ) 21 22 var ( 23 // GasFlag is a flag used for the additional network fee. 24 GasFlag = flags.Fixed8Flag{ 25 Name: "gas, g", 26 Usage: "network fee to add to the transaction (prioritizing it)", 27 } 28 // SysGasFlag is a flag used for the additional system fee. 29 SysGasFlag = flags.Fixed8Flag{ 30 Name: "sysgas, e", 31 Usage: "system fee to add to the transaction (compensating for execution)", 32 } 33 // OutFlag is a flag used for file output. 34 OutFlag = cli.StringFlag{ 35 Name: "out", 36 Usage: "file (JSON) to put signature context with a transaction to", 37 } 38 // ForceFlag is a flag used to force transaction send. 39 ForceFlag = cli.BoolFlag{ 40 Name: "force", 41 Usage: "Do not ask for a confirmation (and ignore errors)", 42 } 43 // AwaitFlag is a flag used to wait for the transaction to be included in a block. 44 AwaitFlag = cli.BoolFlag{ 45 Name: "await", 46 Usage: "wait for the transaction to be included in a block", 47 } 48 ) 49 50 // SignAndSend adds network and system fees to the provided transaction and 51 // either sends it to the network (with a confirmation or --force flag) or saves 52 // it into a file (given in the --out flag). 53 func SignAndSend(ctx *cli.Context, act *actor.Actor, acc *wallet.Account, tx *transaction.Transaction) error { 54 var ( 55 err error 56 gas = flags.Fixed8FromContext(ctx, "gas") 57 sysgas = flags.Fixed8FromContext(ctx, "sysgas") 58 ver = act.GetVersion() 59 aer *state.AppExecResult 60 ) 61 62 tx.SystemFee += int64(sysgas) 63 tx.NetworkFee += int64(gas) 64 65 if outFile := ctx.String("out"); outFile != "" { 66 // Make a long-lived transaction, it's to be signed manually. 67 tx.ValidUntilBlock += (ver.Protocol.MaxValidUntilBlockIncrement - uint32(ver.Protocol.ValidatorsCount)) - 2 68 err = paramcontext.InitAndSave(ver.Protocol.Network, tx, acc, outFile) 69 } else { 70 if !ctx.Bool("force") { 71 promptTime := time.Now() 72 err := input.ConfirmTx(ctx.App.Writer, tx) 73 if err != nil { 74 return cli.NewExitError(err, 1) 75 } 76 waitTime := time.Since(promptTime) 77 // Compensate for confirmation waiting. 78 tx.ValidUntilBlock += uint32(waitTime.Milliseconds()/int64(ver.Protocol.MillisecondsPerBlock)) + 2 79 } 80 var ( 81 resTx util.Uint256 82 vub uint32 83 ) 84 resTx, vub, err = act.SignAndSend(tx) 85 if err != nil { 86 return cli.NewExitError(err, 1) 87 } 88 if ctx.Bool("await") { 89 aer, err = act.Wait(resTx, vub, err) 90 if err != nil { 91 return cli.NewExitError(fmt.Errorf("failed to await transaction %s: %w", resTx.StringLE(), err), 1) 92 } 93 } 94 } 95 if err != nil { 96 return cli.NewExitError(err, 1) 97 } 98 99 DumpTransactionInfo(ctx.App.Writer, tx.Hash(), aer) 100 return nil 101 } 102 103 // DumpTransactionInfo prints transaction info to the given writer. 104 func DumpTransactionInfo(w io.Writer, h util.Uint256, res *state.AppExecResult) { 105 fmt.Fprintln(w, h.StringLE()) 106 if res != nil { 107 fmt.Fprintf(w, "OnChain:\t%t\n", res != nil) 108 fmt.Fprintf(w, "VMState:\t%s\n", res.VMState.String()) 109 if res.FaultException != "" { 110 fmt.Fprintf(w, "FaultException:\t%s\n", res.FaultException) 111 } 112 } 113 }