Merge pull request #2116 from chikeichan/nm
[NewUI] Fix merge conflict with latest masterfeature/default_network_editable
commit
a190bb6043
@ -0,0 +1,15 @@ |
|||||||
|
// log rpc activity
|
||||||
|
module.exports = createLoggerMiddleware |
||||||
|
|
||||||
|
function createLoggerMiddleware({ origin }) { |
||||||
|
return function loggerMiddleware (req, res, next, end) { |
||||||
|
next((cb) => { |
||||||
|
if (res.error) { |
||||||
|
log.error('Error in RPC response:\n', res) |
||||||
|
} |
||||||
|
if (req.isMetamaskInternal) return |
||||||
|
log.info(`RPC (${origin}):`, req, '->', res) |
||||||
|
cb() |
||||||
|
}) |
||||||
|
} |
||||||
|
} |
@ -0,0 +1,9 @@ |
|||||||
|
// append dapp origin domain to request
|
||||||
|
module.exports = createOriginMiddleware |
||||||
|
|
||||||
|
function createOriginMiddleware({ origin }) { |
||||||
|
return function originMiddleware (req, res, next, end) { |
||||||
|
req.origin = origin |
||||||
|
next() |
||||||
|
} |
||||||
|
} |
@ -0,0 +1,13 @@ |
|||||||
|
|
||||||
|
module.exports = createProviderMiddleware |
||||||
|
|
||||||
|
// forward requests to provider
|
||||||
|
function createProviderMiddleware({ provider }) { |
||||||
|
return (req, res, next, end) => { |
||||||
|
provider.sendAsync(req, (err, _res) => { |
||||||
|
if (err) return end(err) |
||||||
|
res.result = _res.result |
||||||
|
end() |
||||||
|
}) |
||||||
|
} |
||||||
|
} |
@ -1,48 +0,0 @@ |
|||||||
const through = require('through2') |
|
||||||
|
|
||||||
module.exports = ObjectMultiplex |
|
||||||
|
|
||||||
function ObjectMultiplex (opts) { |
|
||||||
opts = opts || {} |
|
||||||
// create multiplexer
|
|
||||||
const mx = through.obj(function (chunk, enc, cb) { |
|
||||||
const name = chunk.name |
|
||||||
const data = chunk.data |
|
||||||
if (!name) { |
|
||||||
console.warn(`ObjectMultiplex - Malformed chunk without name "${chunk}"`) |
|
||||||
return cb() |
|
||||||
} |
|
||||||
const substream = mx.streams[name] |
|
||||||
if (!substream) { |
|
||||||
console.warn(`ObjectMultiplex - orphaned data for stream "${name}"`) |
|
||||||
} else { |
|
||||||
if (substream.push) substream.push(data) |
|
||||||
} |
|
||||||
return cb() |
|
||||||
}) |
|
||||||
mx.streams = {} |
|
||||||
// create substreams
|
|
||||||
mx.createStream = function (name) { |
|
||||||
const substream = mx.streams[name] = through.obj(function (chunk, enc, cb) { |
|
||||||
mx.push({ |
|
||||||
name: name, |
|
||||||
data: chunk, |
|
||||||
}) |
|
||||||
return cb() |
|
||||||
}) |
|
||||||
mx.on('end', function () { |
|
||||||
return substream.emit('end') |
|
||||||
}) |
|
||||||
if (opts.error) { |
|
||||||
mx.on('error', function () { |
|
||||||
return substream.emit('error') |
|
||||||
}) |
|
||||||
} |
|
||||||
return substream |
|
||||||
} |
|
||||||
// ignore streams (dont display orphaned data warning)
|
|
||||||
mx.ignoreStream = function (name) { |
|
||||||
mx.streams[name] = true |
|
||||||
} |
|
||||||
return mx |
|
||||||
} |
|
@ -0,0 +1,37 @@ |
|||||||
|
const jsonDiffer = require('fast-json-patch') |
||||||
|
const clone = require('clone') |
||||||
|
|
||||||
|
module.exports = { |
||||||
|
generateHistoryEntry, |
||||||
|
replayHistory, |
||||||
|
snapshotFromTxMeta, |
||||||
|
migrateFromSnapshotsToDiffs, |
||||||
|
} |
||||||
|
|
||||||
|
|
||||||
|
function migrateFromSnapshotsToDiffs(longHistory) { |
||||||
|
return ( |
||||||
|
longHistory |
||||||
|
// convert non-initial history entries into diffs
|
||||||
|
.map((entry, index) => { |
||||||
|
if (index === 0) return entry |
||||||
|
return generateHistoryEntry(longHistory[index - 1], entry) |
||||||
|
}) |
||||||
|
) |
||||||
|
} |
||||||
|
|
||||||
|
function generateHistoryEntry(previousState, newState) { |
||||||
|
return jsonDiffer.compare(previousState, newState) |
||||||
|
} |
||||||
|
|
||||||
|
function replayHistory(shortHistory) { |
||||||
|
return shortHistory.reduce((val, entry) => jsonDiffer.applyPatch(val, entry).newDocument) |
||||||
|
} |
||||||
|
|
||||||
|
function snapshotFromTxMeta(txMeta) { |
||||||
|
// create txMeta snapshot for history
|
||||||
|
const snapshot = clone(txMeta) |
||||||
|
// dont include previous history in this snapshot
|
||||||
|
delete snapshot.history |
||||||
|
return snapshot |
||||||
|
} |
@ -0,0 +1,52 @@ |
|||||||
|
const version = 18 |
||||||
|
|
||||||
|
/* |
||||||
|
|
||||||
|
This migration updates "transaction state history" to diffs style |
||||||
|
|
||||||
|
*/ |
||||||
|
|
||||||
|
const clone = require('clone') |
||||||
|
const txStateHistoryHelper = require('../lib/tx-state-history-helper') |
||||||
|
|
||||||
|
|
||||||
|
module.exports = { |
||||||
|
version, |
||||||
|
|
||||||
|
migrate: function (originalVersionedData) { |
||||||
|
const versionedData = clone(originalVersionedData) |
||||||
|
versionedData.meta.version = version |
||||||
|
try { |
||||||
|
const state = versionedData.data |
||||||
|
const newState = transformState(state) |
||||||
|
versionedData.data = newState |
||||||
|
} catch (err) { |
||||||
|
console.warn(`MetaMask Migration #${version}` + err.stack) |
||||||
|
} |
||||||
|
return Promise.resolve(versionedData) |
||||||
|
}, |
||||||
|
} |
||||||
|
|
||||||
|
function transformState (state) { |
||||||
|
const newState = state |
||||||
|
const transactions = newState.TransactionController.transactions |
||||||
|
newState.TransactionController.transactions = transactions.map((txMeta) => { |
||||||
|
// no history: initialize
|
||||||
|
if (!txMeta.history || txMeta.history.length === 0) { |
||||||
|
const snapshot = txStateHistoryHelper.snapshotFromTxMeta(txMeta) |
||||||
|
txMeta.history = [snapshot] |
||||||
|
return txMeta |
||||||
|
} |
||||||
|
// has history: migrate
|
||||||
|
const newHistory = ( |
||||||
|
txStateHistoryHelper.migrateFromSnapshotsToDiffs(txMeta.history) |
||||||
|
// remove empty diffs
|
||||||
|
.filter((entry) => { |
||||||
|
return !Array.isArray(entry) || entry.length > 0 |
||||||
|
}) |
||||||
|
) |
||||||
|
txMeta.history = newHistory |
||||||
|
return txMeta |
||||||
|
}) |
||||||
|
return newState |
||||||
|
} |
@ -0,0 +1,83 @@ |
|||||||
|
|
||||||
|
const version = 19 |
||||||
|
|
||||||
|
/* |
||||||
|
|
||||||
|
This migration sets transactions as failed |
||||||
|
whos nonce is too high |
||||||
|
|
||||||
|
*/ |
||||||
|
|
||||||
|
const clone = require('clone') |
||||||
|
|
||||||
|
module.exports = { |
||||||
|
version, |
||||||
|
|
||||||
|
migrate: function (originalVersionedData) { |
||||||
|
const versionedData = clone(originalVersionedData) |
||||||
|
versionedData.meta.version = version |
||||||
|
try { |
||||||
|
const state = versionedData.data |
||||||
|
const newState = transformState(state) |
||||||
|
versionedData.data = newState |
||||||
|
} catch (err) { |
||||||
|
console.warn(`MetaMask Migration #${version}` + err.stack) |
||||||
|
} |
||||||
|
return Promise.resolve(versionedData) |
||||||
|
}, |
||||||
|
} |
||||||
|
|
||||||
|
function transformState (state) { |
||||||
|
const newState = state |
||||||
|
const transactions = newState.TransactionController.transactions |
||||||
|
|
||||||
|
newState.TransactionController.transactions = transactions.map((txMeta, _, txList) => { |
||||||
|
if (txMeta.status !== 'submitted') return txMeta |
||||||
|
|
||||||
|
const confirmedTxs = txList.filter((tx) => tx.status === 'confirmed') |
||||||
|
.filter((tx) => tx.txParams.from === txMeta.txParams.from) |
||||||
|
.filter((tx) => tx.metamaskNetworkId.from === txMeta.metamaskNetworkId.from) |
||||||
|
const highestConfirmedNonce = getHighestNonce(confirmedTxs) |
||||||
|
|
||||||
|
const pendingTxs = txList.filter((tx) => tx.status === 'submitted') |
||||||
|
.filter((tx) => tx.txParams.from === txMeta.txParams.from) |
||||||
|
.filter((tx) => tx.metamaskNetworkId.from === txMeta.metamaskNetworkId.from) |
||||||
|
const highestContinuousNonce = getHighestContinuousFrom(pendingTxs, highestConfirmedNonce) |
||||||
|
|
||||||
|
const maxNonce = Math.max(highestContinuousNonce, highestConfirmedNonce) |
||||||
|
|
||||||
|
if (parseInt(txMeta.txParams.nonce, 16) > maxNonce + 1) { |
||||||
|
txMeta.status = 'failed' |
||||||
|
txMeta.err = { |
||||||
|
message: 'nonce too high', |
||||||
|
note: 'migration 019 custom error', |
||||||
|
} |
||||||
|
} |
||||||
|
return txMeta |
||||||
|
}) |
||||||
|
return newState |
||||||
|
} |
||||||
|
|
||||||
|
function getHighestContinuousFrom (txList, startPoint) { |
||||||
|
const nonces = txList.map((txMeta) => { |
||||||
|
const nonce = txMeta.txParams.nonce |
||||||
|
return parseInt(nonce, 16) |
||||||
|
}) |
||||||
|
|
||||||
|
let highest = startPoint |
||||||
|
while (nonces.includes(highest)) { |
||||||
|
highest++ |
||||||
|
} |
||||||
|
|
||||||
|
return highest |
||||||
|
} |
||||||
|
|
||||||
|
function getHighestNonce (txList) { |
||||||
|
const nonces = txList.map((txMeta) => { |
||||||
|
const nonce = txMeta.txParams.nonce |
||||||
|
return parseInt(nonce || '0x0', 16) |
||||||
|
}) |
||||||
|
const highestNonce = Math.max.apply(null, nonces) |
||||||
|
return highestNonce |
||||||
|
} |
||||||
|
|
@ -1,10 +1,17 @@ |
|||||||
machine: |
machine: |
||||||
node: |
node: |
||||||
version: 8.1.4 |
version: 8.1.4 |
||||||
dependencies: |
|
||||||
pre: |
|
||||||
- "npm i -g testem" |
|
||||||
- "npm i -g mocha" |
|
||||||
test: |
test: |
||||||
override: |
override: |
||||||
- "npm run ci" |
- "npm run ci" |
||||||
|
dependencies: |
||||||
|
pre: |
||||||
|
- sudo apt-get update |
||||||
|
# get latest stable firefox |
||||||
|
- sudo apt-get install firefox |
||||||
|
- firefox_cmd=`which firefox`; sudo rm -f $firefox_cmd; sudo ln -s `which firefox.ubuntu` $firefox_cmd |
||||||
|
# get latest stable chrome |
||||||
|
- wget -q -O - https://dl-ssl.google.com/linux/linux_signing_key.pub | sudo apt-key add - |
||||||
|
- sudo sh -c 'echo "deb [arch=amd64] http://dl.google.com/linux/chrome/deb/ stable main" >> /etc/apt/sources.list.d/google.list' |
||||||
|
- sudo apt-get update |
||||||
|
- sudo apt-get install google-chrome-stable |
@ -0,0 +1,61 @@ |
|||||||
|
// Karma configuration
|
||||||
|
// Generated on Mon Sep 11 2017 18:45:48 GMT-0700 (PDT)
|
||||||
|
|
||||||
|
module.exports = function(config) { |
||||||
|
config.set({ |
||||||
|
// base path that will be used to resolve all patterns (eg. files, exclude)
|
||||||
|
basePath: process.cwd(), |
||||||
|
|
||||||
|
browserConsoleLogOptions: { |
||||||
|
terminal: false, |
||||||
|
}, |
||||||
|
|
||||||
|
// frameworks to use
|
||||||
|
// available frameworks: https://npmjs.org/browse/keyword/karma-adapter
|
||||||
|
frameworks: ['qunit'], |
||||||
|
|
||||||
|
// list of files / patterns to load in the browser
|
||||||
|
files: [ |
||||||
|
'development/bundle.js', |
||||||
|
'test/integration/jquery-3.1.0.min.js', |
||||||
|
'test/integration/bundle.js', |
||||||
|
{ pattern: 'dist/chrome/images/**/*.*', watched: false, included: false, served: true }, |
||||||
|
{ pattern: 'dist/chrome/fonts/**/*.*', watched: false, included: false, served: true }, |
||||||
|
], |
||||||
|
|
||||||
|
proxies: { |
||||||
|
'/images/': '/base/dist/chrome/images/', |
||||||
|
'/fonts/': '/base/dist/chrome/fonts/', |
||||||
|
}, |
||||||
|
|
||||||
|
// test results reporter to use
|
||||||
|
// possible values: 'dots', 'progress'
|
||||||
|
// available reporters: https://npmjs.org/browse/keyword/karma-reporter
|
||||||
|
reporters: ['progress'], |
||||||
|
|
||||||
|
// web server port
|
||||||
|
port: 9876, |
||||||
|
|
||||||
|
// enable / disable colors in the output (reporters and logs)
|
||||||
|
colors: true, |
||||||
|
|
||||||
|
// level of logging
|
||||||
|
// possible values: config.LOG_DISABLE || config.LOG_ERROR || config.LOG_WARN || config.LOG_INFO || config.LOG_DEBUG
|
||||||
|
logLevel: config.LOG_INFO, |
||||||
|
|
||||||
|
// enable / disable watching file and executing tests whenever any file changes
|
||||||
|
autoWatch: false, |
||||||
|
|
||||||
|
// start these browsers
|
||||||
|
// available browser launchers: https://npmjs.org/browse/keyword/karma-launcher
|
||||||
|
browsers: ['Chrome', 'Firefox'], |
||||||
|
|
||||||
|
// Continuous Integration mode
|
||||||
|
// if true, Karma captures browsers, runs the tests and exits
|
||||||
|
singleRun: true, |
||||||
|
|
||||||
|
// Concurrency level
|
||||||
|
// how many browser should be started simultaneous
|
||||||
|
concurrency: Infinity |
||||||
|
}) |
||||||
|
} |
File diff suppressed because it is too large
Load Diff
@ -1,7 +0,0 @@ |
|||||||
function wait(time) { |
|
||||||
return new Promise(function (resolve, reject) { |
|
||||||
setTimeout(function () { |
|
||||||
resolve() |
|
||||||
}, time * 3 || 1500) |
|
||||||
}) |
|
||||||
} |
|
@ -0,0 +1,40 @@ |
|||||||
|
const extend = require('xtend') |
||||||
|
const BN = require('ethereumjs-util').BN |
||||||
|
const template = { |
||||||
|
'status': 'submitted', |
||||||
|
'txParams': { |
||||||
|
'from': '0x7d3517b0d011698406d6e0aed8453f0be2697926', |
||||||
|
'gas': '0x30d40', |
||||||
|
'value': '0x0', |
||||||
|
'nonce': '0x3', |
||||||
|
}, |
||||||
|
} |
||||||
|
|
||||||
|
class TxGenerator { |
||||||
|
|
||||||
|
constructor () { |
||||||
|
this.txs = [] |
||||||
|
} |
||||||
|
|
||||||
|
generate (tx = {}, opts = {}) { |
||||||
|
let { count, fromNonce } = opts |
||||||
|
let nonce = fromNonce || this.txs.length |
||||||
|
let txs = [] |
||||||
|
for (let i = 0; i < count; i++) { |
||||||
|
txs.push(extend(template, { |
||||||
|
txParams: { |
||||||
|
nonce: hexify(nonce++), |
||||||
|
} |
||||||
|
}, tx)) |
||||||
|
} |
||||||
|
this.txs = this.txs.concat(txs) |
||||||
|
return txs |
||||||
|
} |
||||||
|
|
||||||
|
} |
||||||
|
|
||||||
|
function hexify (number) { |
||||||
|
return '0x' + (new BN(number)).toString(16) |
||||||
|
} |
||||||
|
|
||||||
|
module.exports = TxGenerator |
@ -1,41 +1,203 @@ |
|||||||
const assert = require('assert') |
const assert = require('assert') |
||||||
const NonceTracker = require('../../app/scripts/lib/nonce-tracker') |
const NonceTracker = require('../../app/scripts/lib/nonce-tracker') |
||||||
|
const MockTxGen = require('../lib/mock-tx-gen') |
||||||
|
let providerResultStub = {} |
||||||
|
|
||||||
describe('Nonce Tracker', function () { |
describe('Nonce Tracker', function () { |
||||||
let nonceTracker, provider, getPendingTransactions, pendingTxs |
let nonceTracker, provider |
||||||
|
let getPendingTransactions, pendingTxs |
||||||
|
let getConfirmedTransactions, confirmedTxs |
||||||
|
|
||||||
|
describe('#getNonceLock', function () { |
||||||
|
|
||||||
|
describe('with 3 confirmed and 1 pending', function () { |
||||||
beforeEach(function () { |
beforeEach(function () { |
||||||
pendingTxs = [{ |
const txGen = new MockTxGen() |
||||||
'status': 'submitted', |
confirmedTxs = txGen.generate({ status: 'confirmed' }, { count: 3 }) |
||||||
'txParams': { |
pendingTxs = txGen.generate({ status: 'submitted' }, { count: 1 }) |
||||||
'from': '0x7d3517b0d011698406d6e0aed8453f0be2697926', |
nonceTracker = generateNonceTrackerWith(pendingTxs, confirmedTxs, '0x1') |
||||||
'gas': '0x30d40', |
}) |
||||||
'value': '0x0', |
|
||||||
'nonce': '0x0', |
|
||||||
}, |
|
||||||
}] |
|
||||||
|
|
||||||
|
it('should return 4', async function () { |
||||||
|
this.timeout(15000) |
||||||
|
const nonceLock = await nonceTracker.getNonceLock('0x7d3517b0d011698406d6e0aed8453f0be2697926') |
||||||
|
assert.equal(nonceLock.nextNonce, '4', `nonce should be 4 got ${nonceLock.nextNonce}`) |
||||||
|
await nonceLock.releaseLock() |
||||||
|
}) |
||||||
|
|
||||||
getPendingTransactions = () => pendingTxs |
it('should use localNonce if network returns a nonce lower then a confirmed tx in state', async function () { |
||||||
provider = { |
this.timeout(15000) |
||||||
sendAsync: (_, cb) => { cb(undefined, {result: '0x0'}) }, |
const nonceLock = await nonceTracker.getNonceLock('0x7d3517b0d011698406d6e0aed8453f0be2697926') |
||||||
_blockTracker: { |
assert.equal(nonceLock.nextNonce, '4', 'nonce should be 4') |
||||||
getCurrentBlock: () => '0x11b568', |
await nonceLock.releaseLock() |
||||||
}, |
|
||||||
} |
|
||||||
nonceTracker = new NonceTracker({ |
|
||||||
provider, |
|
||||||
getPendingTransactions, |
|
||||||
}) |
}) |
||||||
}) |
}) |
||||||
|
|
||||||
describe('#getNonceLock', function () { |
describe('with no previous txs', function () { |
||||||
it('should work', async function () { |
beforeEach(function () { |
||||||
|
nonceTracker = generateNonceTrackerWith([], []) |
||||||
|
}) |
||||||
|
|
||||||
|
it('should return 0', async function () { |
||||||
|
this.timeout(15000) |
||||||
|
const nonceLock = await nonceTracker.getNonceLock('0x7d3517b0d011698406d6e0aed8453f0be2697926') |
||||||
|
assert.equal(nonceLock.nextNonce, '0', `nonce should be 0 returned ${nonceLock.nextNonce}`) |
||||||
|
await nonceLock.releaseLock() |
||||||
|
}) |
||||||
|
}) |
||||||
|
|
||||||
|
describe('with multiple previous txs with same nonce', function () { |
||||||
|
beforeEach(function () { |
||||||
|
const txGen = new MockTxGen() |
||||||
|
confirmedTxs = txGen.generate({ status: 'confirmed' }, { count: 1 }) |
||||||
|
pendingTxs = txGen.generate({ |
||||||
|
status: 'submitted', |
||||||
|
txParams: { nonce: '0x01' }, |
||||||
|
}, { count: 5 }) |
||||||
|
|
||||||
|
nonceTracker = generateNonceTrackerWith(pendingTxs, confirmedTxs, '0x0') |
||||||
|
}) |
||||||
|
|
||||||
|
it('should return nonce after those', async function () { |
||||||
|
this.timeout(15000) |
||||||
|
const nonceLock = await nonceTracker.getNonceLock('0x7d3517b0d011698406d6e0aed8453f0be2697926') |
||||||
|
assert.equal(nonceLock.nextNonce, '2', `nonce should be 2 got ${nonceLock.nextNonce}`) |
||||||
|
await nonceLock.releaseLock() |
||||||
|
}) |
||||||
|
}) |
||||||
|
|
||||||
|
describe('when local confirmed count is higher than network nonce', function () { |
||||||
|
beforeEach(function () { |
||||||
|
const txGen = new MockTxGen() |
||||||
|
confirmedTxs = txGen.generate({ status: 'confirmed' }, { count: 3 }) |
||||||
|
nonceTracker = generateNonceTrackerWith([], confirmedTxs, '0x1') |
||||||
|
}) |
||||||
|
|
||||||
|
it('should return nonce after those', async function () { |
||||||
|
this.timeout(15000) |
||||||
|
const nonceLock = await nonceTracker.getNonceLock('0x7d3517b0d011698406d6e0aed8453f0be2697926') |
||||||
|
assert.equal(nonceLock.nextNonce, '3', `nonce should be 3 got ${nonceLock.nextNonce}`) |
||||||
|
await nonceLock.releaseLock() |
||||||
|
}) |
||||||
|
}) |
||||||
|
|
||||||
|
describe('when local pending count is higher than other metrics', function () { |
||||||
|
beforeEach(function () { |
||||||
|
const txGen = new MockTxGen() |
||||||
|
pendingTxs = txGen.generate({ status: 'submitted' }, { count: 2 }) |
||||||
|
nonceTracker = generateNonceTrackerWith(pendingTxs, []) |
||||||
|
}) |
||||||
|
|
||||||
|
it('should return nonce after those', async function () { |
||||||
|
this.timeout(15000) |
||||||
|
const nonceLock = await nonceTracker.getNonceLock('0x7d3517b0d011698406d6e0aed8453f0be2697926') |
||||||
|
assert.equal(nonceLock.nextNonce, '2', `nonce should be 2 got ${nonceLock.nextNonce}`) |
||||||
|
await nonceLock.releaseLock() |
||||||
|
}) |
||||||
|
}) |
||||||
|
|
||||||
|
describe('when provider nonce is higher than other metrics', function () { |
||||||
|
beforeEach(function () { |
||||||
|
const txGen = new MockTxGen() |
||||||
|
pendingTxs = txGen.generate({ status: 'submitted' }, { count: 2 }) |
||||||
|
nonceTracker = generateNonceTrackerWith(pendingTxs, [], '0x05') |
||||||
|
}) |
||||||
|
|
||||||
|
it('should return nonce after those', async function () { |
||||||
|
this.timeout(15000) |
||||||
|
const nonceLock = await nonceTracker.getNonceLock('0x7d3517b0d011698406d6e0aed8453f0be2697926') |
||||||
|
assert.equal(nonceLock.nextNonce, '5', `nonce should be 5 got ${nonceLock.nextNonce}`) |
||||||
|
await nonceLock.releaseLock() |
||||||
|
}) |
||||||
|
}) |
||||||
|
|
||||||
|
describe('when there are some pending nonces below the remote one and some over.', function () { |
||||||
|
beforeEach(function () { |
||||||
|
const txGen = new MockTxGen() |
||||||
|
pendingTxs = txGen.generate({ status: 'submitted' }, { count: 5 }) |
||||||
|
nonceTracker = generateNonceTrackerWith(pendingTxs, [], '0x03') |
||||||
|
}) |
||||||
|
|
||||||
|
it('should return nonce after those', async function () { |
||||||
|
this.timeout(15000) |
||||||
|
const nonceLock = await nonceTracker.getNonceLock('0x7d3517b0d011698406d6e0aed8453f0be2697926') |
||||||
|
assert.equal(nonceLock.nextNonce, '5', `nonce should be 5 got ${nonceLock.nextNonce}`) |
||||||
|
await nonceLock.releaseLock() |
||||||
|
}) |
||||||
|
}) |
||||||
|
|
||||||
|
describe('when there are pending nonces non sequentially over the network nonce.', function () { |
||||||
|
beforeEach(function () { |
||||||
|
const txGen = new MockTxGen() |
||||||
|
txGen.generate({ status: 'submitted' }, { count: 5 }) |
||||||
|
// 5 over that number
|
||||||
|
pendingTxs = txGen.generate({ status: 'submitted' }, { count: 5 }) |
||||||
|
nonceTracker = generateNonceTrackerWith(pendingTxs, [], '0x00') |
||||||
|
}) |
||||||
|
|
||||||
|
it('should return nonce after network nonce', async function () { |
||||||
|
this.timeout(15000) |
||||||
|
const nonceLock = await nonceTracker.getNonceLock('0x7d3517b0d011698406d6e0aed8453f0be2697926') |
||||||
|
assert.equal(nonceLock.nextNonce, '0', `nonce should be 0 got ${nonceLock.nextNonce}`) |
||||||
|
await nonceLock.releaseLock() |
||||||
|
}) |
||||||
|
}) |
||||||
|
|
||||||
|
describe('When all three return different values', function () { |
||||||
|
beforeEach(function () { |
||||||
|
const txGen = new MockTxGen() |
||||||
|
const confirmedTxs = txGen.generate({ status: 'confirmed' }, { count: 10 }) |
||||||
|
const pendingTxs = txGen.generate({ |
||||||
|
status: 'submitted', |
||||||
|
nonce: 100, |
||||||
|
}, { count: 1 }) |
||||||
|
// 0x32 is 50 in hex:
|
||||||
|
nonceTracker = generateNonceTrackerWith(pendingTxs, confirmedTxs, '0x32') |
||||||
|
}) |
||||||
|
|
||||||
|
it('should return nonce after network nonce', async function () { |
||||||
|
this.timeout(15000) |
||||||
|
const nonceLock = await nonceTracker.getNonceLock('0x7d3517b0d011698406d6e0aed8453f0be2697926') |
||||||
|
assert.equal(nonceLock.nextNonce, '50', `nonce should be 50 got ${nonceLock.nextNonce}`) |
||||||
|
await nonceLock.releaseLock() |
||||||
|
}) |
||||||
|
}) |
||||||
|
|
||||||
|
describe('Faq issue 67', function () { |
||||||
|
beforeEach(function () { |
||||||
|
const txGen = new MockTxGen() |
||||||
|
const confirmedTxs = txGen.generate({ status: 'confirmed' }, { count: 64 }) |
||||||
|
const pendingTxs = txGen.generate({ |
||||||
|
status: 'submitted', |
||||||
|
}, { count: 10 }) |
||||||
|
// 0x40 is 64 in hex:
|
||||||
|
nonceTracker = generateNonceTrackerWith(pendingTxs, [], '0x40') |
||||||
|
}) |
||||||
|
|
||||||
|
it('should return nonce after network nonce', async function () { |
||||||
this.timeout(15000) |
this.timeout(15000) |
||||||
const nonceLock = await nonceTracker.getNonceLock('0x7d3517b0d011698406d6e0aed8453f0be2697926') |
const nonceLock = await nonceTracker.getNonceLock('0x7d3517b0d011698406d6e0aed8453f0be2697926') |
||||||
assert.equal(nonceLock.nextNonce, '1', 'nonce should be 1') |
assert.equal(nonceLock.nextNonce, '74', `nonce should be 74 got ${nonceLock.nextNonce}`) |
||||||
await nonceLock.releaseLock() |
await nonceLock.releaseLock() |
||||||
}) |
}) |
||||||
}) |
}) |
||||||
}) |
}) |
||||||
|
}) |
||||||
|
|
||||||
|
function generateNonceTrackerWith (pending, confirmed, providerStub = '0x0') { |
||||||
|
const getPendingTransactions = () => pending |
||||||
|
const getConfirmedTransactions = () => confirmed |
||||||
|
providerResultStub.result = providerStub |
||||||
|
const provider = { |
||||||
|
sendAsync: (_, cb) => { cb(undefined, providerResultStub) }, |
||||||
|
_blockTracker: { |
||||||
|
getCurrentBlock: () => '0x11b568', |
||||||
|
}, |
||||||
|
} |
||||||
|
return new NonceTracker({ |
||||||
|
provider, |
||||||
|
getPendingTransactions, |
||||||
|
getConfirmedTransactions, |
||||||
|
}) |
||||||
|
} |
||||||
|
|
||||||
|
@ -0,0 +1,26 @@ |
|||||||
|
const assert = require('assert') |
||||||
|
const clone = require('clone') |
||||||
|
const txStateHistoryHelper = require('../../app/scripts/lib/tx-state-history-helper') |
||||||
|
|
||||||
|
describe('deepCloneFromTxMeta', function () { |
||||||
|
it('should clone deep', function () { |
||||||
|
const input = { |
||||||
|
foo: { |
||||||
|
bar: { |
||||||
|
bam: 'baz' |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
const output = txStateHistoryHelper.snapshotFromTxMeta(input) |
||||||
|
assert('foo' in output, 'has a foo key') |
||||||
|
assert('bar' in output.foo, 'has a bar key') |
||||||
|
assert('bam' in output.foo.bar, 'has a bar key') |
||||||
|
assert.equal(output.foo.bar.bam, 'baz', 'has a baz value') |
||||||
|
}) |
||||||
|
|
||||||
|
it('should remove the history key', function () { |
||||||
|
const input = { foo: 'bar', history: 'remembered' } |
||||||
|
const output = txStateHistoryHelper.snapshotFromTxMeta(input) |
||||||
|
assert(typeof output.history, 'undefined', 'should remove history') |
||||||
|
}) |
||||||
|
}) |
@ -0,0 +1,23 @@ |
|||||||
|
const assert = require('assert') |
||||||
|
const txStateHistoryHelper = require('../../app/scripts/lib/tx-state-history-helper') |
||||||
|
const testVault = require('../data/v17-long-history.json') |
||||||
|
|
||||||
|
|
||||||
|
describe('tx-state-history-helper', function () { |
||||||
|
it('migrates history to diffs and can recover original values', function () { |
||||||
|
testVault.data.TransactionController.transactions.forEach((tx, index) => { |
||||||
|
const newHistory = txStateHistoryHelper.migrateFromSnapshotsToDiffs(tx.history) |
||||||
|
newHistory.forEach((newEntry, index) => { |
||||||
|
if (index === 0) { |
||||||
|
assert.equal(Array.isArray(newEntry), false, 'initial history item IS NOT a json patch obj') |
||||||
|
} else { |
||||||
|
assert.equal(Array.isArray(newEntry), true, 'non-initial history entry IS a json patch obj') |
||||||
|
} |
||||||
|
const oldEntry = tx.history[index] |
||||||
|
const historySubset = newHistory.slice(0, index + 1) |
||||||
|
const reconstructedValue = txStateHistoryHelper.replayHistory(historySubset) |
||||||
|
assert.deepEqual(oldEntry, reconstructedValue, 'was able to reconstruct old entry from diffs') |
||||||
|
}) |
||||||
|
}) |
||||||
|
}) |
||||||
|
}) |
@ -1,10 +0,0 @@ |
|||||||
launch_in_dev: |
|
||||||
- Chrome |
|
||||||
- Firefox |
|
||||||
launch_in_ci: |
|
||||||
- Chrome |
|
||||||
- Firefox |
|
||||||
framework: |
|
||||||
- qunit |
|
||||||
before_tests: "npm run buildCiUnits" |
|
||||||
test_page: "test/integration/index.html" |
|
Loading…
Reference in new issue