diff --git a/lib/bcoin/coin.js b/lib/bcoin/coin.js index d51a66fb..abb15466 100644 --- a/lib/bcoin/coin.js +++ b/lib/bcoin/coin.js @@ -176,6 +176,28 @@ Coin.fromRaw = function fromRaw(data, enc) { return new Coin(Coin._fromRaw(data, enc)); }; +Coin.prototype.toUTXO = function toUTXO(enc) { + var data = bcoin.protocol.framer.utxo(this); + + if (enc === 'hex') + data = utils.toHex(data); + + return data; +}; + +Coin._fromUTXO = function _fromUTXO(data, enc) { + if (enc === 'hex') + data = new Buffer(data, 'hex'); + + data = bcoin.protocol.parser.parseUTXO(data); + + return data; +}; + +Coin.fromUTXO = function fromUTXO(data, enc) { + return new Coin(Coin._fromUTXO(data, enc)); +}; + Coin.prototype.toExtended = function toExtended(enc) { var data = bcoin.protocol.framer.coin(this, true); diff --git a/lib/bcoin/ldb.js b/lib/bcoin/ldb.js index 3b2c5a3c..1ed24877 100644 --- a/lib/bcoin/ldb.js +++ b/lib/bcoin/ldb.js @@ -17,30 +17,27 @@ module.exports = function ldb(name, options) { : process.env.BCOIN_DB; if (!db[file]) { - if (options.db && typeof options.db !== 'string') { - bcoin.ensurePrefix(); - backend = options.db; - } else if (bcoin.isBrowser && backend !== 'memdown') { + if (!options) + options = {}; + + if (!backend || backend === 'leveldb') + backend = 'leveldown'; + else if (backend === 'rocksdb') + backend = 'rocksdown'; + else if (backend === 'lmdb') + backend = 'lmdb'; + else if (backend === 'memory') + backend = 'memdown'; + + if (bcoin.isBrowser && backend !== 'memdown') { backend = require('level-js'); } else { - if (!backend || backend === 'leveldb') - backend = 'leveldown'; - else if (backend === 'rocksdb') - backend = 'rocksdown'; - else if (backend === 'lmdb') - backend = 'lmdb'; - else if (backend === 'memory') - backend = 'memdown'; - if (backend !== 'memdown') bcoin.ensurePrefix(); backend = require(backend); } - if (!options) - options = {}; - db[file] = new LowlevelUp(file, { keyEncoding: 'ascii', valueEncoding: 'binary', @@ -100,12 +97,9 @@ function LowlevelUp(file, options) { this.db = this.db.db; this.binding = this.db; - this.hasBinding = false; - if (this.db.binding) { + if (this.db.binding) this.binding = this.db.binding; - this.hasBinding = true; - } this.binding.open(options, function(err) { if (err) @@ -161,8 +155,6 @@ LowlevelUp.prototype.batch = function batch(ops, options, callback) { }; LowlevelUp.prototype.iterator = function iterator(options) { - if (this.hasBinding) - return new Iterator(this.binding, options); return this.db.iterator(options); }; @@ -176,55 +168,3 @@ LowlevelUp.prototype.getProperty = function getProperty(name) { LowlevelUp.prototype.approximateSize = function approximateSize(start, end, callback) { return this.binding.approximateSize(start, end, callback); }; - -function Iterator(binding, options) { - this.binding = binding.iterator(options); - this.cache = null; - this.finished = false; -} - -Iterator.prototype.seek = function (key) { - if (typeof key !== 'string') - throw new Error('seek requires a string key'); - if (this.cache) - this.cache.length = 0; - this.cache = null; - this.binding.seek(key); -}; - -Iterator.prototype.next = function next(callback) { - var self = this; - var key, value; - - if (this.cache && this.cache.length) { - key = this.cache.pop(); - value = this.cache.pop(); - - utils.nextTick(function() { - callback(null, key, value); - }); - } else if (this.finished) { - utils.nextTick(function() { - callback(); - }); - } else { - this.binding.next(function(err, array, finished) { - if (err) - return callback(err); - - self.cache = array; - self.finished = finished; - self.next(callback); - }); - } - - return this; -}; - -Iterator.prototype.end = function end(callback) { - if (this.cache) - this.cache.length = 0; - delete this.cache; - this.binding.end(callback); - delete this.binding; -}; diff --git a/lib/bcoin/mempool.js b/lib/bcoin/mempool.js index 9227bf48..14977c5e 100644 --- a/lib/bcoin/mempool.js +++ b/lib/bcoin/mempool.js @@ -100,7 +100,7 @@ Mempool.prototype.open = function open(callback) { return this.db.open(callback); }; -Mempool.prototype.addBlock = function addBlock(block) { +Mempool.prototype.addBlock = function addBlock(block, callback) { var self = this; callback = utils.ensure(callback); // Remove now-mined transactions @@ -139,7 +139,7 @@ Mempool.prototype.getCoinsByAddress = function getCoinsByAddress(addresses, call }; Mempool.prototype.getByAddress = -Mempool.prototype.getTXByAddress = function getTXByAddress(addresses) { +Mempool.prototype.getTXByAddress = function getTXByAddress(addresses, callback) { return this.tx.getTXByAddress(addresses, callback); }; @@ -253,9 +253,8 @@ Mempool.prototype.addUnchecked = function addUnchecked(tx, peer, callback) { utils.forEachSerial(resolved, function(tx, next) { self.addUnchecked(tx, peer, function(err) { - if (err) { + if (err) self.emit('error', err); - } next(); }, true); }, callback); diff --git a/lib/bcoin/protocol/framer.js b/lib/bcoin/protocol/framer.js index 047e5e7f..26dc428c 100644 --- a/lib/bcoin/protocol/framer.js +++ b/lib/bcoin/protocol/framer.js @@ -106,8 +106,7 @@ Framer.prototype.getBlocks = function getBlocks(hashes, stop) { return this.packet('getblocks', Framer.getBlocks(hashes, stop)); }; -Framer.prototype.utxo = -Framer.prototype.coin = function _coin(coin) { +Framer.prototype.utxo = function _coin(coin) { return this.packet('utxo', Framer.coin(coin, false)); }; @@ -319,8 +318,7 @@ Framer._getBlocks = function _getBlocks(hashes, stop, writer) { return p; }; -Framer.utxo = -Framer.coin = function _coin(coin, extended, writer) { +Framer.utxo = function _utxo(coin, writer) { var p = new BufferWriter(writer); var height = coin.height; @@ -334,8 +332,28 @@ Framer.coin = function _coin(coin, extended, writer) { p.write64(coin.value); p.writeVarBytes(coin.script.encode()); + if (!writer) + p = p.render(); + + return p; +}; + +Framer.coin = function _coin(coin, extended, writer) { + var p = new BufferWriter(writer); + var height = coin.height; + + if (height === -1) + height = 0x7fffffff; + + assert(coin.value.byteLength() <= 8); + + p.writeU32(coin.version); + p.writeU32(height); + p.write64(coin.value); + p.writeVarBytes(coin.script.encode()); + p.writeU8(coin.coinbase ? 1 : 0); + if (extended) { - p.writeU8(coin.coinbase ? 1 : 0); p.writeHash(coin.hash); p.writeU32(coin.index); } diff --git a/lib/bcoin/protocol/parser.js b/lib/bcoin/protocol/parser.js index 96770f2c..ac2a1c90 100644 --- a/lib/bcoin/protocol/parser.js +++ b/lib/bcoin/protocol/parser.js @@ -436,6 +436,29 @@ Parser.parseOutput = function parseOutput(p) { }; }; +Parser.parseUTXO = function parseUTXO(p) { + var version, height, value, script, hash, index, coinbase; + + p = new BufferReader(p); + p.start(); + + version = p.readU32(); + height = p.readU32(); + value = p.read64(); + script = new bcoin.script(p.readVarBytes()); + + if (height === 0x7fffffff) + height = -1; + + return { + version: version, + height: height, + value: value, + script: script, + _size: p.end() + }; +}; + Parser.parseCoin = function parseCoin(p, extended) { var version, height, value, script, hash, index, coinbase; @@ -444,32 +467,26 @@ Parser.parseCoin = function parseCoin(p, extended) { version = p.readU32(); height = p.readU32(); + value = p.read64(); + script = new bcoin.script(p.readVarBytes()); + coinbase = p.readU8() === 1; + + if (extended) { + hash = p.readHash(); + index = p.readU32(); + } if (height === 0x7fffffff) height = -1; - value = p.read64(); - - script = new bcoin.script(p.readVarBytes()); - - if (extended) { - coinbase = p.readU8() === 1; - hash = p.readHash(); - index = p.readU32(); - } else { - coinbase = false; - hash = utils.slice(constants.zeroHash); - index = 0xffffffff; - } - return { version: version, height: height, value: value, script: script, + coinbase: coinbase, hash: hash, index: index, - coinbase: coinbase, _size: p.end() }; }; diff --git a/lib/bcoin/txdb.js b/lib/bcoin/txdb.js index e43371fa..b0d3b6a6 100644 --- a/lib/bcoin/txdb.js +++ b/lib/bcoin/txdb.js @@ -327,7 +327,7 @@ TXPool.prototype._add = function add(tx, map, callback, force) { utils.forEachSerial(tx.inputs, function(input, next, i) { var key; - if (input.isCoinbase()) + if (tx.isCoinbase()) return next(); key = input.prevout.hash + '/' + input.prevout.index; @@ -344,9 +344,6 @@ TXPool.prototype._add = function add(tx, map, callback, force) { // Add TX to inputs and spend money input.output = coin; - assert(input.prevout.hash === coin.hash); - assert(input.prevout.index === coin.index); - // Skip invalid transactions if (self.options.verify) { if (!tx.verify(i)) @@ -487,7 +484,7 @@ TXPool.prototype._add = function add(tx, map, callback, force) { }); } - batch.put(prefix + 'u/t/' + hash + '/' + i, coin.toExtended()); + batch.put(prefix + 'u/t/' + hash + '/' + i, coin.toRaw()); updated = true; } @@ -640,7 +637,7 @@ TXPool.prototype._confirm = function _confirm(tx, map, callback, force) { coin.height = tx.height; - batch.put(prefix + 'u/t/' + hash + '/' + i, coin.toExtended()); + batch.put(prefix + 'u/t/' + hash + '/' + i, coin.toRaw()); next(); }); @@ -768,7 +765,7 @@ TXPool.prototype._remove = function remove(tx, map, callback, force) { tx.inputs.forEach(function(input) { var address = input.getAddress(); - if (input.isCoinbase()) + if (tx.isCoinbase()) return; if (!input.output) @@ -791,7 +788,7 @@ TXPool.prototype._remove = function remove(tx, map, callback, force) { batch.put(prefix + 'u/t/' + input.prevout.hash + '/' + input.prevout.index, - input.output.toExtended()); + input.output.toRaw()); if (self.options.indexSpent) { batch.del(prefix + 's/t/' @@ -920,7 +917,7 @@ TXPool.prototype._unconfirm = function unconfirm(tx, map, callback, force) { coin.height = tx.height; - batch.put(prefix + 'u/t/' + hash + '/' + i, coin.toExtended()); + batch.put(prefix + 'u/t/' + hash + '/' + i, coin.toRaw()); next(); }); @@ -1494,7 +1491,7 @@ TXPool.prototype.getCoin = function getCoin(hash, index, callback) { return callback(); try { - coin = bcoin.coin.fromExtended(coin); + coin = bcoin.coin.fromRaw(coin); coin.hash = hash; coin.index = index; } catch (e) {