diff --git a/bench/coin-old.js b/bench/coin-old.js index 6ee48c83..fee23fae 100644 --- a/bench/coin-old.js +++ b/bench/coin-old.js @@ -15,8 +15,8 @@ wtx = TX.fromRaw(wtx.trim(), 'hex'); var coins = Coins.fromTX(wtx); var raw; -//raw = coins.toRaw2(); -//console.log(Coins.fromRaw2(raw)); +//raw = coins.toRaw(); +//console.log(Coins.fromRaw(raw)); var end = bench('serialize'); for (var i = 0; i < 10000; i++) @@ -34,7 +34,7 @@ for (var i = 0; i < 10000; i++) Coins.parseCoin(raw, hash, 5); end(i); -var coins = Coins.fromRaw2(raw); +var coins = Coins.fromRaw(raw); var end = bench('get'); var j; diff --git a/bench/coin.js b/bench/coin.js index 3596078b..69bff5b8 100644 --- a/bench/coin.js +++ b/bench/coin.js @@ -15,8 +15,8 @@ wtx = TX.fromRaw(wtx.trim(), 'hex'); var coins = Coins.fromTX(wtx); var raw; -//raw = coins.toRaw2(); -//console.log(Coins.fromRaw2(raw)); +//raw = coins.toRaw(); +//console.log(Coins.fromRaw(raw)); var end = bench('serialize'); for (var i = 0; i < 10000; i++) @@ -34,7 +34,7 @@ for (var i = 0; i < 10000; i++) Coins.parseCoin(raw, hash, 5); end(i); -var coins = Coins.fromRaw2(raw); +var coins = Coins.fromRaw(raw); var end = bench('get'); var j; diff --git a/lib/blockchain/chain.js b/lib/blockchain/chain.js index d9cce0fb..e37758c1 100644 --- a/lib/blockchain/chain.js +++ b/lib/blockchain/chain.js @@ -626,10 +626,10 @@ Chain.prototype.verifyInputs = co(function* verifyInputs(block, prev, state) { var i, view, tx, valid; if (this.options.spv) - return new CoinView(); + return new this.db.CoinView(); if (this.isGenesis(block)) - return new CoinView(); + return new this.db.CoinView(); view = yield this.db.getCoinView(block); diff --git a/lib/blockchain/chaindb.js b/lib/blockchain/chaindb.js index 457020b1..2b93dfcb 100644 --- a/lib/blockchain/chaindb.js +++ b/lib/blockchain/chaindb.js @@ -61,6 +61,9 @@ function ChainDB(chain) { this.network = chain.network; this.options = new ChainOptions(chain.options); + this.CoinView = this.options.newCoins ? CoinView : CoinViewOld; + this.Coins = this.options.newCoins ? Coins : CoinsOld; + this.db = LDB({ location: chain.options.location, db: chain.options.db, @@ -151,7 +154,7 @@ ChainDB.prototype._open = co(function* open() { entry = ChainEntry.fromBlock(this.chain, block); this.logger.info('Writing genesis block to ChainDB.'); - yield this.save(entry, block, new CoinView()); + yield this.save(entry, block, new this.CoinView()); } this.logger.info('Chain successfully loaded.'); @@ -635,7 +638,7 @@ ChainDB.prototype.getCoin = co(function* getCoin(hash, index) { coins = this.coinCache.get(hash); if (coins) - return Coins.parseCoin(coins, hash, index); + return this.Coins.parseCoin(coins, hash, index); coins = yield this.db.get(layout.c(hash)); @@ -645,7 +648,7 @@ ChainDB.prototype.getCoin = co(function* getCoin(hash, index) { if (state === this.state) this.coinCache.set(hash, coins); - return Coins.parseCoin(coins, hash, index); + return this.Coins.parseCoin(coins, hash, index); }); /** @@ -664,7 +667,7 @@ ChainDB.prototype.getCoins = co(function* getCoins(hash) { coins = this.coinCache.get(hash); if (coins) - return Coins.fromRaw(coins, hash); + return this.Coins.fromRaw(coins, hash); coins = yield this.db.get(layout.c(hash)); @@ -674,7 +677,7 @@ ChainDB.prototype.getCoins = co(function* getCoins(hash) { if (state === this.state) this.coinCache.set(hash, coins); - return Coins.fromRaw(coins, hash); + return this.Coins.fromRaw(coins, hash); }); /** @@ -695,7 +698,7 @@ ChainDB.prototype.hasCoins = function hasCoins(hash) { */ ChainDB.prototype.getCoinView = co(function* getCoinView(block, callback) { - var view = new CoinView(); + var view = new this.CoinView(); var prevout = block.getPrevout(); var i, prev, coins; @@ -1838,6 +1841,7 @@ function ChainOptions(options) { this.prune = false; this.indexTX = false; this.indexAddress = false; + this.newCoins = false; this.forceWitness = false; @@ -1873,6 +1877,11 @@ ChainOptions.prototype.fromOptions = function fromOptions(options) { this.indexAddress = options.indexAddress; } + if (options.newCoins != null) { + assert(typeof options.newCoins === 'boolean'); + this.newCoins = options.newCoins; + } + if (options.forceWitness != null) { assert(typeof options.forceWitness === 'boolean'); this.forceWitness = options.forceWitness; @@ -1920,6 +1929,12 @@ ChainOptions.prototype.verify = function verify(options) { if (!this.indexAddress && options.indexAddress) throw new Error('Cannot retroactively disable address indexing.'); + + if (this.newCoins && !options.newCoins) + throw new Error('Cannot retroactively enable new coin serialization.'); + + if (!this.newCoins && options.newCoins) + throw new Error('Cannot retroactively disable new coin serialization.'); }; ChainOptions.prototype.toRaw = function toRaw() { @@ -1941,6 +1956,9 @@ ChainOptions.prototype.toRaw = function toRaw() { if (this.indexAddress) flags |= 1 << 4; + if (this.newCoins) + flags |= 1 << 5; + bw.writeU32(this.network.magic); bw.writeU32(flags); bw.writeU32(0); @@ -1961,6 +1979,7 @@ ChainOptions.prototype.fromRaw = function fromRaw(data) { this.prune = (flags & 4) !== 0; this.indexTX = (flags & 8) !== 0; this.indexAddress = (flags & 16) !== 0; + this.newCoins = (flags & 32) !== 0; return this; }; diff --git a/lib/blockchain/coins.js b/lib/blockchain/coins.js index 2d1f66ff..d21c3ca4 100644 --- a/lib/blockchain/coins.js +++ b/lib/blockchain/coins.js @@ -188,7 +188,7 @@ Coins.prototype.cleanup = function cleanup() { * 0x00 = 20 byte pubkey hash * 0x01 = 20 byte script hash * 0x02-0x05 = 32 byte ec-key x-value - * >=0x06 = varint-size + 6 | raw script + * >=0x06 = varint-size + 10 | raw script * data: script data, dictated by the prefix * * The compression below sacrifices some cpu in exchange @@ -232,8 +232,12 @@ Coins.prototype.toRaw = function toRaw() { } } - if (!first && !second) + // First and second bits + // have a double meaning. + if (!first && !second) { + assert(nonzero !== 0); nonzero -= 1; + } // Calculate header code. code = 8 * nonzero; diff --git a/lib/blockchain/compress.js b/lib/blockchain/compress.js index 4a1203ff..b3b8983f 100644 --- a/lib/blockchain/compress.js +++ b/lib/blockchain/compress.js @@ -13,7 +13,7 @@ var ec = require('../crypto/ec'); * Constants */ -var COMPRESS_TYPES = 6; +var COMPRESS_TYPES = 10; // Space for 4 extra. /** * Compress a script, write directly to the buffer. @@ -60,7 +60,7 @@ function compressScript(script, bw) { } } - // Raw -> varlen + 6 | script + // Raw -> varlen + 10 | script bw.writeVarint(script.raw.length + COMPRESS_TYPES); bw.writeBytes(script.raw); diff --git a/lib/node/config.js b/lib/node/config.js index 7ea737ee..1bad216f 100644 --- a/lib/node/config.js +++ b/lib/node/config.js @@ -167,6 +167,7 @@ config.parseData = function parseData(data, prefix, dirname) { options.coinCache = num(data.coincache); options.indexTX = bool(data.indextx); options.indexAddress = bool(data.indexaddress); + options.newCoins = bool(data.newcoins); // Mempool options.limitFree = bool(data.limitfree); diff --git a/lib/node/fullnode.js b/lib/node/fullnode.js index a3124885..d171bf1e 100644 --- a/lib/node/fullnode.js +++ b/lib/node/fullnode.js @@ -74,6 +74,7 @@ function FullNode(options) { coinCache: this.options.coinCache, indexTX: this.options.indexTX, indexAddress: this.options.indexAddress, + newCoins: this.options.newCoins, maxFiles: this.options.maxFiles }); diff --git a/test/chain-test.js b/test/chain-test.js index d797a35a..97a54a19 100644 --- a/test/chain-test.js +++ b/test/chain-test.js @@ -17,7 +17,7 @@ describe('Chain', function() { this.timeout(5000); - node = new bcoin.fullnode({ db: 'memory', apiKey: 'foo' }); + node = new bcoin.fullnode({ db: 'memory', apiKey: 'foo', newCoins: true }); // node.walletdb.client = new Client({ apiKey: 'foo', network: 'regtest' }); chain = node.chain; walletdb = node.walletdb; @@ -55,6 +55,13 @@ describe('Chain', function() { return yield attempt.mineAsync(); }); + it('should use correct coin serialiation', function() { + assert(node.chain.db.CoinView === require('../lib/blockchain/coinview')); + assert(node.chain.db.Coins === require('../lib/blockchain/coins')); + assert(node.chain.db.CoinView !== require('../lib/blockchain/coinview-old')); + assert(node.chain.db.Coins !== require('../lib/blockchain/coins-old')); + }); + it('should open chain and miner', cob(function* () { miner.mempool = null; constants.tx.COINBASE_MATURITY = 0;