2020-03-02 12:39:02 +00:00
|
|
|
package wallet
|
|
|
|
|
|
|
|
import (
|
2022-08-31 12:43:30 +00:00
|
|
|
"encoding/json"
|
2020-03-02 12:39:02 +00:00
|
|
|
"fmt"
|
|
|
|
|
2022-08-05 10:32:37 +00:00
|
|
|
"github.com/nspcc-dev/neo-go/cli/cmdargs"
|
2021-04-16 08:12:51 +00:00
|
|
|
"github.com/nspcc-dev/neo-go/cli/flags"
|
2020-06-17 21:15:13 +00:00
|
|
|
"github.com/nspcc-dev/neo-go/cli/options"
|
2020-10-02 13:13:17 +00:00
|
|
|
"github.com/nspcc-dev/neo-go/cli/paramcontext"
|
2023-12-28 11:58:38 +00:00
|
|
|
"github.com/nspcc-dev/neo-go/cli/txctx"
|
|
|
|
"github.com/nspcc-dev/neo-go/pkg/core/state"
|
2020-03-02 12:39:02 +00:00
|
|
|
"github.com/nspcc-dev/neo-go/pkg/core/transaction"
|
2023-12-28 11:58:38 +00:00
|
|
|
"github.com/nspcc-dev/neo-go/pkg/rpcclient/waiter"
|
2020-03-02 12:39:02 +00:00
|
|
|
"github.com/urfave/cli"
|
|
|
|
)
|
|
|
|
|
2021-03-03 11:47:36 +00:00
|
|
|
func signStoredTransaction(ctx *cli.Context) error {
|
2022-08-31 12:43:30 +00:00
|
|
|
var (
|
|
|
|
out = ctx.String("out")
|
|
|
|
rpcNode = ctx.String(options.RPCEndpointFlag)
|
|
|
|
addrFlag = ctx.Generic("address").(*flags.Address)
|
2023-12-28 11:58:38 +00:00
|
|
|
aer *state.AppExecResult
|
2022-08-31 12:43:30 +00:00
|
|
|
)
|
2022-08-05 10:32:37 +00:00
|
|
|
if err := cmdargs.EnsureNone(ctx); err != nil {
|
|
|
|
return err
|
|
|
|
}
|
2020-03-02 12:39:02 +00:00
|
|
|
|
2022-08-31 12:43:30 +00:00
|
|
|
pc, err := paramcontext.Read(ctx.String("in"))
|
2020-03-02 12:39:02 +00:00
|
|
|
if err != nil {
|
|
|
|
return cli.NewExitError(err, 1)
|
|
|
|
}
|
2022-08-31 12:43:30 +00:00
|
|
|
|
2021-04-16 08:12:51 +00:00
|
|
|
if !addrFlag.IsSet {
|
|
|
|
return cli.NewExitError("address was not provided", 1)
|
2020-03-02 12:39:02 +00:00
|
|
|
}
|
2023-12-04 14:02:44 +00:00
|
|
|
acc, _, err := options.GetAccFromContext(ctx)
|
2020-08-07 09:34:54 +00:00
|
|
|
if err != nil {
|
|
|
|
return cli.NewExitError(err, 1)
|
2020-03-02 12:39:02 +00:00
|
|
|
}
|
|
|
|
|
2022-08-31 12:43:30 +00:00
|
|
|
tx, ok := pc.Verifiable.(*transaction.Transaction)
|
2020-03-02 12:39:02 +00:00
|
|
|
if !ok {
|
|
|
|
return cli.NewExitError("verifiable item is not a transaction", 1)
|
|
|
|
}
|
|
|
|
|
2023-12-04 13:41:33 +00:00
|
|
|
if !tx.HasSigner(acc.ScriptHash()) {
|
2021-03-03 13:05:33 +00:00
|
|
|
return cli.NewExitError("tx signers don't contain provided account", 1)
|
|
|
|
}
|
|
|
|
|
2022-08-31 19:38:35 +00:00
|
|
|
if acc.CanSign() {
|
2022-09-01 17:42:42 +00:00
|
|
|
sign := acc.SignHashable(pc.Network, pc.Verifiable)
|
2023-12-04 13:41:33 +00:00
|
|
|
if err := pc.AddSignature(acc.ScriptHash(), acc.Contract, acc.PublicKey(), sign); err != nil {
|
2022-08-31 19:38:35 +00:00
|
|
|
return cli.NewExitError(fmt.Errorf("can't add signature: %w", err), 1)
|
|
|
|
}
|
|
|
|
} else if rpcNode == "" {
|
|
|
|
return cli.NewExitError(fmt.Errorf("can't sign transactions with the given account and no RPC endpoing given to send anything signed"), 1)
|
2020-10-02 06:40:41 +00:00
|
|
|
}
|
2022-08-31 12:43:30 +00:00
|
|
|
// Not saving and not sending, print.
|
|
|
|
if out == "" && rpcNode == "" {
|
|
|
|
txt, err := json.MarshalIndent(pc, " ", " ")
|
|
|
|
if err != nil {
|
|
|
|
return cli.NewExitError(fmt.Errorf("can't display resulting context: %w", err), 1)
|
|
|
|
}
|
|
|
|
fmt.Fprintln(ctx.App.Writer, string(txt))
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
if out != "" {
|
|
|
|
if err := paramcontext.Save(pc, out); err != nil {
|
|
|
|
return cli.NewExitError(fmt.Errorf("can't save resulting context: %w", err), 1)
|
2020-10-02 06:40:41 +00:00
|
|
|
}
|
2020-03-02 12:39:02 +00:00
|
|
|
}
|
2022-08-31 12:43:30 +00:00
|
|
|
if rpcNode != "" {
|
2022-08-31 19:38:35 +00:00
|
|
|
tx, err = pc.GetCompleteTransaction()
|
|
|
|
if err != nil {
|
|
|
|
return cli.NewExitError(fmt.Errorf("failed to complete transaction: %w", err), 1)
|
2020-03-02 12:39:02 +00:00
|
|
|
}
|
|
|
|
|
2020-06-17 21:15:13 +00:00
|
|
|
gctx, cancel := options.GetTimeoutContext(ctx)
|
2020-03-02 12:39:02 +00:00
|
|
|
defer cancel()
|
|
|
|
|
2021-03-03 13:00:04 +00:00
|
|
|
var err error // `GetRPCClient` returns specialized type.
|
2020-06-17 21:15:13 +00:00
|
|
|
c, err := options.GetRPCClient(gctx, ctx)
|
2020-03-02 12:39:02 +00:00
|
|
|
if err != nil {
|
2021-11-29 08:29:08 +00:00
|
|
|
return cli.NewExitError(fmt.Errorf("failed to create RPC client: %w", err), 1)
|
2020-06-17 21:15:13 +00:00
|
|
|
}
|
2020-07-21 07:31:45 +00:00
|
|
|
res, err := c.SendRawTransaction(tx)
|
|
|
|
if err != nil {
|
2021-11-29 08:29:08 +00:00
|
|
|
return cli.NewExitError(fmt.Errorf("failed to submit transaction to RPC node: %w", err), 1)
|
2020-03-02 12:39:02 +00:00
|
|
|
}
|
2023-12-28 11:58:38 +00:00
|
|
|
if ctx.Bool("await") {
|
|
|
|
version, err := c.GetVersion()
|
|
|
|
aer, err = waiter.New(c, version).Wait(res, tx.ValidUntilBlock, err)
|
|
|
|
if err != nil {
|
|
|
|
return cli.NewExitError(fmt.Errorf("failed to await transaction %s: %w", res.StringLE(), err), 1)
|
|
|
|
}
|
|
|
|
}
|
2020-03-02 12:39:02 +00:00
|
|
|
}
|
|
|
|
|
2023-12-28 11:58:38 +00:00
|
|
|
txctx.DumpTransactionInfo(ctx.App.Writer, tx.Hash(), aer)
|
2020-03-02 12:39:02 +00:00
|
|
|
return nil
|
|
|
|
}
|