rpc/client: use CreateTxFromScript where possible

There is substantial overlap between `CreateTxFromScript` and
`SignAndPushInvocationTx`. This commit refactors both of them
to reuse common code.
This commit is contained in:
Evgenii Stratonikov 2020-08-17 16:49:47 +03:00
parent 16b10ab918
commit 6bdaefcfa4
4 changed files with 54 additions and 46 deletions

View file

@ -100,7 +100,7 @@ func handleCandidate(ctx *cli.Context, method string) error {
w := io.NewBufBinWriter()
emit.AppCallWithOperationAndArgs(w.BinWriter, client.NeoContractHash, method, acc.PrivateKey().PublicKey().Bytes())
emit.Opcode(w.BinWriter, opcode.ASSERT)
tx, err := c.CreateTxFromScript(w.Bytes(), acc, int64(gas))
tx, err := c.CreateTxFromScript(w.Bytes(), acc, -1, int64(gas))
if err != nil {
return cli.NewExitError(err, 1)
} else if err = acc.SignTx(tx); err != nil {
@ -155,7 +155,7 @@ func handleVote(ctx *cli.Context) error {
emit.AppCallWithOperationAndArgs(w.BinWriter, client.NeoContractHash, "vote", addr.BytesBE(), pubArg)
emit.Opcode(w.BinWriter, opcode.ASSERT)
tx, err := c.CreateTxFromScript(w.Bytes(), acc, int64(gas))
tx, err := c.CreateTxFromScript(w.Bytes(), acc, -1, int64(gas))
if err != nil {
return cli.NewExitError(err, 1)
}

View file

@ -134,39 +134,38 @@ func (c *Client) CreateNEP5MultiTransferTx(acc *wallet.Account, gas int64, recip
recipients[i].Address, recipients[i].Amount)
emit.Opcode(w.BinWriter, opcode.ASSERT)
}
return c.CreateTxFromScript(w.Bytes(), acc, gas)
return c.CreateTxFromScript(w.Bytes(), acc, -1, gas)
}
// CreateTxFromScript creates transaction and properly sets cosigners and NetworkFee.
func (c *Client) CreateTxFromScript(script []byte, acc *wallet.Account, gas int64) (*transaction.Transaction, error) {
// If sysFee <= 0, it is determined via result of `invokescript` RPC.
func (c *Client) CreateTxFromScript(script []byte, acc *wallet.Account, sysFee, netFee int64,
cosigners ...transaction.Signer) (*transaction.Transaction, error) {
from, err := address.StringToUint160(acc.Address)
if err != nil {
return nil, fmt.Errorf("bad account address: %v", err)
}
result, err := c.InvokeScript(script, []transaction.Signer{
{
Account: from,
Scopes: transaction.CalledByEntry,
},
})
signers := getSigners(from, cosigners)
if sysFee < 0 {
result, err := c.InvokeScript(script, signers)
if err != nil {
return nil, fmt.Errorf("can't add system fee to transaction: %w", err)
}
tx := transaction.New(c.opts.Network, script, result.GasConsumed)
tx.Signers = []transaction.Signer{
{
Account: from,
Scopes: transaction.CalledByEntry,
},
}
tx.ValidUntilBlock, err = c.CalculateValidUntilBlock()
if err != nil {
return nil, fmt.Errorf("can't calculate validUntilBlock: %w", err)
sysFee = result.GasConsumed
}
err = c.AddNetworkFee(tx, gas, acc)
tx := transaction.New(c.opts.Network, script, sysFee)
tx.Signers = signers
tx.ValidUntilBlock, err = c.CalculateValidUntilBlock()
if err != nil {
return nil, fmt.Errorf("can't add network fee to transaction: %w", err)
return nil, fmt.Errorf("failed to add validUntilBlock to transaction: %w", err)
}
err = c.AddNetworkFee(tx, netFee, acc)
if err != nil {
return nil, fmt.Errorf("failed to add network fee: %w", err)
}
return tx, nil

View file

@ -9,7 +9,6 @@ import (
"github.com/nspcc-dev/neo-go/pkg/core/block"
"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/encoding/address"
"github.com/nspcc-dev/neo-go/pkg/io"
"github.com/nspcc-dev/neo-go/pkg/rpc/request"
"github.com/nspcc-dev/neo-go/pkg/rpc/response/result"
@ -410,26 +409,7 @@ func (c *Client) SignAndPushInvocationTx(script []byte, acc *wallet.Account, sys
var txHash util.Uint256
var err error
tx := transaction.New(c.opts.Network, script, sysfee)
tx.SystemFee = sysfee
addr, err := address.StringToUint160(acc.Address)
if err != nil {
return txHash, fmt.Errorf("failed to get address: %w", err)
}
tx.Signers = getSigners(addr, cosigners)
validUntilBlock, err := c.CalculateValidUntilBlock()
if err != nil {
return txHash, fmt.Errorf("failed to add validUntilBlock to transaction: %w", err)
}
tx.ValidUntilBlock = validUntilBlock
err = c.AddNetworkFee(tx, int64(netfee), acc)
if err != nil {
return txHash, fmt.Errorf("failed to add network fee: %w", err)
}
tx, err := c.CreateTxFromScript(script, acc, sysfee, int64(netfee), cosigners...)
if err = acc.SignTx(tx); err != nil {
return txHash, fmt.Errorf("failed to sign tx: %w", err)
}

View file

@ -169,3 +169,32 @@ func TestPing(t *testing.T) {
httpSrv.Close()
require.Error(t, c.Ping())
}
func TestCreateTxFromScript(t *testing.T) {
chain, rpcSrv, httpSrv := initServerWithInMemoryChain(t)
defer chain.Close()
defer rpcSrv.Shutdown()
c, err := client.New(context.Background(), httpSrv.URL, client.Options{Network: testchain.Network()})
require.NoError(t, err)
priv := testchain.PrivateKey(0)
acc, err := wallet.NewAccountFromWIF(priv.WIF())
require.NoError(t, err)
t.Run("NoSystemFee", func(t *testing.T) {
tx, err := c.CreateTxFromScript([]byte{byte(opcode.PUSH1)}, acc, -1, 10)
require.NoError(t, err)
require.True(t, tx.ValidUntilBlock > chain.BlockHeight())
require.EqualValues(t, 30, tx.SystemFee) // PUSH1
require.True(t, len(tx.Signers) == 1)
require.Equal(t, acc.PrivateKey().GetScriptHash(), tx.Signers[0].Account)
})
t.Run("ProvideSystemFee", func(t *testing.T) {
tx, err := c.CreateTxFromScript([]byte{byte(opcode.PUSH1)}, acc, 123, 10)
require.NoError(t, err)
require.True(t, tx.ValidUntilBlock > chain.BlockHeight())
require.EqualValues(t, 123, tx.SystemFee)
require.True(t, len(tx.Signers) == 1)
require.Equal(t, acc.PrivateKey().GetScriptHash(), tx.Signers[0].Account)
})
}