diff --git a/bench/coin-old.js b/bench/coin-old.js new file mode 100644 index 00000000..6ee48c83 --- /dev/null +++ b/bench/coin-old.js @@ -0,0 +1,44 @@ +'use strict'; + +var BN = require('bn.js'); +var constants = require('../lib/protocol/constants'); +var util = require('../lib/utils/util'); +var assert = require('assert'); +var scriptTypes = constants.scriptTypes; +var bench = require('./bench'); +var fs = require('fs'); +var Coins = require('../lib/blockchain/coins-old'); +var TX = require('../lib/primitives/tx'); + +var wtx = fs.readFileSync(__dirname + '/../test/data/wtx.hex', 'utf8'); +wtx = TX.fromRaw(wtx.trim(), 'hex'); + +var coins = Coins.fromTX(wtx); +var raw; +//raw = coins.toRaw2(); +//console.log(Coins.fromRaw2(raw)); + +var end = bench('serialize'); +for (var i = 0; i < 10000; i++) + raw = coins.toRaw(); +end(i); + +var end = bench('parse'); +for (var i = 0; i < 10000; i++) + Coins.fromRaw(raw); +end(i); + +var end = bench('parse-single'); +var hash = wtx.hash('hex'); +for (var i = 0; i < 10000; i++) + Coins.parseCoin(raw, hash, 5); +end(i); + +var coins = Coins.fromRaw2(raw); +var end = bench('get'); +var j; + +for (var i = 0; i < 10000; i++) + for (var j = 0; j < coins.outputs.length; j++) + coins.get(j); +end(i * coins.outputs.length); diff --git a/bench/coin.js b/bench/coin.js index b7405476..3596078b 100644 --- a/bench/coin.js +++ b/bench/coin.js @@ -20,18 +20,18 @@ var raw; var end = bench('serialize'); for (var i = 0; i < 10000; i++) - raw = coins.toRaw2(); + raw = coins.toRaw(); end(i); var end = bench('parse'); for (var i = 0; i < 10000; i++) - Coins.fromRaw2(raw); + Coins.fromRaw(raw); end(i); var end = bench('parse-single'); var hash = wtx.hash('hex'); for (var i = 0; i < 10000; i++) - Coins.parseCoin2(raw, hash, 5); + Coins.parseCoin(raw, hash, 5); end(i); var coins = Coins.fromRaw2(raw); @@ -40,5 +40,5 @@ var j; for (var i = 0; i < 10000; i++) for (var j = 0; j < coins.outputs.length; j++) - coins.get2(j); + coins.get(j); end(i * coins.outputs.length); diff --git a/lib/blockchain/chain.js b/lib/blockchain/chain.js index 8dac98f8..d9cce0fb 100644 --- a/lib/blockchain/chain.js +++ b/lib/blockchain/chain.js @@ -639,7 +639,7 @@ Chain.prototype.verifyInputs = co(function* verifyInputs(block, prev, state) { // Ensure tx is not double spending an output. if (!tx.isCoinbase()) { - if (!view.fillCoins2(tx)) { + if (!view.fillCoins(tx)) { assert(!historical, 'BUG: Spent inputs in historical data!'); throw new VerifyError(block, 'invalid', diff --git a/lib/blockchain/chaindb.js b/lib/blockchain/chaindb.js index 1c818db1..457020b1 100644 --- a/lib/blockchain/chaindb.js +++ b/lib/blockchain/chaindb.js @@ -19,6 +19,8 @@ var co = require('../utils/co'); var Network = require('../protocol/network'); var CoinView = require('./coinview'); var Coins = require('./coins'); +var CoinViewOld = require('./coinview-old'); +var CoinsOld = require('./coins-old'); var LDB = require('../db/ldb'); var layout = require('./layout'); var LRU = require('../utils/lru'); @@ -633,7 +635,7 @@ ChainDB.prototype.getCoin = co(function* getCoin(hash, index) { coins = this.coinCache.get(hash); if (coins) - return Coins.parseCoin2(coins, hash, index); + return Coins.parseCoin(coins, hash, index); coins = yield this.db.get(layout.c(hash)); @@ -643,7 +645,7 @@ ChainDB.prototype.getCoin = co(function* getCoin(hash, index) { if (state === this.state) this.coinCache.set(hash, coins); - return Coins.parseCoin2(coins, hash, index); + return Coins.parseCoin(coins, hash, index); }); /** @@ -662,7 +664,7 @@ ChainDB.prototype.getCoins = co(function* getCoins(hash) { coins = this.coinCache.get(hash); if (coins) - return Coins.fromRaw2(coins, hash); + return Coins.fromRaw(coins, hash); coins = yield this.db.get(layout.c(hash)); @@ -672,7 +674,7 @@ ChainDB.prototype.getCoins = co(function* getCoins(hash) { if (state === this.state) this.coinCache.set(hash, coins); - return Coins.fromRaw2(coins, hash); + return Coins.fromRaw(coins, hash); }); /** @@ -1672,7 +1674,7 @@ ChainDB.prototype.connectBlock = co(function* connectBlock(block, view) { for (i = 0; i < view.length; i++) { coins = view[i]; - raw = coins.toRaw2(); + raw = coins.toRaw(); if (!raw) { this.del(layout.c(coins.hash)); this.coinCache.unpush(coins.hash); @@ -1768,7 +1770,7 @@ ChainDB.prototype.disconnectBlock = co(function* disconnectBlock(block) { for (i = 0; i < view.length; i++) { coins = view[i]; - raw = coins.toRaw2(); + raw = coins.toRaw(); if (!raw) { this.del(layout.c(coins.hash)); this.coinCache.unpush(coins.hash); diff --git a/lib/blockchain/coins-old.js b/lib/blockchain/coins-old.js new file mode 100644 index 00000000..45907b6c --- /dev/null +++ b/lib/blockchain/coins-old.js @@ -0,0 +1,614 @@ +/*! + * coins.js - coins object for bcoin + * Copyright (c) 2014-2016, Christopher Jeffrey (MIT License). + * https://github.com/bcoin-org/bcoin + */ + +'use strict'; + +var util = require('../utils/util'); +var assert = require('assert'); +var constants = require('../protocol/constants'); +var Coin = require('../primitives/coin'); +var Output = require('../primitives/output'); +var BufferReader = require('../utils/reader'); +var BufferWriter = require('../utils/writer'); +var compressor = require('./compress-old'); +var compress = compressor.compress; +var decompress = compressor.decompress; + +/** + * Represents the outputs for a single transaction. + * @exports Coins + * @constructor + * @param {TX|Object} tx/options - TX or options object. + * @property {Hash} hash - Transaction hash. + * @property {Number} version - Transaction version. + * @property {Number} height - Transaction height (-1 if unconfirmed). + * @property {Boolean} coinbase - Whether the containing + * transaction is a coinbase. + * @property {Coin[]} outputs - Coins. + */ + +function Coins(options) { + if (!(this instanceof Coins)) + return new Coins(options); + + this.version = 1; + this.hash = constants.NULL_HASH; + this.height = -1; + this.coinbase = true; + this.outputs = []; + + if (options) + this.fromOptions(options); +} + +/** + * Inject properties from options object. + * @private + * @param {Object} options + */ + +Coins.prototype.fromOptions = function fromOptions(options) { + if (options.version != null) { + assert(util.isNumber(options.version)); + this.version = options.version; + } + + if (options.hash) { + assert(typeof options.hash === 'string'); + this.hash = options.hash; + } + + if (options.height != null) { + assert(util.isNumber(options.height)); + this.height = options.height; + } + + if (options.coinbase != null) { + assert(typeof options.coinbase === 'boolean'); + this.coinbase = options.coinbase; + } + + if (options.outputs) { + assert(Array.isArray(options.outputs)); + this.outputs = options.outputs; + } + + return this; +}; + +/** + * Instantiate coins from options object. + * @param {Object} options + * @returns {Coins} + */ + +Coins.fromOptions = function fromOptions(options) { + return new Coins().fromOptions(options); +}; + +/** + * Add a single coin to the collection. + * @param {Coin} coin + */ + +Coins.prototype.add = function add(coin) { + if (this.outputs.length === 0) { + this.version = coin.version; + this.hash = coin.hash; + this.height = coin.height; + this.coinbase = coin.coinbase; + } + + while (this.outputs.length <= coin.index) + this.outputs.push(null); + + if (coin.script.isUnspendable()) { + this.outputs[coin.index] = null; + return; + } + + this.outputs[coin.index] = CoinEntry.fromCoin(coin); +}; + +/** + * Test whether the collection has a coin. + * @param {Number} index + * @returns {Boolean} + */ + +Coins.prototype.has = function has(index) { + if (index >= this.outputs.length) + return false; + + return this.outputs[index] != null; +}; + +/** + * Get a coin. + * @param {Number} index + * @returns {Coin} + */ + +Coins.prototype.get = function get(index) { + var coin; + + if (index >= this.outputs.length) + return; + + coin = this.outputs[index]; + + if (!coin) + return; + + return coin.toCoin(this, index); +}; + +/** + * Remove a coin and return it. + * @param {Number} index + * @returns {Coin} + */ + +Coins.prototype.spend = function spend(index) { + var coin = this.get(index); + + if (!coin) + return; + + this.outputs[index] = null; + + return coin; +}; + +/** + * Count up to the last available index. + * @returns {Number} + */ + +Coins.prototype.size = function size() { + var index = -1; + var i, output; + + for (i = this.outputs.length - 1; i >= 0; i--) { + output = this.outputs[i]; + if (output) { + index = i; + break; + } + } + + return index + 1; +}; + +/* + * Coins serialization: + * version: varint + * bits: uint32 (31-bit height | 1-bit coinbase-flag) + * spent-field: varint size | bitfield (0=unspent, 1=spent) + * outputs (repeated): + * compressed-script: + * prefix: 0x00 = varint size | raw script + * 0x01 = 20 byte pubkey hash + * 0x02 = 20 byte script hash + * 0x03 = 33 byte compressed key + * data: script data, dictated by the prefix + * value: varint + * + * The compression below sacrifices some cpu in exchange + * for reduced size, but in some cases the use of varints + * actually increases speed (varint versions and values + * for example). We do as much compression as possible + * without sacrificing too much cpu. Value compression + * is intentionally excluded for now as it seems to be + * too much of a perf hit. Maybe when v8 optimizes + * non-smi arithmetic better we can enable it. + */ + +/** + * Serialize the coins object. + * @param {TX|Coins} tx + * @returns {Buffer} + */ + +Coins.prototype.toRaw = function toRaw() { + var bw = new BufferWriter(); + var length = this.size(); + var len = Math.ceil(length / 8); + var i, output, bits, start, bit, oct, data; + + // Return nothing if we're fully spent. + if (length === 0) + return; + + // Varint version: hopefully we + // never run into `-1` versions. + bw.writeVarint(this.version); + + // Create the `bits` value: + // (height | coinbase-flag). + bits = this.height << 1; + + // Append the coinbase bit. + if (this.coinbase) + bits |= 1; + + if (bits < 0) + bits += 0x100000000; + + // Making this a varint would actually + // make 99% of coins bigger. Varints + // are really only useful up until + // 0x10000, but since we're also + // storing the coinbase flag on the + // lo bit, varints are useless (and + // actually harmful) after height + // 32767 (0x7fff). + bw.writeU32(bits); + + // Fill the spent field with zeroes to avoid + // allocating a buffer. We mark the spents + // after rendering the final buffer. + bw.writeVarint(len); + start = bw.written; + bw.fill(0, len); + + // Write the compressed outputs. + for (i = 0; i < length; i++) { + output = this.outputs[i]; + + if (!output) + continue; + + output.toWriter(bw); + } + + // Render the buffer with all + // zeroes in the spent field. + data = bw.render(); + + // Mark the spents in the spent field. + // This is essentially a NOP for new coins. + for (i = 0; i < length; i++) { + output = this.outputs[i]; + + if (output) + continue; + + bit = i % 8; + oct = (i - bit) / 8; + oct += start; + + data[oct] |= 1 << (7 - bit); + } + + return data; +}; + +/** + * Parse serialized coins. + * @param {Buffer} data + * @param {Hash} hash + * @returns {Object} A "naked" coins object. + */ + +Coins.prototype.fromRaw = function fromRaw(data, hash, index) { + var br = new BufferReader(data); + var pos = 0; + var bits, len, start, bit, oct, spent, coin; + + this.version = br.readVarint(); + + bits = br.readU32(); + + this.height = bits >>> 1; + this.hash = hash; + this.coinbase = (bits & 1) !== 0; + + // Mark the start of the spent field and + // seek past it to avoid reading a buffer. + len = br.readVarint(); + start = br.offset; + br.seek(len); + + while (br.left()) { + bit = pos % 8; + oct = (pos - bit) / 8; + oct += start; + + // Read a single bit out of the spent field. + spent = data[oct] >>> (7 - bit); + spent &= 1; + + // Already spent. + if (spent) { + this.outputs.push(null); + pos++; + continue; + } + + // Store the offset and size + // in the compressed coin object. + coin = CoinEntry.fromReader(br); + + this.outputs.push(coin); + pos++; + } + + return this; +}; + +/** + * Parse a single serialized coin. + * @param {Buffer} data + * @param {Hash} hash + * @param {Number} index + * @returns {Coin} + */ + +Coins.parseCoin = function parseCoin(data, hash, index) { + var br = new BufferReader(data); + var coin = new Coin(); + var pos = 0; + var bits, len, start, bit, oct, spent; + + coin.version = br.readVarint(); + + bits = br.readU32(); + + coin.hash = hash; + coin.index = index; + coin.height = bits >>> 1; + coin.hash = hash; + coin.coinbase = (bits & 1) !== 0; + + // Mark the start of the spent field and + // seek past it to avoid reading a buffer. + len = br.readVarint(); + start = br.offset; + br.seek(len); + + while (br.left()) { + bit = pos % 8; + oct = (pos - bit) / 8; + oct += start; + + // Read a single bit out of the spent field. + spent = data[oct] >>> (7 - bit); + spent &= 1; + + // We found our coin. + if (pos === index) { + if (spent) + return; + decompress.script(coin.script, br); + coin.value = br.readVarint(); + return coin; + } + + // Already spent. + if (spent) { + pos++; + continue; + } + + // Skip past the compressed coin. + skipCoin(br); + pos++; + } +}; + +/** + * Instantiate coins from a serialized Buffer. + * @param {Buffer} data + * @param {Hash} hash - Transaction hash. + * @returns {Coins} + */ + +Coins.fromRaw = function fromRaw(data, hash) { + return new Coins().fromRaw(data, hash); +}; + +/** + * Inject properties from tx. + * @private + * @param {TX} tx + */ + +Coins.prototype.fromTX = function fromTX(tx) { + var i, output; + + this.version = tx.version; + this.hash = tx.hash('hex'); + this.height = tx.height; + this.coinbase = tx.isCoinbase(); + + for (i = 0; i < tx.outputs.length; i++) { + output = tx.outputs[i]; + + if (output.script.isUnspendable()) { + this.outputs.push(null); + continue; + } + + this.outputs.push(CoinEntry.fromTX(tx, i)); + } + + return this; +}; + +/** + * Instantiate a coins object from a transaction. + * @param {TX} tx + * @returns {Coins} + */ + +Coins.fromTX = function fromTX(tx) { + return new Coins().fromTX(tx); +}; + +/** + * A compressed coin is an object which defers + * parsing of a coin. Say there is a transaction + * with 100 outputs. When a block comes in, + * there may only be _one_ input in that entire + * block which redeems an output from that + * transaction. When parsing the Coins, there + * is no sense to get _all_ of them into their + * abstract form. A compressed coin is just a + * pointer to that coin in the Coins buffer, as + * well as a size. Parsing is done only if that + * coin is being redeemed. + * @constructor + * @private + * @param {Number} offset + * @param {Number} size + * @param {Buffer} raw + */ + +function CoinEntry() { + this.offset = 0; + this.size = 0; + this.raw = null; + this.output = null; +} + +/** + * Parse the deferred data and return a Coin. + * @param {Coins} coins + * @param {Number} index + * @returns {Coin} + */ + +CoinEntry.prototype.toCoin = function toCoin(coins, index) { + var coin = new Coin(); + var br; + + // Load in all necessary properties + // from the parent Coins object. + coin.version = coins.version; + coin.coinbase = coins.coinbase; + coin.height = coins.height; + coin.hash = coins.hash; + coin.index = index; + + if (this.output) { + coin.script = this.output.script; + coin.value = this.output.value; + return coin; + } + + br = new BufferReader(this.raw); + + // Seek to the coin's offset. + br.seek(this.offset); + + decompress.script(coin.script, br); + + coin.value = br.readVarint(); + + return coin; +}; + +/** + * Slice off the part of the buffer + * relevant to this particular coin. + */ + +CoinEntry.prototype.toWriter = function toWriter(bw) { + var raw; + + if (this.output) { + compress.script(this.output.script, bw); + bw.writeVarint(this.output.value); + return; + } + + assert(this.raw); + + // If we read this coin from the db and + // didn't use it, it's still in its + // compressed form. Just write it back + // as a buffer for speed. + raw = this.raw.slice(this.offset, this.offset + this.size); + + bw.writeBytes(raw); +}; + +/** + * Instantiate compressed coin from reader. + * @param {BufferReader} br + * @returns {CoinEntry} + */ + +CoinEntry.fromReader = function fromReader(br) { + var entry = new CoinEntry(); + entry.offset = br.offset; + entry.size = skipCoin(br); + entry.raw = br.data; + return entry; +}; + +/** + * Instantiate compressed coin from tx. + * @param {TX} tx + * @param {Number} index + * @returns {CoinEntry} + */ + +CoinEntry.fromTX = function fromTX(tx, index) { + var entry = new CoinEntry(); + entry.output = tx.outputs[index]; + return entry; +}; + +/** + * Instantiate compressed coin from coin. + * @param {Coin} coin + * @returns {CoinEntry} + */ + +CoinEntry.fromCoin = function fromCoin(coin) { + var entry = new CoinEntry(); + entry.output = new Output(); + entry.output.script = coin.script; + entry.output.value = coin.value; + return entry; +}; + +/* + * Helpers + */ + +function skipCoin(br) { + var start = br.offset; + + // Skip past the compressed scripts. + switch (br.readU8()) { + case 0: + br.seek(br.readVarint()); + break; + case 1: + case 2: + br.seek(20); + break; + case 3: + br.seek(33); + break; + default: + throw new Error('Bad prefix.'); + } + + // Skip past the value. + br.skipVarint(); + + return br.offset - start; +} + +/* + * Expose + */ + +module.exports = Coins; diff --git a/lib/blockchain/coins.js b/lib/blockchain/coins.js index b1e34d2b..2d1f66ff 100644 --- a/lib/blockchain/coins.js +++ b/lib/blockchain/coins.js @@ -162,44 +162,6 @@ Coins.prototype.spend = function spend(index) { return coin; }; -/** - * Get a coin. - * @param {Number} index - * @returns {Coin} - */ - -Coins.prototype.get2 = function get2(index) { - var coin; - - if (index >= this.outputs.length) - return; - - coin = this.outputs[index]; - - if (!coin) - return; - - return coin.toCoin2(this, index); -}; - -/** - * Remove a coin and return it. - * @param {Number} index - * @returns {Coin} - */ - -Coins.prototype.spend2 = function spend2(index) { - var coin = this.get2(index); - - if (!coin) - return; - - this.outputs[index] = null; - this.cleanup(); - - return coin; -}; - /** * Cleanup spent outputs. */ @@ -213,39 +175,21 @@ Coins.prototype.cleanup = function cleanup() { this.outputs.length = len; }; -/** - * Count up to the last available index. - * @returns {Number} - */ - -Coins.prototype.size = function size() { - var index = -1; - var i, output; - - for (i = this.outputs.length - 1; i >= 0; i--) { - output = this.outputs[i]; - if (output) { - index = i; - break; - } - } - - return index + 1; -}; - /* * Coins serialization: * version: varint - * bits: uint32 (31-bit height | 1-bit coinbase-flag) - * spent-field: varint size | bitfield (0=unspent, 1=spent) + * height: uint32 + * header-code: varint (31-bit fields | 1-bit coinbase-flag) + * spent-field: bitfield (0=spent, 1=unspent) * outputs (repeated): - * compressed-script: - * prefix: 0x00 = varint size | raw script - * 0x01 = 20 byte pubkey hash - * 0x02 = 20 byte script hash - * 0x03 = 33 byte compressed key - * data: script data, dictated by the prefix * value: varint + * compressed-script: + * prefix: + * 0x00 = 20 byte pubkey hash + * 0x01 = 20 byte script hash + * 0x02-0x05 = 32 byte ec-key x-value + * >=0x06 = varint-size + 6 | raw script + * data: script data, dictated by the prefix * * The compression below sacrifices some cpu in exchange * for reduced size, but in some cases the use of varints @@ -259,215 +203,10 @@ Coins.prototype.size = function size() { /** * Serialize the coins object. - * @param {TX|Coins} tx * @returns {Buffer} */ Coins.prototype.toRaw = function toRaw() { - var bw = new BufferWriter(); - var length = this.size(); - var len = Math.ceil(length / 8); - var i, output, bits, start, bit, oct, data; - - // Return nothing if we're fully spent. - if (length === 0) - return; - - // Varint version: hopefully we - // never run into `-1` versions. - bw.writeVarint(this.version); - - // Create the `bits` value: - // (height | coinbase-flag). - bits = this.height << 1; - - // Append the coinbase bit. - if (this.coinbase) - bits |= 1; - - if (bits < 0) - bits += 0x100000000; - - // Making this a varint would actually - // make 99% of coins bigger. Varints - // are really only useful up until - // 0x10000, but since we're also - // storing the coinbase flag on the - // lo bit, varints are useless (and - // actually harmful) after height - // 32767 (0x7fff). - bw.writeU32(bits); - - // Fill the spent field with zeroes to avoid - // allocating a buffer. We mark the spents - // after rendering the final buffer. - bw.writeVarint(len); - start = bw.written; - bw.fill(0, len); - - // Write the compressed outputs. - for (i = 0; i < length; i++) { - output = this.outputs[i]; - - if (!output) - continue; - - output.toWriter(bw); - } - - // Render the buffer with all - // zeroes in the spent field. - data = bw.render(); - - // Mark the spents in the spent field. - // This is essentially a NOP for new coins. - for (i = 0; i < length; i++) { - output = this.outputs[i]; - - if (output) - continue; - - bit = i % 8; - oct = (i - bit) / 8; - oct += start; - - data[oct] |= 1 << (7 - bit); - } - - return data; -}; - -/** - * Parse serialized coins. - * @param {Buffer} data - * @param {Hash} hash - * @returns {Object} A "naked" coins object. - */ - -Coins.prototype.fromRaw = function fromRaw(data, hash) { - var br = new BufferReader(data); - var pos = 0; - var bits, len, start, bit, oct, spent, coin; - - this.version = br.readVarint(); - - bits = br.readU32(); - - this.height = bits >>> 1; - this.hash = hash; - this.coinbase = (bits & 1) !== 0; - - // Mark the start of the spent field and - // seek past it to avoid reading a buffer. - len = br.readVarint(); - start = br.offset; - br.seek(len); - - while (br.left()) { - bit = pos % 8; - oct = (pos - bit) / 8; - oct += start; - - // Read a single bit out of the spent field. - spent = data[oct] >>> (7 - bit); - spent &= 1; - - // Already spent. - if (spent) { - this.outputs.push(null); - pos++; - continue; - } - - // Store the offset and size - // in the compressed coin object. - coin = CoinEntry.fromReader(br); - - this.outputs.push(coin); - pos++; - } - - return this; -}; - -/** - * Parse a single serialized coin. - * @param {Buffer} data - * @param {Hash} hash - * @param {Number} index - * @returns {Coin} - */ - -Coins.parseCoin = function parseCoin(data, hash, index) { - var br = new BufferReader(data); - var coin = new Coin(); - var pos = 0; - var bits, len, start, bit, oct, spent; - - coin.version = br.readVarint(); - - bits = br.readU32(); - - coin.hash = hash; - coin.index = index; - coin.height = bits >>> 1; - coin.hash = hash; - coin.coinbase = (bits & 1) !== 0; - - // Mark the start of the spent field and - // seek past it to avoid reading a buffer. - len = br.readVarint(); - start = br.offset; - br.seek(len); - - while (br.left()) { - bit = pos % 8; - oct = (pos - bit) / 8; - oct += start; - - // Read a single bit out of the spent field. - spent = data[oct] >>> (7 - bit); - spent &= 1; - - // We found our coin. - if (pos === index) { - if (spent) - return; - decompress.script(coin.script, br); - coin.value = br.readVarint(); - return coin; - } - - // Already spent. - if (spent) { - pos++; - continue; - } - - // Skip past the compressed coin. - decompress.skip(br); - pos++; - } -}; - -/** - * Instantiate coins from a serialized Buffer. - * @param {Buffer} data - * @param {Hash} hash - Transaction hash. - * @returns {Coins} - */ - -Coins.fromRaw = function fromRaw(data, hash) { - return new Coins().fromRaw(data, hash); -}; - -/** - * Serialize the coins object. - * @param {TX|Coins} tx - * @returns {Buffer} - */ - -Coins.prototype.toRaw2 = function toRaw2() { var bw = new BufferWriter(); var len = this.outputs.length; var first = len > 0 && this.outputs[0]; @@ -530,20 +269,21 @@ Coins.prototype.toRaw2 = function toRaw2() { if (!output) continue; - output.toWriter2(bw); + output.toWriter(bw); } return bw.render(); }; /** - * Parse serialized coins. + * Inject data from serialized coins. + * @private * @param {Buffer} data * @param {Hash} hash - * @returns {Object} A "naked" coins object. + * @returns {Coins} */ -Coins.prototype.fromRaw2 = function fromRaw2(data, hash) { +Coins.prototype.fromRaw = function fromRaw(data, hash) { var br = new BufferReader(data); var i, code, field, nonzero, ch, unspent, coin; @@ -587,7 +327,7 @@ Coins.prototype.fromRaw2 = function fromRaw2(data, hash) { // Store the offset and size // in the compressed coin object. - coin = CoinEntry.fromReader2(br); + coin = CoinEntry.fromReader(br); this.outputs.push(coin); } @@ -605,7 +345,7 @@ Coins.prototype.fromRaw2 = function fromRaw2(data, hash) { * @returns {Coin} */ -Coins.parseCoin2 = function parseCoin2(data, hash, index) { +Coins.parseCoin = function parseCoin(data, hash, index) { var br = new BufferReader(data); var coin = new Coin(); var i, code, field, nonzero, ch, unspent; @@ -657,7 +397,7 @@ Coins.parseCoin2 = function parseCoin2(data, hash, index) { return; // Read compressed output. - decompress.output2(coin, br); + decompress.output(coin, br); break; } @@ -665,7 +405,7 @@ Coins.parseCoin2 = function parseCoin2(data, hash, index) { if (!field[i]) continue; - decompress.skip2(br); + decompress.skip(br); } return coin; @@ -678,8 +418,8 @@ Coins.parseCoin2 = function parseCoin2(data, hash, index) { * @returns {Coins} */ -Coins.fromRaw2 = function fromRaw2(data, hash) { - return new Coins().fromRaw2(data, hash); +Coins.fromRaw = function fromRaw(data, hash) { + return new Coins().fromRaw(data, hash); }; /** @@ -783,41 +523,6 @@ CoinEntry.prototype.toCoin = function toCoin(coins, index) { return coin; }; -/** - * Parse the deferred data and return a Coin. - * @param {Coins} coins - * @param {Number} index - * @returns {Coin} - */ - -CoinEntry.prototype.toCoin2 = function toCoin2(coins, index) { - var coin = new Coin(); - var br; - - // Load in all necessary properties - // from the parent Coins object. - coin.version = coins.version; - coin.coinbase = coins.coinbase; - coin.height = coins.height; - coin.hash = coins.hash; - coin.index = index; - - if (this.output) { - coin.script = this.output.script; - coin.value = this.output.value; - return coin; - } - - br = new BufferReader(this.raw); - - // Seek to the coin's offset. - br.seek(this.offset); - - decompress.output2(coin, br); - - return coin; -}; - /** * Slice off the part of the buffer * relevant to this particular coin. @@ -842,30 +547,6 @@ CoinEntry.prototype.toWriter = function toWriter(bw) { bw.writeBytes(raw); }; -/** - * Slice off the part of the buffer - * relevant to this particular coin. - */ - -CoinEntry.prototype.toWriter2 = function toWriter2(bw) { - var raw; - - if (this.output) { - compress.output2(this.output, bw); - return; - } - - assert(this.raw); - - // If we read this coin from the db and - // didn't use it, it's still in its - // compressed form. Just write it back - // as a buffer for speed. - raw = this.raw.slice(this.offset, this.offset + this.size); - - bw.writeBytes(raw); -}; - /** * Instantiate compressed coin from reader. * @param {BufferReader} br @@ -880,20 +561,6 @@ CoinEntry.fromReader = function fromReader(br) { return entry; }; -/** - * Instantiate compressed coin from reader. - * @param {BufferReader} br - * @returns {CoinEntry} - */ - -CoinEntry.fromReader2 = function fromReader2(br) { - var entry = new CoinEntry(); - entry.offset = br.offset; - entry.size = decompress.skip2(br); - entry.raw = br.data; - return entry; -}; - /** * Instantiate compressed coin from tx. * @param {TX} tx diff --git a/lib/blockchain/coinview-old.js b/lib/blockchain/coinview-old.js new file mode 100644 index 00000000..5e0961a6 --- /dev/null +++ b/lib/blockchain/coinview-old.js @@ -0,0 +1,147 @@ +/*! + * coinview.js - coinview object for bcoin + * Copyright (c) 2014-2016, Christopher Jeffrey (MIT License). + * https://github.com/bcoin-org/bcoin + */ + +'use strict'; + +var assert = require('assert'); +var Coins = require('./coins-old'); + +/** + * A collections of {@link Coins} objects. + * @exports CoinView + * @constructor + * @param {Object} coins - A hash-to-coins map. + * @property {Object} coins + */ + +function CoinView(coins) { + if (!(this instanceof CoinView)) + return new CoinView(coins); + + this.coins = coins || {}; +} + +/** + * Add coins to the collection. + * @param {Coins} coins + */ + +CoinView.prototype.add = function add(coins) { + this.coins[coins.hash] = coins; +}; + +/** + * Add a coin to the collection. + * @param {Coin} coin + */ + +CoinView.prototype.addCoin = function addCoin(coin) { + assert(typeof coin.hash === 'string'); + if (!this.coins[coin.hash]) + this.coins[coin.hash] = new Coins(); + this.coins[coin.hash].add(coin); +}; + +/** + * Add a tx to the collection. + * @param {TX} tx + */ + +CoinView.prototype.addTX = function addTX(tx) { + this.add(Coins.fromTX(tx)); +}; + +/** + * Get a coin. + * @param {Hash} hash + * @param {Number} index + * @returns {Coin} + */ + +CoinView.prototype.get = function get(hash, index) { + var coins = this.coins[hash]; + + if (!coins) + return; + + return coins.get(index); +}; + +/** + * Test whether the collection has a coin. + * @param {Hash} hash + * @param {Number} index + * @returns {Boolean} + */ + +CoinView.prototype.has = function has(hash, index) { + var coins = this.coins[hash]; + + if (!coins) + return false; + + return coins.has(index); +}; + +/** + * Remove a coin and return it. + * @param {Hash} hash + * @param {Number} index + * @returns {Coin} + */ + +CoinView.prototype.spend = function spend(hash, index) { + var coins = this.coins[hash]; + + if (!coins) + return; + + return coins.spend(index); +}; + +/** + * Fill transaction(s) with coins. + * @param {TX} tx + * @returns {Boolean} True if all inputs were filled. + */ + +CoinView.prototype.fillCoins = function fillCoins(tx) { + var i, input, prevout; + + for (i = 0; i < tx.inputs.length; i++) { + input = tx.inputs[i]; + prevout = input.prevout; + input.coin = this.spend(prevout.hash, prevout.index); + if (!input.coin) + return false; + } + + return true; +}; + +/** + * Convert collection to an array. + * @returns {Coins[]} + */ + +CoinView.prototype.toArray = function toArray() { + var keys = Object.keys(this.coins); + var out = []; + var i, hash; + + for (i = 0; i < keys.length; i++) { + hash = keys[i]; + out.push(this.coins[hash]); + } + + return out; +}; + +/* + * Expose + */ + +module.exports = CoinView; diff --git a/lib/blockchain/coinview.js b/lib/blockchain/coinview.js index aa9ecd23..a7cb371f 100644 --- a/lib/blockchain/coinview.js +++ b/lib/blockchain/coinview.js @@ -70,22 +70,6 @@ CoinView.prototype.get = function get(hash, index) { return coins.get(index); }; -/** - * Get a coin. - * @param {Hash} hash - * @param {Number} index - * @returns {Coin} - */ - -CoinView.prototype.get2 = function get2(hash, index) { - var coins = this.coins[hash]; - - if (!coins) - return; - - return coins.get2(index); -}; - /** * Test whether the collection has a coin. * @param {Hash} hash @@ -118,22 +102,6 @@ CoinView.prototype.spend = function spend(hash, index) { return coins.spend(index); }; -/** - * Remove a coin and return it. - * @param {Hash} hash - * @param {Number} index - * @returns {Coin} - */ - -CoinView.prototype.spend2 = function spend2(hash, index) { - var coins = this.coins[hash]; - - if (!coins) - return; - - return coins.spend2(index); -}; - /** * Fill transaction(s) with coins. * @param {TX} tx @@ -154,26 +122,6 @@ CoinView.prototype.fillCoins = function fillCoins(tx) { return true; }; -/** - * Fill transaction(s) with coins. - * @param {TX} tx - * @returns {Boolean} True if all inputs were filled. - */ - -CoinView.prototype.fillCoins2 = function fillCoins2(tx) { - var i, input, prevout; - - for (i = 0; i < tx.inputs.length; i++) { - input = tx.inputs[i]; - prevout = input.prevout; - input.coin = this.spend2(prevout.hash, prevout.index); - if (!input.coin) - return false; - } - - return true; -}; - /** * Convert collection to an array. * @returns {Coins[]} diff --git a/lib/blockchain/compress-old.js b/lib/blockchain/compress-old.js new file mode 100644 index 00000000..32ff8756 --- /dev/null +++ b/lib/blockchain/compress-old.js @@ -0,0 +1,253 @@ +/*! + * compress.js - coin compressor for bcoin + * Copyright (c) 2014-2016, Christopher Jeffrey (MIT License). + * https://github.com/bcoin-org/bcoin + */ + +'use strict'; + +var assert = require('assert'); +var ec = require('../crypto/ec'); + +/* + * Compression + */ + +/** + * Compress a script, write directly to the buffer. + * @param {Script} script + * @param {BufferWriter} bw + */ + +function compressScript(script, bw) { + var data; + + // Attempt to compress the output scripts. + // We can _only_ ever compress them if + // they are serialized as minimaldata, as + // we need to recreate them when we read + // them. + + // P2PKH -> 1 | key-hash + // Saves 5 bytes. + if (script.isPubkeyhash(true)) { + data = script.code[2].data; + bw.writeU8(1); + bw.writeBytes(data); + return bw; + } + + // P2SH -> 2 | script-hash + // Saves 3 bytes. + if (script.isScripthash()) { + data = script.code[1].data; + bw.writeU8(2); + bw.writeBytes(data); + return bw; + } + + // P2PK -> 3 | compressed-key + // Only works if the key is valid. + // Saves up to 34 bytes. + if (script.isPubkey(true)) { + data = script.code[0].data; + if (ec.publicKeyVerify(data)) { + data = compressKey(data); + bw.writeU8(3); + bw.writeBytes(data); + return bw; + } + } + + // Raw -> 0 | varlen | script + bw.writeU8(0); + bw.writeVarBytes(script.toRaw()); + + return bw; +} + +/** + * Decompress a script from buffer reader. + * @param {Script} script + * @param {BufferReader} br + */ + +function decompressScript(script, br) { + var data; + + // Decompress the script. + switch (br.readU8()) { + case 0: + data = br.readVarBytes(); + script.fromRaw(data); + break; + case 1: + data = br.readBytes(20, true); + script.fromPubkeyhash(data); + break; + case 2: + data = br.readBytes(20, true); + script.fromScripthash(data); + break; + case 3: + data = br.readBytes(33, true); + // Decompress the key. If this fails, + // we have database corruption! + data = decompressKey(data); + script.fromPubkey(data); + break; + default: + throw new Error('Bad prefix.'); + } + + return script; +} + +/** + * Compress value using an exponent. Takes advantage of + * the fact that many bitcoin values are divisible by 10. + * @see https://github.com/btcsuite/btcd/blob/master/blockblockchain/compress.go + * @param {Amount} value + * @returns {Number} + */ + +function compressValue(value) { + var exp, last; + + if (value === 0) + return 0; + + exp = 0; + while (value % 10 === 0 && exp < 9) { + value /= 10; + exp++; + } + + if (exp < 9) { + last = value % 10; + value = (value - last) / 10; + return 1 + 10 * (9 * value + last - 1) + exp; + } + + return 10 + 10 * (value - 1); +} + +/** + * Decompress value. + * @param {Number} value - Compressed value. + * @returns {Amount} value + */ + +function decompressValue(value) { + var exp, n, last; + + if (value === 0) + return 0; + + value--; + + exp = value % 10; + value = (value - exp) / 10; + + if (exp < 9) { + last = value % 9; + value = (value - last) / 9; + n = value * 10 + last + 1; + } else { + n = value + 1; + } + + while (exp > 0) { + n *= 10; + exp--; + } + + return n; +} + +/** + * Compress a public key to coins compression format. + * @param {Buffer} key + * @returns {Buffer} + */ + +function compressKey(key) { + var out; + + switch (key[0]) { + case 0x02: + case 0x03: + // Key is already compressed. + out = key; + break; + case 0x04: + case 0x06: + case 0x07: + // Compress the key normally. + out = ec.publicKeyConvert(key, true); + // Store the original format (which + // may be a hybrid byte) in the hi + // 3 bits so we can restore it later. + // The hi bits being set also lets us + // know that this key was originally + // decompressed. + out[0] |= key[0] << 2; + break; + default: + throw new Error('Bad point format.'); + } + + assert(out.length === 33); + + return out; +} + +/** + * Decompress a public key from the coins compression format. + * @param {Buffer} key + * @returns {Buffer} + */ + +function decompressKey(key) { + var format = key[0] >>> 2; + var out; + + assert(key.length === 33); + + // Hi bits are not set. This key + // is not meant to be decompressed. + if (format === 0) + return key; + + // Decompress the key, and off the + // low bits so publicKeyConvert + // actually understands it. + key[0] &= 0x03; + out = ec.publicKeyConvert(key, false); + + // Reset the hi bits so as not to + // mutate the original buffer. + key[0] |= format << 2; + + // Set the original format, which + // may have been a hybrid prefix byte. + out[0] = format; + + return out; +} + +/* + * Expose + */ + +exports.compress = { + script: compressScript, + value: compressValue, + key: compressKey +}; + +exports.decompress = { + script: decompressScript, + value: decompressValue, + key: decompressKey +}; diff --git a/lib/blockchain/compress.js b/lib/blockchain/compress.js index 95dc1970..4a1203ff 100644 --- a/lib/blockchain/compress.js +++ b/lib/blockchain/compress.js @@ -10,9 +10,11 @@ var assert = require('assert'); var ec = require('../crypto/ec'); /* - * Compression + * Constants */ +var COMPRESS_TYPES = 6; + /** * Compress a script, write directly to the buffer. * @param {Script} script @@ -28,96 +30,6 @@ function compressScript(script, bw) { // we need to recreate them when we read // them. - // P2PKH -> 1 | key-hash - // Saves 5 bytes. - if (script.isPubkeyhash(true)) { - data = script.code[2].data; - bw.writeU8(1); - bw.writeBytes(data); - return bw; - } - - // P2SH -> 2 | script-hash - // Saves 3 bytes. - if (script.isScripthash()) { - data = script.code[1].data; - bw.writeU8(2); - bw.writeBytes(data); - return bw; - } - - // P2PK -> 3 | compressed-key - // Only works if the key is valid. - // Saves up to 34 bytes. - if (script.isPubkey(true)) { - data = script.code[0].data; - if (ec.publicKeyVerify(data)) { - data = compressKey(data); - bw.writeU8(3); - bw.writeBytes(data); - return bw; - } - } - - // Raw -> 0 | varlen | script - bw.writeU8(0); - bw.writeVarBytes(script.toRaw()); - - return bw; -} - -/** - * Decompress a script from buffer reader. - * @param {Script} script - * @param {BufferReader} br - */ - -function decompressScript(script, br) { - var data; - - // Decompress the script. - switch (br.readU8()) { - case 0: - data = br.readVarBytes(); - script.fromRaw(data); - break; - case 1: - data = br.readBytes(20, true); - script.fromPubkeyhash(data); - break; - case 2: - data = br.readBytes(20, true); - script.fromScripthash(data); - break; - case 3: - data = br.readBytes(33, true); - // Decompress the key. If this fails, - // we have database corruption! - data = decompressKey(data); - script.fromPubkey(data); - break; - default: - throw new Error('Bad prefix.'); - } - - return script; -} - -/** - * Compress a script, write directly to the buffer. - * @param {Script} script - * @param {BufferWriter} bw - */ - -function compressScript2(script, bw) { - var data; - - // Attempt to compress the output scripts. - // We can _only_ ever compress them if - // they are serialized as minimaldata, as - // we need to recreate them when we read - // them. - // P2PKH -> 0 | key-hash // Saves 5 bytes. if (script.isPubkeyhash(true)) { @@ -142,14 +54,14 @@ function compressScript2(script, bw) { if (script.isPubkey(true)) { data = script.code[0].data; if (publicKeyVerify(data)) { - data = compressKey2(data); + data = compressKey(data); bw.writeBytes(data); return bw; } } // Raw -> varlen + 6 | script - bw.writeVarint(script.raw.length + 6); + bw.writeVarint(script.raw.length + COMPRESS_TYPES); bw.writeBytes(script.raw); return bw; @@ -161,7 +73,7 @@ function compressScript2(script, bw) { * @param {BufferReader} br */ -function decompressScript2(script, br) { +function decompressScript(script, br) { var size, data; // Decompress the script. @@ -182,16 +94,16 @@ function decompressScript2(script, br) { data = br.readBytes(33, true); // Decompress the key. If this fails, // we have database corruption! - data = decompressKey2(data); + data = decompressKey(data); script.fromPubkey(data); break; default: br.offset -= 1; - size = br.readVarint() - 6; + size = br.readVarint() - COMPRESS_TYPES; if (size > 10000) { // This violates consensus rules. // We don't need to read it. - script.fromUnspendable(); + script.fromNulldata(new Buffer(0)); p.seek(size); } else { data = br.readBytes(size); @@ -210,8 +122,8 @@ function decompressScript2(script, br) { */ function compressOutput(output, bw) { - compressScript(output.script, bw); bw.writeVarint(output.value); + compressScript(output.script, bw); return bw; } @@ -222,8 +134,8 @@ function compressOutput(output, bw) { */ function decompressOutput(output, br) { - decompressScript(output.script, br); output.value = br.readVarint(); + decompressScript(output.script, br); return output; } @@ -236,61 +148,9 @@ function decompressOutput(output, br) { function skipOutput(br) { var start = br.offset; - // Skip past the compressed scripts. - switch (br.readU8()) { - case 0: - br.seek(br.readVarint()); - break; - case 1: - case 2: - br.seek(20); - break; - case 3: - br.seek(33); - break; - default: - throw new Error('Bad prefix.'); - } - // Skip past the value. br.skipVarint(); - return br.offset - start; -} - -/** - * Compress an output. - * @param {Output|Coin} output - * @param {BufferWriter} bw - */ - -function compressOutput2(output, bw) { - compressScript2(output.script, bw); - bw.writeVarint(output.value); - return bw; -} - -/** - * Decompress a script from buffer reader. - * @param {Output|Coin} output - * @param {BufferReader} br - */ - -function decompressOutput2(output, br) { - decompressScript2(output.script, br); - output.value = br.readVarint(); - return output; -} - -/** - * Skip past a compressed output. - * @param {BufferWriter} bw - * @returns {Number} - */ - -function skipOutput2(br) { - var start = br.offset; - // Skip past the compressed scripts. switch (br.readU8()) { case 0: @@ -305,13 +165,10 @@ function skipOutput2(br) { break; default: br.offset -= 1; - br.seek(br.readVarint() - 6); + br.seek(br.readVarint() - COMPRESS_TYPES); break; } - // Skip past the value. - br.skipVarint(); - return br.offset - start; } @@ -377,77 +234,6 @@ function decompressValue(value) { return n; } -/** - * Compress a public key to coins compression format. - * @param {Buffer} key - * @returns {Buffer} - */ - -function compressKey(key) { - var out; - - switch (key[0]) { - case 0x02: - case 0x03: - // Key is already compressed. - out = key; - break; - case 0x04: - case 0x06: - case 0x07: - // Compress the key normally. - out = ec.publicKeyConvert(key, true); - // Store the original format (which - // may be a hybrid byte) in the hi - // 3 bits so we can restore it later. - // The hi bits being set also lets us - // know that this key was originally - // decompressed. - out[0] |= key[0] << 2; - break; - default: - throw new Error('Bad point format.'); - } - - assert(out.length === 33); - - return out; -} - -/** - * Decompress a public key from the coins compression format. - * @param {Buffer} key - * @returns {Buffer} - */ - -function decompressKey(key) { - var format = key[0] >>> 2; - var out; - - assert(key.length === 33); - - // Hi bits are not set. This key - // is not meant to be decompressed. - if (format === 0) - return key; - - // Decompress the key, and off the - // low bits so publicKeyConvert - // actually understands it. - key[0] &= 0x03; - out = ec.publicKeyConvert(key, false); - - // Reset the hi bits so as not to - // mutate the original buffer. - key[0] |= format << 2; - - // Set the original format, which - // may have been a hybrid prefix byte. - out[0] = format; - - return out; -} - /** * Verify a public key (no hybrid keys allowed). * @param {Buffer} key @@ -478,7 +264,7 @@ function publicKeyVerify(key) { * @returns {Buffer} */ -function compressKey2(key) { +function compressKey(key) { var out; switch (key[0]) { @@ -491,6 +277,7 @@ function compressKey2(key) { // Compress the key normally. out = ec.publicKeyConvert(key, true); // Store the oddness. + // Pseudo-hybrid format. out[0] = 0x04 | (key[64] & 0x01); break; default: @@ -508,7 +295,7 @@ function compressKey2(key) { * @returns {Buffer} */ -function decompressKey2(key) { +function decompressKey(key) { var format = key[0]; var out; @@ -528,9 +315,7 @@ function decompressKey2(key) { throw new Error('Bad point format.'); } - // Decompress the key, and off the - // low bits so publicKeyConvert - // actually understands it. + // Decompress the key. out = ec.publicKeyConvert(key, false); // Reset the first byte so as not to @@ -546,22 +331,15 @@ function decompressKey2(key) { exports.compress = { output: compressOutput, - output2: compressOutput2, script: compressScript, - script2: compressScript2, value: compressValue, - key: compressKey, - key2: compressKey2 + key: compressKey }; exports.decompress = { output: decompressOutput, - output2: decompressOutput2, skip: skipOutput, - skip2: skipOutput2, script: decompressScript, - script2: decompressScript2, value: decompressValue, - key: decompressKey, - key2: decompressKey + key: decompressKey }; diff --git a/lib/primitives/coin.js b/lib/primitives/coin.js index a561e5ac..d4d67bd1 100644 --- a/lib/primitives/coin.js +++ b/lib/primitives/coin.js @@ -17,9 +17,6 @@ var Script = require('../script/script'); var Network = require('../protocol/network'); var BufferWriter = require('../utils/writer'); var BufferReader = require('../utils/reader'); -var compressor = require('../blockchain/compress'); -var compress = compressor.compress; -var decompress = compressor.decompress; /** * Represents an unspent output. @@ -255,75 +252,6 @@ Coin.fromRaw = function fromRaw(data, enc) { return new Coin().fromRaw(data); }; -/** - * Serialize the coin to its compressed form. - * @param {String?} enc - Encoding, can be `'hex'` or null. - * @returns {Buffer|String} - */ - -Coin.prototype.toCompressed = function toCompressed(writer) { - var bw = BufferWriter(writer); - var height = this.height; - var bits; - - if (height === -1) - height = 0x7fffffff; - - bits = height << 1; - - if (this.coinbase) - bits |= 1; - - if (bits < 0) - bits += 0x100000000; - - bw.writeVarint(this.version); - bw.writeU32(bits); - bw.writeVarint(this.value); - compress.script(this.script, bw); - - if (!writer) - bw = bw.render(); - - return bw; -}; - -/** - * Inject properties from compressed serialized data. - * @private - * @param {Buffer} data - */ - -Coin.prototype.fromCompressed = function fromCompressed(data) { - var br = BufferReader(data); - var bits; - - this.version = br.readVarint(); - bits = br.readU32(); - this.height = bits >>> 1; - this.coinbase = (bits & 1) !== 0; - this.value = br.readVarint(); - decompress.script(this.script, br); - - if (this.height === 0x7fffffff) - this.height = -1; - - return this; -}; - -/** - * Instantiate an coin from a serialized Buffer. - * @param {Buffer} data - * @param {String?} enc - Encoding, can be `'hex'` or null. - * @returns {Coin} - */ - -Coin.fromCompressed = function fromCompressed(data, enc) { - if (typeof data === 'string') - data = new Buffer(data, enc); - return new Coin().fromCompressed(data); -}; - /** * Inject properties from TX. * @param {TX} tx diff --git a/lib/script/script.js b/lib/script/script.js index 4d785bcc..1d37ac39 100644 --- a/lib/script/script.js +++ b/lib/script/script.js @@ -1500,28 +1500,6 @@ Script.isCode = function isCode(raw) { return true; }; -/** - * Inject properties from a unspendable script. - * @private - * @param {Buffer} key - */ - -Script.prototype.fromUnspendable = function fromUnspendable() { - this.raw = new Buffer(1); - this.raw[0] = opcodes.OP_RETURN; - this.code.push(new Opcode(opcodes.OP_RETURN)); - return this; -}; - -/** - * Create an unspendable script. - * @returns {Script} - */ - -Script.fromUnspendable = function fromUnspendable() { - return new Script().fromUnspendable(); -}; - /** * Inject properties from a pay-to-pubkey script. * @private