@@ -23,7 +23,6 @@ import (
23
23
"fmt"
24
24
"math/big"
25
25
"strings"
26
- "sync"
27
26
"time"
28
27
29
28
"github.com/ethereum/go-ethereum/accounts"
@@ -204,12 +203,13 @@ func (s *PublicAccountAPI) Accounts() []common.Address {
204
203
// It offers methods to create, (un)lock en list accounts. Some methods accept
205
204
// passwords and are therefore considered private by default.
206
205
type PrivateAccountAPI struct {
207
- am * accounts.Manager
208
- b Backend
206
+ am * accounts.Manager
207
+ nonceLock * AddrLocker
208
+ b Backend
209
209
}
210
210
211
211
// NewPrivateAccountAPI create a new PrivateAccountAPI.
212
- func NewPrivateAccountAPI (b Backend ) * PrivateAccountAPI {
212
+ func NewPrivateAccountAPI (b Backend , nonceLock * AddrLocker ) * PrivateAccountAPI {
213
213
return & PrivateAccountAPI {
214
214
am : b .AccountManager (),
215
215
b : b ,
@@ -316,17 +316,25 @@ func (s *PrivateAccountAPI) LockAccount(addr common.Address) bool {
316
316
// tries to sign it with the key associated with args.To. If the given passwd isn't
317
317
// able to decrypt the key it fails.
318
318
func (s * PrivateAccountAPI ) SendTransaction (ctx context.Context , args SendTxArgs , passwd string ) (common.Hash , error ) {
319
- // Set some sanity defaults and terminate on failure
320
- if err := args .setDefaults (ctx , s .b ); err != nil {
321
- return common.Hash {}, err
322
- }
323
319
// Look up the wallet containing the requested signer
324
320
account := accounts.Account {Address : args .From }
325
321
326
322
wallet , err := s .am .Find (account )
327
323
if err != nil {
328
324
return common.Hash {}, err
329
325
}
326
+
327
+ if args .Nonce == nil {
328
+ // Hold the addresse's mutex around signing to prevent concurrent assignment of
329
+ // the same nonce to multiple accounts.
330
+ s .nonceLock .LockAddr (args .From )
331
+ defer s .nonceLock .UnlockAddr (args .From )
332
+ }
333
+
334
+ // Set some sanity defaults and terminate on failure
335
+ if err := args .setDefaults (ctx , s .b ); err != nil {
336
+ return common.Hash {}, err
337
+ }
330
338
// Assemble the transaction and sign with the wallet
331
339
tx := args .toTransaction ()
332
340
@@ -886,18 +894,13 @@ func newRPCTransaction(b *types.Block, txHash common.Hash) (*RPCTransaction, err
886
894
887
895
// PublicTransactionPoolAPI exposes methods for the RPC interface
888
896
type PublicTransactionPoolAPI struct {
889
- b Backend
897
+ b Backend
898
+ nonceLock * AddrLocker
890
899
}
891
900
892
- // nonceMutex is a global mutex for locking the nonce while a transaction
893
- // is being submitted. This should be used when a nonce has not been provided by the user,
894
- // and we get a nonce from the pools. The mutex prevents the (an identical nonce) from being
895
- // read again during the time that the first transaction is being signed.
896
- var nonceMutex sync.RWMutex
897
-
898
901
// NewPublicTransactionPoolAPI creates a new RPC service with methods specific for the transaction pool.
899
- func NewPublicTransactionPoolAPI (b Backend ) * PublicTransactionPoolAPI {
900
- return & PublicTransactionPoolAPI {b }
902
+ func NewPublicTransactionPoolAPI (b Backend , nonceLock * AddrLocker ) * PublicTransactionPoolAPI {
903
+ return & PublicTransactionPoolAPI {b , nonceLock }
901
904
}
902
905
903
906
func getTransaction (chainDb ethdb.Database , b Backend , txHash common.Hash ) (* types.Transaction , bool , error ) {
@@ -1176,24 +1179,25 @@ func submitTransaction(ctx context.Context, b Backend, tx *types.Transaction) (c
1176
1179
// transaction pool.
1177
1180
func (s * PublicTransactionPoolAPI ) SendTransaction (ctx context.Context , args SendTxArgs ) (common.Hash , error ) {
1178
1181
1179
- if args .Nonce == nil {
1180
- // We'll need to set nonce from pool, and thus we need to lock here
1181
- nonceMutex .Lock ()
1182
- defer nonceMutex .Unlock ()
1183
-
1184
- }
1185
-
1186
- // Set some sanity defaults and terminate on failure
1187
- if err := args .setDefaults (ctx , s .b ); err != nil {
1188
- return common.Hash {}, err
1189
- }
1190
1182
// Look up the wallet containing the requested signer
1191
1183
account := accounts.Account {Address : args .From }
1192
1184
1193
1185
wallet , err := s .b .AccountManager ().Find (account )
1194
1186
if err != nil {
1195
1187
return common.Hash {}, err
1196
1188
}
1189
+
1190
+ if args .Nonce == nil {
1191
+ // Hold the addresse's mutex around signing to prevent concurrent assignment of
1192
+ // the same nonce to multiple accounts.
1193
+ s .nonceLock .LockAddr (args .From )
1194
+ defer s .nonceLock .UnlockAddr (args .From )
1195
+ }
1196
+
1197
+ // Set some sanity defaults and terminate on failure
1198
+ if err := args .setDefaults (ctx , s .b ); err != nil {
1199
+ return common.Hash {}, err
1200
+ }
1197
1201
// Assemble the transaction and sign with the wallet
1198
1202
tx := args .toTransaction ()
1199
1203
@@ -1270,14 +1274,12 @@ type SignTransactionResult struct {
1270
1274
// The node needs to have the private key of the account corresponding with
1271
1275
// the given from address and it needs to be unlocked.
1272
1276
func (s * PublicTransactionPoolAPI ) SignTransaction (ctx context.Context , args SendTxArgs ) (* SignTransactionResult , error ) {
1273
-
1274
1277
if args .Nonce == nil {
1275
- // We'll need to set nonce from pool, and thus we need to lock here
1276
- nonceMutex . Lock ()
1277
- defer nonceMutex . Unlock ( )
1278
-
1278
+ // Hold the addresse's mutex around signing to prevent concurrent assignment of
1279
+ // the same nonce to multiple accounts.
1280
+ s . nonceLock . LockAddr ( args . From )
1281
+ defer s . nonceLock . UnlockAddr ( args . From )
1279
1282
}
1280
-
1281
1283
if err := args .setDefaults (ctx , s .b ); err != nil {
1282
1284
return nil , err
1283
1285
}
0 commit comments