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: |
||||
node: |
||||
version: 8.1.4 |
||||
dependencies: |
||||
pre: |
||||
- "npm i -g testem" |
||||
- "npm i -g mocha" |
||||
test: |
||||
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 NonceTracker = require('../../app/scripts/lib/nonce-tracker') |
||||
const MockTxGen = require('../lib/mock-tx-gen') |
||||
let providerResultStub = {} |
||||
|
||||
describe('Nonce Tracker', function () { |
||||
let nonceTracker, provider, getPendingTransactions, pendingTxs |
||||
|
||||
|
||||
beforeEach(function () { |
||||
pendingTxs = [{ |
||||
'status': 'submitted', |
||||
'txParams': { |
||||
'from': '0x7d3517b0d011698406d6e0aed8453f0be2697926', |
||||
'gas': '0x30d40', |
||||
'value': '0x0', |
||||
'nonce': '0x0', |
||||
}, |
||||
}] |
||||
|
||||
|
||||
getPendingTransactions = () => pendingTxs |
||||
provider = { |
||||
sendAsync: (_, cb) => { cb(undefined, {result: '0x0'}) }, |
||||
_blockTracker: { |
||||
getCurrentBlock: () => '0x11b568', |
||||
}, |
||||
} |
||||
nonceTracker = new NonceTracker({ |
||||
provider, |
||||
getPendingTransactions, |
||||
}) |
||||
}) |
||||
let nonceTracker, provider |
||||
let getPendingTransactions, pendingTxs |
||||
let getConfirmedTransactions, confirmedTxs |
||||
|
||||
describe('#getNonceLock', function () { |
||||
it('should work', async function () { |
||||
this.timeout(15000) |
||||
const nonceLock = await nonceTracker.getNonceLock('0x7d3517b0d011698406d6e0aed8453f0be2697926') |
||||
assert.equal(nonceLock.nextNonce, '1', 'nonce should be 1') |
||||
await nonceLock.releaseLock() |
||||
|
||||
describe('with 3 confirmed and 1 pending', function () { |
||||
beforeEach(function () { |
||||
const txGen = new MockTxGen() |
||||
confirmedTxs = txGen.generate({ status: 'confirmed' }, { count: 3 }) |
||||
pendingTxs = txGen.generate({ status: 'submitted' }, { count: 1 }) |
||||
nonceTracker = generateNonceTrackerWith(pendingTxs, confirmedTxs, '0x1') |
||||
}) |
||||
|
||||
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() |
||||
}) |
||||
|
||||
it('should use localNonce if network returns a nonce lower then a confirmed tx in state', async function () { |
||||
this.timeout(15000) |
||||
const nonceLock = await nonceTracker.getNonceLock('0x7d3517b0d011698406d6e0aed8453f0be2697926') |
||||
assert.equal(nonceLock.nextNonce, '4', 'nonce should be 4') |
||||
await nonceLock.releaseLock() |
||||
}) |
||||
}) |
||||
|
||||
describe('with no previous txs', 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) |
||||
const nonceLock = await nonceTracker.getNonceLock('0x7d3517b0d011698406d6e0aed8453f0be2697926') |
||||
assert.equal(nonceLock.nextNonce, '74', `nonce should be 74 got ${nonceLock.nextNonce}`) |
||||
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