diff --git a/lib/bcoin/protocol/framer.js b/lib/bcoin/protocol/framer.js index fd28a6de..2c135b2e 100644 --- a/lib/bcoin/protocol/framer.js +++ b/lib/bcoin/protocol/framer.js @@ -7,6 +7,7 @@ var bcoin = require('../../bcoin'); var network = require('./network'); var constants = require('./constants'); +var bn = require('bn.js'); var utils = bcoin.utils; var assert = utils.assert; @@ -487,6 +488,57 @@ Framer.tx = function _tx(tx) { return p; }; +Framer.btx = function btx(tx, writer) { + var p = new BufferWriter(writer); + + p.write32(tx.version); + + p.writeUIntv(tx.inputs.length); + for (i = 0; i < tx.inputs.length; i++) + Framer.binput(tx.inputs[i], p); + + p.writeUIntv(tx.outputs.length); + for (i = 0; i < tx.outputs.length; i++) + Framer.boutput(tx.outputs[i], p); + + p.writeU32(tx.locktime); + + if (!writer) + p = p.render(); + + p._witnessSize = 0; + + return p; +}; + +Framer.binput = function _input(input, writer) { + var p = new BufferWriter(writer); + + p.writeHash(input.prevout.hash); + p.writeU32(input.prevout.index); + p.writeVarBytes(input.script.encode()); + p.writeU32(input.sequence); + + if (!writer) + p = p.render(); + + return p; +}; + +Framer.boutput = function _output(output, writer) { + var p = new BufferWriter(writer); + + assert(output.value.byteLength() <= 8); + + p.write64(output.value); + p.writeVarBytes(output.script.encode()); + + if (!writer) + p = p.render(); + + return p; +}; + Framer.witnessTX = function _witnessTX(tx) { var inputs = []; var outputs = []; @@ -818,204 +870,165 @@ Framer.mempool = function mempool() { return new Buffer([]); }; -function BufferWriter(size, offset) { - this.buffers = []; - if (Buffer.isBuffer(size)) { - this.offset = offset || 0; - this.size = 100; - this.buffers.push(size); - } else { - this.offset = 0; - this.size = size || 100; - } - this.data = new Buffer(this.size); +function BufferWriter(options) { + if (options instanceof BufferWriter) + return options; + + if (!(this instanceof BufferWriter)) + return new BufferWriter(options); + + this.data = []; + this.written = 0; + this.offset = 0; } BufferWriter.prototype.render = function render() { - this.buffers.push(this.data.slice(this.offset)); - var ret = Buffer.concat(this.buffers); - this.buffers.length = 0; - delete this.size; - delete this.offset; - delete this.buffers; - delete this.data; - return ret; -}; + var data = new Buffer(this.written); + var off = 0; + var i; -BufferWriter.prototype._realloc = function _realloc(size) { - if (this.data.length >= size) - return; + for (i = 0; i < this.data.length; i++) { + item = this.data[i]; + switch (item[0]) { + case 'u8': off += utils.writeU8(data, item[1], off); break; + case 'u16': off += utils.writeU16(data, item[1], off); break; + case 'u16be': off += utils.writeU16BE(data, item[1], off); break; + case 'u32': off += utils.writeU32(data, item[1], off); break; + case 'u32be': off += utils.writeU32BE(data, item[1], off); break; + case 'u64': off += utils.writeU64(data, item[1], off); break; + case 'u64be': off += utils.writeU64BE(data, item[1], off); break; + case '8': off += utils.write8(data, item[1], off); break; + case '16': off += utils.write16(data, item[1], off); break; + case '16be': off += utils.write16BE(data, item[1], off); break; + case '32': off += utils.write32(data, item[1], off); break; + case '32be': off += utils.write32BE(data, item[1], off); break; + case '64': off += utils.write64(data, item[1], off); break; + case '64be': off += utils.write64BE(data, item[1], off); break; + case 'varint': off += utils.writeIntv(data, item[1], off); break; + case 'bytes': off += utils.copy(item[1], data, off); break; + } + } - var len = this.data.length; - var newSize = len + (len / 2 | 0); - - if (size > newSize) - newSize = size + (size / 2 | 0); - - this.buffers.push(this.data.slice(this.offset)); - this.data = new Buffer(newSize); + return data; }; BufferWriter.prototype.writeU8 = function writeU8(value) { - this._realloc(this.offset + 1); - var ret = utils.writeU8(this.data, value, this.offset); - this.offset += ret; - return ret; + this.written += 1; + this.data.push(['u8', value]); }; BufferWriter.prototype.writeU16 = function writeU16(value) { - this._realloc(this.offset + 2); - var ret = utils.writeU16(this.data, value, this.offset); - this.offset += ret; - return ret; + this.written += 2; + this.data.push(['u16', value]); }; BufferWriter.prototype.writeU16BE = function writeU16BE(value) { - this._realloc(this.offset + 2); - var ret = utils.writeU16BE(this.data, value, this.offset); - this.offset += ret; - return ret; + this.written += 2; + this.data.push(['u16be', value]); }; BufferWriter.prototype.writeU32 = function writeU32(value) { - this._realloc(this.offset + 4); - var ret = utils.writeU32(this.data, value, this.offset); - this.offset += ret; - return ret; + this.written += 4; + this.data.push(['u32', value]); }; BufferWriter.prototype.writeU32BE = function writeU32BE(value) { - this._realloc(this.offset + 4); - var ret = utils.writeU32BE(this.data, value, this.offset); - this.offset += ret; - return ret; + this.written += 4; + this.data.push(['u32be', value]); }; BufferWriter.prototype.writeU64 = function writeU64(value) { - this._realloc(this.offset + 8); - var ret = utils.writeU64(this.data, value, this.offset); - this.offset += ret; - return ret; + this.written += 8; + this.data.push(['u64', value]); }; BufferWriter.prototype.writeU64BE = function writeU64BE(value) { - this._realloc(this.offset + 8); - var ret = utils.writeU64BE(this.data, value, this.offset); - this.offset += ret; - return ret; + this.written += 8; + this.data.push(['u64be', value]); }; BufferWriter.prototype.write8 = function write8(value) { - this._realloc(this.offset + 1); - var ret = utils.write8(this.data, value, this.offset); - this.offset += ret; - return ret; + this.written += 1; + this.data.push(['8', value]); }; BufferWriter.prototype.write16 = function write16(value) { - this._realloc(this.offset + 2); - var ret = utils.write16(this.data, value, this.offset); - this.offset += ret; - return ret; + this.written += 2; + this.data.push(['16', value]); }; BufferWriter.prototype.write16BE = function write16BE(value) { - this._realloc(this.offset + 2); - var ret = utils.write16BE(this.data, value, this.offset); - this.offset += ret; - return ret; + this.written += 2; + this.data.push(['16be', value]); }; BufferWriter.prototype.write32 = function write32(value) { - this._realloc(this.offset + 4); - var ret = utils.write32(this.data, value, this.offset); - this.offset += ret; - return ret; + this.written += 4; + this.data.push(['32', value]); }; BufferWriter.prototype.write32BE = function write32BE(value) { - this._realloc(this.offset + 4); - var ret = utils.write32BE(this.data, value, this.offset); - this.offset += ret; - return ret; + this.written += 4; + this.data.push(['32be', value]); }; BufferWriter.prototype.write64 = function write64(value) { - this._realloc(this.offset + 8); - var ret = utils.write64(this.data, value, this.offset); - this.offset += ret; - return ret; + this.written += 8; + this.data.push(['64', value]); }; BufferWriter.prototype.write64BE = function write64BE(value) { - this._realloc(this.offset + 8); - var ret = utils.write64BE(this.data, value, this.offset); - this.offset += ret; - return ret; + this.written += 8; + this.data.push(['64be', value]); }; BufferWriter.prototype.writeBytes = function writeBytes(value) { - assert(Buffer.isBuffer(value)); - if (this.left() > value.length) - return utils.copy(value, this.data, 0); - this.buffers.push(this.data.slice(this.offset)); - this.buffers.push(value); - this.data = new Buffer(100); - this.offset += value.length; - return value.length; -}; - -BufferWriter.prototype.left = function left() { - return this.data.length - this.offset; + this.written += value.length; + this.data.push(['bytes', value]); }; BufferWriter.prototype.getSize = function getSize() { - return this.offset; + return this.written; }; BufferWriter.prototype.writeString = function writeString(value, enc) { if (typeof value === 'string') value = new Buffer(value, enc); - return this.writeBytes(value); + this.writeBytes(value); }; BufferWriter.prototype.writeHash = function writeHash(value) { if (typeof value === 'string') value = new Buffer(value, 'hex'); - assert(value.length === 32 || value.length === 20); - return this.writeBytes(value); + this.writeBytes(value); }; BufferWriter.prototype.writeVarString = function writeVarString(value, enc) { - var len = typeof value === 'string' - ? Buffer.byteLength(value, enc) - : value.length; - var ret = this.writeUIntv(len); - return this.writeString(value, enc) + ret; + if (typeof value === 'string') + value = new Buffer(value, enc); + this.writeVarBytes(value); }; BufferWriter.prototype.writeVarBytes = function writeVarBytes(value) { - var ret = this.writeUIntv(value.length); - return this.writeBytes(value) + ret; + this.written += utils.sizeIntv(value.length); + this.written += value.length; + this.data.push(['varint', value.length]); + this.data.push(['bytes', value]); }; BufferWriter.prototype.writeNullString = function writeNullString(value, enc) { - var ret = this.writeString(value, enc); + this.writeString(value, enc); this.writeU8(0); - return ret + 1; }; BufferWriter.prototype.writeIntv = function writeIntv(value) { - this._realloc(this.offset + utils.sizeIntv(value)); - return utils.writeIntv(this.data, value, this.offset); + this.written += utils.sizeIntv(value); + this.data.push(['varint', value]); }; BufferWriter.prototype.writeUIntv = function writeUIntv(value) { - if (value instanceof bn) - assert(value.cmpn(0) >= 0); - else - assert(value >= 0); - return this.writeIntv(value); + this.written += utils.sizeIntv(value); + this.data.push(['varint', value]); }; /**