From 1f22013ce0a5e2e0dadd9ecf3eb33f1db2b91872 Mon Sep 17 00:00:00 2001 From: Christopher Jeffrey Date: Wed, 23 Nov 2016 15:18:38 -0800 Subject: [PATCH] chain: versionbits refactor. --- lib/blockchain/chain.js | 111 +++++++++++++++---------------- lib/blockchain/chaindb.js | 61 +++++++++-------- lib/blockchain/chainentry.js | 19 +++++- lib/blockchain/layout-browser.js | 8 +-- lib/blockchain/layout.js | 8 +-- lib/mempool/mempool.js | 6 +- lib/protocol/network.js | 47 +++++++++++++ lib/protocol/networks.js | 61 +++++++++++++++++ test/chain-test.js | 9 +-- 9 files changed, 227 insertions(+), 103 deletions(-) diff --git a/lib/blockchain/chain.js b/lib/blockchain/chain.js index 9d39de52..c6d5144c 100644 --- a/lib/blockchain/chain.js +++ b/lib/blockchain/chain.js @@ -436,6 +436,7 @@ Chain.prototype.verify = co(function* verify(block, prev) { */ Chain.prototype.getDeployments = co(function* getDeployments(block, prev) { + var deployments = this.network.deployments; var height = prev.height + 1; var state = new DeploymentState(); var active; @@ -496,7 +497,7 @@ Chain.prototype.getDeployments = co(function* getDeployments(block, prev) { // CHECKSEQUENCEVERIFY and median time // past locktimes are now usable (bip9 & bip113). - active = yield this.isActive(prev, 'csv'); + active = yield this.isActive(prev, deployments.csv); if (active) { state.flags |= constants.flags.VERIFY_CHECKSEQUENCEVERIFY; state.lockFlags |= constants.flags.VERIFY_SEQUENCE; @@ -504,7 +505,7 @@ Chain.prototype.getDeployments = co(function* getDeployments(block, prev) { } // Segregrated witness is now usable (bip141 - segnet4) - active = yield this.isActive(prev, 'witness'); + active = yield this.isActive(prev, deployments.witness); if (active) { if (this.options.witness) state.flags |= constants.flags.VERIFY_WITNESS; @@ -645,7 +646,7 @@ Chain.prototype.verifyInputs = co(function* verifyInputs(block, prev, state) { } // Verify sequence locks. - valid = yield this.checkLocks(prev, tx, state.lockFlags); + valid = yield this.verifyLocks(prev, tx, state.lockFlags); if (!valid) { throw new VerifyError(block, @@ -936,6 +937,13 @@ Chain.prototype.setBestChain = co(function* setBestChain(entry, block, prev) { yield this.reorganize(entry, block); } + // Warn of unknown versionbits. + if (entry.hasUnknown()) { + this.logger.warning( + 'Unknown version bits in block %d: %d.', + entry.height, entry.version); + } + // Otherwise, everything is in order. // Do "contextual" verification on our block // now that we're certain its previous @@ -995,6 +1003,13 @@ Chain.prototype.saveAlternate = co(function* saveAlternate(entry, block, prev) { throw e; } + // Warn of unknown versionbits. + if (entry.hasUnknown()) { + this.logger.warning( + 'Unknown version bits in block %d: %d.', + entry.height, entry.version); + } + yield this.db.save(entry, block); }); @@ -1912,7 +1927,7 @@ Chain.prototype.findLocator = co(function* findLocator(locator) { * @returns {Promise} - Returns Number. */ -Chain.prototype.isActive = co(function* isActive(prev, id) { +Chain.prototype.isActive = co(function* isActive(prev, deployment) { var state; if (!this.options.witness) { @@ -1920,7 +1935,7 @@ Chain.prototype.isActive = co(function* isActive(prev, id) { return false; } - state = yield this.getState(prev, id); + state = yield this.getState(prev, deployment); return state === constants.thresholdStates.ACTIVE; }); @@ -1935,20 +1950,14 @@ Chain.prototype.isActive = co(function* isActive(prev, id) { * @returns {Promise} - Returns Number. */ -Chain.prototype.getState = co(function* getState(prev, id) { +Chain.prototype.getState = co(function* getState(prev, deployment) { var period = this.network.minerWindow; var threshold = this.network.activationThreshold; - var deployment = this.network.deployments[id]; var thresholdStates = constants.thresholdStates; var bit = deployment.bit; - var timeStart, timeTimeout, compute, height; - var i, entry, count, state, block, medianTime; - - assert(deployment); - - timeStart = deployment.startTime; - timeTimeout = deployment.timeout; - compute = []; + var compute = []; + var i, entry, count, state; + var block, time, height; if (!prev) return thresholdStates.DEFINED; @@ -1972,9 +1981,9 @@ Chain.prototype.getState = co(function* getState(prev, id) { break; } - medianTime = yield entry.getMedianTimeAsync(); + time = yield entry.getMedianTimeAsync(); - if (medianTime < timeStart) { + if (time < deployment.startTime) { state = thresholdStates.DEFINED; this.db.stateCache.set(bit, entry, state); break; @@ -1991,23 +2000,23 @@ Chain.prototype.getState = co(function* getState(prev, id) { switch (state) { case thresholdStates.DEFINED: - medianTime = yield entry.getMedianTimeAsync(); + time = yield entry.getMedianTimeAsync(); - if (medianTime >= timeTimeout) { + if (time >= deployment.timeout) { state = thresholdStates.FAILED; break; } - if (medianTime >= timeStart) { + if (time >= deployment.startTime) { state = thresholdStates.STARTED; break; } break; case thresholdStates.STARTED: - medianTime = yield entry.getMedianTimeAsync(); + time = yield entry.getMedianTimeAsync(); - if (medianTime >= timeTimeout) { + if (time >= deployment.timeout) { state = thresholdStates.FAILED; break; } @@ -2016,7 +2025,7 @@ Chain.prototype.getState = co(function* getState(prev, id) { count = 0; for (i = 0; i < period; i++) { - if (block.hasBit(deployment)) + if (block.hasBit(bit)) count++; if (count >= threshold) { @@ -2054,18 +2063,16 @@ Chain.prototype.getState = co(function* getState(prev, id) { */ Chain.prototype.computeBlockVersion = co(function* computeBlockVersion(prev) { - var keys = Object.keys(this.network.deployments); var version = 0; - var i, id, deployment, state; + var i, deployment, state; - for (i = 0; i < keys.length; i++) { - id = keys[i]; - deployment = this.network.deployments[id]; - state = yield this.getState(prev, id); + for (i = 0; i < this.network.deploys.length; i++) { + deployment = this.network.deploys[i]; + state = yield this.getState(prev, deployment); if (state === constants.thresholdStates.LOCKED_IN || state === constants.thresholdStates.STARTED) { - version |= (1 << deployment.bit); + version |= 1 << deployment.bit; } } @@ -2165,31 +2172,6 @@ Chain.prototype.getLocks = co(function* getLocks(prev, tx, flags) { return new LockTimes(minHeight, minTime); }); -/** - * Evaluate sequence locks. - * @param {ChainEntry} prev - * @param {Number} minHeight - * @param {Number} minTime - * @returns {Promise} - Returns Boolean. - */ - -Chain.prototype.evalLocks = co(function* evalLocks(prev, minHeight, minTime) { - var medianTime; - - if (minHeight >= prev.height + 1) - return false; - - if (minTime === -1) - return true; - - medianTime = yield prev.getMedianTimeAsync(); - - if (minTime >= medianTime) - return false; - - return true; -}); - /** * Verify sequence locks. * @param {TX} tx @@ -2198,9 +2180,22 @@ Chain.prototype.evalLocks = co(function* evalLocks(prev, minHeight, minTime) { * @returns {Promise} - Returns Boolean. */ -Chain.prototype.checkLocks = co(function* checkLocks(prev, tx, flags) { - var times = yield this.getLocks(prev, tx, flags); - return yield this.evalLocks(prev, times.height, times.time); +Chain.prototype.verifyLocks = co(function* verifyLocks(prev, tx, flags) { + var locks = yield this.getLocks(prev, tx, flags); + var medianTime; + + if (locks.height >= prev.height + 1) + return false; + + if (locks.time === -1) + return true; + + medianTime = yield prev.getMedianTimeAsync(); + + if (locks.time >= medianTime) + return false; + + return true; }); /** diff --git a/lib/blockchain/chaindb.js b/lib/blockchain/chaindb.js index 9f76168d..838ea0d2 100644 --- a/lib/blockchain/chaindb.js +++ b/lib/blockchain/chaindb.js @@ -144,6 +144,8 @@ ChainDB.prototype._open = co(function* open() { block = Block.fromRaw(this.network.genesisBlock, 'hex'); block.setHeight(0); entry = ChainEntry.fromBlock(this.chain, block); + + this.logger.info('Writing genesis block to ChainDB.'); yield this.save(entry, block, new CoinView()); } @@ -793,8 +795,8 @@ ChainDB.prototype.getStateCache = co(function* getStateCache() { var i, items, item; items = yield this.db.range({ - gte: layout.s(0, constants.ZERO_HASH), - lte: layout.s(255, constants.MAX_HASH), + gte: layout.v(0, constants.ZERO_HASH), + lte: layout.v(255, constants.MAX_HASH), values: true }); @@ -816,8 +818,8 @@ ChainDB.prototype.invalidateCache = co(function* invalidateCache(bit, batch) { var i, keys, key; keys = yield this.db.keys({ - gte: layout.s(bit, constants.ZERO_HASH), - lte: layout.s(bit, constants.MAX_HASH) + gte: layout.v(bit, constants.ZERO_HASH), + lte: layout.v(bit, constants.MAX_HASH) }); for (i = 0; i < keys.length; i++) { @@ -833,11 +835,12 @@ ChainDB.prototype.invalidateCache = co(function* invalidateCache(bit, batch) { ChainDB.prototype.verifyDeployments = co(function* verifyDeployments() { var expected = this.stateCache.toDeployments(); - var current = yield this.db.get(layout.v); + var current = yield this.db.get(layout.V); var i, invalid, bit, batch; if (!current) { - yield this.db.put(layout.v, expected); + this.logger.info('Writing deployment params to ChainDB.'); + yield this.db.put(layout.V, expected); return true; } @@ -855,7 +858,7 @@ ChainDB.prototype.verifyDeployments = co(function* verifyDeployments() { yield this.invalidateCache(bit, batch); } - batch.put(layout.v, expected); + batch.put(layout.V, expected); yield batch.write(); @@ -1358,7 +1361,7 @@ ChainDB.prototype.saveUpdates = function saveUpdates() { for (i = 0; i < updates.length; i++) { update = updates[i]; - this.put(layout.s(update.bit, update.hash), update.toRaw()); + this.put(layout.v(update.bit, update.hash), update.toRaw()); } }; @@ -2001,34 +2004,33 @@ ChainState.fromRaw = function fromRaw(data) { */ function StateCache(network) { - this.deployments = network.deployments; - this.bits = {}; - this.cache = {}; + this.network = network; + this.cache = []; this.updates = []; this._init(); } StateCache.prototype._init = function _init() { - var keys = Object.keys(this.deployments); - var i, key, deployment, bit; + var i, deployment; - for (i = 0; i < keys.length; i++) { - key = keys[i]; - deployment = this.deployments[key]; - bit = deployment.bit; - this.cache[bit] = {}; - this.bits[bit] = deployment; + for (i = 0; i < 32; i++) + this.cache.push(null); + + for (i = 0; i < this.network.deploys.length; i++) { + deployment = this.network.deploys[i]; + assert(!this.cache[deployment.bit]); + this.cache[deployment.bit] = {}; } }; StateCache.prototype.toDeployments = function toDeployments() { var p = new BufferWriter(); - var keys = Object.keys(this.deployments); - var i, key, deployment; + var i, deployment; - for (i = 0; i < keys.length; i++) { - key = keys[i]; - deployment = this.deployments[key]; + p.writeU8(this.network.deploys.length); + + for (i = 0; i < this.network.deploys.length; i++) { + deployment = this.network.deploys[i]; p.writeU8(deployment.bit); p.writeU32(deployment.startTime); p.writeU32(deployment.timeout); @@ -2040,13 +2042,16 @@ StateCache.prototype.toDeployments = function toDeployments() { StateCache.prototype.verifyDeployments = function verifyDeployments(raw) { var p = new BufferReader(raw); var invalid = []; - var deployment, bit, start, timeout; + var i, count, deployment; + var bit, start, timeout; - while (p.left()) { + count = p.readU8(); + + for (i = 0; i < count; i++) { bit = p.readU8(); start = p.readU32(); timeout = p.readU32(); - deployment = this.bits[bit]; + deployment = this.network.byBit(bit); if (deployment && start === deployment.startTime @@ -2103,7 +2108,7 @@ StateCache.prototype.drop = function drop() { }; StateCache.prototype.setRaw = function setRaw(key, value) { - var pair = layout.ss(key); + var pair = layout.vv(key); var bit = pair[0]; var hash = pair[1]; var state = value[0]; diff --git a/lib/blockchain/chainentry.js b/lib/blockchain/chainentry.js index 289d6145..766ab457 100644 --- a/lib/blockchain/chainentry.js +++ b/lib/blockchain/chainentry.js @@ -362,16 +362,31 @@ ChainEntry.prototype.isHistorical = function isHistorical() { return false; }; +/** + * Test whether the entry contains an unknown version bit. + * @returns {Boolean} + */ + +ChainEntry.prototype.hasUnknown = function hasUnknown() { + var bits = this.version & constants.versionbits.TOP_MASK; + var topBits = constants.versionbits.TOP_BITS; + + if ((bits >>> 0) !== topBits) + return false; + + return (this.version & this.network.unknownBits) !== 0; +}; + /** * Test whether the entry contains a version bit. * @param {Object} deployment * @returns {Boolean} */ -ChainEntry.prototype.hasBit = function hasBit(deployment) { +ChainEntry.prototype.hasBit = function hasBit(bit) { var bits = this.version & constants.versionbits.TOP_MASK; var topBits = constants.versionbits.TOP_BITS; - var mask = 1 << deployment.bit; + var mask = 1 << bit; return (bits >>> 0) === topBits && (this.version & mask) !== 0; }; diff --git a/lib/blockchain/layout-browser.js b/lib/blockchain/layout-browser.js index 9b7fb06b..16587191 100644 --- a/lib/blockchain/layout-browser.js +++ b/lib/blockchain/layout-browser.js @@ -13,7 +13,7 @@ var pad32 = util.pad32; var layout = { R: 'R', O: 'O', - v: 'v', + V: 'v', e: function e(hash) { return 'e' + hex(hash); }, @@ -41,10 +41,10 @@ var layout = { u: function u(hash) { return 'u' + hex(hash); }, - s: function s(bit, hash) { - return 's' + pad8(bit) + hex(hash); + v: function v(bit, hash) { + return 'v' + pad8(bit) + hex(hash); }, - ss: function ss(key) { + vv: function vv(key) { return [+key.slice(1, 4), key.slice(4, 36)]; }, T: function T(address, hash) { diff --git a/lib/blockchain/layout.js b/lib/blockchain/layout.js index 659b743f..6a8925f5 100644 --- a/lib/blockchain/layout.js +++ b/lib/blockchain/layout.js @@ -30,7 +30,7 @@ var layout = { R: new Buffer([0x52]), O: new Buffer([0x4f]), - v: new Buffer([0x76]), + V: new Buffer([0x76]), e: function e(hash) { return pair(0x65, hash); }, @@ -58,14 +58,14 @@ var layout = { u: function u(hash) { return pair(0x75, hash); }, - s: function s(bit, hash) { + v: function v(bit, hash) { var key = new Buffer(1 + 1 + 32); - key[0] = 0x73; + key[0] = 0x76; key[1] = bit; write(key, hash, 2); return key; }, - ss: function ss(key) { + vv: function vv(key) { return [key[1], key.toString('hex', 2, 34)]; }, T: function T(address, hash) { diff --git a/lib/mempool/mempool.js b/lib/mempool/mempool.js index 6bf8ce93..9496af71 100644 --- a/lib/mempool/mempool.js +++ b/lib/mempool/mempool.js @@ -848,7 +848,7 @@ Mempool.prototype.verify = co(function* verify(entry) { var ret = new VerifyResult(); var now, minFee, count, result; - result = yield this.checkLocks(tx, lockFlags); + result = yield this.verifyLocks(tx, lockFlags); if (!result) { throw new VerifyError(tx, @@ -1522,8 +1522,8 @@ Mempool.prototype.getSnapshot = function getSnapshot() { * @returns {Promise} - Returns Boolean. */ -Mempool.prototype.checkLocks = function checkLocks(tx, flags) { - return this.chain.checkLocks(this.chain.tip, tx, flags); +Mempool.prototype.verifyLocks = function verifyLocks(tx, flags) { + return this.chain.verifyLocks(this.chain.tip, tx, flags); }; /** diff --git a/lib/protocol/network.js b/lib/protocol/network.js index ab55d6c6..d291ed89 100644 --- a/lib/protocol/network.js +++ b/lib/protocol/network.js @@ -8,7 +8,9 @@ 'use strict'; var assert = require('assert'); +var util = require('../utils/util'); var networks = require('./networks'); +var constants = require('./constants'); /** * Represents a network. @@ -39,6 +41,8 @@ function Network(options) { this.activationThreshold = options.activationThreshold; this.minerWindow = options.minerWindow; this.deployments = options.deployments; + this.deploys = options.deploys; + this.unknownBits = ~constants.versionbits.TOP_MASK; this.keyPrefix = options.keyPrefix; this.addressPrefix = options.addressPrefix; this.requireStandard = options.requireStandard; @@ -49,6 +53,8 @@ function Network(options) { this.selfConnect = options.selfConnect; this.requestMempool = options.requestMempool; this.batchSize = options.batchSize; + + this._init(); } /** @@ -76,6 +82,39 @@ Network.segnet3 = null; Network.segnet4 = null; Network.simnet = null; +/** + * Get a deployment by bit index. + * @param {Number} bit + * @returns {Object} + */ + +Network.prototype._init = function _init() { + var bits = 0; + var i, deployment; + + for (i = 0; i < this.deploys.length; i++) { + deployment = this.deploys[i]; + bits |= 1 << deployment.bit; + } + + bits |= constants.versionbits.TOP_MASK; + + this.unknownBits = ~bits; +}; + +/** + * Get a deployment by bit index. + * @param {Number} bit + * @returns {Object} + */ + +Network.prototype.byBit = function byBit(bit) { + var index = util.binarySearch(this.deploys, bit, cmpBit); + if (index === -1) + return null; + return this.deploys[index]; +}; + /** * Determine how many blocks to request * based on current height of the chain. @@ -240,6 +279,14 @@ Network.isNetwork = function isNetwork(obj) { Network.set(process.env.BCOIN_NETWORK || 'main'); +/* + * Helpers + */ + +function cmpBit(a, b) { + return a.bit - b; +} + /* * Expose */ diff --git a/lib/protocol/networks.js b/lib/protocol/networks.js index b6060dba..0c8fc3e4 100644 --- a/lib/protocol/networks.js +++ b/lib/protocol/networks.js @@ -334,24 +334,28 @@ main.minerWindow = 2016; // nPowTargetTimespan / nPowTargetSpacing main.deployments = { testdummy: { + name: 'testdummy', bit: 28, startTime: 1199145601, // January 1, 2008 timeout: 1230767999, // December 31, 2008 force: true }, csv: { + name: 'csv', bit: 0, startTime: 1462060800, // May 1st, 2016 timeout: 1493596800, // May 1st, 2017 force: true }, witness: { + name: 'witness', bit: 1, startTime: 1479168000, // November 15th, 2016. timeout: 1510704000, // November 15th, 2017. force: false }, mast: { + name: 'mast', bit: 2, startTime: 0xffffffff, // Far in the future timeout: 0xffffffff, @@ -359,6 +363,19 @@ main.deployments = { } }; +/** + * Deployments for versionbits (array form, sorted). + * @const {Array} + * @default + */ + +main.deploys = [ + main.deployments.csv, + main.deployments.witness, + main.deployments.mast, + main.deployments.testdummy +]; + /** * Key prefixes. * @enum {Number} @@ -562,24 +579,28 @@ testnet.minerWindow = 2016; // nPowTargetTimespan / nPowTargetSpacing testnet.deployments = { testdummy: { + name: 'testdummy', bit: 28, startTime: 1199145601, // January 1, 2008 timeout: 1230767999, // December 31, 2008 force: true }, csv: { + name: 'csv', bit: 0, startTime: 1456790400, // March 1st, 2016 timeout: 1493596800, // May 1st, 2017 force: true }, witness: { + name: 'witness', bit: 1, startTime: 1462060800, // May 1st 2016 timeout: 1493596800, // May 1st 2017 force: false }, mast: { + name: 'mast', bit: 2, startTime: 0xffffffff, // Far in the future timeout: 0xffffffff, @@ -587,6 +608,13 @@ testnet.deployments = { } }; +testnet.deploys = [ + testnet.deployments.csv, + testnet.deployments.witness, + testnet.deployments.mast, + testnet.deployments.testdummy +]; + testnet.keyPrefix = { privkey: 0xef, xpubkey: 0x043587cf, @@ -709,24 +737,28 @@ regtest.minerWindow = 144; // Faster than normal for regtest (144 instead of 201 regtest.deployments = { testdummy: { + name: 'testdummy', bit: 28, startTime: 0, timeout: 0xffffffff, force: true }, csv: { + name: 'csv', bit: 0, startTime: 0, timeout: 0xffffffff, force: true }, witness: { + name: 'witness', bit: 1, startTime: 0, timeout: 0xffffffff, force: false }, mast: { + name: 'mast', bit: 2, startTime: 0xffffffff, // Far in the future timeout: 0xffffffff, @@ -734,6 +766,13 @@ regtest.deployments = { } }; +regtest.deploys = [ + regtest.deployments.csv, + regtest.deployments.witness, + regtest.deployments.mast, + regtest.deployments.testdummy +]; + regtest.keyPrefix = { privkey: 0xef, xpubkey: 0x043587cf, @@ -857,6 +896,8 @@ segnet3.minerWindow = 144; segnet3.deployments = {}; +segnet3.deploys = []; + segnet3.keyPrefix = { privkey: 0x9e, xpubkey: 0x053587cf, @@ -978,18 +1019,21 @@ segnet4.minerWindow = 144; segnet4.deployments = { testdummy: { + name: 'testdummy', bit: 28, startTime: 1199145601, // January 1, 2008 timeout: 1230767999, // December 31, 2008 force: true }, csv: { + name: 'csv', bit: 0, startTime: 1456790400, // March 1st, 2016 timeout: 1493596800, // May 1st, 2017 force: true }, witness: { + name: 'witness', bit: 1, startTime: 0, timeout: 999999999999, @@ -997,6 +1041,12 @@ segnet4.deployments = { } }; +segnet4.deploys = [ + segnet4.deployments.csv, + segnet4.deployments.witness, + segnet4.deployments.testdummy +]; + segnet4.keyPrefix = { privkey: 0x9e, xpubkey: 0x053587cf, @@ -1120,24 +1170,28 @@ simnet.minerWindow = 2016; // nPowTargetTimespan / nPowTargetSpacing simnet.deployments = { testdummy: { + name: 'testdummy', bit: 28, startTime: 1199145601, // January 1, 2008 timeout: 1230767999, // December 31, 2008 force: true }, csv: { + name: 'csv', bit: 0, startTime: 1456790400, // March 1st, 2016 timeout: 1493596800, // May 1st, 2017 force: true }, witness: { + name: 'witness', bit: 1, startTime: 1462060800, // May 1st 2016 timeout: 1493596800, // May 1st 2017 force: false }, mast: { + name: 'mast', bit: 2, startTime: 0xffffffff, // Far in the future timeout: 0xffffffff, @@ -1145,6 +1199,13 @@ simnet.deployments = { } }; +simnet.deploys = [ + simnet.deployments.csv, + simnet.deployments.witness, + simnet.deployments.mast, + simnet.deployments.testdummy +]; + simnet.keyPrefix = { privkey: 0x64, xpubkey: 0x0420bd3a, diff --git a/test/chain-test.js b/test/chain-test.js index 9ed082ce..5ed1b7c9 100644 --- a/test/chain-test.js +++ b/test/chain-test.js @@ -263,10 +263,11 @@ describe('Chain', function() { })); it('should activate csv', cob(function* () { + var deployments = chain.network.deployments; var i, block, prev, state, cache; prev = yield chain.tip.getPrevious(); - state = yield chain.getState(prev, 'csv'); + state = yield chain.getState(prev, deployments.csv); assert(state === 0); for (i = 0; i < 417; i++) { @@ -275,17 +276,17 @@ describe('Chain', function() { switch (chain.height) { case 144: prev = yield chain.tip.getPrevious(); - state = yield chain.getState(prev, 'csv'); + state = yield chain.getState(prev, deployments.csv); assert(state === 1); break; case 288: prev = yield chain.tip.getPrevious(); - state = yield chain.getState(prev, 'csv'); + state = yield chain.getState(prev, deployments.csv); assert(state === 2); break; case 432: prev = yield chain.tip.getPrevious(); - state = yield chain.getState(prev, 'csv'); + state = yield chain.getState(prev, deployments.csv); assert(state === 3); break; }