cli: rework registration commands with Actor

And reduce the amount of wasted GAS.
This commit is contained in:
Roman Khimov 2022-08-08 18:19:33 +03:00
parent 593fa4cac8
commit e98ac8bc53

View file

@ -12,8 +12,10 @@ import (
"github.com/nspcc-dev/neo-go/pkg/crypto/keys" "github.com/nspcc-dev/neo-go/pkg/crypto/keys"
"github.com/nspcc-dev/neo-go/pkg/encoding/address" "github.com/nspcc-dev/neo-go/pkg/encoding/address"
"github.com/nspcc-dev/neo-go/pkg/rpcclient" "github.com/nspcc-dev/neo-go/pkg/rpcclient"
"github.com/nspcc-dev/neo-go/pkg/rpcclient/actor"
"github.com/nspcc-dev/neo-go/pkg/smartcontract" "github.com/nspcc-dev/neo-go/pkg/smartcontract"
"github.com/nspcc-dev/neo-go/pkg/util" "github.com/nspcc-dev/neo-go/pkg/util"
"github.com/nspcc-dev/neo-go/pkg/vm/vmstate"
"github.com/nspcc-dev/neo-go/pkg/wallet" "github.com/nspcc-dev/neo-go/pkg/wallet"
"github.com/urfave/cli" "github.com/urfave/cli"
) )
@ -76,14 +78,24 @@ func newValidatorCommands() []cli.Command {
} }
func handleRegister(ctx *cli.Context) error { func handleRegister(ctx *cli.Context) error {
return handleCandidate(ctx, "registerCandidate", 100000000) // 1 additional GAS. return handleCandidate(ctx, true)
} }
func handleUnregister(ctx *cli.Context) error { func handleUnregister(ctx *cli.Context) error {
return handleCandidate(ctx, "unregisterCandidate", -1) return handleCandidate(ctx, false)
} }
func handleCandidate(ctx *cli.Context, method string, sysGas int64) error { func handleCandidate(ctx *cli.Context, register bool) error {
const (
regMethod = "registerCandidate"
unregMethod = "unregisterCandidate"
)
var (
err error
script []byte
sysGas int64
)
if err := cmdargs.EnsureNone(ctx); err != nil { if err := cmdargs.EnsureNone(ctx); err != nil {
return err return err
} }
@ -110,12 +122,9 @@ func handleCandidate(ctx *cli.Context, method string, sysGas int64) error {
return cli.NewExitError(err, 1) return cli.NewExitError(err, 1)
} }
if sysGas >= 0 { act, err := actor.NewSimple(c, acc)
regPrice, err := c.GetCandidateRegisterPrice() if err != nil {
if err != nil { return cli.NewExitError(fmt.Errorf("RPC actor issue: %w", err), 1)
return cli.NewExitError(err, 1)
}
sysGas += regPrice
} }
gas := flags.Fixed8FromContext(ctx, "gas") gas := flags.Fixed8FromContext(ctx, "gas")
@ -123,17 +132,40 @@ func handleCandidate(ctx *cli.Context, method string, sysGas int64) error {
if err != nil { if err != nil {
return err return err
} }
script, err := smartcontract.CreateCallWithAssertScript(neoContractHash, method, acc.PrivateKey().PublicKey().Bytes()) unregScript, err := smartcontract.CreateCallWithAssertScript(neoContractHash, unregMethod, acc.PrivateKey().PublicKey().Bytes())
if err != nil { if err != nil {
return cli.NewExitError(err, 1) return cli.NewExitError(err, 1)
} }
res, err := c.SignAndPushInvocationTx(script, acc, sysGas, gas, []rpcclient.SignerAccount{{ //nolint:staticcheck // SA1019: c.SignAndPushInvocationTx is deprecated if !register {
Signer: transaction.Signer{ script = unregScript
Account: acc.Contract.ScriptHash(), } else {
Scopes: transaction.CalledByEntry, script, err = smartcontract.CreateCallWithAssertScript(neoContractHash, regMethod, acc.PrivateKey().PublicKey().Bytes())
}, if err != nil {
Account: acc, return cli.NewExitError(err, 1)
}}) }
}
// Registration price is normally much bigger than MaxGasInvoke, so to
// determine proper amount of GAS we _always_ run unreg script and then
// add registration price to it if needed.
r, err := act.Run(unregScript)
if err != nil {
return cli.NewExitError(fmt.Errorf("Run failure: %w", err), 1)
}
sysGas = r.GasConsumed
if register {
// Deregistration will fail, so there is no point in checking State.
regPrice, err := c.GetCandidateRegisterPrice()
if err != nil {
return cli.NewExitError(err, 1)
}
sysGas += regPrice
} else if r.State != vmstate.Halt.String() {
return cli.NewExitError(fmt.Errorf("unregister transaction failed: %s", r.FaultException), 1)
}
res, _, err := act.SendUncheckedRun(script, sysGas, nil, func(t *transaction.Transaction) error {
t.NetworkFee += int64(gas)
return nil
})
if err != nil { if err != nil {
return cli.NewExitError(fmt.Errorf("failed to push transaction: %w", err), 1) return cli.NewExitError(fmt.Errorf("failed to push transaction: %w", err), 1)
} }