diff --git a/lib/bcoin/block.js b/lib/bcoin/block.js index aefa636c..86221361 100644 --- a/lib/bcoin/block.js +++ b/lib/bcoin/block.js @@ -384,6 +384,65 @@ Block.fromRaw = function fromRaw(data, enc, type) { return new Block(Block._fromRaw(data, enc)); }; +Block.prototype.toSmall = function toSmall() { + var block = this.abbr(); + var buf = new Buffer(block.length + 4 + this.txs.length * 32); + var height = this.height; + var off = 0; + + if (height === -1) + height = 0x7fffffff; + + off += utils.copy(block, buf, off); + off += utils.writeU32(buf, height, off); + + off += utils.writeIntv(buf, this.txs.length, off); + this.txs.forEach(function(tx) { + off += utils.copy(tx.hash(), buf, off); + }); + + return buf; +}; + +Block.fromSmall = function fromSmall(buf) { + var tx, txCount, i; + var off = 0; + var hashes = []; + + var version = utils.read32(buf, 0); + var prevBlock = buf.slice(4, 36); + var merkleRoot = buf.slice(36, 68); + var ts = utils.readU32(buf, 68); + var bits = utils.readU32(buf, 72); + var nonce = utils.readU32(buf, 76); + var height = utils.readU32(buf, 80); + var txCount = utils.readIntv(buf, 84); + off = txCount.off; + txCount = txCount.r; + + for (i = 0; i < txCount; i++) { + if (off + 32 > buf.length) + throw new Error('Bad TX count.'); + hashes.push(utils.toHex(buf.slice(off, off + 32))); + off += 32; + } + + if (height === 0x7fffffff) + height = -1; + + return { + version: version, + prevBlock: utils.toHex(prevBlock), + merkleRoot: utils.toHex(merkleRoot), + ts: ts, + bits: bits, + nonce: nonce, + height: height, + totalTX: txCount, + hashes: hashes + }; +}; + /** * Expose */ diff --git a/lib/bcoin/blockdb.js b/lib/bcoin/blockdb.js index 122e645c..7d0dce08 100644 --- a/lib/bcoin/blockdb.js +++ b/lib/bcoin/blockdb.js @@ -161,23 +161,11 @@ BlockDB.prototype.parseOffset = function parseOffset(data) { BlockDB.prototype.saveBlock = function saveBlock(block, callback) { var self = this; - this.data.saveAsync(block._raw, function(err, data) { - var batch, blockOffset; + var batch = self.index.batch(); - if (err) - return callback(err); + batch.put('b/b/' + block.hash('hex'), block.toSmall()); - batch = self.index.batch(); - - block._fileOffset = data.offset; - assert(block._size === data.size); - - blockOffset = self.createOffset(block._size, block._fileOffset, block.height); - - batch.put('b/b/' + block.hash('hex'), blockOffset); - - self.connectBlock(block, callback, batch, blockOffset); - }); + self.connectBlock(block, callback, batch); }; BlockDB.prototype.removeBlock = function removeBlock(hash, callback) { @@ -229,23 +217,14 @@ BlockDB.prototype.connectBlock = function connectBlock(block, callback, batch, b if (!batch) batch = self.index.batch(); - if (!blockOffset) - blockOffset = self.createOffset(block._size, block._fileOffset, block.height); - - batch.put('b/h/' + block.height, blockOffset); + batch.put('b/h/' + block.height, block.hash()); block.txs.forEach(function(tx, i) { var hash = tx.hash('hex'); var uniq = {}; var txOffset; - txOffset = self.createOffset( - tx._size, - block._fileOffset + tx._offset, - block.height - ); - - batch.put('t/t/' + hash, txOffset); + batch.put('t/t/' + hash, tx.toExtended()); tx.inputs.forEach(function(input) { var type = input.getType(); @@ -268,7 +247,7 @@ BlockDB.prototype.connectBlock = function connectBlock(block, callback, batch, b } if (uaddr) - batch.put('t/a/' + uaddr + '/' + hash, txOffset); + batch.put('t/a/' + uaddr + '/' + hash, new Buffer([])); if (address) { batch.del( @@ -300,19 +279,13 @@ BlockDB.prototype.connectBlock = function connectBlock(block, callback, batch, b uaddr = null; } - coinOffset = self.createOffset( - output._size, - block._fileOffset + tx._offset + output._offset, - block.height - ); - if (uaddr) - batch.put('t/a/' + uaddr + '/' + hash, txOffset); + batch.put('t/a/' + uaddr + '/' + hash, new Buffer([])); if (address) - batch.put('u/a/' + address + '/' + hash + '/' + i, coinOffset); + batch.put('u/a/' + address + '/' + hash + '/' + i, new Buffer([])); - batch.put('u/t/' + hash + '/' + i, coinOffset); + batch.put('u/t/' + hash + '/' + i, bcoin.coin(tx, i).toRaw()); }); }); @@ -516,7 +489,6 @@ BlockDB.prototype.fillTX = function fillTX(tx, callback) { if (tx) { input.output = bcoin.coin(tx, input.prevout.index); - input.output._fileOffset = tx._fileOffset + input.output._offset; } next(); @@ -633,6 +605,7 @@ BlockDB.prototype.getCoin = function getCoin(hash, index, callback) { return callback(err); } + return callback(null, bcoin.coin.fromRaw(record)); record = self.parseOffset(record); self.data.getAsync(record.size, record.offset, function(err, data) { @@ -790,6 +763,7 @@ BlockDB.prototype.getTX = function getTX(hash, callback) { return callback(err); } + return callback(null, bcoin.tx.fromExtended(record)); record = self.parseOffset(record); self.data.getAsync(record.size, record.offset, function(err, data) { @@ -931,47 +905,27 @@ BlockDB.prototype.getBlock = function getBlock(hash, callback) { return callback(err); } - record = self.parseOffset(record); + var block = bcoin.block.fromSmall(record); + block.txs = []; - self.data.getAsync(record.size, record.offset, function(err, data) { - var block; + utils.forEach(block.hashes, function(hash, next, i) { + self.getTX(hash, function(err, tx) { + if (err) + return next(err); + if (!tx) + return next(new Error('TX not found.')); + + block.txs[i] = tx; + + next(); + }) + }, function(err) { if (err) return callback(err); - if (data) { - try { - block = bcoin.protocol.parser.parseBlock(data); - block = new bcoin.block(block); - } catch (e) { - return callback(e); - } - block._fileOffset = record.offset; - block.height = record.height; - block.txs.forEach(function(tx) { - tx.height = block.height; - }); - if (self.options.paranoid) { - if (typeof hash === 'number') { - self._getEntry(hash, function(err, entry) { - if (err) - return callback(err); - - if (!entry) - return callback(null, block); - - if (block.hash('hex') !== entry.hash) - return callback(new Error('BlockDB is corrupt. All is lost.')); - - return callback(null, block); - }); - return; - } - if (block.hash('hex') !== hash) - return callback(new Error('BlockDB is corrupt. All is lost.')); - } - } - + delete block.hashes; + block = new bcoin.block(block); return callback(null, block); }); });