Adding QuorumPrivateTxSigner for signing and recovering private txs. (#767)

Refactor private transaction signing and add a QuorumPrivateTxSigner for signing and recovering private txs.
This commit is contained in:
libby kent 2019-07-11 13:32:19 -04:00 committed by Samer Falah
parent 0b12c423e0
commit e0564f7b41
14 changed files with 231 additions and 74 deletions

View File

@ -111,7 +111,7 @@ type Wallet interface {
// about which fields or actions are needed. The user may retry by providing
// the needed details via SignTxWithPassphrase, or by other means (e.g. unlock
// the account in a keystore).
SignTx(account Account, tx *types.Transaction, chainID *big.Int, isQuorum bool) (*types.Transaction, error)
SignTx(account Account, tx *types.Transaction, chainID *big.Int) (*types.Transaction, error)
// SignHashWithPassphrase requests the wallet to sign the given hash with the
// given passphrase as extra authentication information.

View File

@ -25,6 +25,7 @@ import (
crand "crypto/rand"
"errors"
"fmt"
"github.com/ethereum/go-ethereum/log"
"math/big"
"os"
"path/filepath"
@ -268,7 +269,7 @@ func (ks *KeyStore) SignHash(a accounts.Account, hash []byte) ([]byte, error) {
}
// SignTx signs the given transaction with the requested account.
func (ks *KeyStore) SignTx(a accounts.Account, tx *types.Transaction, chainID *big.Int, isQuorum bool) (*types.Transaction, error) {
func (ks *KeyStore) SignTx(a accounts.Account, tx *types.Transaction, chainID *big.Int) (*types.Transaction, error) {
// Look up the key to sign with and abort if it cannot be found
ks.mu.RLock()
defer ks.mu.RUnlock()
@ -277,8 +278,15 @@ func (ks *KeyStore) SignTx(a accounts.Account, tx *types.Transaction, chainID *b
if !found {
return nil, ErrLocked
}
// start quorum specific
if tx.IsPrivate() {
log.Info("Private transaction signing with QuorumPrivateTxSigner")
return types.SignTx(tx, types.QuorumPrivateTxSigner{}, unlockedKey.PrivateKey)
} // End quorum specific
// Depending on the presence of the chain ID, sign with EIP155 or homestead
if chainID != nil && !tx.IsPrivate() {
if chainID != nil {
return types.SignTx(tx, types.NewEIP155Signer(chainID), unlockedKey.PrivateKey)
}
return types.SignTx(tx, types.HomesteadSigner{}, unlockedKey.PrivateKey)
@ -305,6 +313,9 @@ func (ks *KeyStore) SignTxWithPassphrase(a accounts.Account, passphrase string,
}
defer zeroKey(key.PrivateKey)
if tx.IsPrivate() {
return types.SignTx(tx, types.QuorumPrivateTxSigner{}, key.PrivateKey)
}
// Depending on the presence of the chain ID, sign with EIP155 or homestead
if chainID != nil {
return types.SignTx(tx, types.NewEIP155Signer(chainID), key.PrivateKey)

View File

@ -98,7 +98,7 @@ func (w *keystoreWallet) SignHash(account accounts.Account, hash []byte) ([]byte
// with the given account. If the wallet does not wrap this particular account,
// an error is returned to avoid account leakage (even though in theory we may
// be able to sign via our shared keystore backend).
func (w *keystoreWallet) SignTx(account accounts.Account, tx *types.Transaction, chainID *big.Int, isQuorum bool) (*types.Transaction, error) {
func (w *keystoreWallet) SignTx(account accounts.Account, tx *types.Transaction, chainID *big.Int) (*types.Transaction, error) {
// Make sure the requested account is contained within
if account.Address != w.account.Address {
return nil, accounts.ErrUnknownAccount
@ -107,7 +107,7 @@ func (w *keystoreWallet) SignTx(account accounts.Account, tx *types.Transaction,
return nil, accounts.ErrUnknownAccount
}
// Account seems valid, request the keystore to sign
return w.keystore.SignTx(account, tx, chainID, isQuorum)
return w.keystore.SignTx(account, tx, chainID)
}
// SignHashWithPassphrase implements accounts.Wallet, attempting to sign the

View File

@ -509,12 +509,12 @@ func (w *wallet) SignHash(account accounts.Account, hash []byte) ([]byte, error)
// Note, if the version of the Ethereum application running on the Ledger wallet is
// too old to sign EIP-155 transactions, but such is requested nonetheless, an error
// will be returned opposed to silently signing in Homestead mode.
func (w *wallet) SignTx(account accounts.Account, tx *types.Transaction, chainID *big.Int, isQuorum bool) (*types.Transaction, error) {
func (w *wallet) SignTx(account accounts.Account, tx *types.Transaction, chainID *big.Int) (*types.Transaction, error) {
w.stateLock.RLock() // Comms have own mutex, this is for the state fields
defer w.stateLock.RUnlock()
if isQuorum {
return nil, errors.New("Signing Quorum transactions with a USB wallet not yet supported")
if tx.IsPrivate() {
return nil, errors.New("Signing Quorum Private transactions with a USB wallet not yet supported")
}
// If the wallet is closed, abort
@ -563,5 +563,5 @@ func (w *wallet) SignHashWithPassphrase(account accounts.Account, passphrase str
// transaction with the given account using passphrase as extra authentication.
// Since USB wallets don't rely on passphrases, these are silently ignored.
func (w *wallet) SignTxWithPassphrase(account accounts.Account, passphrase string, tx *types.Transaction, chainID *big.Int) (*types.Transaction, error) {
return w.SignTx(account, tx, chainID, false)
return w.SignTx(account, tx, chainID)
}

View File

@ -473,7 +473,7 @@ func (f *faucet) apiHandler(conn *websocket.Conn) {
amount = new(big.Int).Div(amount, new(big.Int).Exp(big.NewInt(2), big.NewInt(int64(msg.Tier)), nil))
tx := types.NewTransaction(f.nonce+uint64(len(f.reqs)), address, amount, 21000, f.price, nil)
signed, err := f.keystore.SignTx(f.account, tx, f.config.ChainID, false)
signed, err := f.keystore.SignTx(f.account, tx, f.config.ChainID)
if err != nil {
f.lock.Unlock()
if err = sendError(conn, err); err != nil {

View File

@ -47,7 +47,12 @@ func (cg *callHelper) MakeCall(private bool, key *ecdsa.PrivateKey, to common.Ad
cg.header.GasLimit = 4700000
signer := types.MakeSigner(params.QuorumTestChainConfig, cg.header.Number)
if private {
signer = types.QuorumPrivateTxSigner{}
}
tx, err := types.SignTx(types.NewTransaction(cg.TxNonce(from), to, new(big.Int), 1000000, new(big.Int), input), signer, key)
if err != nil {
return err
}
@ -60,15 +65,13 @@ func (cg *callHelper) MakeCall(private bool, key *ecdsa.PrivateKey, to common.Ad
publicState, privateState := cg.PublicState, cg.PrivateState
if !private {
privateState = publicState
} else {
tx.SetPrivate()
}
// TODO(joel): can we just pass nil instead of bc?
bc, _ := NewBlockChain(cg.db, nil, params.QuorumTestChainConfig, ethash.NewFaker(), vm.Config{}, nil)
context := NewEVMContext(msg, &cg.header, bc, &from)
vmenv := vm.NewEVM(context, publicState, privateState, params.QuorumTestChainConfig, vm.Config{})
_, _, _, err = ApplyMessage(vmenv, msg, cg.gp)
sender := vm.AccountRef(msg.From())
vmenv.Call(sender, to, msg.Data(), 100000000, new(big.Int))
if err != nil {
return err
}

View File

@ -263,13 +263,15 @@ func runTessera() (*osExec.Cmd, error) {
}
// 600a600055600060006001a1
// [1] PUSH1 0x0a (store value)
// [3] PUSH1 0x00 (store addr)
// [4] SSTORE
// [6] PUSH1 0x00
// [8] PUSH1 0x00
// [10] PUSH1 0x01
// [11] LOG1
// 60 0a, 60 00, 55, 60 00, 60 00, 60 01, a1
// [1] (0x60) PUSH1 0x0a (store value)
// [3] (0x60) PUSH1 0x00 (store addr)
// [4] (0x55) SSTORE (Store (k-00,v-a))
// [6] (0x60) PUSH1 0x00
// [8] (0x60) PUSH1 0x00
// [10](0x60) PUSH1 0x01
// [11](0xa1) LOG1 offset(0x01), len(0x00), topic(0x00)
//
// Store then log
func TestPrivateTransaction(t *testing.T) {
@ -294,10 +296,12 @@ func TestPrivateTransaction(t *testing.T) {
prvContractAddr := common.Address{1}
pubContractAddr := common.Address{2}
// SSTORE (K,V) SSTORE(0, 10): 600a600055
// +
// LOG1 OFFSET LEN TOPIC, LOG1 (a1) 01, 00, 00: 600060006001a1
privateState.SetCode(prvContractAddr, common.Hex2Bytes("600a600055600060006001a1"))
privateState.SetState(prvContractAddr, common.Hash{}, common.Hash{9})
// SSTORE (K,V) SSTORE(0, 14): 6014600055
publicState.SetCode(pubContractAddr, common.Hex2Bytes("6014600055"))
publicState.SetState(pubContractAddr, common.Hash{}, common.Hash{19})
if publicState.Exist(prvContractAddr) {
t.Error("didn't expect private contract address to exist on public state")
@ -305,6 +309,7 @@ func TestPrivateTransaction(t *testing.T) {
// Private transaction 1
err = helper.MakeCall(true, key, prvContractAddr, nil)
if err != nil {
t.Fatal(err)
}

View File

@ -42,6 +42,8 @@ func deriveSigner(V *big.Int) Signer {
// joel: this is one of the two places we used a wrong signer to print txes
if V.Sign() != 0 && isProtectedV(V) {
return NewEIP155Signer(deriveChainId(V))
} else if isPrivate(V) {
return QuorumPrivateTxSigner{}
} else {
return HomesteadSigner{}
}
@ -404,7 +406,7 @@ func NewTransactionsByPriceAndNonce(signer Signer, txs map[common.Address]Transa
for from, accTxs := range txs {
// Ensure the sender address is from the signer
acc, err := Sender(signer, accTxs[0])
if (err == nil) {
if err == nil {
heads = append(heads, accTxs[0])
txs[acc] = accTxs[1:]
} else {
@ -498,6 +500,14 @@ func (tx *Transaction) IsPrivate() bool {
return tx.data.V.Uint64() == 37 || tx.data.V.Uint64() == 38
}
/*
* Indicates that a transaction is private, but doesn't necessarily set the correct v value, as it can be called on
* an unsigned transaction.
* pre homestead signer, all v values were v=27 or v=28, with EIP155Signer that change,
* but SetPrivate() is also used on unsigned transactions to temporarily set the v value to indicate
* the transaction is intended to be private, and so that the correct signer can be selected. The signer will correctly
* set the valid v value (37 or 38): This helps minimize changes vs upstream go-ethereum code.
*/
func (tx *Transaction) SetPrivate() {
if tx.IsPrivate() {
return

View File

@ -126,7 +126,7 @@ var big8 = big.NewInt(8)
func (s EIP155Signer) Sender(tx *Transaction) (common.Address, error) {
if tx.IsPrivate() {
return HomesteadSigner{}.Sender(tx)
return QuorumPrivateTxSigner{}.Sender(tx)
}
if !tx.Protected() {
return HomesteadSigner{}.Sender(tx)
@ -136,16 +136,12 @@ func (s EIP155Signer) Sender(tx *Transaction) (common.Address, error) {
}
V := new(big.Int).Sub(tx.data.V, s.chainIdMul)
V.Sub(V, big8)
return recoverPlain(s.Hash(tx), tx.data.R, tx.data.S, V, true, tx.IsPrivate())
return recoverPlain(s.Hash(tx), tx.data.R, tx.data.S, V, true)
}
// SignatureValues returns signature values. This signature
// needs to be in the [R || S || V] format where V is 0 or 1.
func (s EIP155Signer) SignatureValues(tx *Transaction, sig []byte) (R, S, V *big.Int, err error) {
if tx.IsPrivate() {
return HomesteadSigner{}.SignatureValues(tx, sig)
}
R, S, V, err = HomesteadSigner{}.SignatureValues(tx, sig)
if err != nil {
return nil, nil, nil, err
@ -187,7 +183,7 @@ func (hs HomesteadSigner) SignatureValues(tx *Transaction, sig []byte) (r, s, v
}
func (hs HomesteadSigner) Sender(tx *Transaction) (common.Address, error) {
return recoverPlain(hs.Hash(tx), tx.data.R, tx.data.S, tx.data.V, true, tx.IsPrivate())
return recoverPlain(hs.Hash(tx), tx.data.R, tx.data.S, tx.data.V, true)
}
type FrontierSigner struct{}
@ -205,11 +201,7 @@ func (fs FrontierSigner) SignatureValues(tx *Transaction, sig []byte) (r, s, v *
}
r = new(big.Int).SetBytes(sig[:32])
s = new(big.Int).SetBytes(sig[32:64])
if tx.IsPrivate() {
v = new(big.Int).SetBytes([]byte{sig[64] + 37})
} else {
v = new(big.Int).SetBytes([]byte{sig[64] + 27})
}
v = new(big.Int).SetBytes([]byte{sig[64] + 27})
return r, s, v, nil
}
@ -227,15 +219,16 @@ func (fs FrontierSigner) Hash(tx *Transaction) common.Hash {
}
func (fs FrontierSigner) Sender(tx *Transaction) (common.Address, error) {
return recoverPlain(fs.Hash(tx), tx.data.R, tx.data.S, tx.data.V, false, tx.IsPrivate())
return recoverPlain(fs.Hash(tx), tx.data.R, tx.data.S, tx.data.V, false)
}
func recoverPlain(sighash common.Hash, R, S, Vb *big.Int, homestead bool, isPrivate bool) (common.Address, error) {
func recoverPlain(sighash common.Hash, R, S, Vb *big.Int, homestead bool) (common.Address, error) {
if Vb.BitLen() > 8 {
return common.Address{}, ErrInvalidSig
}
var offset uint64
if isPrivate {
// private transaction has a v value of 37 or 38
if isPrivate(Vb) {
offset = 37
} else {
offset = 27

View File

@ -0,0 +1,61 @@
// Copyright 2016 The go-ethereum Authors
// This file is part of the go-ethereum library.
//
// The go-ethereum library is free software: you can redistribute it and/or modify
// it under the terms of the GNU Lesser General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// The go-ethereum library is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU Lesser General Public License for more details.
//
// You should have received a copy of the GNU Lesser General Public License
// along with the go-ethereum library. If not, see <http://www.gnu.org/licenses/>.
package types
import (
"math/big"
"github.com/ethereum/go-ethereum/common"
)
// Signs with Homestead
// obtains sender from EIP55Signer
type QuorumPrivateTxSigner struct{ HomesteadSigner }
func (s QuorumPrivateTxSigner) Sender(tx *Transaction) (common.Address, error) {
return HomesteadSigner{}.Sender(tx)
}
// SignatureValues returns signature values. This signature
// needs to be in the [R || S || V] format where V is 0 or 1.
func (qs QuorumPrivateTxSigner) SignatureValues(tx *Transaction, sig []byte) (R, S, V *big.Int, err error) {
r, s, v, err := HomesteadSigner{}.SignatureValues(tx, sig)
// update v for private transaction marker: needs to be 37 (0+37) or 38 (1+37) for a private transaction.
v = new(big.Int).SetBytes([]byte{sig[64] + 37})
return r, s, v, nil
}
// Hash returns the hash to be signed by the sender.
// It does not uniquely identify the transaction.
func (s QuorumPrivateTxSigner) Hash(tx *Transaction) common.Hash {
return s.HomesteadSigner.Hash(tx)
}
func (s QuorumPrivateTxSigner) Equal(s2 Signer) bool {
_, ok := s2.(QuorumPrivateTxSigner)
return ok
}
/*
* If v is `37` or `38` that marks the transaction as private in Quorum.
* Note: this means quorum chains cannot have a public ethereum chainId == 1, as the EIP155 v
* param is `37` and `38` for the public Ethereum chain. Having a private chain with a chainId ==1
* is discouraged in the general Ethereum ecosystem.
*/
func isPrivate(v *big.Int) bool {
return v.Cmp(big.NewInt(37)) == 0 || v.Cmp(big.NewInt(38)) == 0
}

View File

@ -0,0 +1,63 @@
// Copyright 2014 The go-ethereum Authors
// This file is part of the go-ethereum library.
//
// The go-ethereum library is free software: you can redistribute it and/or modify
// it under the terms of the GNU Lesser General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// The go-ethereum library is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU Lesser General Public License for more details.
//
// You should have received a copy of the GNU Lesser General Public License
// along with the go-ethereum library. If not, see <http://www.gnu.org/licenses/>.
package types
import (
"crypto/ecdsa"
"fmt"
"math/big"
"testing"
"github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/crypto"
testifyassert "github.com/stretchr/testify/assert"
)
func signTxWithSigner(signer Signer, key *ecdsa.PrivateKey) (*Transaction, common.Address, error) {
addr := crypto.PubkeyToAddress(key.PublicKey)
tx := NewTransaction(0, addr, new(big.Int), 0, new(big.Int), nil)
signedTx, err := SignTx(tx, signer, key)
return signedTx, addr, err
}
// run all the tests in this file
// $> go test $(go list ./...) -run QuorumSignPrivate
// test with QuorumPrivateSigner
/*
* $> go test -run TestQuorumSignPrivateQuorum
*/
func TestQuorumSignPrivateQuorum(t *testing.T) {
assert := testifyassert.New(t)
keys := []*big.Int{k0v, k1v}
for i := 0; i < len(keys); i++ {
key, _ := createKey(crypto.S256(), keys[i])
qpPrivateSigner := QuorumPrivateTxSigner{HomesteadSigner{}}
signedTx, addr, err := signTxWithSigner(qpPrivateSigner, key)
assert.Nil(err, err)
assert.True(signedTx.IsPrivate(),
fmt.Sprintf("The signed transaction is not private, signedTx.data.V is [%v]", signedTx.data.V))
from, err := Sender(qpPrivateSigner, signedTx)
assert.Nil(err, err)
assert.True(from == addr, fmt.Sprintf("Expected from == address, [%x] == [%x]", from, addr))
}
}

View File

@ -392,7 +392,14 @@ func (s *PrivateAccountAPI) SendTransaction(ctx context.Context, args SendTxArgs
defer s.nonceLock.UnlockAddr(args.From)
}
isPrivate := args.PrivateFor != nil
// Set some sanity defaults and terminate on failure
if err := args.setDefaults(ctx, s.b); err != nil {
return common.Hash{}, err
}
// Assemble the transaction and sign with the wallet
tx := args.toTransaction()
isPrivate := args.IsPrivate()
if isPrivate {
data := []byte(*args.Data)
@ -407,25 +414,18 @@ func (s *PrivateAccountAPI) SendTransaction(ctx context.Context, args SendTxArgs
// zekun: HACK
d := hexutil.Bytes(data)
args.Data = &d
tx = args.toTransaction()
// set to private before submitting to signer
// this sets the v value to 37 temporarily to indicate a private tx, and to choose the correct signer.
tx.SetPrivate()
}
// Set some sanity defaults and terminate on failure
if err := args.setDefaults(ctx, s.b); err != nil {
return common.Hash{}, err
}
// Assemble the transaction and sign with the wallet
tx := args.toTransaction()
var chainID *big.Int
if config := s.b.ChainConfig(); config.IsEIP155(s.b.CurrentBlock().Number()) && !isPrivate {
chainID = config.ChainID
}
signed, err := wallet.SignTxWithPassphrase(account, passwd, tx, chainID)
signed, err := wallet.SignTxWithPassphrase(account, passwd, tx, s.b.ChainConfig().ChainID)
if err != nil {
log.Warn("Failed transaction send attempt", "from", args.From, "to", args.To, "value", args.Value.ToInt(), "err", err)
return common.Hash{}, err
}
return submitTransaction(ctx, s.b, signed, isPrivate)
return submitTransaction(ctx, s.b, signed)
}
// SignTransaction will create a transaction from the given arguments and
@ -1238,6 +1238,7 @@ func (s *PublicTransactionPoolAPI) GetTransactionReceipt(ctx context.Context, ha
return fields, nil
}
// quorum: if signing a private TX set with tx.SetPrivate() before calling this method.
// sign is a helper function that signs a transaction with the private key of the given address.
func (s *PublicTransactionPoolAPI) sign(addr common.Address, tx *types.Transaction) (*types.Transaction, error) {
// Look up the wallet containing the requested signer
@ -1249,11 +1250,10 @@ func (s *PublicTransactionPoolAPI) sign(addr common.Address, tx *types.Transacti
}
// Request the wallet to sign the transaction
var chainID *big.Int
isQuorum := tx.IsPrivate()
if config := s.b.ChainConfig(); config.IsEIP155(s.b.CurrentBlock().Number()) && !tx.IsPrivate() {
chainID = config.ChainID
}
return wallet.SignTx(account, tx, chainID, isQuorum)
return wallet.SignTx(account, tx, chainID)
}
// SendTxArgs represents the arguments to sumbit a new transaction into the transaction pool.
@ -1276,6 +1276,10 @@ type SendTxArgs struct {
//End-Quorum
}
func (s SendTxArgs) IsPrivate() bool {
return s.PrivateFor != nil
}
// SendRawTxArgs represents the arguments to submit a new signed private transaction into the transaction pool.
type SendRawTxArgs struct {
PrivateFor []string `json:"privateFor"`
@ -1325,17 +1329,19 @@ func (args *SendTxArgs) toTransaction() *types.Transaction {
return types.NewTransaction(uint64(*args.Nonce), *args.To, (*big.Int)(args.Value), uint64(*args.Gas), (*big.Int)(args.GasPrice), input)
}
// TODO: this submits a signed transaction, if it is a signed private transaction that should already be recorded in the tx.
// submitTransaction is a helper function that submits tx to txPool and logs a message.
func submitTransaction(ctx context.Context, b Backend, tx *types.Transaction, isPrivate bool) (common.Hash, error) {
if isPrivate {
tx.SetPrivate()
}
func submitTransaction(ctx context.Context, b Backend, tx *types.Transaction) (common.Hash, error) {
if err := b.SendTx(ctx, tx); err != nil {
return common.Hash{}, err
}
if tx.To() == nil {
signer := types.MakeSigner(b.ChainConfig(), b.CurrentBlock().Number())
var signer types.Signer
if tx.IsPrivate() {
signer = types.QuorumPrivateTxSigner{}
} else {
signer = types.MakeSigner(b.ChainConfig(), b.CurrentBlock().Number())
}
from, err := types.Sender(signer, tx)
if err != nil {
return common.Hash{}, err
@ -1369,7 +1375,7 @@ func (s *PublicTransactionPoolAPI) SendTransaction(ctx context.Context, args Sen
defer s.nonceLock.UnlockAddr(args.From)
}
isPrivate := args.PrivateFor != nil
isPrivate := args.IsPrivate()
var data []byte
if isPrivate {
if args.Data != nil {
@ -1401,15 +1407,19 @@ func (s *PublicTransactionPoolAPI) SendTransaction(ctx context.Context, args Sen
tx := args.toTransaction()
var chainID *big.Int
isQuorum := tx.IsPrivate()
if config := s.b.ChainConfig(); config.IsEIP155(s.b.CurrentBlock().Number()) && !isPrivate {
chainID = config.ChainID
}
signed, err := wallet.SignTx(account, tx, chainID, isQuorum)
if isPrivate {
tx.SetPrivate()
}
signed, err := wallet.SignTx(account, tx, chainID)
if err != nil {
return common.Hash{}, err
}
return submitTransaction(ctx, s.b, signed, isPrivate)
return submitTransaction(ctx, s.b, signed)
}
// SendRawTransaction will add the signed transaction to the transaction pool.
@ -1419,7 +1429,7 @@ func (s *PublicTransactionPoolAPI) SendRawTransaction(ctx context.Context, encod
if err := rlp.DecodeBytes(encodedTx, tx); err != nil {
return common.Hash{}, err
}
return submitTransaction(ctx, s.b, tx, tx.IsPrivate())
return submitTransaction(ctx, s.b, tx)
}
// SendRawPrivateTransaction will add the signed transaction to the transaction pool.
@ -1432,7 +1442,7 @@ func (s *PublicTransactionPoolAPI) SendRawPrivateTransaction(ctx context.Context
}
txHash := []byte(tx.Data())
isPrivate := args.PrivateFor != nil
isPrivate := (args.PrivateFor != nil) && tx.IsPrivate()
if isPrivate {
if len(txHash) > 0 {
@ -1447,8 +1457,7 @@ func (s *PublicTransactionPoolAPI) SendRawPrivateTransaction(ctx context.Context
} else {
return common.Hash{}, fmt.Errorf("transaction is not private")
}
return submitTransaction(ctx, s.b, tx, isPrivate)
return submitTransaction(ctx, s.b, tx)
}
// Sign calculates an ECDSA signature for:
@ -1556,7 +1565,9 @@ func (s *PublicTransactionPoolAPI) Resend(ctx context.Context, sendArgs SendTxAr
for _, p := range pending {
var signer types.Signer = types.HomesteadSigner{}
if p.Protected() && !p.IsPrivate() {
if p.IsPrivate() {
signer = types.QuorumPrivateTxSigner{}
} else if p.Protected() {
signer = types.NewEIP155Signer(p.ChainId())
}
wantSigHash := signer.Hash(matchTx)
@ -1570,10 +1581,10 @@ func (s *PublicTransactionPoolAPI) Resend(ctx context.Context, sendArgs SendTxAr
sendArgs.Gas = gasLimit
}
newTx := sendArgs.toTransaction()
// set v param to 37 to indicate private tx before submitting to the signer.
if len(sendArgs.PrivateFor) > 0 {
newTx.SetPrivate()
}
signedTx, err := s.sign(sendArgs.From, newTx)
if err != nil {
return common.Hash{}, err

View File

@ -85,7 +85,7 @@ func TestAccountManagement(t *testing.T) {
if err := ks.Unlock(signer, "Signer password"); err != nil {
t.Fatalf("Failed to unlock account: %v", err)
}
if _, err := ks.SignTx(signer, tx, chain, false); err != nil {
if _, err := ks.SignTx(signer, tx, chain); err != nil {
t.Fatalf("Failed to sign with unlocked account: %v", err)
}
if err := ks.Lock(signer.Address); err != nil {
@ -95,7 +95,7 @@ func TestAccountManagement(t *testing.T) {
if err := ks.TimedUnlock(signer, "Signer password", time.Second); err != nil {
t.Fatalf("Failed to time unlock account: %v", err)
}
if _, err := ks.SignTx(signer, tx, chain, false); err != nil {
if _, err := ks.SignTx(signer, tx, chain); err != nil {
t.Fatalf("Failed to sign with time unlocked account: %v", err)
}
}

View File

@ -120,7 +120,7 @@ func (ks *KeyStore) SignTx(account *Account, tx *Transaction, chainID *BigInt) (
if chainID == nil { // Null passed from mobile app
chainID = new(BigInt)
}
signed, err := ks.keystore.SignTx(account.account, tx.tx, chainID.bigint, false)
signed, err := ks.keystore.SignTx(account.account, tx.tx, chainID.bigint)
if err != nil {
return nil, err
}