diff --git a/lib/indexer/txindexer.js b/lib/indexer/txindexer.js index ad953b63..b09d48a2 100644 --- a/lib/indexer/txindexer.js +++ b/lib/indexer/txindexer.js @@ -6,8 +6,12 @@ 'use strict'; +const assert = require('bsert'); const bdb = require('bdb'); +const bio = require('bufio'); const layout = require('./layout'); +const consensus = require('../protocol/consensus'); +const TX = require('../primitives/tx'); const TXMeta = require('../primitives/txmeta'); const Indexer = require('./indexer'); @@ -20,6 +24,83 @@ Object.assign(layout, { t: bdb.key('t', ['hash256']) }); +/** + * Transaction Record + */ + +class TxRecord { + /** + * Create a block record. + * @constructor + */ + + constructor(options = {}) { + this.block = options.block || consensus.ZERO_HASH; + this.height = options.height || 0; + this.time = options.time || 0; + this.index = options.index || 0; + this.offset = options.offset || 0; + this.length = options.length || 0; + + assert((this.height >>> 0) === this.height); + assert((this.time >>> 0) === this.time); + assert((this.index >>> 0) === this.index); + assert((this.offset >>> 0) === this.offset); + assert((this.length >>> 0) === this.length); + } + + /** + * Inject properties from serialized data. + * @private + * @param {Buffer} data + */ + + fromRaw(data) { + const br = bio.read(data); + + this.block = br.readHash(); + this.height = br.readU32(); + this.time = br.readU32(); + this.index = br.readU32(); + if (this.index === 0x7fffffff) + this.index = -1; + + this.offset = br.readU32(); + this.length = br.readU32(); + + return this; + } + + /** + * Instantiate block record from serialized data. + * @param {Hash} hash + * @param {Buffer} data + * @returns {BlockRecord} + */ + + static fromRaw(data) { + return new this().fromRaw(data); + } + + /** + * Serialize the block record. + * @returns {Buffer} + */ + + toRaw() { + const bw = bio.write(52); + + bw.writeHash(this.block); + bw.writeU32(this.height); + bw.writeU32(this.time); + bw.writeU32(this.index); + bw.writeU32(this.offset); + bw.writeU32(this.length); + + return bw.render(); + } +} + /** * TXIndexer * @alias module:indexer.TXIndexer @@ -50,11 +131,27 @@ class TXIndexer extends Indexer { async indexBlock(entry, block, view) { const b = this.db.batch(); - for (let i = 0; i < block.txs.length; i++) { - const tx = block.txs[i]; + const data = block.toRaw(); + const br = bio.read(data); + // ignore header + br.readBytes(80); + const count = br.readVarint(); + + for (let i = 0; i < count; i++) { + const offset = br.offset; + const tx = TX.fromReader(br); + const length = br.offset - offset; const hash = tx.hash(); - const meta = TXMeta.fromTX(tx, entry, i); - b.put(layout.t.encode(hash), meta.toRaw()); + + const txrecord = new TxRecord({ + block: entry.hash, + height: entry.height, + time: entry.time, + index: i, + offset: offset, + length: length + }); + b.put(layout.t.encode(hash), txrecord.toRaw()); } return b.write(); @@ -87,12 +184,22 @@ class TXIndexer extends Indexer { */ async getMeta(hash) { - const data = await this.db.get(layout.t.encode(hash)); - - if (!data) + const raw = await this.db.get(layout.t.encode(hash)); + if (!raw) return null; - return TXMeta.fromRaw(data); + const record = TxRecord.fromRaw(raw); + + const data = await this.read(record.block, record.offset, record.length); + const tx = TX.fromRaw(data); + + const meta = TXMeta.fromTX(tx); + meta.height = record.height; + meta.block = record.block; + meta.time = record.time; + meta.index = record.index; + + return meta; } /**