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() w := io.NewBufBinWriter()
emit.AppCallWithOperationAndArgs(w.BinWriter, client.NeoContractHash, method, acc.PrivateKey().PublicKey().Bytes()) emit.AppCallWithOperationAndArgs(w.BinWriter, client.NeoContractHash, method, acc.PrivateKey().PublicKey().Bytes())
emit.Opcode(w.BinWriter, opcode.ASSERT) 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 { if err != nil {
return cli.NewExitError(err, 1) return cli.NewExitError(err, 1)
} else if err = acc.SignTx(tx); err != nil { } 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.AppCallWithOperationAndArgs(w.BinWriter, client.NeoContractHash, "vote", addr.BytesBE(), pubArg)
emit.Opcode(w.BinWriter, opcode.ASSERT) 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 { if err != nil {
return cli.NewExitError(err, 1) 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) recipients[i].Address, recipients[i].Amount)
emit.Opcode(w.BinWriter, opcode.ASSERT) 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. // 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) from, err := address.StringToUint160(acc.Address)
if err != nil { if err != nil {
return nil, fmt.Errorf("bad account address: %v", err) return nil, fmt.Errorf("bad account address: %v", err)
} }
result, err := c.InvokeScript(script, []transaction.Signer{
{ signers := getSigners(from, cosigners)
Account: from, if sysFee < 0 {
Scopes: transaction.CalledByEntry, result, err := c.InvokeScript(script, signers)
},
})
if err != nil { if err != nil {
return nil, fmt.Errorf("can't add system fee to transaction: %w", err) return nil, fmt.Errorf("can't add system fee to transaction: %w", err)
} }
tx := transaction.New(c.opts.Network, script, result.GasConsumed) sysFee = 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)
} }
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 { 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 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/block"
"github.com/nspcc-dev/neo-go/pkg/core/state" "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/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/io"
"github.com/nspcc-dev/neo-go/pkg/rpc/request" "github.com/nspcc-dev/neo-go/pkg/rpc/request"
"github.com/nspcc-dev/neo-go/pkg/rpc/response/result" "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 txHash util.Uint256
var err error var err error
tx := transaction.New(c.opts.Network, script, sysfee) tx, err := c.CreateTxFromScript(script, acc, sysfee, int64(netfee), cosigners...)
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)
}
if err = acc.SignTx(tx); err != nil { if err = acc.SignTx(tx); err != nil {
return txHash, fmt.Errorf("failed to sign tx: %w", err) return txHash, fmt.Errorf("failed to sign tx: %w", err)
} }

View file

@ -169,3 +169,32 @@ func TestPing(t *testing.T) {
httpSrv.Close() httpSrv.Close()
require.Error(t, c.Ping()) 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)
})
}