8d0d5cb7cd
To prevent `Expired transaction (-510) - transaction has expired: ValidUntilBlock = 8, current height = 8` VUB have been increased. Close #3343 Signed-off-by: Ekaterina Pavlova <ekt@morphbits.io>
113 lines
3.4 KiB
Go
113 lines
3.4 KiB
Go
/*
|
|
Package txctx contains helper functions that deal with transactions in CLI context.
|
|
*/
|
|
package txctx
|
|
|
|
import (
|
|
"fmt"
|
|
"io"
|
|
"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/state"
|
|
"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/util"
|
|
"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)",
|
|
}
|
|
// AwaitFlag is a flag used to wait for the transaction to be included in a block.
|
|
AwaitFlag = cli.BoolFlag{
|
|
Name: "await",
|
|
Usage: "wait for the transaction to be included in a block",
|
|
}
|
|
)
|
|
|
|
// 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()
|
|
aer *state.AppExecResult
|
|
)
|
|
|
|
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)) + 2
|
|
}
|
|
var (
|
|
resTx util.Uint256
|
|
vub uint32
|
|
)
|
|
resTx, vub, err = act.SignAndSend(tx)
|
|
if err != nil {
|
|
return cli.NewExitError(err, 1)
|
|
}
|
|
if ctx.Bool("await") {
|
|
aer, err = act.Wait(resTx, vub, err)
|
|
if err != nil {
|
|
return cli.NewExitError(fmt.Errorf("failed to await transaction %s: %w", resTx.StringLE(), err), 1)
|
|
}
|
|
}
|
|
}
|
|
if err != nil {
|
|
return cli.NewExitError(err, 1)
|
|
}
|
|
|
|
DumpTransactionInfo(ctx.App.Writer, tx.Hash(), aer)
|
|
return nil
|
|
}
|
|
|
|
// DumpTransactionInfo prints transaction info to the given writer.
|
|
func DumpTransactionInfo(w io.Writer, h util.Uint256, res *state.AppExecResult) {
|
|
fmt.Fprintln(w, h.StringLE())
|
|
if res != nil {
|
|
fmt.Fprintf(w, "OnChain:\t%t\n", res != nil)
|
|
fmt.Fprintf(w, "VMState:\t%s\n", res.VMState.String())
|
|
if res.FaultException != "" {
|
|
fmt.Fprintf(w, "FaultException:\t%s\n", res.FaultException)
|
|
}
|
|
}
|
|
}
|