Skip to content

Commit 9ce8264

Browse files
authored
Merge pull request #1973 from MetaMask/hotfix-migration019
hotfix - fail submitted txs whos nonce is out of bound
2 parents 799c4cb + c2624dd commit 9ce8264

File tree

3 files changed

+85
-1
lines changed

3 files changed

+85
-1
lines changed

app/scripts/lib/nonce-tracker.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -88,7 +88,7 @@ class NonceTracker {
8888
// and pending count are from the same block
8989
const currentBlock = await this._getCurrentBlock()
9090
const blockNumber = currentBlock.blockNumber
91-
const baseCountBN = await this.ethQuery.getTransactionCount(address, blockNumber)
91+
const baseCountBN = await this.ethQuery.getTransactionCount(address, blockNumber || 'latest')
9292
const baseCount = baseCountBN.toNumber()
9393
assert(Number.isInteger(baseCount), `nonce-tracker - baseCount is not an integer - got: (${typeof baseCount}) "${baseCount}"`)
9494
const nonceDetails = { blockNumber, baseCount }

app/scripts/migrations/019.js

Lines changed: 83 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,83 @@
1+
2+
const version = 19
3+
4+
/*
5+
6+
This migration sets transactions as failed
7+
whos nonce is too high
8+
9+
*/
10+
11+
const clone = require('clone')
12+
13+
module.exports = {
14+
version,
15+
16+
migrate: function (originalVersionedData) {
17+
const versionedData = clone(originalVersionedData)
18+
versionedData.meta.version = version
19+
try {
20+
const state = versionedData.data
21+
const newState = transformState(state)
22+
versionedData.data = newState
23+
} catch (err) {
24+
console.warn(`MetaMask Migration #${version}` + err.stack)
25+
}
26+
return Promise.resolve(versionedData)
27+
},
28+
}
29+
30+
function transformState (state) {
31+
const newState = state
32+
const transactions = newState.TransactionController.transactions
33+
34+
newState.TransactionController.transactions = transactions.map((txMeta, _, txList) => {
35+
if (txMeta.status !== 'submitted') return txMeta
36+
37+
const confirmedTxs = txList.filter((tx) => tx.status === 'confirmed')
38+
.filter((tx) => tx.txParams.from === txMeta.txParams.from)
39+
.filter((tx) => tx.metamaskNetworkId.from === txMeta.metamaskNetworkId.from)
40+
const highestConfirmedNonce = getHighestNonce(confirmedTxs)
41+
42+
const pendingTxs = txList.filter((tx) => tx.status === 'submitted')
43+
.filter((tx) => tx.txParams.from === txMeta.txParams.from)
44+
.filter((tx) => tx.metamaskNetworkId.from === txMeta.metamaskNetworkId.from)
45+
const highestContinuousNonce = getHighestContinuousFrom(pendingTxs, highestConfirmedNonce)
46+
47+
const maxNonce = Math.max(highestContinuousNonce, highestConfirmedNonce)
48+
49+
if (parseInt(txMeta.txParams.nonce, 16) > maxNonce + 1) {
50+
txMeta.status = 'failed'
51+
txMeta.err = {
52+
message: 'nonce too high',
53+
note: 'migration 019 custom error',
54+
}
55+
}
56+
return txMeta
57+
})
58+
return newState
59+
}
60+
61+
function getHighestContinuousFrom (txList, startPoint) {
62+
const nonces = txList.map((txMeta) => {
63+
const nonce = txMeta.txParams.nonce
64+
return parseInt(nonce, 16)
65+
})
66+
67+
let highest = startPoint
68+
while (nonces.includes(highest)) {
69+
highest++
70+
}
71+
72+
return highest
73+
}
74+
75+
function getHighestNonce (txList) {
76+
const nonces = txList.map((txMeta) => {
77+
const nonce = txMeta.txParams.nonce
78+
return parseInt(nonce || '0x0', 16)
79+
})
80+
const highestNonce = Math.max.apply(null, nonces)
81+
return highestNonce
82+
}
83+

app/scripts/migrations/index.js

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -29,4 +29,5 @@ module.exports = [
2929
require('./016'),
3030
require('./017'),
3131
require('./018'),
32+
require('./019'),
3233
]

0 commit comments

Comments
 (0)