diff --git a/cli/wallet/wallet.go b/cli/wallet/wallet.go index dc97a7661..e677c6959 100644 --- a/cli/wallet/wallet.go +++ b/cli/wallet/wallet.go @@ -16,7 +16,6 @@ import ( "github.com/CityOfZion/neo-go/pkg/rpc/client" "github.com/CityOfZion/neo-go/pkg/rpc/request" "github.com/CityOfZion/neo-go/pkg/util" - "github.com/CityOfZion/neo-go/pkg/vm/opcode" "github.com/CityOfZion/neo-go/pkg/wallet" "github.com/urfave/cli" "golang.org/x/crypto/ssh/terminal" @@ -232,7 +231,7 @@ func claimGas(ctx *cli.Context) error { ScriptHash: scriptHash, }) - signTx(tx, acc) + _ = acc.SignTx(tx) if err := c.SendRawTransaction(tx); err != nil { return cli.NewExitError(err, 1) } @@ -433,7 +432,7 @@ func transferAsset(ctx *cli.Context) error { Position: 1, }) - signTx(tx, acc) + _ = acc.SignTx(tx) if err := c.SendRawTransaction(tx); err != nil { return cli.NewExitError(err, 1) } @@ -495,23 +494,6 @@ func createWallet(ctx *cli.Context) error { return nil } -func signTx(tx *transaction.Transaction, acc *wallet.Account) { - priv := acc.PrivateKey() - sign := priv.Sign(tx.GetSignedPart()) - invoc := append([]byte{byte(opcode.PUSHBYTES64)}, sign...) - tx.Scripts = []transaction.Witness{{ - InvocationScript: invoc, - VerificationScript: getVerificationScript(acc), - }} -} - -func getVerificationScript(acc *wallet.Account) []byte { - if acc.Contract != nil { - return acc.Contract.Script - } - return acc.PrivateKey().PublicKey().GetVerificationScript() -} - func readAccountInfo() (string, string, error) { buf := bufio.NewReader(os.Stdin) fmt.Print("Enter the name of the account > ") diff --git a/integration/performance_test.go b/integration/performance_test.go index e75e45087..7945ddfce 100644 --- a/integration/performance_test.go +++ b/integration/performance_test.go @@ -11,7 +11,7 @@ import ( "github.com/CityOfZion/neo-go/pkg/crypto/keys" "github.com/CityOfZion/neo-go/pkg/encoding/address" "github.com/CityOfZion/neo-go/pkg/network" - "github.com/CityOfZion/neo-go/pkg/rpc/request" + "github.com/CityOfZion/neo-go/pkg/wallet" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" "go.uber.org/zap/zaptest" @@ -49,10 +49,12 @@ func prepareData(t *testing.B) []*transaction.Transaction { var data []*transaction.Transaction wif := getWif(t) + acc, err := wallet.NewAccountFromWIF(wif.S) + require.NoError(t, err) for n := 0; n < t.N; n++ { tx := getTX(t, wif) - require.NoError(t, request.SignTx(tx, wif)) + require.NoError(t, acc.SignTx(tx)) data = append(data, tx) } return data diff --git a/pkg/core/helper_test.go b/pkg/core/helper_test.go index 7814a616a..4ec207744 100644 --- a/pkg/core/helper_test.go +++ b/pkg/core/helper_test.go @@ -20,6 +20,7 @@ import ( "github.com/CityOfZion/neo-go/pkg/util" "github.com/CityOfZion/neo-go/pkg/vm/emit" "github.com/CityOfZion/neo-go/pkg/vm/opcode" + "github.com/CityOfZion/neo-go/pkg/wallet" "github.com/stretchr/testify/require" "go.uber.org/zap/zaptest" ) @@ -276,11 +277,9 @@ func _(t *testing.T) { ScriptHash: priv1.GetScriptHash(), }) - tx5.Scripts = []transaction.Witness{{ - InvocationScript: getInvocationScript(tx5.GetSignedPart(), priv), - VerificationScript: priv.PublicKey().GetVerificationScript(), - }} - + acc, err := wallet.NewAccountFromWIF(priv.WIF()) + require.NoError(t, err) + require.NoError(t, acc.SignTx(tx5)) b = bc.newBlock(newMinerTX(), tx5) require.NoError(t, bc.AddBlock(b)) diff --git a/pkg/rpc/client/rpc.go b/pkg/rpc/client/rpc.go index d12a23d03..5cb38dbeb 100644 --- a/pkg/rpc/client/rpc.go +++ b/pkg/rpc/client/rpc.go @@ -11,6 +11,7 @@ import ( "github.com/CityOfZion/neo-go/pkg/rpc/response/result" "github.com/CityOfZion/neo-go/pkg/smartcontract" "github.com/CityOfZion/neo-go/pkg/util" + "github.com/CityOfZion/neo-go/pkg/wallet" "github.com/pkg/errors" ) @@ -179,7 +180,10 @@ func (c *Client) SignAndPushInvocationTx(script []byte, wif *keys.WIF, gas util. } } - if err = request.SignTx(tx, wif); err != nil { + acc, err := wallet.NewAccountFromWIF(wif.S) + if err != nil { + return txHash, err + } else if err = acc.SignTx(tx); err != nil { return txHash, errors.Wrap(err, "failed to sign tx") } txHash = tx.Hash() diff --git a/pkg/rpc/request/txBuilder.go b/pkg/rpc/request/txBuilder.go index 25738d7e5..e7aa6c376 100644 --- a/pkg/rpc/request/txBuilder.go +++ b/pkg/rpc/request/txBuilder.go @@ -13,6 +13,7 @@ import ( "github.com/CityOfZion/neo-go/pkg/util" "github.com/CityOfZion/neo-go/pkg/vm/emit" "github.com/CityOfZion/neo-go/pkg/vm/opcode" + "github.com/CityOfZion/neo-go/pkg/wallet" errs "github.com/pkg/errors" ) @@ -48,7 +49,9 @@ func CreateRawContractTransaction(params ContractTxParams) (*transaction.Transac } receiverOutput = transaction.NewOutput(assetID, amount, toAddressHash) tx.AddOutput(receiverOutput) - if err = SignTx(tx, &wif); err != nil { + if acc, err := wallet.NewAccountFromWIF(wif.S); err != nil { + return nil, err + } else if err = acc.SignTx(tx); err != nil { return nil, errs.Wrap(err, "failed to sign tx") } @@ -77,27 +80,6 @@ func AddInputsAndUnspentsToTx(tx *transaction.Transaction, addr string, assetID 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 errs.Wrap(err, "failed to create invocation script") - } - witness.VerificationScript = wif.PrivateKey.PublicKey().GetVerificationScript() - tx.Scripts = append(tx.Scripts, witness) - tx.Hash() - - return nil -} - -// GetInvocationScript returns NEO VM script containing transaction signature. -func GetInvocationScript(tx *transaction.Transaction, wif *keys.WIF) ([]byte, error) { - signature := wif.PrivateKey.Sign(tx.GetSignedPart()) - return append([]byte{byte(opcode.PUSHBYTES64)}, signature...), nil -} - // CreateDeploymentScript returns a script that deploys given smart contract // with its metadata. func CreateDeploymentScript(avm []byte, contract *ContractDetails) ([]byte, error) { diff --git a/pkg/wallet/account.go b/pkg/wallet/account.go index 90635e5c6..68a44363b 100644 --- a/pkg/wallet/account.go +++ b/pkg/wallet/account.go @@ -7,11 +7,13 @@ import ( "errors" "fmt" + "github.com/CityOfZion/neo-go/pkg/core/transaction" "github.com/CityOfZion/neo-go/pkg/crypto/hash" "github.com/CityOfZion/neo-go/pkg/crypto/keys" "github.com/CityOfZion/neo-go/pkg/encoding/address" "github.com/CityOfZion/neo-go/pkg/smartcontract" "github.com/CityOfZion/neo-go/pkg/util" + "github.com/CityOfZion/neo-go/pkg/vm/opcode" ) // Account represents a NEO account. It holds the private and public key @@ -122,6 +124,29 @@ func NewAccount() (*Account, error) { return newAccountFromPrivateKey(priv), nil } +// SignTx signs transaction t and updates it's Witnesses. +func (a *Account) SignTx(t *transaction.Transaction) error { + if a.privateKey == nil { + return errors.New("account is not unlocked") + } + data := t.GetSignedPart() + sign := a.privateKey.Sign(data) + + t.Scripts = append(t.Scripts, transaction.Witness{ + InvocationScript: append([]byte{byte(opcode.PUSHBYTES64)}, sign...), + VerificationScript: a.getVerificationScript(), + }) + + return nil +} + +func (a *Account) getVerificationScript() []byte { + if a.Contract != nil { + return a.Contract.Script + } + return a.PrivateKey().PublicKey().GetVerificationScript() +} + // Decrypt decrypts the EncryptedWIF with the given passphrase returning error // if anything goes wrong. func (a *Account) Decrypt(passphrase string) error {