diff options
author | Péter Szilágyi <peterke@gmail.com> | 2017-05-30 23:15:57 +0800 |
---|---|---|
committer | GitHub <noreply@github.com> | 2017-05-30 23:15:57 +0800 |
commit | 41bdf49eedf003a051446ec3831a4c04178ac040 (patch) | |
tree | 3e732a610f12e77808cd7f3755bdd0f2262af70f /internal/ethapi/api.go | |
parent | 8df24760d74176cb01559e581b140e52b18cdc62 (diff) | |
parent | ea11f7dd7aa77856a04d83d0db8f303d02e0ce14 (diff) | |
download | dexon-41bdf49eedf003a051446ec3831a4c04178ac040.tar dexon-41bdf49eedf003a051446ec3831a4c04178ac040.tar.gz dexon-41bdf49eedf003a051446ec3831a4c04178ac040.tar.bz2 dexon-41bdf49eedf003a051446ec3831a4c04178ac040.tar.lz dexon-41bdf49eedf003a051446ec3831a4c04178ac040.tar.xz dexon-41bdf49eedf003a051446ec3831a4c04178ac040.tar.zst dexon-41bdf49eedf003a051446ec3831a4c04178ac040.zip |
Merge pull request #14516 from holiman/noncefixes
internal/ethapi: add mutex around signing + nonce assignment
Diffstat (limited to 'internal/ethapi/api.go')
-rw-r--r-- | internal/ethapi/api.go | 70 |
1 files changed, 36 insertions, 34 deletions
diff --git a/internal/ethapi/api.go b/internal/ethapi/api.go index cab33c191..c4a871e48 100644 --- a/internal/ethapi/api.go +++ b/internal/ethapi/api.go @@ -23,7 +23,6 @@ import ( "fmt" "math/big" "strings" - "sync" "time" "github.com/ethereum/go-ethereum/accounts" @@ -204,12 +203,13 @@ func (s *PublicAccountAPI) Accounts() []common.Address { // It offers methods to create, (un)lock en list accounts. Some methods accept // passwords and are therefore considered private by default. type PrivateAccountAPI struct { - am *accounts.Manager - b Backend + am *accounts.Manager + nonceLock *AddrLocker + b Backend } // NewPrivateAccountAPI create a new PrivateAccountAPI. -func NewPrivateAccountAPI(b Backend) *PrivateAccountAPI { +func NewPrivateAccountAPI(b Backend, nonceLock *AddrLocker) *PrivateAccountAPI { return &PrivateAccountAPI{ am: b.AccountManager(), b: b, @@ -316,10 +316,6 @@ func (s *PrivateAccountAPI) LockAccount(addr common.Address) bool { // tries to sign it with the key associated with args.To. If the given passwd isn't // able to decrypt the key it fails. func (s *PrivateAccountAPI) SendTransaction(ctx context.Context, args SendTxArgs, passwd string) (common.Hash, error) { - // Set some sanity defaults and terminate on failure - if err := args.setDefaults(ctx, s.b); err != nil { - return common.Hash{}, err - } // Look up the wallet containing the requested signer account := accounts.Account{Address: args.From} @@ -327,6 +323,18 @@ func (s *PrivateAccountAPI) SendTransaction(ctx context.Context, args SendTxArgs if err != nil { return common.Hash{}, err } + + if args.Nonce == nil { + // Hold the addresse's mutex around signing to prevent concurrent assignment of + // the same nonce to multiple accounts. + s.nonceLock.LockAddr(args.From) + defer s.nonceLock.UnlockAddr(args.From) + } + + // 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() @@ -886,18 +894,13 @@ func newRPCTransaction(b *types.Block, txHash common.Hash) (*RPCTransaction, err // PublicTransactionPoolAPI exposes methods for the RPC interface type PublicTransactionPoolAPI struct { - b Backend + b Backend + nonceLock *AddrLocker } -// nonceMutex is a global mutex for locking the nonce while a transaction -// is being submitted. This should be used when a nonce has not been provided by the user, -// and we get a nonce from the pools. The mutex prevents the (an identical nonce) from being -// read again during the time that the first transaction is being signed. -var nonceMutex sync.RWMutex - // NewPublicTransactionPoolAPI creates a new RPC service with methods specific for the transaction pool. -func NewPublicTransactionPoolAPI(b Backend) *PublicTransactionPoolAPI { - return &PublicTransactionPoolAPI{b} +func NewPublicTransactionPoolAPI(b Backend, nonceLock *AddrLocker) *PublicTransactionPoolAPI { + return &PublicTransactionPoolAPI{b, nonceLock} } func getTransaction(chainDb ethdb.Database, b Backend, txHash common.Hash) (*types.Transaction, bool, error) { @@ -1176,17 +1179,6 @@ func submitTransaction(ctx context.Context, b Backend, tx *types.Transaction) (c // transaction pool. func (s *PublicTransactionPoolAPI) SendTransaction(ctx context.Context, args SendTxArgs) (common.Hash, error) { - if args.Nonce == nil { - // We'll need to set nonce from pool, and thus we need to lock here - nonceMutex.Lock() - defer nonceMutex.Unlock() - - } - - // Set some sanity defaults and terminate on failure - if err := args.setDefaults(ctx, s.b); err != nil { - return common.Hash{}, err - } // Look up the wallet containing the requested signer account := accounts.Account{Address: args.From} @@ -1194,6 +1186,18 @@ func (s *PublicTransactionPoolAPI) SendTransaction(ctx context.Context, args Sen if err != nil { return common.Hash{}, err } + + if args.Nonce == nil { + // Hold the addresse's mutex around signing to prevent concurrent assignment of + // the same nonce to multiple accounts. + s.nonceLock.LockAddr(args.From) + defer s.nonceLock.UnlockAddr(args.From) + } + + // 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() @@ -1270,14 +1274,12 @@ type SignTransactionResult struct { // The node needs to have the private key of the account corresponding with // the given from address and it needs to be unlocked. func (s *PublicTransactionPoolAPI) SignTransaction(ctx context.Context, args SendTxArgs) (*SignTransactionResult, error) { - if args.Nonce == nil { - // We'll need to set nonce from pool, and thus we need to lock here - nonceMutex.Lock() - defer nonceMutex.Unlock() - + // Hold the addresse's mutex around signing to prevent concurrent assignment of + // the same nonce to multiple accounts. + s.nonceLock.LockAddr(args.From) + defer s.nonceLock.UnlockAddr(args.From) } - if err := args.setDefaults(ctx, s.b); err != nil { return nil, err } |