mirror of
https://github.com/kremalicious/metamask-extension.git
synced 2024-12-23 09:52:26 +01:00
Merge pull request #4557 from MetaMask/nonce-tracker-mutex-fix
Bug: Mutex locks not released on error
This commit is contained in:
commit
0740dd6a5b
@ -165,7 +165,7 @@ class TransactionController extends EventEmitter {
|
|||||||
// add default tx params
|
// add default tx params
|
||||||
txMeta = await this.addTxGasDefaults(txMeta)
|
txMeta = await this.addTxGasDefaults(txMeta)
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.log(error)
|
log.warn(error)
|
||||||
this.txStateManager.setTxStatusFailed(txMeta.id, error)
|
this.txStateManager.setTxStatusFailed(txMeta.id, error)
|
||||||
throw error
|
throw error
|
||||||
}
|
}
|
||||||
@ -264,7 +264,12 @@ class TransactionController extends EventEmitter {
|
|||||||
// must set transaction to submitted/failed before releasing lock
|
// must set transaction to submitted/failed before releasing lock
|
||||||
nonceLock.releaseLock()
|
nonceLock.releaseLock()
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
this.txStateManager.setTxStatusFailed(txId, err)
|
// this is try-catch wrapped so that we can guarantee that the nonceLock is released
|
||||||
|
try {
|
||||||
|
this.txStateManager.setTxStatusFailed(txId, err)
|
||||||
|
} catch (err) {
|
||||||
|
log.error(err)
|
||||||
|
}
|
||||||
// must set transaction to submitted/failed before releasing lock
|
// must set transaction to submitted/failed before releasing lock
|
||||||
if (nonceLock) nonceLock.releaseLock()
|
if (nonceLock) nonceLock.releaseLock()
|
||||||
// continue with error chain
|
// continue with error chain
|
||||||
|
@ -49,29 +49,35 @@ class NonceTracker {
|
|||||||
await this._globalMutexFree()
|
await this._globalMutexFree()
|
||||||
// await lock free, then take lock
|
// await lock free, then take lock
|
||||||
const releaseLock = await this._takeMutex(address)
|
const releaseLock = await this._takeMutex(address)
|
||||||
// evaluate multiple nextNonce strategies
|
try {
|
||||||
const nonceDetails = {}
|
// evaluate multiple nextNonce strategies
|
||||||
const networkNonceResult = await this._getNetworkNextNonce(address)
|
const nonceDetails = {}
|
||||||
const highestLocallyConfirmed = this._getHighestLocallyConfirmed(address)
|
const networkNonceResult = await this._getNetworkNextNonce(address)
|
||||||
const nextNetworkNonce = networkNonceResult.nonce
|
const highestLocallyConfirmed = this._getHighestLocallyConfirmed(address)
|
||||||
const highestSuggested = Math.max(nextNetworkNonce, highestLocallyConfirmed)
|
const nextNetworkNonce = networkNonceResult.nonce
|
||||||
|
const highestSuggested = Math.max(nextNetworkNonce, highestLocallyConfirmed)
|
||||||
|
|
||||||
const pendingTxs = this.getPendingTransactions(address)
|
const pendingTxs = this.getPendingTransactions(address)
|
||||||
const localNonceResult = this._getHighestContinuousFrom(pendingTxs, highestSuggested) || 0
|
const localNonceResult = this._getHighestContinuousFrom(pendingTxs, highestSuggested) || 0
|
||||||
|
|
||||||
nonceDetails.params = {
|
nonceDetails.params = {
|
||||||
highestLocallyConfirmed,
|
highestLocallyConfirmed,
|
||||||
highestSuggested,
|
highestSuggested,
|
||||||
nextNetworkNonce,
|
nextNetworkNonce,
|
||||||
|
}
|
||||||
|
nonceDetails.local = localNonceResult
|
||||||
|
nonceDetails.network = networkNonceResult
|
||||||
|
|
||||||
|
const nextNonce = Math.max(networkNonceResult.nonce, localNonceResult.nonce)
|
||||||
|
assert(Number.isInteger(nextNonce), `nonce-tracker - nextNonce is not an integer - got: (${typeof nextNonce}) "${nextNonce}"`)
|
||||||
|
|
||||||
|
// return nonce and release cb
|
||||||
|
return { nextNonce, nonceDetails, releaseLock }
|
||||||
|
} catch (err) {
|
||||||
|
// release lock if we encounter an error
|
||||||
|
releaseLock()
|
||||||
|
throw err
|
||||||
}
|
}
|
||||||
nonceDetails.local = localNonceResult
|
|
||||||
nonceDetails.network = networkNonceResult
|
|
||||||
|
|
||||||
const nextNonce = Math.max(networkNonceResult.nonce, localNonceResult.nonce)
|
|
||||||
assert(Number.isInteger(nextNonce), `nonce-tracker - nextNonce is not an integer - got: (${typeof nextNonce}) "${nextNonce}"`)
|
|
||||||
|
|
||||||
// return nonce and release cb
|
|
||||||
return { nextNonce, nonceDetails, releaseLock }
|
|
||||||
}
|
}
|
||||||
|
|
||||||
async _getCurrentBlock () {
|
async _getCurrentBlock () {
|
||||||
@ -85,8 +91,8 @@ class NonceTracker {
|
|||||||
|
|
||||||
async _globalMutexFree () {
|
async _globalMutexFree () {
|
||||||
const globalMutex = this._lookupMutex('global')
|
const globalMutex = this._lookupMutex('global')
|
||||||
const release = await globalMutex.acquire()
|
const releaseLock = await globalMutex.acquire()
|
||||||
release()
|
releaseLock()
|
||||||
}
|
}
|
||||||
|
|
||||||
async _takeMutex (lockId) {
|
async _takeMutex (lockId) {
|
||||||
|
@ -196,14 +196,14 @@ class PendingTransactionTracker extends EventEmitter {
|
|||||||
async _checkPendingTxs () {
|
async _checkPendingTxs () {
|
||||||
const signedTxList = this.getPendingTransactions()
|
const signedTxList = this.getPendingTransactions()
|
||||||
// in order to keep the nonceTracker accurate we block it while updating pending transactions
|
// in order to keep the nonceTracker accurate we block it while updating pending transactions
|
||||||
const nonceGlobalLock = await this.nonceTracker.getGlobalLock()
|
const { releaseLock } = await this.nonceTracker.getGlobalLock()
|
||||||
try {
|
try {
|
||||||
await Promise.all(signedTxList.map((txMeta) => this._checkPendingTx(txMeta)))
|
await Promise.all(signedTxList.map((txMeta) => this._checkPendingTx(txMeta)))
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
log.error('PendingTransactionWatcher - Error updating pending transactions')
|
log.error('PendingTransactionWatcher - Error updating pending transactions')
|
||||||
log.error(err)
|
log.error(err)
|
||||||
}
|
}
|
||||||
nonceGlobalLock.releaseLock()
|
releaseLock()
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -436,28 +436,24 @@ module.exports = class MetamaskController extends EventEmitter {
|
|||||||
* @returns {Object} vault
|
* @returns {Object} vault
|
||||||
*/
|
*/
|
||||||
async createNewVaultAndKeychain (password) {
|
async createNewVaultAndKeychain (password) {
|
||||||
const release = await this.createVaultMutex.acquire()
|
const releaseLock = await this.createVaultMutex.acquire()
|
||||||
let vault
|
|
||||||
|
|
||||||
try {
|
try {
|
||||||
|
let vault
|
||||||
const accounts = await this.keyringController.getAccounts()
|
const accounts = await this.keyringController.getAccounts()
|
||||||
|
|
||||||
if (accounts.length > 0) {
|
if (accounts.length > 0) {
|
||||||
vault = await this.keyringController.fullUpdate()
|
vault = await this.keyringController.fullUpdate()
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
vault = await this.keyringController.createNewVaultAndKeychain(password)
|
vault = await this.keyringController.createNewVaultAndKeychain(password)
|
||||||
const accounts = await this.keyringController.getAccounts()
|
const accounts = await this.keyringController.getAccounts()
|
||||||
this.preferencesController.setAddresses(accounts)
|
this.preferencesController.setAddresses(accounts)
|
||||||
this.selectFirstIdentity()
|
this.selectFirstIdentity()
|
||||||
}
|
}
|
||||||
release()
|
releaseLock()
|
||||||
|
return vault
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
release()
|
releaseLock()
|
||||||
throw err
|
throw err
|
||||||
}
|
}
|
||||||
|
|
||||||
return vault
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -466,7 +462,7 @@ module.exports = class MetamaskController extends EventEmitter {
|
|||||||
* @param {} seed
|
* @param {} seed
|
||||||
*/
|
*/
|
||||||
async createNewVaultAndRestore (password, seed) {
|
async createNewVaultAndRestore (password, seed) {
|
||||||
const release = await this.createVaultMutex.acquire()
|
const releaseLock = await this.createVaultMutex.acquire()
|
||||||
try {
|
try {
|
||||||
// clear known identities
|
// clear known identities
|
||||||
this.preferencesController.setAddresses([])
|
this.preferencesController.setAddresses([])
|
||||||
@ -476,10 +472,10 @@ module.exports = class MetamaskController extends EventEmitter {
|
|||||||
const accounts = await this.keyringController.getAccounts()
|
const accounts = await this.keyringController.getAccounts()
|
||||||
this.preferencesController.setAddresses(accounts)
|
this.preferencesController.setAddresses(accounts)
|
||||||
this.selectFirstIdentity()
|
this.selectFirstIdentity()
|
||||||
release()
|
releaseLock()
|
||||||
return vault
|
return vault
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
release()
|
releaseLock()
|
||||||
throw err
|
throw err
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user