From cd75d861874f300fdca7b20274d170d0023d6caf Mon Sep 17 00:00:00 2001 From: Kevin Serrano Date: Tue, 14 Feb 2017 13:21:00 -0800 Subject: [PATCH 1/5] Add migrations for removing terms of use data. --- app/scripts/migrations/011.js | 30 ++++++++++++++++++++++++++++++ app/scripts/migrations/index.js | 1 + test/unit/migrations-test.js | 8 ++++++-- 3 files changed, 37 insertions(+), 2 deletions(-) create mode 100644 app/scripts/migrations/011.js diff --git a/app/scripts/migrations/011.js b/app/scripts/migrations/011.js new file mode 100644 index 000000000..227fd87f7 --- /dev/null +++ b/app/scripts/migrations/011.js @@ -0,0 +1,30 @@ +const version = 11 + +/* + +This migration breaks out the CurrencyController substate + +*/ + +module.exports = { + version, + + migrate: function (versionedData) { + 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 + delete newState.TOSHash + delete newState.isDisclaimerConfirmed + return newState +} diff --git a/app/scripts/migrations/index.js b/app/scripts/migrations/index.js index 2db8646b0..a3dd48c17 100644 --- a/app/scripts/migrations/index.js +++ b/app/scripts/migrations/index.js @@ -21,4 +21,5 @@ module.exports = [ require('./008'), require('./009'), require('./010'), + require('./011'), ] diff --git a/test/unit/migrations-test.js b/test/unit/migrations-test.js index 715a5feb0..e4353b313 100644 --- a/test/unit/migrations-test.js +++ b/test/unit/migrations-test.js @@ -6,6 +6,7 @@ const wallet1 = require(path.join('..', 'lib', 'migrations', '001.json')) const migration2 = require(path.join('..', '..', 'app', 'scripts', 'migrations', '002')) const migration3 = require(path.join('..', '..', 'app', 'scripts', 'migrations', '003')) const migration4 = require(path.join('..', '..', 'app', 'scripts', 'migrations', '004')) +const migration11 = require(path.join('..', '..', 'app', 'scripts', 'migrations', '011')) const oldTestRpc = 'https://rawtestrpc.metamask.io/' const newTestRpc = 'https://testrpc.metamask.io/' @@ -27,8 +28,11 @@ describe('wallet1 is migrated successfully', function() { }).then((thirdResult) => { assert.equal(thirdResult.data.config.provider.rpcTarget, null) assert.equal(thirdResult.data.config.provider.type, 'testnet') + return migration11.migrate(thirdResult) + }).then((eleventhResult) => { + assert.equal(eleventhResult.data.isDisclaimerConfirmed, null) + assert.equal(eleventhResult.data.TOSHash, null) }) - + }) }) - From 75f7c1244a43e48d45767e559a3b1b48f068030b Mon Sep 17 00:00:00 2001 From: Kevin Serrano Date: Wed, 15 Feb 2017 11:14:53 -0800 Subject: [PATCH 2/5] Made migrations non-destructive; fixed currency migration. --- app/scripts/migrations/002.js | 6 +++++- app/scripts/migrations/003.js | 5 ++++- app/scripts/migrations/004.js | 17 ++++++++++------- app/scripts/migrations/005.js | 7 +++++-- app/scripts/migrations/006.js | 6 ++++-- app/scripts/migrations/007.js | 6 ++++-- app/scripts/migrations/008.js | 6 ++++-- app/scripts/migrations/009.js | 9 ++++++--- app/scripts/migrations/010.js | 4 +++- app/scripts/migrations/011.js | 5 ++++- 10 files changed, 49 insertions(+), 22 deletions(-) diff --git a/app/scripts/migrations/002.js b/app/scripts/migrations/002.js index 476b0a43a..36a870342 100644 --- a/app/scripts/migrations/002.js +++ b/app/scripts/migrations/002.js @@ -1,9 +1,13 @@ const version = 2 +const clone = require('clone') + + module.exports = { version, - migrate: function (versionedData) { + migrate: function (originalVersionedData) { + let versionedData = clone(originalVersionedData) versionedData.meta.version = version try { if (versionedData.data.config.provider.type === 'etherscan') { diff --git a/app/scripts/migrations/003.js b/app/scripts/migrations/003.js index eceaeaa4b..1893576ad 100644 --- a/app/scripts/migrations/003.js +++ b/app/scripts/migrations/003.js @@ -2,10 +2,13 @@ const version = 3 const oldTestRpc = 'https://rawtestrpc.metamask.io/' const newTestRpc = 'https://testrpc.metamask.io/' +const clone = require('clone') + module.exports = { version, - migrate: function (versionedData) { + migrate: function (originalVersionedData) { + let versionedData = clone(originalVersionedData) versionedData.meta.version = version try { if (versionedData.data.config.provider.rpcTarget === oldTestRpc) { diff --git a/app/scripts/migrations/004.js b/app/scripts/migrations/004.js index 0f9850208..405d932f8 100644 --- a/app/scripts/migrations/004.js +++ b/app/scripts/migrations/004.js @@ -1,25 +1,28 @@ const version = 4 +const clone = require('clone') + module.exports = { - version, + version, migrate: function (versionedData) { - versionedData.meta.version = version + let safeVersionedData = clone(versionedData) + safeVersionedData.meta.version = version try { - if (versionedData.data.config.provider.type !== 'rpc') return Promise.resolve(versionedData) - switch (versionedData.data.config.provider.rpcTarget) { + if (safeVersionedData.data.config.provider.type !== 'rpc') return Promise.resolve(safeVersionedData) + switch (safeVersionedData.data.config.provider.rpcTarget) { case 'https://testrpc.metamask.io/': - versionedData.data.config.provider = { + safeVersionedData.data.config.provider = { type: 'testnet', } break case 'https://rpc.metamask.io/': - versionedData.data.config.provider = { + safeVersionedData.data.config.provider = { type: 'mainnet', } break } } catch (_) {} - return Promise.resolve(versionedData) + return Promise.resolve(safeVersionedData) }, } diff --git a/app/scripts/migrations/005.js b/app/scripts/migrations/005.js index 65f62a861..e4b84f460 100644 --- a/app/scripts/migrations/005.js +++ b/app/scripts/migrations/005.js @@ -7,11 +7,14 @@ This migration moves state from the flat state trie into KeyringController subst */ const extend = require('xtend') +const clone = require('clone') + module.exports = { - version, + version, - migrate: function (versionedData) { + migrate: function (originalVersionedData) { + let versionedData = clone(originalVersionedData) versionedData.meta.version = version try { const state = versionedData.data diff --git a/app/scripts/migrations/006.js b/app/scripts/migrations/006.js index 950c4deb8..94d1b6ecd 100644 --- a/app/scripts/migrations/006.js +++ b/app/scripts/migrations/006.js @@ -7,11 +7,13 @@ This migration moves KeyringController.selectedAddress to PreferencesController. */ const extend = require('xtend') +const clone = require('clone') module.exports = { - version, + version, - migrate: function (versionedData) { + migrate: function (originalVersionedData) { + let versionedData = clone(originalVersionedData) versionedData.meta.version = version try { const state = versionedData.data diff --git a/app/scripts/migrations/007.js b/app/scripts/migrations/007.js index 3ae8cdc2d..236e35224 100644 --- a/app/scripts/migrations/007.js +++ b/app/scripts/migrations/007.js @@ -7,11 +7,13 @@ This migration breaks out the TransactionManager substate */ const extend = require('xtend') +const clone = require('clone') module.exports = { - version, + version, - migrate: function (versionedData) { + migrate: function (originalVersionedData) { + let versionedData = clone(originalVersionedData) versionedData.meta.version = version try { const state = versionedData.data diff --git a/app/scripts/migrations/008.js b/app/scripts/migrations/008.js index 7f6e72ee6..cd5e95d22 100644 --- a/app/scripts/migrations/008.js +++ b/app/scripts/migrations/008.js @@ -7,11 +7,13 @@ This migration breaks out the NoticeController substate */ const extend = require('xtend') +const clone = require('clone') module.exports = { - version, + version, - migrate: function (versionedData) { + migrate: function (originalVersionedData) { + let versionedData = clone(originalVersionedData) versionedData.meta.version = version try { const state = versionedData.data diff --git a/app/scripts/migrations/009.js b/app/scripts/migrations/009.js index 38e6dcc09..4612fefdc 100644 --- a/app/scripts/migrations/009.js +++ b/app/scripts/migrations/009.js @@ -7,11 +7,13 @@ This migration breaks out the CurrencyController substate */ const merge = require('deep-extend') +const clone = require('clone') module.exports = { - version, + version, - migrate: function (versionedData) { + migrate: function (originalVersionedData) { + let versionedData = clone(originalVersionedData) versionedData.meta.version = version try { const state = versionedData.data @@ -27,12 +29,13 @@ module.exports = { function transformState (state) { const newState = merge({}, state, { CurrencyController: { - currentCurrency: state.currentFiat || 'USD', + currentCurrency: state.currentFiat || state.fiatCurrency || 'USD', conversionRate: state.conversionRate, conversionDate: state.conversionDate, }, }) delete newState.currentFiat + delete newState.fiatCurrency delete newState.conversionRate delete newState.conversionDate diff --git a/app/scripts/migrations/010.js b/app/scripts/migrations/010.js index d41c63fcd..48a841bc1 100644 --- a/app/scripts/migrations/010.js +++ b/app/scripts/migrations/010.js @@ -7,11 +7,13 @@ This migration breaks out the CurrencyController substate */ const merge = require('deep-extend') +const clone = require('clone') module.exports = { version, - migrate: function (versionedData) { + migrate: function (originalVersionedData) { + let versionedData = clone(originalVersionedData) versionedData.meta.version = version try { const state = versionedData.data diff --git a/app/scripts/migrations/011.js b/app/scripts/migrations/011.js index 227fd87f7..bf283ef98 100644 --- a/app/scripts/migrations/011.js +++ b/app/scripts/migrations/011.js @@ -6,10 +6,13 @@ This migration breaks out the CurrencyController substate */ +const clone = require('clone') + module.exports = { version, - migrate: function (versionedData) { + migrate: function (originalVersionedData) { + let versionedData = clone(originalVersionedData) versionedData.meta.version = version try { const state = versionedData.data From 6ddd613a156b4af9965ebb73c75f2182709e63ae Mon Sep 17 00:00:00 2001 From: Kevin Serrano Date: Wed, 15 Feb 2017 11:15:33 -0800 Subject: [PATCH 3/5] Adding additional migration state to account for moving data. --- test/lib/migrations/004.json | 138 +++++++++++++++++++++++++++++++++++ 1 file changed, 138 insertions(+) create mode 100644 test/lib/migrations/004.json diff --git a/test/lib/migrations/004.json b/test/lib/migrations/004.json new file mode 100644 index 000000000..0e2075c46 --- /dev/null +++ b/test/lib/migrations/004.json @@ -0,0 +1,138 @@ +{ + "meta":{ + "version":4 + }, + "data":{ + "seedWords":null, + "fiatCurrency":"USD", + "isDisclaimerConfirmed":true, + "TOSHash":"a4f4e23f823a7ac51783e7ffba7914a911b09acdb97263296b7e14b527f80c5b", + "shapeShiftTxList":[ + { + "depositAddress": "1L8BJCR6KHkCiVceDqibt7zJscqPpH7pFw", + "depositType": "BTC", + "key": "shapeshift", + "time": 1471564825772, + "response": { + "status": "complete", + "outgoingCoin": "100.00", + "incomingCoin": "1.000", + "transaction": "0x3701e0ac344a12a1fc5417cf251109a7c41f3edab922310202630d9c012414c8" + } + }, + { + "depositAddress": "1L8BJCR6KHkCiVceDqibt7zJscqPpH7pFw", + "depositType": "BTC", + "key": "shapeshift", + "time": 1471566579224, + "response": { + "status": "no_deposits", + "depositAddress": "1L8BJCR6KHkCiVceDqibt7zJscqPpH7pFw" + } + }, + { + "depositAddress": "1L8BJCR6KHkCiVceDqibt7zJscqPpH7pFw", + "depositType": "BTC", + "key": "shapeshift", + "time": 1471566565378, + "response": { + "status": "received", + "depositAddress": "1L8BJCR6KHkCiVceDqibt7zJscqPpH7pFw" + } + } + ], + "noticesList":[ + { + "read":true, + "date":"Fri Dec 16 2016", + "title":"Ending Morden Support", + "body":"Due to [recent events](https://blog.ethereum.org/2016/11/20/from-morden-to-ropsten/), MetaMask is now deprecating support for the Morden Test Network.\n\nUsers will still be able to access Morden through a locally hosted node, but we will no longer be providing hosted access to this network through [Infura](http://infura.io/).\n\nPlease use the new Ropsten Network as your new default test network.\n\nYou can fund your Ropsten account using the buy button on your account page.\n\nBest wishes!\nThe MetaMask Team\n\n", + "id":0 + } + ], + "conversionRate":12.66441492, + "conversionDate":1487184182, + "vault":"{\"data\":\"Z5UFCeI/Tg9F9No0dC7eIhe4evCG91m6qeXhGpSeX48HHCQ/BepyNONKrh05YjB9hXCAd3Jy93judD+pcXNy7WS9zLujjmMI6sI90ToSrzThnMrOE6ixcH7HGS+TCcqvwBhZEsAQqUcQeHhT9CcdCQAxkKwBk8CK8W290MVeZoQVGK88hB2R8kL3mo/uayS5AnHPwWOS0rocgSfd/ioiucClpw==\",\"iv\":\"AYufeEPwp9f2Rdrfq7yS8g==\",\"salt\":\"g7BQIEx8tosH3IxWhPnrgZFu1XRkQn1Pp7l1ehTQQCo=\"}", + "config":{ + "provider":{ + "type":"testnet" + }, + "selectedAccount":"0x0beb674745816b125fbc07285d39fd373e64895c" + }, + "walletNicknames":{ + "0x0beb674745816b125fbc07285d39fd373e64895c":"Account 1", + "0x433eb37d2e4895815b90f555425dfa123ddaed40":"Account 2" + }, + "transactions":[ + { + "id":3922064325443430, + "time":1487184358262, + "status":"confirmed", + "gasMultiplier":1, + "metamaskNetworkId":"3", + "txParams":{ + "from":"0x0beb674745816b125fbc07285d39fd373e64895c", + "to":"0x18a3462427bcc9133bb46e88bcbe39cd7ef0e761", + "value":"0xde0b6b3a7640000", + "metamaskId":3922064325443430, + "metamaskNetworkId":"3", + "gas":"0x5209", + "gasPrice":"0x04a817c800", + "nonce":"0x0", + "gasLimit":"0x5209" + }, + "gasLimitSpecified":false, + "estimatedGas":"0x5209", + "txFee":"17e0186e60800", + "txValue":"de0b6b3a7640000", + "maxCost":"de234b52e4a0800", + "hash":"0x0b36c5bb31528044e6a71e45a64e9872f5f365a14ac42ee1bea49e7766216c12" + }, + { + "id":3922064325443431, + "time":1487184373172, + "status":"confirmed", + "gasMultiplier":1, + "metamaskNetworkId":"3", + "txParams":{ + "from":"0x0beb674745816b125fbc07285d39fd373e64895c", + "to":"0x433eb37d2e4895815b90f555425dfa123ddaed40", + "value":"0xde0b6b3a7640000", + "metamaskId":3922064325443431, + "metamaskNetworkId":"3", + "gas":"0x5209", + "nonce":"0x01", + "gasPrice":"0x04a817c800", + "gasLimit":"0x5209" + }, + "gasLimitSpecified":false, + "estimatedGas":"0x5209", + "txFee":"17e0186e60800", + "txValue":"de0b6b3a7640000", + "maxCost":"de234b52e4a0800", + "hash":"0x305548a8b8bb72de0ca8cf77df45e4fe2b29383e58c4da6b7eac7e9bd59e85e9" + }, + { + "id":3922064325443432, + "time":1487184391226, + "status":"unapproved", + "gasMultiplier":1, + "metamaskNetworkId":"3", + "txParams":{ + "from":"0x0beb674745816b125fbc07285d39fd373e64895c", + "to":"0x18a3462427bcc9133bb46e88bcbe39cd7ef0e761", + "value":"0xde0b6b3a7640000", + "metamaskId":3922064325443432, + "metamaskNetworkId":"3", + "gas":"0x5209" + }, + "gasLimitSpecified":false, + "estimatedGas":"0x5209", + "txFee":"17e0186e60800", + "txValue":"de0b6b3a7640000", + "maxCost":"de234b52e4a0800" + } + ], + "gasMultiplier":1 + } +} From d0e2846eca6f8d2ad16c9338a95fbaac294bac4a Mon Sep 17 00:00:00 2001 From: Kevin Serrano Date: Wed, 15 Feb 2017 11:15:47 -0800 Subject: [PATCH 4/5] Complete migration tests. --- package.json | 1 + test/unit/migrations-test.js | 89 ++++++++++++++++++++++++++++++------ 2 files changed, 75 insertions(+), 15 deletions(-) diff --git a/package.json b/package.json index 16246f77c..11cb353ea 100644 --- a/package.json +++ b/package.json @@ -117,6 +117,7 @@ "brfs": "^1.4.3", "browserify": "^13.0.0", "chai": "^3.5.0", + "clone": "^1.0.2", "deep-freeze-strict": "^1.1.1", "del": "^2.2.0", "fs-promise": "^1.0.0", diff --git a/test/unit/migrations-test.js b/test/unit/migrations-test.js index e4353b313..d2a83be77 100644 --- a/test/unit/migrations-test.js +++ b/test/unit/migrations-test.js @@ -2,36 +2,95 @@ const assert = require('assert') const path = require('path') const wallet1 = require(path.join('..', 'lib', 'migrations', '001.json')) +const vault4 = require(path.join('..', 'lib', 'migrations', '004.json')) +let vault5, vault6, vault7, vault8, vault9, vault10, vault11 const migration2 = require(path.join('..', '..', 'app', 'scripts', 'migrations', '002')) const migration3 = require(path.join('..', '..', 'app', 'scripts', 'migrations', '003')) const migration4 = require(path.join('..', '..', 'app', 'scripts', 'migrations', '004')) +const migration5 = require(path.join('..', '..', 'app', 'scripts', 'migrations', '005')) +const migration6 = require(path.join('..', '..', 'app', 'scripts', 'migrations', '006')) +const migration7 = require(path.join('..', '..', 'app', 'scripts', 'migrations', '007')) +const migration8 = require(path.join('..', '..', 'app', 'scripts', 'migrations', '008')) +const migration9 = require(path.join('..', '..', 'app', 'scripts', 'migrations', '009')) +const migration10 = require(path.join('..', '..', 'app', 'scripts', 'migrations', '010')) const migration11 = require(path.join('..', '..', 'app', 'scripts', 'migrations', '011')) const oldTestRpc = 'https://rawtestrpc.metamask.io/' const newTestRpc = 'https://testrpc.metamask.io/' -describe('wallet1 is migrated successfully', function() { - it('should convert providers', function() { +describe('wallet1 is migrated successfully', () => { + it('should convert providers', () => { wallet1.data.config.provider = { type: 'etherscan', rpcTarget: null } return migration2.migrate(wallet1) - .then((firstResult) => { - assert.equal(firstResult.data.config.provider.type, 'rpc', 'provider should be rpc') - assert.equal(firstResult.data.config.provider.rpcTarget, 'https://rpc.metamask.io/', 'main provider should be our rpc') - firstResult.data.config.provider.rpcTarget = oldTestRpc - return migration3.migrate(firstResult) - }).then((secondResult) => { - assert.equal(secondResult.data.config.provider.rpcTarget, newTestRpc) - return migration4.migrate(secondResult) + .then((secondResult) => { + const secondData = secondResult.data + assert.equal(secondData.config.provider.type, 'rpc', 'provider should be rpc') + assert.equal(secondData.config.provider.rpcTarget, 'https://rpc.metamask.io/', 'main provider should be our rpc') + secondResult.data.config.provider.rpcTarget = oldTestRpc + return migration3.migrate(secondResult) }).then((thirdResult) => { - assert.equal(thirdResult.data.config.provider.rpcTarget, null) - assert.equal(thirdResult.data.config.provider.type, 'testnet') - return migration11.migrate(thirdResult) + assert.equal(thirdResult.data.config.provider.rpcTarget, newTestRpc, 'config.provider.rpcTarget should be set to the proper testrpc url.') + return migration4.migrate(thirdResult) + }).then((fourthResult) => { + const fourthData = fourthResult.data + assert.equal(fourthData.config.provider.rpcTarget, null, 'old rpcTarget should not exist.') + assert.equal(fourthData.config.provider.type, 'testnet', 'config.provider should be set to testnet.') + + return migration5.migrate(vault4) + }).then((fifthResult) => { + const fifthData = fifthResult.data + assert.equal(fifthData.vault, null, 'old vault should not exist') + assert.equal(fifthData.walletNicknames, null, 'old walletNicknames should not exist') + assert.equal(fifthData.config.selectedAccount, null, 'old config.selectedAccount should not exist') + assert.equal(fifthData.KeyringController.vault, vault4.data.vault, 'KeyringController.vault should exist') + assert.equal(fifthData.KeyringController.selectedAccount, vault4.data.config.selectedAccount, 'KeyringController.selectedAccount should have moved') + assert.equal(fifthData.KeyringController.walletNicknames['0x0beb674745816b125fbc07285d39fd373e64895c'], vault4.data.walletNicknames['0x0beb674745816b125fbc07285d39fd373e64895c'], 'KeyringController.walletNicknames should have moved') + + vault5 = fifthResult + return migration6.migrate(fifthResult) + }).then((sixthResult) => { + assert.equal(sixthResult.data.KeyringController.selectedAccount, null, 'old selectedAccount should not exist') + assert.equal(sixthResult.data.PreferencesController.selectedAddress, vault5.data.KeyringController.selectedAccount, 'selectedAccount should have moved') + + vault6 = sixthResult + return migration7.migrate(sixthResult) + }).then((seventhResult) => { + assert.equal(seventhResult.data.transactions, null, 'old transactions should not exist') + assert.equal(seventhResult.data.gasMultiplier, null, 'old gasMultiplier should not exist') + assert.equal(seventhResult.data.TransactionManager.transactions[0].id, vault6.data.transactions[0].id, 'transactions should have moved') + assert.equal(seventhResult.data.TransactionManager.gasMultiplier, vault6.data.gasMultiplier, 'gasMultiplier should have moved') + + vault7 = seventhResult + return migration8.migrate(seventhResult) + }).then((eighthResult) => { + assert.equal(eighthResult.data.noticesList, null, 'old noticesList should not exist') + assert.equal(eighthResult.data.NoticeController.noticesList[0].title, vault7.data.noticesList[0].title, 'noticesList should have moved') + + vault8 = eighthResult + return migration9.migrate(eighthResult) + }).then((ninthResult) => { + assert.equal(ninthResult.data.currentFiat, null, 'old currentFiat should not exist') + assert.equal(ninthResult.data.fiatCurrency, null, 'old fiatCurrency should not exist') + assert.equal(ninthResult.data.conversionRate, null, 'old conversionRate should not exist') + assert.equal(ninthResult.data.conversionDate, null, 'old conversionDate should not exist') + + assert.equal(ninthResult.data.CurrencyController.currentCurrency, vault8.data.fiatCurrency, 'currentFiat should have moved') + assert.equal(ninthResult.data.CurrencyController.conversionRate, vault8.data.conversionRate, 'conversionRate should have moved') + assert.equal(ninthResult.data.CurrencyController.conversionDate, vault8.data.conversionDate, 'conversionDate should have moved') + + vault9 = ninthResult + return migration10.migrate(ninthResult) + }).then((tenthResult) => { + assert.equal(tenthResult.data.shapeShiftTxList, null, 'old shapeShiftTxList should not exist') + assert.equal(tenthResult.data.ShapeShiftController.shapeShiftTxList[0].transaction, vault9.data.shapeShiftTxList[0].transaction) + + return migration11.migrate(tenthResult) }).then((eleventhResult) => { - assert.equal(eleventhResult.data.isDisclaimerConfirmed, null) - assert.equal(eleventhResult.data.TOSHash, null) + assert.equal(eleventhResult.data.isDisclaimerConfirmed, null, 'isDisclaimerConfirmed should not exist') + assert.equal(eleventhResult.data.TOSHash, null, 'TOSHash should not exist') }) }) From 6ef78eb02bf856c85f6acbf3ad8e343ab281f63c Mon Sep 17 00:00:00 2001 From: Kevin Serrano Date: Wed, 15 Feb 2017 11:16:35 -0800 Subject: [PATCH 5/5] Add to changelog. --- CHANGELOG.md | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 1d1a2370b..d98cc798f 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,7 @@ ## Current Master - net_version has been made synchronous. +- Test suite for migrations expanded. ## 3.2.1 2017-2-8