From 310104667dac8fb7e77d4eb4dca46488c805bc00 Mon Sep 17 00:00:00 2001 From: Roman Khimov Date: Wed, 20 Nov 2019 13:14:01 +0300 Subject: [PATCH] rpc: refactor out reusable parts of CreateRawContractTransaction() Signing and inputs/outputs management is common for different transactions, so make separate functions for them. --- pkg/rpc/txBuilder.go | 46 ++++++++++++++++++++++++++++++++------------ 1 file changed, 34 insertions(+), 12 deletions(-) diff --git a/pkg/rpc/txBuilder.go b/pkg/rpc/txBuilder.go index 72a2298af..abe1c581f 100644 --- a/pkg/rpc/txBuilder.go +++ b/pkg/rpc/txBuilder.go @@ -16,10 +16,7 @@ func CreateRawContractTransaction(params ContractTxParams) (*transaction.Transac tx = transaction.NewContractTX() toAddressHash, fromAddressHash util.Uint160 fromAddress string - senderOutput, receiverOutput *transaction.Output - inputs []transaction.Input - spent util.Fixed8 - witness transaction.Witness + receiverOutput *transaction.Output wif, assetID, address, amount, balancer = params.wif, params.assetID, params.address, params.value, params.balancer ) @@ -39,32 +36,57 @@ func CreateRawContractTransaction(params ContractTxParams) (*transaction.Transac Data: fromAddressHash.Bytes(), }) - if inputs, spent, err = balancer.CalculateInputs(fromAddress, assetID, amount); err != nil { - return nil, errs.Wrap(err, "Failed to get inputs for transaction") + if err = AddInputsAndUnspentsToTx(tx, fromAddress, assetID, amount, balancer); err != nil { + return nil, errs.Wrap(err, "failed to add inputs and unspents to transaction") + } + receiverOutput = transaction.NewOutput(assetID, amount, toAddressHash) + tx.AddOutput(receiverOutput) + if err = SignTx(tx, &wif); err != nil { + return nil, errs.Wrap(err, "failed to sign tx") + } + + return tx, nil +} + +// AddInputsAndUnspentsToTx adds inputs needed to transaction and one output +// with change. +func AddInputsAndUnspentsToTx(tx *transaction.Transaction, address string, assetID util.Uint256, amount util.Fixed8, balancer BalanceGetter) error { + scriptHash, err := crypto.Uint160DecodeAddress(address) + if err != nil { + return errs.Wrapf(err, "failed to take script hash from address: %v", address) + } + inputs, spent, err := balancer.CalculateInputs(address, assetID, amount) + if err != nil { + return errs.Wrap(err, "failed to get inputs") } for _, input := range inputs { tx.AddInput(&input) } if senderUnspent := spent - amount; senderUnspent > 0 { - senderOutput = transaction.NewOutput(assetID, senderUnspent, fromAddressHash) + senderOutput := transaction.NewOutput(assetID, senderUnspent, scriptHash) tx.AddOutput(senderOutput) } - receiverOutput = transaction.NewOutput(assetID, amount, toAddressHash) - tx.AddOutput(receiverOutput) + return nil +} + +// SignTx signs given transaction in-place using given key. +func SignTx(tx *transaction.Transaction, wif *keys.WIF) error { + var witness transaction.Witness + var err error if witness.InvocationScript, err = GetInvocationScript(tx, wif); err != nil { - return nil, errs.Wrap(err, "Failed to create invocation script") + return errs.Wrap(err, "failed to create invocation script") } witness.VerificationScript = wif.GetVerificationScript() tx.Scripts = append(tx.Scripts, &witness) tx.Hash() - return tx, nil + return nil } // GetInvocationScript returns NEO VM script containing transaction signature. -func GetInvocationScript(tx *transaction.Transaction, wif keys.WIF) ([]byte, error) { +func GetInvocationScript(tx *transaction.Transaction, wif *keys.WIF) ([]byte, error) { const ( pushbytes64 = 0x40 )