serialization: less polymorphism.

This commit is contained in:
Christopher Jeffrey 2016-12-03 18:02:10 -08:00
parent ba88ffab01
commit a95aba92fb
No known key found for this signature in database
GPG Key ID: 8962AB9DE6666BBD
49 changed files with 1894 additions and 1422 deletions

View File

@ -95,8 +95,8 @@ Payment.fromRaw = function fromRaw(data, enc) {
return new Payment().fromRaw(data); return new Payment().fromRaw(data);
}; };
Payment.prototype.toRaw = function toRaw(writer) { Payment.prototype.toRaw = function toRaw() {
var bw = new ProtoWriter(writer); var bw = new ProtoWriter();
var i, tx, op, output; var i, tx, op, output;
if (this.merchantData) if (this.merchantData)
@ -118,10 +118,7 @@ Payment.prototype.toRaw = function toRaw(writer) {
if (this.memo != null) if (this.memo != null)
bw.writeFieldString(4, this.memo); bw.writeFieldString(4, this.memo);
if (!writer) return bw.render();
bw = bw.render();
return bw;
}; };
module.exports = Payment; module.exports = Payment;

View File

@ -54,18 +54,15 @@ PaymentACK.fromRaw = function fromRaw(data, enc) {
return new PaymentACK().fromRaw(data); return new PaymentACK().fromRaw(data);
}; };
PaymentACK.prototype.toRaw = function toRaw(writer) { PaymentACK.prototype.toRaw = function toRaw() {
var bw = new ProtoWriter(writer); var bw = new ProtoWriter();
bw.writeFieldBytes(1, this.payment.toRaw()); bw.writeFieldBytes(1, this.payment.toRaw());
if (this.memo != null) if (this.memo != null)
bw.writeFieldString(2, this.memo); bw.writeFieldString(2, this.memo);
if (!writer) return bw.render();
bw = bw.render();
return bw;
}; };
module.exports = PaymentACK; module.exports = PaymentACK;

View File

@ -147,8 +147,8 @@ PaymentDetails.fromRaw = function fromRaw(data, enc) {
return new PaymentDetails().fromRaw(data); return new PaymentDetails().fromRaw(data);
}; };
PaymentDetails.prototype.toRaw = function toRaw(writer) { PaymentDetails.prototype.toRaw = function toRaw() {
var bw = new ProtoWriter(writer); var bw = new ProtoWriter();
var i, op, output; var i, op, output;
if (this.network != null) if (this.network != null)
@ -176,10 +176,7 @@ PaymentDetails.prototype.toRaw = function toRaw(writer) {
if (this.merchantData) if (this.merchantData)
bw.writeFieldString(7, this.merchantData); bw.writeFieldString(7, this.merchantData);
if (!writer) return bw.render();
bw = bw.render();
return bw;
}; };
module.exports = PaymentDetails; module.exports = PaymentDetails;

View File

@ -83,8 +83,8 @@ PaymentRequest.fromRaw = function fromRaw(data, enc) {
return new PaymentRequest().fromRaw(data); return new PaymentRequest().fromRaw(data);
}; };
PaymentRequest.prototype.toRaw = function toRaw(writer) { PaymentRequest.prototype.toRaw = function toRaw() {
var bw = new ProtoWriter(writer); var bw = new ProtoWriter();
if (this.version !== -1) if (this.version !== -1)
bw.writeFieldU32(1, this.version); bw.writeFieldU32(1, this.version);
@ -100,10 +100,7 @@ PaymentRequest.prototype.toRaw = function toRaw(writer) {
if (this.signature) if (this.signature)
bw.writeFieldBytes(5, this.signature); bw.writeFieldBytes(5, this.signature);
if (!writer) return bw.render();
bw = bw.render();
return bw;
}; };
PaymentRequest.prototype.getAlgorithm = function getAlgorithm() { PaymentRequest.prototype.getAlgorithm = function getAlgorithm() {

View File

@ -432,8 +432,8 @@ ChainEntry.fromBlock = function fromBlock(chain, block, prev) {
* @returns {Buffer} * @returns {Buffer}
*/ */
ChainEntry.prototype.toRaw = function toRaw(writer) { ChainEntry.prototype.toRaw = function toRaw() {
var bw = new BufferWriter(writer); var bw = new BufferWriter();
bw.writeU32(this.version); bw.writeU32(this.version);
bw.writeHash(this.prevBlock); bw.writeHash(this.prevBlock);
@ -444,10 +444,7 @@ ChainEntry.prototype.toRaw = function toRaw(writer) {
bw.writeU32(this.height); bw.writeU32(this.height);
bw.writeBytes(this.chainwork.toArrayLike(Buffer, 'le', 32)); bw.writeBytes(this.chainwork.toArrayLike(Buffer, 'le', 32));
if (!writer) return bw.render();
bw = bw.render();
return bw;
}; };
/** /**

View File

@ -56,7 +56,7 @@ UndoCoins.prototype.toRaw = function toRaw() {
for (i = 0; i < this.items.length; i++) { for (i = 0; i < this.items.length; i++) {
coin = this.items[i]; coin = this.items[i];
coin.toRaw(bw); coin.toWriter(bw);
} }
return bw.render(); return bw.render();
@ -75,7 +75,7 @@ UndoCoins.prototype.fromRaw = function fromRaw(data) {
var i; var i;
for (i = 0; i < count; i++) for (i = 0; i < count; i++)
this.items.push(UndoCoin.fromRaw(br)); this.items.push(UndoCoin.fromReader(br));
return this; return this;
}; };
@ -187,12 +187,11 @@ UndoCoin.prototype.toOutput = function toOutput() {
}; };
/** /**
* Serialize the undo coin. * Write the undo coin to a buffer writer.
* @returns {Buffer} * @param {BufferWriter} bw
*/ */
UndoCoin.prototype.toRaw = function toRaw(writer) { UndoCoin.prototype.toWriter = function toWriter(bw) {
var bw = new BufferWriter(writer);
var height = this.height; var height = this.height;
assert(height !== 0); assert(height !== 0);
@ -214,21 +213,26 @@ UndoCoin.prototype.toRaw = function toRaw(writer) {
compress.output(this.output, bw); compress.output(this.output, bw);
} }
if (!writer)
bw = bw.render();
return bw; return bw;
}; };
/** /**
* Inject properties from serialized data. * Serialize the undo coin.
* @returns {Buffer}
*/
UndoCoin.prototype.toRaw = function toRaw() {
return this.toWriter(new BufferWriter()).render();
};
/**
* Inject properties from buffer reader.
* @private * @private
* @param {Buffer} data * @param {BufferReader} br
* @returns {UndoCoin} * @returns {UndoCoin}
*/ */
UndoCoin.prototype.fromRaw = function fromRaw(data) { UndoCoin.prototype.fromReader = function fromReader(br) {
var br = new BufferReader(data);
var code = br.readVarint(); var code = br.readVarint();
this.output = new Output(); this.output = new Output();
@ -248,6 +252,27 @@ UndoCoin.prototype.fromRaw = function fromRaw(data) {
return this; return this;
}; };
/**
* Inject properties from serialized data.
* @private
* @param {Buffer} data
* @returns {UndoCoin}
*/
UndoCoin.prototype.fromRaw = function fromRaw(data) {
return this.fromReader(new BufferReader(data));
};
/**
* Instantiate undo coin from serialized data.
* @param {Buffer} data
* @returns {UndoCoin}
*/
UndoCoin.fromReader = function fromReader(br) {
return new UndoCoin().fromReader(br);
};
/** /**
* Instantiate undo coin from serialized data. * Instantiate undo coin from serialized data.
* @param {Buffer} data * @param {Buffer} data

View File

@ -414,12 +414,11 @@ Mnemonic.fromJSON = function fromJSON(json) {
}; };
/** /**
* Serialize mnemonic. * Write the mnemonic to a buffer writer.
* @returns {Buffer} * @params {BufferWriter} bw
*/ */
Mnemonic.prototype.toRaw = function toRaw(writer) { Mnemonic.prototype.toWriter = function toWriter(bw) {
var bw = new BufferWriter(writer);
var lang = Mnemonic.languages.indexOf(this.language); var lang = Mnemonic.languages.indexOf(this.language);
assert(lang !== -1); assert(lang !== -1);
@ -430,21 +429,25 @@ Mnemonic.prototype.toRaw = function toRaw(writer) {
bw.writeVarString(this.getPhrase(), 'utf8'); bw.writeVarString(this.getPhrase(), 'utf8');
bw.writeVarString(this.passphrase, 'utf8'); bw.writeVarString(this.passphrase, 'utf8');
if (!writer)
bw = bw.render();
return bw; return bw;
}; };
/** /**
* Inject properties from serialized data. * Serialize mnemonic.
* @private * @returns {Buffer}
* @param {Buffer} data
*/ */
Mnemonic.prototype.fromRaw = function fromRaw(data) { Mnemonic.prototype.toRaw = function toRaw(writer) {
var br = new BufferReader(data); return this.toWriter(new BufferWriter()).render();
};
/**
* Inject properties from buffer reader.
* @private
* @param {BufferReader} br
*/
Mnemonic.prototype.fromReader = function fromReader(br) {
this.bits = br.readU16(); this.bits = br.readU16();
this.language = Mnemonic.languages[br.readU8()]; this.language = Mnemonic.languages[br.readU8()];
this.entropy = br.readBytes(this.bits / 8); this.entropy = br.readBytes(this.bits / 8);
@ -459,6 +462,26 @@ Mnemonic.prototype.fromRaw = function fromRaw(data) {
return this; return this;
}; };
/**
* Inject properties from serialized data.
* @private
* @param {Buffer} data
*/
Mnemonic.prototype.fromRaw = function fromRaw(data) {
return this.fromReader(new BufferReader(data));
};
/**
* Instantiate mnemonic from buffer reader.
* @param {BufferReader} br
* @returns {Mnemonic}
*/
Mnemonic.fromReader = function fromReader(br) {
return new Mnemonic().fromReader(br);
};
/** /**
* Instantiate mnemonic from serialized data. * Instantiate mnemonic from serialized data.
* @param {Buffer} data * @param {Buffer} data

View File

@ -623,8 +623,7 @@ HDPrivateKey.prototype.fromBase58 = function fromBase58(xkey) {
* @param {Buffer} raw * @param {Buffer} raw
*/ */
HDPrivateKey.prototype.fromRaw = function fromRaw(raw) { HDPrivateKey.prototype.fromReader = function fromReader(br) {
var br = new BufferReader(raw);
var i, version, type, prefix; var i, version, type, prefix;
version = br.readU32BE(); version = br.readU32BE();
@ -651,6 +650,16 @@ HDPrivateKey.prototype.fromRaw = function fromRaw(raw) {
return this; return this;
}; };
/**
* Inject properties from serialized data.
* @private
* @param {Buffer} raw
*/
HDPrivateKey.prototype.fromRaw = function fromRaw(raw) {
return this.fromReader(new BufferReader(raw));
};
/** /**
* Serialize key to a base58 string. * Serialize key to a base58 string.
* @param {(Network|NetworkType)?} network * @param {(Network|NetworkType)?} network
@ -662,14 +671,12 @@ HDPrivateKey.prototype.toBase58 = function toBase58(network) {
}; };
/** /**
* Serialize the key. * Write the key to a buffer writer.
* @param {BufferWriter} bw
* @param {(Network|NetworkType)?} network * @param {(Network|NetworkType)?} network
* @returns {Buffer}
*/ */
HDPrivateKey.prototype.toRaw = function toRaw(network, writer) { HDPrivateKey.prototype.toWriter = function toWriter(bw, network) {
var bw = new BufferWriter(writer);
if (!network) if (!network)
network = this.network; network = this.network;
@ -684,8 +691,35 @@ HDPrivateKey.prototype.toRaw = function toRaw(network, writer) {
bw.writeBytes(this.privateKey); bw.writeBytes(this.privateKey);
bw.writeChecksum(); bw.writeChecksum();
if (!writer) return bw;
bw = bw.render(); };
/**
* Serialize the key.
* @param {(Network|NetworkType)?} network
* @returns {Buffer}
*/
HDPrivateKey.prototype.toRaw = function toRaw(network) {
return this.toWriter(new BufferWriter(), network).render();
};
/**
* Write the key in "extended"
* format to a buffer writer.
* @param {BufferWriter} bw
* @param {(Network|NetworkType)?} network
*/
HDPrivateKey.prototype.toExtendedWriter = function toExtendedWriter(bw, network) {
this.toWriter(bw, network);
if (this.mnemonic) {
bw.writeU8(1);
this.mnemonic.toWriter(bw);
} else {
bw.writeU8(0);
}
return bw; return bw;
}; };
@ -697,22 +731,21 @@ HDPrivateKey.prototype.toRaw = function toRaw(network, writer) {
* @returns {Buffer} * @returns {Buffer}
*/ */
HDPrivateKey.prototype.toExtended = function toExtended(network, writer) { HDPrivateKey.prototype.toExtended = function toExtended(network) {
var bw = new BufferWriter(writer); return this.toExtendedWriter(new BufferWriter(), network).render();
};
this.toRaw(network, bw); /**
* Inject properties from buffer reader.
* @private
* @param {BufferReader} br
*/
if (this.mnemonic) { HDPrivateKey.prototype.fromExtendedReader = function fromExtendedReader(br) {
bw.writeU8(1); this.fromReader(br);
this.mnemonic.toRaw(bw); if (br.readU8() === 1)
} else { this.mnemonic = Mnemonic.fromReader(br);
bw.writeU8(0); return this;
}
if (!writer)
bw = bw.render();
return bw;
}; };
/** /**
@ -722,11 +755,17 @@ HDPrivateKey.prototype.toExtended = function toExtended(network, writer) {
*/ */
HDPrivateKey.prototype.fromExtended = function fromExtended(data) { HDPrivateKey.prototype.fromExtended = function fromExtended(data) {
var br = new BufferReader(data); return this.fromExtendedReader(new BufferReader(data));
this.fromRaw(br); };
if (br.readU8() === 1)
this.mnemonic = Mnemonic.fromRaw(br); /**
return this; * Instantiate key from "extended" buffer reader.
* @param {BufferReader} br
* @returns {HDPrivateKey}
*/
HDPrivateKey.fromExtendedReader = function fromExtendedReader(br) {
return new HDPrivateKey().fromExtendedReader(br);
}; };
/** /**
@ -749,6 +788,16 @@ HDPrivateKey.fromBase58 = function fromBase58(xkey) {
return new HDPrivateKey().fromBase58(xkey); return new HDPrivateKey().fromBase58(xkey);
}; };
/**
* Instantiate key from buffer reader.
* @param {BufferReader} br
* @returns {HDPrivateKey}
*/
HDPrivateKey.fromReader = function fromReader(br) {
return new HDPrivateKey().fromReader(br);
};
/** /**
* Instantiate key from serialized data. * Instantiate key from serialized data.
* @param {Buffer} raw * @param {Buffer} raw

View File

@ -485,8 +485,7 @@ HDPublicKey.prototype.fromBase58 = function fromBase58(xkey) {
* @param {Buffer} raw * @param {Buffer} raw
*/ */
HDPublicKey.prototype.fromRaw = function fromRaw(raw) { HDPublicKey.prototype.fromReader = function fromReader(br) {
var br = new BufferReader(raw);
var i, version, type, prefix; var i, version, type, prefix;
version = br.readU32BE(); version = br.readU32BE();
@ -511,6 +510,16 @@ HDPublicKey.prototype.fromRaw = function fromRaw(raw) {
return this; return this;
}; };
/**
* Inject properties from serialized data.
* @private
* @param {Buffer} raw
*/
HDPublicKey.prototype.fromRaw = function fromRaw(raw) {
return this.fromReader(new BufferReader(raw));
};
/** /**
* Serialize key data to base58 extended key. * Serialize key data to base58 extended key.
* @param {Network|String} network * @param {Network|String} network
@ -522,14 +531,12 @@ HDPublicKey.prototype.toBase58 = function toBase58(network) {
}; };
/** /**
* Serialize the key. * Write the key to a buffer writer.
* @param {BufferWriter} bw
* @param {Network|NetworkType} network * @param {Network|NetworkType} network
* @returns {Buffer}
*/ */
HDPublicKey.prototype.toRaw = function toRaw(network, writer) { HDPublicKey.prototype.toWriter = function toWriter(bw, network) {
var bw = new BufferWriter(writer);
if (!network) if (!network)
network = this.network; network = this.network;
@ -543,12 +550,19 @@ HDPublicKey.prototype.toRaw = function toRaw(network, writer) {
bw.writeBytes(this.publicKey); bw.writeBytes(this.publicKey);
bw.writeChecksum(); bw.writeChecksum();
if (!writer)
bw = bw.render();
return bw; return bw;
}; };
/**
* Serialize the key.
* @param {Network|NetworkType} network
* @returns {Buffer}
*/
HDPublicKey.prototype.toRaw = function toRaw(network) {
return this.toWriter(new BufferWriter(), network).render();
};
/** /**
* Instantiate an HD public key from a base58 string. * Instantiate an HD public key from a base58 string.
* @param {Base58String} xkey * @param {Base58String} xkey
@ -559,6 +573,16 @@ HDPublicKey.fromBase58 = function fromBase58(xkey) {
return new HDPublicKey().fromBase58(xkey); return new HDPublicKey().fromBase58(xkey);
}; };
/**
* Instantiate key from serialized data.
* @param {BufferReader} br
* @returns {HDPublicKey}
*/
HDPublicKey.fromReader = function fromReader(br) {
return new HDPublicKey().fromReader(br);
};
/** /**
* Instantiate key from serialized data. * Instantiate key from serialized data.
* @param {Buffer} raw * @param {Buffer} raw

View File

@ -2163,7 +2163,7 @@ RPC.prototype.signrawtransaction = co(function* signrawtransaction(args) {
txs = []; txs = [];
while (br.left()) while (br.left())
txs.push(MTX.fromRaw(br)); txs.push(MTX.fromReader(br));
merged = txs[0]; merged = txs[0];

View File

@ -320,8 +320,8 @@ ConfirmStats.prototype.removeTX = function removeTX(entryHeight, bestHeight, buc
* @returns {Buffer} * @returns {Buffer}
*/ */
ConfirmStats.prototype.toRaw = function toRaw(writer) { ConfirmStats.prototype.toRaw = function toRaw() {
var bw = new BufferWriter(writer); var bw = new BufferWriter();
var i; var i;
function writeArray(buckets) { function writeArray(buckets) {
@ -342,10 +342,7 @@ ConfirmStats.prototype.toRaw = function toRaw(writer) {
for (i = 0; i < this.maxConfirms; i++) for (i = 0; i < this.maxConfirms; i++)
writeArray(this.confAvg[i]); writeArray(this.confAvg[i]);
if (!writer) return bw.render();
bw = bw.render();
return bw;
}; };
/** /**
@ -805,18 +802,15 @@ PolicyEstimator.prototype.estimatePriority = function estimatePriority(target, s
* @returns {Buffer} * @returns {Buffer}
*/ */
PolicyEstimator.prototype.toRaw = function toRaw(writer) { PolicyEstimator.prototype.toRaw = function toRaw() {
var bw = new BufferWriter(writer); var bw = new BufferWriter();
bw.writeU32(this.network.magic); bw.writeU32(this.network.magic);
bw.writeU32(this.bestHeight); bw.writeU32(this.bestHeight);
bw.writeVarBytes(this.feeStats.toRaw()); bw.writeVarBytes(this.feeStats.toRaw());
bw.writeVarBytes(this.priStats.toRaw()); bw.writeVarBytes(this.priStats.toRaw());
if (!writer) return bw.render();
bw = bw.render();
return bw;
}; };
/** /**

View File

@ -116,8 +116,8 @@ CompactBlock.prototype.fromRaw = function fromRaw(data) {
index = br.readVarint(); index = br.readVarint();
assert(index <= 0xffff); assert(index <= 0xffff);
assert(index < this.totalTX); assert(index < this.totalTX);
tx = TX.fromRaw(br); tx = TX.fromReader(br);
this.ptx.push([index, tx]); this.ptx.push(new PrefilledTX(index, tx));
} }
this.init(); this.init();
@ -131,16 +131,27 @@ CompactBlock.fromRaw = function fromRaw(data, enc) {
return new CompactBlock().fromRaw(data); return new CompactBlock().fromRaw(data);
}; };
CompactBlock.prototype.toRaw = function toRaw(writer) { CompactBlock.prototype.toRaw = function toRaw() {
return this.frame(true, writer); return this.frame(true);
}; };
CompactBlock.prototype.toNormal = function toNormal(writer) { CompactBlock.prototype.toNormal = function toNormal() {
return this.frame(false, writer); return this.frame(false);
}; };
CompactBlock.prototype.frame = function frame(witness, writer) { CompactBlock.prototype.toWriter = function toWriter(bw) {
var bw = BufferWriter(writer); return this.frameWriter(bw, true);
};
CompactBlock.prototype.toNormalWriter = function toNormalWriter(bw) {
return this.frameWriter(bw, false);
};
CompactBlock.prototype.frame = function frame(witness) {
return this.frameWriter(new BufferWriter(), witness).render();
};
CompactBlock.prototype.frameWriter = function frameWriter(bw, witness) {
var i, id, lo, hi, ptx; var i, id, lo, hi, ptx;
bw.writeU32(this.version); bw.writeU32(this.version);
@ -167,16 +178,13 @@ CompactBlock.prototype.frame = function frame(witness, writer) {
for (i = 0; i < this.ptx.length; i++) { for (i = 0; i < this.ptx.length; i++) {
ptx = this.ptx[i]; ptx = this.ptx[i];
bw.writeVarint(ptx[0]); bw.writeVarint(ptx.index);
if (witness) if (witness)
ptx[1].toRaw(bw); ptx.tx.toWriter(bw);
else else
ptx[1].toNormal(bw); ptx.tx.toNormalWriter(bw);
} }
if (!writer)
bw = bw.render();
return bw; return bw;
}; };
@ -286,10 +294,10 @@ CompactBlock.prototype.init = function init() {
for (i = 0; i < this.ptx.length; i++) { for (i = 0; i < this.ptx.length; i++) {
ptx = this.ptx[i]; ptx = this.ptx[i];
assert(ptx); assert(ptx);
last += ptx[0] + 1; last += ptx.index + 1;
assert(last <= 0xffff); assert(last <= 0xffff);
assert(last <= this.ids.length + i); assert(last <= this.ids.length + i);
this.available[last] = ptx[1]; this.available[last] = ptx.tx;
this.count++; this.count++;
} }
@ -364,7 +372,7 @@ CompactBlock.prototype.fromBlock = function fromBlock(block, witness, nonce) {
this.ids.push(id); this.ids.push(id);
} }
this.ptx.push([0, block.txs[0]]); this.ptx.push(new PrefilledTX(0, block.txs[0]));
return this; return this;
}; };
@ -455,8 +463,7 @@ TXRequest.fromCompact = function fromCompact(block) {
return new TXRequest().fromCompact(block); return new TXRequest().fromCompact(block);
}; };
TXRequest.prototype.fromRaw = function fromRaw(data) { TXRequest.prototype.fromReader = function fromReader(br) {
var br = BufferReader(data);
var i, count, index, offset; var i, count, index, offset;
this.hash = br.readHash('hex'); this.hash = br.readHash('hex');
@ -482,12 +489,19 @@ TXRequest.prototype.fromRaw = function fromRaw(data) {
return this; return this;
}; };
TXRequest.prototype.fromRaw = function fromRaw(data) {
return this.fromReader(new BufferReader(data));
};
TXRequest.fromReader = function fromReader(br) {
return new TXRequest().fromReader(br);
};
TXRequest.fromRaw = function fromRaw(data) { TXRequest.fromRaw = function fromRaw(data) {
return new TXRequest().fromRaw(data); return new TXRequest().fromRaw(data);
}; };
TXRequest.prototype.toRaw = function toRaw(writer) { TXRequest.prototype.toWriter = function toWriter(bw) {
var bw = BufferWriter(writer);
var i, index; var i, index;
bw.writeHash(this.hash); bw.writeHash(this.hash);
@ -499,12 +513,13 @@ TXRequest.prototype.toRaw = function toRaw(writer) {
bw.writeVarint(index); bw.writeVarint(index);
} }
if (!writer)
bw = bw.render();
return bw; return bw;
}; };
TXRequest.prototype.toRaw = function toRaw() {
return this.toWriter(new BufferWriter()).render();
};
/** /**
* Represents BlockTransactions (bip152): `blocktxn` packet. * Represents BlockTransactions (bip152): `blocktxn` packet.
* @see https://github.com/bitcoin/bips/blob/master/bip-0152.mediawiki * @see https://github.com/bitcoin/bips/blob/master/bip-0152.mediawiki
@ -535,8 +550,7 @@ TXResponse.fromOptions = function fromOptions(options) {
return new TXResponse().fromOptions(options); return new TXResponse().fromOptions(options);
}; };
TXResponse.prototype.fromRaw = function fromRaw(data) { TXResponse.prototype.fromReader = function fromReader(br) {
var br = BufferReader(data);
var i, count; var i, count;
this.hash = br.readHash('hex'); this.hash = br.readHash('hex');
@ -544,11 +558,19 @@ TXResponse.prototype.fromRaw = function fromRaw(data) {
count = br.readVarint(); count = br.readVarint();
for (i = 0; i < count; i++) for (i = 0; i < count; i++)
this.txs.push(TX.fromRaw(br)); this.txs.push(TX.fromReader(br));
return this; return this;
}; };
TXResponse.prototype.fromRaw = function fromRaw(data) {
return this.fromReader(new BufferReader(data));
};
TXResponse.fromReader = function fromReader(br) {
return new TXResponse().fromReader(br);
};
TXResponse.fromRaw = function fromRaw(data) { TXResponse.fromRaw = function fromRaw(data) {
return new TXResponse().fromRaw(data); return new TXResponse().fromRaw(data);
}; };
@ -572,16 +594,23 @@ TXResponse.fromBlock = function fromBlock(block, req) {
return new TXResponse().fromBlock(block, req); return new TXResponse().fromBlock(block, req);
}; };
TXResponse.prototype.toRaw = function toRaw(writer) { TXResponse.prototype.toRaw = function toRaw() {
return this.frame(true, writer); return this.frame(true);
}; };
TXResponse.prototype.toNormal = function toNormal(writer) { TXResponse.prototype.toNormal = function toNormal() {
return this.frame(false, writer); return this.frame(false);
}; };
TXResponse.prototype.frame = function frame(witness, writer) { TXResponse.prototype.toWriter = function toWriter(bw) {
var bw = BufferWriter(writer); return this.frameWriter(bw, true);
};
TXResponse.prototype.toNormalWriter = function toNormalWriter(bw) {
return this.frameWriter(bw, false);
};
TXResponse.prototype.frameWriter = function frameWriter(bw, witness) {
var i, tx; var i, tx;
bw.writeHash(this.hash); bw.writeHash(this.hash);
@ -591,17 +620,27 @@ TXResponse.prototype.frame = function frame(witness, writer) {
for (i = 0; i < this.txs.length; i++) { for (i = 0; i < this.txs.length; i++) {
tx = this.txs[i]; tx = this.txs[i];
if (witness) if (witness)
tx.toRaw(bw); tx.toWriter(bw);
else else
tx.toNormal(bw); tx.toNormalWriter(bw);
} }
if (!writer)
bw = bw.render();
return bw; return bw;
}; };
TXResponse.prototype.frame = function frame(witness) {
return this.frameWriter(new BufferWriter(), witness).render();
};
/*
* Helpers
*/
function PrefilledTX(index, tx) {
this.index = index;
this.tx = tx;
}
/* /*
* Expose * Expose
*/ */

View File

@ -186,23 +186,20 @@ VersionPacket.fromOptions = function fromOptions(options) {
* @returns {Buffer} * @returns {Buffer}
*/ */
VersionPacket.prototype.toRaw = function toRaw(writer) { VersionPacket.prototype.toRaw = function toRaw() {
var bw = BufferWriter(writer); var bw = new BufferWriter();
bw.write32(this.version); bw.write32(this.version);
bw.writeU64(this.services); bw.writeU64(this.services);
bw.write64(this.ts); bw.write64(this.ts);
this.recv.toRaw(false, bw); this.recv.toWriter(bw, false);
this.from.toRaw(false, bw); this.from.toWriter(bw, false);
bw.writeBytes(this.nonce); bw.writeBytes(this.nonce);
bw.writeVarString(this.agent, 'ascii'); bw.writeVarString(this.agent, 'ascii');
bw.write32(this.height); bw.write32(this.height);
bw.writeU8(this.relay ? 1 : 0); bw.writeU8(this.relay ? 1 : 0);
if (!writer) return bw.render();
bw = bw.render();
return bw;
}; };
/** /**
@ -272,10 +269,10 @@ VersionPacket.prototype.fromRaw = function fromRaw(data) {
this.version = br.read32(); this.version = br.read32();
this.services = br.readU53(); this.services = br.readU53();
this.ts = br.read53(); this.ts = br.read53();
this.recv.fromRaw(br, false); this.recv.fromReader(br, false);
if (br.left() > 0) { if (br.left() > 0) {
this.from.fromRaw(br, false); this.from.fromReader(br, false);
this.nonce = br.readBytes(8); this.nonce = br.readBytes(8);
} }
@ -332,8 +329,8 @@ VerackPacket.prototype.type = exports.types.VERACK;
* @returns {Buffer} * @returns {Buffer}
*/ */
VerackPacket.prototype.toRaw = function toRaw(writer) { VerackPacket.prototype.toRaw = function toRaw() {
return writer || DUMMY; return DUMMY;
}; };
/** /**
@ -386,16 +383,13 @@ PingPacket.prototype.type = exports.types.PING;
* @returns {Buffer} * @returns {Buffer}
*/ */
PingPacket.prototype.toRaw = function toRaw(writer) { PingPacket.prototype.toRaw = function toRaw() {
var bw = BufferWriter(writer); var bw = new BufferWriter();
if (this.nonce) if (this.nonce)
bw.writeBytes(this.nonce); bw.writeBytes(this.nonce);
if (!writer) return bw.render();
bw = bw.render();
return bw;
}; };
/** /**
@ -451,15 +445,10 @@ PongPacket.prototype.type = exports.types.PONG;
* @returns {Buffer} * @returns {Buffer}
*/ */
PongPacket.prototype.toRaw = function toRaw(writer) { PongPacket.prototype.toRaw = function toRaw() {
var bw = BufferWriter(writer); var bw = new BufferWriter();
bw.writeBytes(this.nonce); bw.writeBytes(this.nonce);
return bw.render();
if (!writer)
bw = bw.render();
return bw;
}; };
/** /**
@ -650,20 +639,24 @@ AlertPacket.prototype.verify = function verify(key) {
}; };
/** /**
* Serialize the alert packet (includes payload _and_ signature). * Write the alert packet to a buffer writer.
* @param {BufferWriter} bw
*/
AlertPacket.prototype.toWriter = function toWriter(bw) {
bw.writeVarBytes(this.toPayload());
bw.writeVarBytes(this.signature);
return bw;
};
/**
* Serialize the alert packet (includes
* payload _and_ signature).
* @returns {Buffer} * @returns {Buffer}
*/ */
AlertPacket.prototype.toRaw = function toRaw(writer) { AlertPacket.prototype.toRaw = function toRaw() {
var bw = BufferWriter(writer); return this.toWriter(new BufferWriter()).render();
bw.writeVarBytes(this.toPayload());
bw.writeVarBytes(this.signature);
if (!writer)
bw = bw.render();
return bw;
}; };
/** /**
@ -672,8 +665,8 @@ AlertPacket.prototype.toRaw = function toRaw(writer) {
* @returns {Buffer} * @returns {Buffer}
*/ */
AlertPacket.prototype.framePayload = function framePayload(writer) { AlertPacket.prototype.framePayload = function framePayload() {
var bw = BufferWriter(writer); var bw = new BufferWriter();
var i; var i;
bw.write32(this.version); bw.write32(this.version);
@ -698,26 +691,22 @@ AlertPacket.prototype.framePayload = function framePayload(writer) {
bw.writeVarString(this.statusBar, 'ascii'); bw.writeVarString(this.statusBar, 'ascii');
bw.writeVarString(this.reserved, 'ascii'); bw.writeVarString(this.reserved, 'ascii');
if (!writer) return bw.render();
bw = bw.render();
return bw;
}; };
/** /**
* Inject properties from serialized data. * Inject properties from buffer reader.
* @private * @private
* @param {Buffer} data * @param {BufferReader} br
*/ */
AlertPacket.prototype.fromRaw = function fromRaw(data) { AlertPacket.prototype.fromReader = function fromReader(br) {
var br = BufferReader(data);
var i, count; var i, count;
this._payload = br.readVarBytes(); this._payload = br.readVarBytes();
this.signature = br.readVarBytes(); this.signature = br.readVarBytes();
br = BufferReader(this._payload); br = new BufferReader(this._payload);
this.version = br.read32(); this.version = br.read32();
this.relayUntil = br.read53(); this.relayUntil = br.read53();
@ -744,6 +733,26 @@ AlertPacket.prototype.fromRaw = function fromRaw(data) {
return this; return this;
}; };
/**
* Inject properties from serialized data.
* @private
* @param {Buffer} data
*/
AlertPacket.prototype.fromRaw = function fromRaw(data) {
return this.fromReader(new BufferReader(data));
};
/**
* Instantiate alert packet from buffer reader.
* @param {BufferReader} br
* @returns {AlertPacket}
*/
AlertPacket.fromReader = function fromReader(br) {
return new AlertPacket().fromReader(br);
};
/** /**
* Instantiate alert packet from serialized data. * Instantiate alert packet from serialized data.
* @param {Buffer} data * @param {Buffer} data
@ -780,8 +789,8 @@ GetAddrPacket.prototype.type = exports.types.GETADDR;
* @returns {Buffer} * @returns {Buffer}
*/ */
GetAddrPacket.prototype.toRaw = function toRaw(writer) { GetAddrPacket.prototype.toRaw = function toRaw() {
return writer || DUMMY; return DUMMY;
}; };
/** /**
@ -834,19 +843,16 @@ AddrPacket.prototype.type = exports.types.ADDR;
* @returns {Buffer} * @returns {Buffer}
*/ */
AddrPacket.prototype.toRaw = function toRaw(writer) { AddrPacket.prototype.toRaw = function toRaw() {
var bw = BufferWriter(writer); var bw = new BufferWriter();
var i; var i;
bw.writeVarint(this.items.length); bw.writeVarint(this.items.length);
for (i = 0; i < this.items.length; i++) for (i = 0; i < this.items.length; i++)
this.items[i].toRaw(true, bw); this.items[i].toWriter(bw, true);
if (!writer) return bw.render();
bw = bw.render();
return bw;
}; };
/** /**
@ -862,7 +868,7 @@ AddrPacket.prototype.fromRaw = function fromRaw(data) {
count = br.readVarint(); count = br.readVarint();
for (i = 0; i < count; i++) for (i = 0; i < count; i++)
this.items.push(NetworkAddress.fromRaw(br, true)); this.items.push(NetworkAddress.fromReader(br, true));
return this; return this;
}; };
@ -907,19 +913,16 @@ InvPacket.prototype.type = exports.types.INV;
* @returns {Buffer} * @returns {Buffer}
*/ */
InvPacket.prototype.toRaw = function toRaw(writer) { InvPacket.prototype.toRaw = function toRaw() {
var bw = BufferWriter(writer); var bw = new BufferWriter();
var i; var i;
bw.writeVarint(this.items.length); bw.writeVarint(this.items.length);
for (i = 0; i < this.items.length; i++) for (i = 0; i < this.items.length; i++)
this.items[i].toRaw(bw); this.items[i].toWriter(bw);
if (!writer) return bw.render();
bw = bw.render();
return bw;
}; };
/** /**
@ -929,13 +932,13 @@ InvPacket.prototype.toRaw = function toRaw(writer) {
*/ */
InvPacket.prototype.fromRaw = function fromRaw(data) { InvPacket.prototype.fromRaw = function fromRaw(data) {
var br = BufferReader(data); var br = new BufferReader(data);
var i, count; var i, count;
count = br.readVarint(); count = br.readVarint();
for (i = 0; i < count; i++) for (i = 0; i < count; i++)
this.items.push(InvItem.fromRaw(br)); this.items.push(InvItem.fromReader(br));
return this; return this;
}; };
@ -1050,8 +1053,8 @@ GetBlocksPacket.prototype.type = exports.types.GETBLOCKS;
* @returns {Buffer} * @returns {Buffer}
*/ */
GetBlocksPacket.prototype.toRaw = function toRaw(writer) { GetBlocksPacket.prototype.toRaw = function toRaw() {
var bw = BufferWriter(writer); var bw = new BufferWriter();
var i; var i;
bw.writeU32(this.version); bw.writeU32(this.version);
@ -1062,10 +1065,7 @@ GetBlocksPacket.prototype.toRaw = function toRaw(writer) {
bw.writeHash(this.stop || constants.ZERO_HASH); bw.writeHash(this.stop || constants.ZERO_HASH);
if (!writer) return bw.render();
bw = bw.render();
return bw;
}; };
/** /**
@ -1167,19 +1167,16 @@ HeadersPacket.prototype.type = exports.types.HEADERS;
* @returns {Buffer} * @returns {Buffer}
*/ */
HeadersPacket.prototype.toRaw = function toRaw(writer) { HeadersPacket.prototype.toRaw = function toRaw() {
var bw = BufferWriter(writer); var bw = new BufferWriter();
var i; var i;
bw.writeVarint(this.items.length); bw.writeVarint(this.items.length);
for (i = 0; i < this.items.length; i++) for (i = 0; i < this.items.length; i++)
this.items[i].toRaw(bw); this.items[i].toWriter(bw);
if (!writer) return bw.render();
bw = bw.render();
return bw;
}; };
/** /**
@ -1195,7 +1192,7 @@ HeadersPacket.prototype.fromRaw = function fromRaw(data) {
count = br.readVarint(); count = br.readVarint();
for (i = 0; i < count; i++) for (i = 0; i < count; i++)
this.items.push(Headers.fromRaw(br)); this.items.push(Headers.fromReader(br));
return this; return this;
}; };
@ -1236,8 +1233,8 @@ SendHeadersPacket.prototype.type = exports.types.SENDHEADERS;
* @returns {Buffer} * @returns {Buffer}
*/ */
SendHeadersPacket.prototype.toRaw = function toRaw(writer) { SendHeadersPacket.prototype.toRaw = function toRaw() {
return writer || DUMMY; return DUMMY;
}; };
/** /**
@ -1293,10 +1290,10 @@ BlockPacket.prototype.type = exports.types.BLOCK;
* @returns {Buffer} * @returns {Buffer}
*/ */
BlockPacket.prototype.toRaw = function toRaw(writer) { BlockPacket.prototype.toRaw = function toRaw() {
if (this.witness) if (this.witness)
return this.block.toRaw(writer); return this.block.toRaw();
return this.block.toNormal(writer); return this.block.toNormal();
}; };
/** /**
@ -1353,10 +1350,10 @@ TXPacket.prototype.type = exports.types.TX;
* @returns {Buffer} * @returns {Buffer}
*/ */
TXPacket.prototype.toRaw = function toRaw(writer) { TXPacket.prototype.toRaw = function toRaw() {
if (this.witness) if (this.witness)
return this.tx.toRaw(writer); return this.tx.toRaw();
return this.tx.toNormal(writer); return this.tx.toNormal();
}; };
/** /**
@ -1460,8 +1457,8 @@ RejectPacket.fromOptions = function fromOptions(options) {
* @returns {Buffer} * @returns {Buffer}
*/ */
RejectPacket.prototype.toRaw = function toRaw(writer) { RejectPacket.prototype.toRaw = function toRaw() {
var bw = BufferWriter(writer); var bw = new BufferWriter();
assert(this.message.length <= 12); assert(this.message.length <= 12);
assert(this.reason.length <= 111); assert(this.reason.length <= 111);
@ -1473,10 +1470,7 @@ RejectPacket.prototype.toRaw = function toRaw(writer) {
if (this.data) if (this.data)
bw.writeHash(this.data); bw.writeHash(this.data);
if (!writer) return bw.render();
bw = bw.render();
return bw;
}; };
/** /**
@ -1603,8 +1597,8 @@ MempoolPacket.prototype.type = exports.types.MEMPOOL;
* @returns {Buffer} * @returns {Buffer}
*/ */
MempoolPacket.prototype.toRaw = function toRaw(writer) { MempoolPacket.prototype.toRaw = function toRaw() {
return writer || DUMMY; return DUMMY;
}; };
/** /**
@ -1656,8 +1650,8 @@ FilterLoadPacket.prototype.type = exports.types.FILTERLOAD;
* @returns {Buffer} * @returns {Buffer}
*/ */
FilterLoadPacket.prototype.toRaw = function toRaw(writer) { FilterLoadPacket.prototype.toRaw = function toRaw() {
return this.filter.toRaw(writer); return this.filter.toRaw();
}; };
/** /**
@ -1726,15 +1720,10 @@ FilterAddPacket.prototype.type = exports.types.FILTERADD;
* @returns {Buffer} * @returns {Buffer}
*/ */
FilterAddPacket.prototype.toRaw = function toRaw(writer) { FilterAddPacket.prototype.toRaw = function toRaw() {
var bw = BufferWriter(writer); var bw = new BufferWriter();
bw.writeVarBytes(this.data); bw.writeVarBytes(this.data);
return bw.render();
if (!writer)
bw = bw.render();
return bw;
}; };
/** /**
@ -1785,8 +1774,8 @@ FilterClearPacket.prototype.type = exports.types.FILTERCLEAR;
* @returns {Buffer} * @returns {Buffer}
*/ */
FilterClearPacket.prototype.toRaw = function toRaw(writer) { FilterClearPacket.prototype.toRaw = function toRaw() {
return writer || DUMMY; return DUMMY;
}; };
/** /**
@ -1839,8 +1828,8 @@ MerkleBlockPacket.prototype.type = exports.types.MERKLEBLOCK;
* @returns {Buffer} * @returns {Buffer}
*/ */
MerkleBlockPacket.prototype.toRaw = function toRaw(writer) { MerkleBlockPacket.prototype.toRaw = function toRaw() {
return this.block.toRaw(writer); return this.block.toRaw();
}; };
/** /**
@ -1897,20 +1886,17 @@ GetUTXOsPacket.prototype.type = exports.types.GETUTXOS;
* @returns {Buffer} * @returns {Buffer}
*/ */
GetUTXOsPacket.prototype.toRaw = function toRaw(writer) { GetUTXOsPacket.prototype.toRaw = function toRaw() {
var bw = BufferWriter(writer); var bw = new BufferWriter();
var i; var i;
bw.writeU8(this.mempool ? 1 : 0); bw.writeU8(this.mempool ? 1 : 0);
bw.writeVarint(this.prevout.length); bw.writeVarint(this.prevout.length);
for (i = 0; i < this.prevout.length; i++) for (i = 0; i < this.prevout.length; i++)
this.prevout[i].toRaw(bw); this.prevout[i].toWriter(bw);
if (!writer) return bw.render();
bw = bw.render();
return bw;
}; };
/** /**
@ -1928,7 +1914,7 @@ GetUTXOsPacket.prototype.fromRaw = function fromRaw(data) {
count = br.readVarint(); count = br.readVarint();
for (i = 0; i < count; i++) for (i = 0; i < count; i++)
this.prevout.push(Outpoint.fromRaw(br)); this.prevout.push(Outpoint.fromReader(br));
return this; return this;
}; };
@ -2023,8 +2009,8 @@ UTXOsPacket.fromOptions = function fromOptions(options) {
* @returns {Buffer} * @returns {Buffer}
*/ */
UTXOsPacket.prototype.toRaw = function toRaw(writer) { UTXOsPacket.prototype.toRaw = function toRaw() {
var bw = BufferWriter(writer); var bw = new BufferWriter();
var map = new Buffer((this.hits.length + 7) / 8 | 0); var map = new Buffer((this.hits.length + 7) / 8 | 0);
var i, bit, oct, coin, height; var i, bit, oct, coin, height;
@ -2052,10 +2038,7 @@ UTXOsPacket.prototype.toRaw = function toRaw(writer) {
bw.writeVarBytes(coin.script.toRaw()); bw.writeVarBytes(coin.script.toRaw());
} }
if (!writer) return bw.render();
bw = bw.render();
return bw;
}; };
/** /**
@ -2089,7 +2072,7 @@ UTXOsPacket.prototype.fromRaw = function fromRaw(data) {
if (height === 0x7fffffff) if (height === 0x7fffffff)
height = -1; height = -1;
output = Output.fromRaw(br); output = Output.fromReader(br);
coin.version = version; coin.version = version;
coin.height = height; coin.height = height;
@ -2138,8 +2121,8 @@ HaveWitnessPacket.prototype.type = exports.types.HAVEWITNESS;
* @returns {Buffer} * @returns {Buffer}
*/ */
HaveWitnessPacket.prototype.toRaw = function toRaw(writer) { HaveWitnessPacket.prototype.toRaw = function toRaw() {
return writer || DUMMY; return DUMMY;
}; };
/** /**
@ -2192,15 +2175,10 @@ FeeFilterPacket.prototype.type = exports.types.FEEFILTER;
* @returns {Buffer} * @returns {Buffer}
*/ */
FeeFilterPacket.prototype.toRaw = function toRaw(writer) { FeeFilterPacket.prototype.toRaw = function toRaw() {
var bw = BufferWriter(writer); var bw = new BufferWriter();
bw.write64(this.rate); bw.write64(this.rate);
return bw.render();
if (!writer)
bw = bw.render();
return bw;
}; };
/** /**
@ -2258,16 +2236,11 @@ SendCmpctPacket.prototype.type = exports.types.SENDCMPCT;
* @returns {Buffer} * @returns {Buffer}
*/ */
SendCmpctPacket.prototype.toRaw = function toRaw(writer) { SendCmpctPacket.prototype.toRaw = function toRaw() {
var bw = BufferWriter(writer); var bw = new BufferWriter();
bw.writeU8(this.mode); bw.writeU8(this.mode);
bw.writeU64(this.version); bw.writeU64(this.version);
return bw.render();
if (!writer)
bw = bw.render();
return bw;
}; };
/** /**
@ -2326,10 +2299,10 @@ CmpctBlockPacket.prototype.type = exports.types.CMPCTBLOCK;
* @returns {Buffer} * @returns {Buffer}
*/ */
CmpctBlockPacket.prototype.toRaw = function toRaw(writer) { CmpctBlockPacket.prototype.toRaw = function toRaw() {
if (this.witness) if (this.witness)
return this.block.toRaw(writer); return this.block.toRaw();
return this.block.toNormal(writer); return this.block.toNormal();
}; };
/** /**
@ -2383,8 +2356,8 @@ GetBlockTxnPacket.prototype.type = exports.types.GETBLOCKTXN;
* @returns {Buffer} * @returns {Buffer}
*/ */
GetBlockTxnPacket.prototype.toRaw = function toRaw(writer) { GetBlockTxnPacket.prototype.toRaw = function toRaw() {
return this.request.toRaw(writer); return this.request.toRaw();
}; };
/** /**
@ -2441,10 +2414,10 @@ BlockTxnPacket.prototype.type = exports.types.BLOCKTXN;
* @returns {Buffer} * @returns {Buffer}
*/ */
BlockTxnPacket.prototype.toRaw = function toRaw(writer) { BlockTxnPacket.prototype.toRaw = function toRaw() {
if (this.witness) if (this.witness)
return this.response.toRaw(writer); return this.response.toRaw();
return this.response.toNormal(writer); return this.response.toNormal();
}; };
/** /**
@ -2501,16 +2474,11 @@ EncinitPacket.prototype.type = exports.types.ENCINIT;
* @returns {Buffer} * @returns {Buffer}
*/ */
EncinitPacket.prototype.toRaw = function toRaw(writer) { EncinitPacket.prototype.toRaw = function toRaw() {
var bw = BufferWriter(writer); var bw = new BufferWriter();
bw.writeBytes(this.publicKey); bw.writeBytes(this.publicKey);
bw.writeU8(this.cipher); bw.writeU8(this.cipher);
return bw.render();
if (!writer)
bw = bw.render();
return bw;
}; };
/** /**
@ -2566,15 +2534,10 @@ EncackPacket.prototype.type = exports.types.ENCACK;
* @returns {Buffer} * @returns {Buffer}
*/ */
EncackPacket.prototype.toRaw = function toRaw(writer) { EncackPacket.prototype.toRaw = function toRaw() {
var bw = BufferWriter(writer); var bw = new BufferWriter();
bw.writeBytes(this.publicKey); bw.writeBytes(this.publicKey);
return bw.render();
if (!writer)
bw = bw.render();
return bw;
}; };
/** /**
@ -2629,15 +2592,10 @@ AuthChallengePacket.prototype.type = exports.types.AUTHCHALLENGE;
* @returns {Buffer} * @returns {Buffer}
*/ */
AuthChallengePacket.prototype.toRaw = function toRaw(writer) { AuthChallengePacket.prototype.toRaw = function toRaw() {
var bw = BufferWriter(writer); var bw = new BufferWriter();
bw.writeBytes(this.hash); bw.writeBytes(this.hash);
return bw.render();
if (!writer)
bw = bw.render();
return bw;
}; };
/** /**
@ -2692,15 +2650,10 @@ AuthReplyPacket.prototype.type = exports.types.AUTHREPLY;
* @returns {Buffer} * @returns {Buffer}
*/ */
AuthReplyPacket.prototype.toRaw = function toRaw(writer) { AuthReplyPacket.prototype.toRaw = function toRaw() {
var bw = BufferWriter(writer); var bw = new BufferWriter();
bw.writeBytes(this.signature); bw.writeBytes(this.signature);
return bw.render();
if (!writer)
bw = bw.render();
return bw;
}; };
/** /**
@ -2755,15 +2708,10 @@ AuthProposePacket.prototype.type = exports.types.AUTHPROPOSE;
* @returns {Buffer} * @returns {Buffer}
*/ */
AuthProposePacket.prototype.toRaw = function toRaw(writer) { AuthProposePacket.prototype.toRaw = function toRaw() {
var bw = BufferWriter(writer); var bw = new BufferWriter();
bw.writeBytes(this.hash); bw.writeBytes(this.hash);
return bw.render();
if (!writer)
bw = bw.render();
return bw;
}; };
/** /**
@ -2820,15 +2768,10 @@ UnknownPacket.prototype.type = exports.types.UNKNOWN;
* @returns {Buffer} * @returns {Buffer}
*/ */
UnknownPacket.prototype.toRaw = function toRaw(writer) { UnknownPacket.prototype.toRaw = function toRaw() {
var bw = BufferWriter(writer); var bw = new BufferWriter();
bw.writeBytes(this.data); bw.writeBytes(this.data);
return bw.render();
if (!writer)
bw = bw.render();
return bw;
}; };
/** /**

View File

@ -52,6 +52,7 @@ function AbstractBlock(options) {
this.txs = null; this.txs = null;
this.mutable = false; this.mutable = false;
this.memory = false;
this._valid = null; this._valid = null;
this._validHeaders = null; this._validHeaders = null;
@ -165,20 +166,15 @@ AbstractBlock.prototype.hash = function hash(enc) {
* @returns {Buffer} * @returns {Buffer}
*/ */
AbstractBlock.prototype.abbr = function abbr(writer) { AbstractBlock.prototype.abbr = function abbr() {
var bw = BufferWriter(writer); var bw = new BufferWriter();
bw.writeU32(this.version); bw.writeU32(this.version);
bw.writeHash(this.prevBlock); bw.writeHash(this.prevBlock);
bw.writeHash(this.merkleRoot); bw.writeHash(this.merkleRoot);
bw.writeU32(this.ts); bw.writeU32(this.ts);
bw.writeU32(this.bits); bw.writeU32(this.bits);
bw.writeU32(this.nonce); bw.writeU32(this.nonce);
return bw.render();
if (!writer)
bw = bw.render();
return bw;
}; };
/** /**

View File

@ -176,11 +176,9 @@ Address.prototype.inspect = function inspect() {
*/ */
Address.prototype.fromRaw = function fromRaw(data) { Address.prototype.fromRaw = function fromRaw(data) {
var i, br, prefix, network, type, version, hash; var br = new BufferReader(data, true);
var i, prefix, network, type, version, hash;
assert(Buffer.isBuffer(data));
br = new BufferReader(data, true);
prefix = br.readU8(); prefix = br.readU8();
for (i = 0; i < networks.types.length; i++) { for (i = 0; i < networks.types.length; i++) {

View File

@ -43,7 +43,6 @@ function Block(options) {
this._raw = null; this._raw = null;
this._size = -1; this._size = -1;
this._witnessSize = -1; this._witnessSize = -1;
this._lastWitnessSize = 0;
if (options) if (options)
this.fromOptions(options); this.fromOptions(options);
@ -81,13 +80,8 @@ Block.fromOptions = function fromOptions(options) {
* @returns {Buffer} * @returns {Buffer}
*/ */
Block.prototype.toRaw = function toRaw(writer) { Block.prototype.toRaw = function toRaw() {
var raw = this.getRaw(); return this.getRaw().data;
if (writer) {
writer.writeBytes(raw);
return writer;
}
return raw;
}; };
/** /**
@ -95,51 +89,82 @@ Block.prototype.toRaw = function toRaw(writer) {
* @returns {Buffer} * @returns {Buffer}
*/ */
Block.prototype.toNormal = function toNormal(writer) { Block.prototype.toNormal = function toNormal() {
var raw; if (this.hasWitness())
if (!this.hasWitness()) { return this.frameNormal().data;
raw = this.getRaw(); return this.toRaw();
if (writer) {
writer.writeBytes(raw);
return writer;
}
return raw;
}
return this.frameNormal(writer);
}; };
/** /**
* Serialize the block. Include witnesses if present. * Serialize the block. Include witnesses if present.
* @returns {Buffer} * @param {BufferWriter} bw
*/ */
Block.prototype.toWitness = function toWitness(writer) { Block.prototype.toWriter = function toWriter(bw) {
return this.toRaw(writer); this.writeRaw(bw);
return bw;
};
/**
* Serialize the block, do not include witnesses.
* @param {BufferWriter} bw
*/
Block.prototype.toNormalWriter = function toNormalWriter(bw) {
if (this.hasWitness()) {
this.frameNormalWriter(bw);
return bw;
}
return this.toWriter(bw);
}; };
/** /**
* Get the raw block serialization. * Get the raw block serialization.
* Include witnesses if present. * Include witnesses if present.
* @returns {Buffer} * @private
* @returns {RawBlock}
*/ */
Block.prototype.getRaw = function getRaw() { Block.prototype.getRaw = function getRaw() {
var raw; var raw;
if (this.mutable) {
assert(!this._raw);
return this.frameNormal();
}
if (this._raw) { if (this._raw) {
assert(this._size > 0); assert(this._size > 0);
assert(this._witnessSize >= 0); assert(this._witnessSize >= 0);
this._lastWitnessSize = this._witnessSize; raw = new RawBlock(this._size, this._witnessSize);
return this._raw; raw.data = this._raw;
return raw;
} }
raw = this.frameWitness(); raw = this.frameWitness();
if (!this.mutable) { this._raw = raw.data;
this._size = raw.length; this._size = raw.total;
this._witnessSize = this._lastWitnessSize; this._witnessSize = raw.witness;
this._raw = raw;
} return raw;
};
/**
* Write the raw block serialization
* to a buffer writer. Include the
* witnesses if present.
* @returns {RawBlock}
*/
Block.prototype.writeRaw = function writeRaw(bw) {
var raw;
if (this.mutable)
return this.frameWitnessWriter(bw);
raw = this.getRaw();
bw.writeBytes(raw.data);
return raw; return raw;
}; };
@ -150,31 +175,9 @@ Block.prototype.getRaw = function getRaw() {
*/ */
Block.prototype.getSizes = function getSizes() { Block.prototype.getSizes = function getSizes() {
var sizes = new BlockSizes(); if (this.mutable)
var writer; return this.writeRaw(new BufferWriter());
return this.getRaw();
if (this._size !== -1) {
sizes.total = this._size;
sizes.witness = this._witnessSize;
return sizes;
}
if (!this.mutable) {
assert(!this._raw);
this.getRaw();
sizes.total = this._size;
sizes.witness = this._witnessSize;
return sizes;
}
writer = new BufferWriter();
this.toRaw(writer);
sizes.total = writer.written;
sizes.witness = this._lastWitnessSize;
return sizes;
}; };
/** /**
@ -224,13 +227,14 @@ Block.prototype.getBaseSize = function getBaseSize() {
*/ */
Block.prototype.hasWitness = function hasWitness() { Block.prototype.hasWitness = function hasWitness() {
var i; var i, tx;
if (this._witnessSize !== -1) if (this._witnessSize !== -1)
return this._witnessSize !== 0; return this._witnessSize !== 0;
for (i = 0; i < this.txs.length; i++) { for (i = 0; i < this.txs.length; i++) {
if (this.txs[i].hasWitness()) tx = this.txs[i];
if (tx.hasWitness())
return true; return true;
} }
@ -239,7 +243,7 @@ Block.prototype.hasWitness = function hasWitness() {
/** /**
* Add a transaction to the block's tx vector. * Add a transaction to the block's tx vector.
* @param {TX|NakedTX} tx * @param {TX} tx
* @returns {TX} * @returns {TX}
*/ */
@ -443,7 +447,7 @@ Block.prototype._verify = function _verify(ret) {
if (!this.verifyHeaders(ret)) if (!this.verifyHeaders(ret))
return false; return false;
// Check merkle root // Check merkle root.
merkle = this.createMerkleRoot('hex'); merkle = this.createMerkleRoot('hex');
// If the merkle is mutated, // If the merkle is mutated,
@ -460,6 +464,7 @@ Block.prototype._verify = function _verify(ret) {
return false; return false;
} }
// Check base size.
if (this.txs.length === 0 if (this.txs.length === 0
|| this.txs.length > constants.block.MAX_SIZE || this.txs.length > constants.block.MAX_SIZE
|| this.getBaseSize() > constants.block.MAX_SIZE) { || this.getBaseSize() > constants.block.MAX_SIZE) {
@ -468,29 +473,29 @@ Block.prototype._verify = function _verify(ret) {
return false; return false;
} }
// First TX must be a coinbase // First TX must be a coinbase.
if (this.txs.length === 0 || !this.txs[0].isCoinbase()) { if (this.txs.length === 0 || !this.txs[0].isCoinbase()) {
ret.reason = 'bad-cb-missing'; ret.reason = 'bad-cb-missing';
ret.score = 100; ret.score = 100;
return false; return false;
} }
// Test all txs // Test all transactions.
for (i = 0; i < this.txs.length; i++) { for (i = 0; i < this.txs.length; i++) {
tx = this.txs[i]; tx = this.txs[i];
// The rest of the txs must not be coinbases // The rest of the txs must not be coinbases.
if (i > 0 && tx.isCoinbase()) { if (i > 0 && tx.isCoinbase()) {
ret.reason = 'bad-cb-multiple'; ret.reason = 'bad-cb-multiple';
ret.score = 100; ret.score = 100;
return false; return false;
} }
// Sanity checks // Sanity checks.
if (!tx.isSane(ret)) if (!tx.isSane(ret))
return false; return false;
// Count legacy sigops (do not count scripthash or witness) // Count legacy sigops (do not count scripthash or witness).
sigops += tx.getLegacySigops(); sigops += tx.getLegacySigops();
if (sigops * scale > constants.block.MAX_SIGOPS_WEIGHT) { if (sigops * scale > constants.block.MAX_SIGOPS_WEIGHT) {
ret.reason = 'bad-blk-sigops'; ret.reason = 'bad-blk-sigops';
@ -685,9 +690,9 @@ Block.fromJSON = function fromJSON(json) {
* @param {Buffer} data * @param {Buffer} data
*/ */
Block.prototype.fromRaw = function fromRaw(data) { Block.prototype.fromReader = function fromReader(br) {
var br = BufferReader(data); var witnessSize = 0;
var i, tx, witnessSize; var i, tx;
br.start(); br.start();
@ -699,10 +704,8 @@ Block.prototype.fromRaw = function fromRaw(data) {
this.nonce = br.readU32(); this.nonce = br.readU32();
this.totalTX = br.readVarint(); this.totalTX = br.readVarint();
witnessSize = 0;
for (i = 0; i < this.totalTX; i++) { for (i = 0; i < this.totalTX; i++) {
tx = TX.fromRaw(br); tx = TX.fromReader(br);
witnessSize += tx._witnessSize; witnessSize += tx._witnessSize;
this.addTX(tx); this.addTX(tx);
} }
@ -716,6 +719,27 @@ Block.prototype.fromRaw = function fromRaw(data) {
return this; return this;
}; };
/**
* Inject properties from serialized data.
* @private
* @param {Buffer} data
*/
Block.prototype.fromRaw = function fromRaw(data) {
return this.fromReader(new BufferReader(data));
};
/**
* Instantiate a block from a serialized Buffer.
* @param {Buffer} data
* @param {String?} enc - Encoding, can be `'hex'` or null.
* @returns {Block}
*/
Block.fromReader = function fromReader(data) {
return new Block().fromReader(data);
};
/** /**
* Instantiate a block from a serialized Buffer. * Instantiate a block from a serialized Buffer.
* @param {Buffer} data * @param {Buffer} data
@ -749,9 +773,7 @@ Block.prototype.toMerkle = function toMerkle(filter) {
* @returns {Buffer} * @returns {Buffer}
*/ */
Block.prototype.frame = function frame(witness, writer) { Block.prototype.frameNormalWriter = function frameNormalWriter(bw) {
var bw = BufferWriter(writer);
var witnessSize = 0;
var i, tx; var i, tx;
bw.writeU32(this.version); bw.writeU32(this.version);
@ -764,20 +786,54 @@ Block.prototype.frame = function frame(witness, writer) {
for (i = 0; i < this.txs.length; i++) { for (i = 0; i < this.txs.length; i++) {
tx = this.txs[i]; tx = this.txs[i];
if (witness) { tx.toNormalWriter(bw);
tx.toRaw(bw);
witnessSize += tx._lastWitnessSize;
} else {
tx.toNormal(bw);
}
} }
this._lastWitnessSize = witnessSize; return new RawBlock(bw.written, 0);
};
if (!writer) /**
bw = bw.render(); * Serialze block with or without witness data.
* @private
* @param {Boolean} witness
* @param {BufferWriter?} writer
* @returns {Buffer}
*/
return bw; Block.prototype.frameWitnessWriter = function frameWitnessWriter(bw) {
var witnessSize = 0;
var i, tx, raw;
bw.writeU32(this.version);
bw.writeHash(this.prevBlock);
bw.writeHash(this.merkleRoot);
bw.writeU32(this.ts);
bw.writeU32(this.bits);
bw.writeU32(this.nonce);
bw.writeVarint(this.txs.length);
for (i = 0; i < this.txs.length; i++) {
tx = this.txs[i];
raw = tx.writeRaw(bw);
witnessSize += raw.witness;
}
return new RawBlock(bw.written, witnessSize);
};
/**
* Serialze block with or without witness data.
* @private
* @param {Boolean} witness
* @param {BufferWriter?} writer
* @returns {Buffer}
*/
Block.prototype.frameNormal = function frameNormal() {
var bw = new BufferWriter();
var raw = this.frameNormalWriter(bw);
raw.data = bw.render();
return raw;
}; };
/** /**
@ -787,19 +843,11 @@ Block.prototype.frame = function frame(witness, writer) {
* @returns {Buffer} * @returns {Buffer}
*/ */
Block.prototype.frameNormal = function frameNormal(writer) { Block.prototype.frameWitness = function frameWitness() {
return this.frame(false, writer); var bw = new BufferWriter();
}; var raw = this.frameWitnessWriter(bw);
raw.data = bw.render();
/** return raw;
* Serialze block with witness data.
* @private
* @param {BufferWriter?} writer
* @returns {Buffer}
*/
Block.prototype.frameWitness = function frameWitness(writer) {
return this.frame(true, writer);
}; };
/** /**
@ -827,9 +875,10 @@ Block.isBlock = function isBlock(obj) {
* Helpers * Helpers
*/ */
function BlockSizes() { function RawBlock(total, witness) {
this.total = 0; this.data = null;
this.witness = 0; this.total = total;
this.witness = witness;
} }
/* /*

View File

@ -194,13 +194,11 @@ Coin.prototype.fromJSON = function fromJSON(json) {
}; };
/** /**
* Serialize the coin. * Write the coin to a buffer writer.
* @param {String?} enc - Encoding, can be `'hex'` or null. * @param {BufferWriter} bw
* @returns {Buffer|String}
*/ */
Coin.prototype.toRaw = function toRaw(writer) { Coin.prototype.toWriter = function toWriter(bw) {
var bw = BufferWriter(writer);
var height = this.height; var height = this.height;
if (height === -1) if (height === -1)
@ -212,21 +210,25 @@ Coin.prototype.toRaw = function toRaw(writer) {
bw.writeVarBytes(this.script.toRaw()); bw.writeVarBytes(this.script.toRaw());
bw.writeU8(this.coinbase ? 1 : 0); bw.writeU8(this.coinbase ? 1 : 0);
if (!writer)
bw = bw.render();
return bw; return bw;
}; };
/** /**
* Inject properties from serialized data. * Serialize the coin.
* @private * @returns {Buffer|String}
* @param {Buffer} data
*/ */
Coin.prototype.fromRaw = function fromRaw(data) { Coin.prototype.toRaw = function toRaw() {
var br = BufferReader(data); return this.toWriter(new BufferWriter()).render();
};
/**
* Inject properties from serialized buffer writer.
* @private
* @param {BufferReader} br
*/
Coin.prototype.fromReader = function fromReader(br) {
this.version = br.readU32(); this.version = br.readU32();
this.height = br.readU32(); this.height = br.readU32();
this.value = br.read64(); this.value = br.read64();
@ -240,7 +242,27 @@ Coin.prototype.fromRaw = function fromRaw(data) {
}; };
/** /**
* Instantiate an coin from a serialized Buffer. * Inject properties from serialized data.
* @private
* @param {Buffer} data
*/
Coin.prototype.fromRaw = function fromRaw(data) {
return this.fromReader(new BufferReader(data));
};
/**
* Instantiate a coin from a buffer reader.
* @param {BufferReader} br
* @returns {Coin}
*/
Coin.fromReader = function fromReader(br) {
return new Coin().fromReader(br);
};
/**
* Instantiate a coin from a serialized Buffer.
* @param {Buffer} data * @param {Buffer} data
* @param {String?} enc - Encoding, can be `'hex'` or null. * @param {String?} enc - Encoding, can be `'hex'` or null.
* @returns {Coin} * @returns {Coin}
@ -260,6 +282,7 @@ Coin.fromRaw = function fromRaw(data, enc) {
Coin.prototype.fromTX = function fromTX(tx, index) { Coin.prototype.fromTX = function fromTX(tx, index) {
assert(util.isNumber(index)); assert(util.isNumber(index));
assert(index < tx.outputs.length);
this.version = tx.version; this.version = tx.version;
this.height = tx.height; this.height = tx.height;
this.value = tx.outputs[index].value; this.value = tx.outputs[index].value;

View File

@ -47,42 +47,15 @@ Headers.prototype._verify = function _verify(ret) {
*/ */
Headers.prototype.getSize = function getSize() { Headers.prototype.getSize = function getSize() {
var writer = new BufferWriter(); return this.toWriter(new BufferWriter()).written;
this.toRaw(writer);
return writer.written;
}; };
/** /**
* Inspect the headers and return a more * Serialize the headers to a buffer writer.
* user-friendly representation of the data. * @param {BufferWriter} bw
* @returns {Object}
*/ */
Headers.prototype.inspect = function inspect() { Headers.prototype.toWriter = function toWriter(bw) {
return {
type: 'headers',
hash: this.rhash(),
height: this.height,
date: util.date(this.ts),
version: util.hex32(this.version),
prevBlock: util.revHex(this.prevBlock),
merkleRoot: util.revHex(this.merkleRoot),
ts: this.ts,
bits: this.bits,
nonce: this.nonce,
totalTX: this.totalTX
};
};
/**
* Serialize the headers.
* @param {String?} enc - Encoding, can be `'hex'` or null.
* @returns {Buffer|String}
*/
Headers.prototype.toRaw = function toRaw(writer) {
var bw = BufferWriter(writer);
bw.writeU32(this.version); bw.writeU32(this.version);
bw.writeHash(this.prevBlock); bw.writeHash(this.prevBlock);
bw.writeHash(this.merkleRoot); bw.writeHash(this.merkleRoot);
@ -90,13 +63,35 @@ Headers.prototype.toRaw = function toRaw(writer) {
bw.writeU32(this.bits); bw.writeU32(this.bits);
bw.writeU32(this.nonce); bw.writeU32(this.nonce);
bw.writeVarint(this.totalTX); bw.writeVarint(this.totalTX);
if (!writer)
bw = bw.render();
return bw; return bw;
}; };
/**
* Serialize the headers.
* @returns {Buffer|String}
*/
Headers.prototype.toRaw = function toRaw() {
return this.toWriter(new BufferWriter()).render();
};
/**
* Inject properties from buffer reader.
* @private
* @param {Buffer} data
*/
Headers.prototype.fromReader = function fromReader(br) {
this.version = br.readU32(); // Technically signed
this.prevBlock = br.readHash('hex');
this.merkleRoot = br.readHash('hex');
this.ts = br.readU32();
this.bits = br.readU32();
this.nonce = br.readU32();
this.totalTX = br.readVarint();
return this;
};
/** /**
* Inject properties from serialized data. * Inject properties from serialized data.
* @private * @private
@ -104,17 +99,17 @@ Headers.prototype.toRaw = function toRaw(writer) {
*/ */
Headers.prototype.fromRaw = function fromRaw(data) { Headers.prototype.fromRaw = function fromRaw(data) {
var br = BufferReader(data); return this.fromReader(new BufferReader(data));
};
this.version = br.readU32(); // Technically signed /**
this.prevBlock = br.readHash('hex'); * Instantiate headers from buffer reader.
this.merkleRoot = br.readHash('hex'); * @param {BufferReader} br
this.ts = br.readU32(); * @returns {Headers}
this.bits = br.readU32(); */
this.nonce = br.readU32();
this.totalTX = br.readVarint();
return this; Headers.fromReader = function fromReader(br) {
return new Headers().fromReader(br);
}; };
/** /**
@ -131,24 +126,41 @@ Headers.fromRaw = function fromRaw(data, enc) {
}; };
/** /**
* Inject properties from serialized data. * Inject properties from buffer reader.
* @private * @private
* @param {Buffer} data * @param {BufferReader} br
*/ */
Headers.prototype.fromAbbr = function fromAbbr(data) { Headers.prototype.fromAbbrReader = function fromAbbrReader(br) {
var br = BufferReader(data);
this.version = br.readU32(); // Technically signed this.version = br.readU32(); // Technically signed
this.prevBlock = br.readHash('hex'); this.prevBlock = br.readHash('hex');
this.merkleRoot = br.readHash('hex'); this.merkleRoot = br.readHash('hex');
this.ts = br.readU32(); this.ts = br.readU32();
this.bits = br.readU32(); this.bits = br.readU32();
this.nonce = br.readU32(); this.nonce = br.readU32();
return this; return this;
}; };
/**
* Inject properties from serialized data.
* @private
* @param {Buffer} data
*/
Headers.prototype.fromAbbr = function fromAbbr(data) {
return this.fromAbbrReader(new BufferReader(data));
};
/**
* Instantiate headers from buffer reader.
* @param {BufferReader} br
* @returns {Headers}
*/
Headers.fromAbbrReader = function fromAbbrReader(br) {
return new Headers().fromAbbrReader(br);
};
/** /**
* Instantiate headers from serialized data. * Instantiate headers from serialized data.
* @param {Buffer} data * @param {Buffer} data
@ -197,6 +209,27 @@ Headers.fromBlock = function fromBlock(block) {
return headers; return headers;
}; };
/**
* Inspect the headers and return a more
* user-friendly representation of the data.
* @returns {Object}
*/
Headers.prototype.inspect = function inspect() {
return {
hash: this.rhash(),
height: this.height,
date: util.date(this.ts),
version: util.hex32(this.version),
prevBlock: util.revHex(this.prevBlock),
merkleRoot: util.revHex(this.merkleRoot),
ts: this.ts,
bits: this.bits,
nonce: this.nonce,
totalTX: this.totalTX
};
};
/** /**
* Test an object to see if it is a Headers object. * Test an object to see if it is a Headers object.
* @param {Object} obj * @param {Object} obj

View File

@ -316,32 +316,52 @@ Input.fromJSON = function fromJSON(json) {
* @returns {Buffer|String} * @returns {Buffer|String}
*/ */
Input.prototype.toRaw = function toRaw(writer) { Input.prototype.toRaw = function toRaw() {
var bw = BufferWriter(writer); return this.toWriter(new BufferWriter()).render();
};
this.prevout.toRaw(bw); /**
* Write the input to a buffer writer.
* @param {BufferWriter} bw
*/
Input.prototype.toWriter = function toWriter(bw) {
this.prevout.toWriter(bw);
bw.writeVarBytes(this.script.toRaw()); bw.writeVarBytes(this.script.toRaw());
bw.writeU32(this.sequence); bw.writeU32(this.sequence);
if (!writer)
bw = bw.render();
return bw; return bw;
}; };
/**
* Inject properties from buffer reader.
* @private
* @param {BufferReader} br
*/
Input.prototype.fromReader = function fromReader(br) {
this.prevout.fromReader(br);
this.script.fromRaw(br.readVarBytes());
this.sequence = br.readU32();
return this;
};
/** /**
* Inject properties from serialized data. * Inject properties from serialized data.
* @param {Buffer} data * @param {Buffer} data
*/ */
Input.prototype.fromRaw = function fromRaw(data) { Input.prototype.fromRaw = function fromRaw(data) {
var br = BufferReader(data); return this.fromReader(new BufferReader(data));
};
this.prevout.fromRaw(br); /**
this.script.fromRaw(br.readVarBytes()); * Instantiate an input from a buffer reader.
this.sequence = br.readU32(); * @param {BufferReader} br
* @returns {Input}
*/
return this; Input.fromReader = function fromReader(br) {
return new Input().fromReader(br);
}; };
/** /**
@ -357,52 +377,6 @@ Input.fromRaw = function fromRaw(data, enc) {
return new Input().fromRaw(data); return new Input().fromRaw(data);
}; };
/**
* Serialize the input to an "extended" format,
* including both the input and the witness.
* @param {String?} enc - Encoding, can be `'hex'` or null.
* @returns {Buffer|String}
*/
Input.prototype.toExtended = function toExtended(writer) {
var bw = BufferWriter(writer);
this.toRaw(bw);
this.witness.toRaw(bw);
if (!writer)
bw = bw.render();
return bw;
};
/**
* Inject properties from extended serialized data.
* @private
* @param {Buffer} data
*/
Input.prototype.fromExtended = function fromExtended(data) {
var br = BufferReader(data);
this.fromRaw(br);
this.witness.fromRaw(br);
return this;
};
/**
* Instantiate an input from a Buffer
* in "extended" serialization format.
* @param {Buffer} data
* @param {String?} enc - Encoding, can be `'hex'` or null.
* @returns {TX}
*/
Input.fromExtended = function fromExtended(data, enc) {
if (typeof data === 'string')
data = new Buffer(data, enc);
return new Input().fromExtended(data);
};
/** /**
* Inject properties from coin. * Inject properties from coin.
* @private * @private

View File

@ -27,21 +27,36 @@ function InvItem(type, hash) {
this.hash = hash; this.hash = hash;
} }
/**
* Write inv item to buffer writer.
* @param {BufferWriter} bw
*/
InvItem.prototype.toWriter = function toWriter(bw) {
bw.writeU32(this.type);
bw.writeHash(this.hash);
return bw;
};
/** /**
* Serialize inv item. * Serialize inv item.
* @returns {Buffer} * @returns {Buffer}
*/ */
InvItem.prototype.toRaw = function toRaw(writer) { InvItem.prototype.toRaw = function toRaw() {
var bw = BufferWriter(writer); return this.toWriter(new BufferWriter()).render();
};
bw.writeU32(this.type); /**
bw.writeHash(this.hash); * Inject properties from buffer reader.
* @private
* @param {BufferReader} br
*/
if (!writer) InvItem.prototype.fromReader = function fromReader(br) {
bw = bw.render(); this.type = br.readU32();
this.hash = br.readHash('hex');
return bw; return this;
}; };
/** /**
@ -50,10 +65,17 @@ InvItem.prototype.toRaw = function toRaw(writer) {
*/ */
InvItem.prototype.fromRaw = function fromRaw(data) { InvItem.prototype.fromRaw = function fromRaw(data) {
var br = BufferReader(data); return this.fromReader(new BufferReader(data));
this.type = br.readU32(); };
this.hash = br.readHash('hex');
return this; /**
* Instantiate inv item from buffer reader.
* @param {BufferReader} br
* @returns {InvItem}
*/
InvItem.fromReader = function fromReader(br) {
return new InvItem().fromReader(br);
}; };
/** /**

View File

@ -811,12 +811,11 @@ KeyRing.fromJSON = function fromJSON(json) {
}; };
/** /**
* Serialize the keyring. * Write the keyring to a buffer writer.
* @returns {Buffer} * @param {BufferWriter} bw
*/ */
KeyRing.prototype.toRaw = function toRaw(writer) { KeyRing.prototype.toWriter = function toWriter(bw) {
var bw = new BufferWriter(writer);
var field = 0; var field = 0;
if (this.witness) if (this.witness)
@ -839,20 +838,26 @@ KeyRing.prototype.toRaw = function toRaw(writer) {
else else
bw.writeVarint(0); bw.writeVarint(0);
if (!writer)
bw = bw.render();
return bw; return bw;
}; };
/** /**
* Inject properties from serialized data. * Serialize the keyring.
* @private * @returns {Buffer}
* @param {Buffer} data
*/ */
KeyRing.prototype.fromRaw = function fromRaw(data, network) { KeyRing.prototype.toRaw = function toRaw() {
var br = new BufferReader(data); return this.toWriter(new BufferWriter()).render();
};
/**
* Inject properties from buffer reader.
* @private
* @param {BufferReader} br
* @param {Network?} network
*/
KeyRing.prototype.fromReader = function fromReader(br, network) {
var field, compressed, key, script; var field, compressed, key, script;
this.network = Network.get(network); this.network = Network.get(network);
@ -881,6 +886,27 @@ KeyRing.prototype.fromRaw = function fromRaw(data, network) {
return this; return this;
}; };
/**
* Inject properties from serialized data.
* @private
* @param {Buffer} data
* @param {Network?} network
*/
KeyRing.prototype.fromRaw = function fromRaw(data, network) {
return this.fromReader(new BufferReader(data), network);
};
/**
* Instantiate a keyring from buffer reader.
* @param {BufferReader} br
* @returns {KeyRing}
*/
KeyRing.fromReader = function fromReader(br) {
return new KeyRing().fromReader(br);
};
/** /**
* Instantiate a keyring from serialized data. * Instantiate a keyring from serialized data.
* @param {Buffer} data * @param {Buffer} data

View File

@ -83,15 +83,8 @@ MemBlock.fromOptions = function fromOptions(options) {
* @returns {Buffer} * @returns {Buffer}
*/ */
MemBlock.prototype.abbr = function abbr(writer) { MemBlock.prototype.abbr = function abbr() {
var data = this.raw.slice(0, 80); return this.raw.slice(0, 80);
if (writer) {
writer.writeBytes(data);
return writer;
}
return data;
}; };
/** /**
@ -132,7 +125,7 @@ MemBlock.prototype.getCoinbaseHeight = function getCoinbaseHeight() {
*/ */
MemBlock.prototype.fromRaw = function fromRaw(data) { MemBlock.prototype.fromRaw = function fromRaw(data) {
var br = BufferReader(data, true); var br = new BufferReader(data, true);
var height = -1; var height = -1;
var inCount, input; var inCount, input;

View File

@ -94,14 +94,12 @@ MerkleBlock.fromOptions = function fromOptions(data) {
*/ */
MerkleBlock.prototype.getSize = function getSize() { MerkleBlock.prototype.getSize = function getSize() {
var writer = new BufferWriter(); return this.toWriter(new BufferWriter()).written;
this.toRaw(writer);
return writer.written;
}; };
/** /**
* Add a transaction to the block's tx vector. * Add a transaction to the block's tx vector.
* @param {TX|NakedTX} tx * @param {TX} tx
* @returns {TX} * @returns {TX}
*/ */
@ -338,13 +336,11 @@ MerkleBlock.prototype.inspect = function inspect() {
}; };
/** /**
* Serialize the merkleblock. * Write the merkleblock to a buffer writer.
* @param {String?} enc - Encoding, can be `'hex'` or null. * @param {BufferWriter} bw
* @returns {Buffer|String}
*/ */
MerkleBlock.prototype.toRaw = function toRaw(writer) { MerkleBlock.prototype.toWriter = function toWriter(bw) {
var bw = BufferWriter(writer);
var i; var i;
bw.writeU32(this.version); bw.writeU32(this.version);
@ -362,20 +358,26 @@ MerkleBlock.prototype.toRaw = function toRaw(writer) {
bw.writeVarBytes(this.flags); bw.writeVarBytes(this.flags);
if (!writer)
bw = bw.render();
return bw; return bw;
}; };
/** /**
* Inject properties from serialized data. * Serialize the merkleblock.
* @private * @param {String?} enc - Encoding, can be `'hex'` or null.
* @param {Buffer} data * @returns {Buffer|String}
*/ */
MerkleBlock.prototype.fromRaw = function fromRaw(data) { MerkleBlock.prototype.toRaw = function toRaw() {
var br = BufferReader(data); return this.toWriter(new BufferWriter()).render();
};
/**
* Inject properties from buffer reader.
* @private
* @param {BufferReader} br
*/
MerkleBlock.prototype.fromReader = function fromReader(br) {
var i, count; var i, count;
this.version = br.readU32(); this.version = br.readU32();
@ -396,6 +398,26 @@ MerkleBlock.prototype.fromRaw = function fromRaw(data) {
return this; return this;
}; };
/**
* Inject properties from serialized data.
* @private
* @param {Buffer} data
*/
MerkleBlock.prototype.fromRaw = function fromRaw(data) {
return this.fromReader(new BufferReader(data));
};
/**
* Instantiate a merkleblock from a buffer reader.
* @param {BufferReader} br
* @returns {MerkleBlock}
*/
MerkleBlock.fromReader = function fromReader(br) {
return new MerkleBlock().fromReader(br);
};
/** /**
* Instantiate a merkleblock from a serialized data. * Instantiate a merkleblock from a serialized data.
* @param {Buffer} data * @param {Buffer} data

View File

@ -1386,6 +1386,14 @@ MTX.fromJSON = function fromJSON(json) {
return new MTX().fromJSON(JSON)._mutable(); return new MTX().fromJSON(JSON)._mutable();
}; };
/**
* @see TX.fromReader
*/
MTX.fromReader = function fromReader(br) {
return new MTX().fromReader(br)._mutable();
};
/** /**
* @see TX.fromRaw * @see TX.fromRaw
*/ */

View File

@ -247,15 +247,13 @@ NetworkAddress.fromSocket = function fromSocket(hostname, network) {
}; };
/** /**
* Inject properties from serialized data. * Inject properties from buffer reader.
* @private * @private
* @param {Buffer} data * @param {BufferReader} br
* @param {Boolean?} full - Include timestamp. * @param {Boolean?} full - Include timestamp.
*/ */
NetworkAddress.prototype.fromRaw = function fromRaw(data, full) { NetworkAddress.prototype.fromReader = function fromReader(br, full) {
var br = BufferReader(data);
// only version >= 31402 // only version >= 31402
this.ts = full ? br.readU32() : 0; this.ts = full ? br.readU32() : 0;
this.services = br.readU53(); this.services = br.readU53();
@ -267,6 +265,28 @@ NetworkAddress.prototype.fromRaw = function fromRaw(data, full) {
return this; return this;
}; };
/**
* Inject properties from serialized data.
* @private
* @param {Buffer} data
* @param {Boolean?} full - Include timestamp.
*/
NetworkAddress.prototype.fromRaw = function fromRaw(data, full) {
return this.fromReader(new BufferReader(data), full);
};
/**
* Insantiate a network address from buffer reader.
* @param {BufferReader} br
* @param {Boolean?} full - Include timestamp.
* @returns {NetworkAddress}
*/
NetworkAddress.fromReader = function fromReader(br, full) {
return new NetworkAddress().fromReader(br, full);
};
/** /**
* Insantiate a network address from serialized data. * Insantiate a network address from serialized data.
* @param {Buffer} data * @param {Buffer} data
@ -279,14 +299,13 @@ NetworkAddress.fromRaw = function fromRaw(data, full) {
}; };
/** /**
* Serialize network address. * Write network address to a buffer writer.
* @param {Boolean} full - Include timestamp. * @param {BufferWriter} bw
* @param {Boolean?} full - Include timestamp.
* @returns {Buffer} * @returns {Buffer}
*/ */
NetworkAddress.prototype.toRaw = function toRaw(full, writer) { NetworkAddress.prototype.toWriter = function toWriter(bw, full) {
var bw = BufferWriter(writer);
if (full) if (full)
bw.writeU32(this.ts); bw.writeU32(this.ts);
@ -294,12 +313,19 @@ NetworkAddress.prototype.toRaw = function toRaw(full, writer) {
bw.writeBytes(IP.toBuffer(this.host)); bw.writeBytes(IP.toBuffer(this.host));
bw.writeU16BE(this.port); bw.writeU16BE(this.port);
if (!writer)
bw = bw.render();
return bw; return bw;
}; };
/**
* Serialize network address.
* @param {Boolean?} full - Include timestamp.
* @returns {Buffer}
*/
NetworkAddress.prototype.toRaw = function toRaw(full) {
return this.toWriter(new BufferWriter(), full).render();
};
/* /*
* Expose * Expose
*/ */

View File

@ -64,21 +64,36 @@ Outpoint.prototype.isNull = function isNull() {
return this.index === 0xffffffff && this.hash === constants.NULL_HASH; return this.index === 0xffffffff && this.hash === constants.NULL_HASH;
}; };
/**
* Write outpoint to a buffer writer.
* @param {BufferWriter} bw
*/
Outpoint.prototype.toWriter = function toWriter(bw) {
bw.writeHash(this.hash);
bw.writeU32(this.index);
return bw;
};
/** /**
* Serialize outpoint. * Serialize outpoint.
* @returns {Buffer} * @returns {Buffer}
*/ */
Outpoint.prototype.toRaw = function toRaw(writer) { Outpoint.prototype.toRaw = function toRaw() {
var bw = BufferWriter(writer); return this.toWriter(new BufferWriter()).render();
};
bw.writeHash(this.hash); /**
bw.writeU32(this.index); * Inject properties from buffer reader.
* @private
* @param {BufferReader} br
*/
if (!writer) Outpoint.prototype.fromReader = function fromReader(br) {
bw = bw.render(); this.hash = br.readHash('hex');
this.index = br.readU32();
return bw; return this;
}; };
/** /**
@ -88,10 +103,17 @@ Outpoint.prototype.toRaw = function toRaw(writer) {
*/ */
Outpoint.prototype.fromRaw = function fromRaw(data) { Outpoint.prototype.fromRaw = function fromRaw(data) {
var br = BufferReader(data); return this.fromReader(new BufferReader(data));
this.hash = br.readHash('hex'); };
this.index = br.readU32();
return this; /**
* Instantiate outpoint from a buffer reader.
* @param {BufferReader} br
* @returns {Outpoint}
*/
Outpoint.fromReader = function fromReader(br) {
return new Outpoint().fromReader(br);
}; };
/** /**

View File

@ -181,7 +181,7 @@ Output.prototype.getDustThreshold = function getDustThreshold(rate) {
*/ */
Output.prototype.getSize = function getSize() { Output.prototype.getSize = function getSize() {
return this.toRaw(BufferWriter()).written; return this.toWriter(new BufferWriter()).written;
}; };
/** /**
@ -217,22 +217,37 @@ Output.fromJSON = function fromJSON(json) {
return new Output().fromJSON(json); return new Output().fromJSON(json);
}; };
/**
* Write the output to a buffer writer.
* @param {BufferWriter} bw
*/
Output.prototype.toWriter = function toWriter(bw) {
bw.write64(this.value);
bw.writeVarBytes(this.script.toRaw());
return bw;
};
/** /**
* Serialize the output. * Serialize the output.
* @param {String?} enc - Encoding, can be `'hex'` or null. * @param {String?} enc - Encoding, can be `'hex'` or null.
* @returns {Buffer|String} * @returns {Buffer|String}
*/ */
Output.prototype.toRaw = function toRaw(writer) { Output.prototype.toRaw = function toRaw() {
var bw = BufferWriter(writer); return this.toWriter(new BufferWriter()).render();
};
bw.write64(this.value); /**
bw.writeVarBytes(this.script.toRaw()); * Inject properties from buffer reader.
* @private
* @param {BufferReader} br
*/
if (!writer) Output.prototype.fromReader = function fromReader(br) {
bw = bw.render(); this.value = br.read64();
this.script.fromRaw(br.readVarBytes());
return bw; return this;
}; };
/** /**
@ -242,12 +257,17 @@ Output.prototype.toRaw = function toRaw(writer) {
*/ */
Output.prototype.fromRaw = function fromRaw(data) { Output.prototype.fromRaw = function fromRaw(data) {
var br = BufferReader(data); return this.fromReader(new BufferReader(data));
};
this.value = br.read64(); /**
this.script.fromRaw(br.readVarBytes()); * Instantiate an output from a buffer reader.
* @param {BufferReader} br
* @returns {Output}
*/
return this; Output.fromReader = function fromReader(br) {
return new Output().fromReader(br);
}; };
/** /**
@ -260,7 +280,6 @@ Output.prototype.fromRaw = function fromRaw(data) {
Output.fromRaw = function fromRaw(data, enc) { Output.fromRaw = function fromRaw(data, enc) {
if (typeof data === 'string') if (typeof data === 'string')
data = new Buffer(data, enc); data = new Buffer(data, enc);
return new Output().fromRaw(data); return new Output().fromRaw(data);
}; };

View File

@ -9,13 +9,13 @@
var assert = require('assert'); var assert = require('assert');
var util = require('../utils/util'); var util = require('../utils/util');
var co = require('../utils/co');
var crypto = require('../crypto/crypto'); var crypto = require('../crypto/crypto');
var btcutils = require('../btc/utils'); var btcutils = require('../btc/utils');
var Amount = require('../btc/amount'); var Amount = require('../btc/amount');
var constants = require('../protocol/constants'); var constants = require('../protocol/constants');
var Network = require('../protocol/network'); var Network = require('../protocol/network');
var Script = require('../script/script'); var Script = require('../script/script');
var Stack = require('../script/stack');
var BufferWriter = require('../utils/writer'); var BufferWriter = require('../utils/writer');
var VerifyResult = require('../btc/errors').VerifyResult; var VerifyResult = require('../btc/errors').VerifyResult;
var Input = require('./input'); var Input = require('./input');
@ -92,7 +92,6 @@ function TX(options) {
this._raw = null; this._raw = null;
this._size = -1; this._size = -1;
this._witnessSize = -1; this._witnessSize = -1;
this._lastWitnessSize = 0;
this._outputValue = -1; this._outputValue = -1;
this._inputValue = -1; this._inputValue = -1;
@ -253,17 +252,11 @@ TX.prototype.hash = function _hash(enc) {
TX.prototype.witnessHash = function witnessHash(enc) { TX.prototype.witnessHash = function witnessHash(enc) {
var hash = this._whash; var hash = this._whash;
if (this.isCoinbase()) {
return enc === 'hex'
? constants.NULL_HASH
: util.copy(constants.ZERO_HASH);
}
if (!this.hasWitness()) if (!this.hasWitness())
return this.hash(enc); return this.hash(enc);
if (!hash) { if (!hash) {
hash = crypto.hash256(this.toWitness()); hash = crypto.hash256(this.toRaw());
if (!this.mutable) if (!this.mutable)
this._whash = hash; this._whash = hash;
} }
@ -279,13 +272,8 @@ TX.prototype.witnessHash = function witnessHash(enc) {
* @returns {Buffer} Serialized transaction. * @returns {Buffer} Serialized transaction.
*/ */
TX.prototype.toRaw = function toRaw(writer) { TX.prototype.toRaw = function toRaw() {
var raw = this.getRaw(); return this.getRaw().data;
if (writer) {
writer.writeBytes(raw);
return writer;
}
return raw;
}; };
/** /**
@ -295,27 +283,34 @@ TX.prototype.toRaw = function toRaw(writer) {
* @returns {Buffer} Serialized transaction. * @returns {Buffer} Serialized transaction.
*/ */
TX.prototype.toNormal = function toNormal(writer) { TX.prototype.toNormal = function toNormal() {
var raw = this.getRaw(); if (this.hasWitness())
if (!TX.isWitness(raw)) { return this.frameNormal().data;
if (writer) { return this.toRaw();
writer.writeBytes(raw);
return writer;
}
return raw;
}
return this.frameNormal(writer);
}; };
/** /**
* Serialize the transaction with the * Write the transaction to a buffer writer.
* witness vector. Will use normal * @param {BufferWriter} bw
* serialization if witness vector is empty.
* @returns {Buffer} Serialized transaction.
*/ */
TX.prototype.toWitness = function toWitness(writer) { TX.prototype.toWriter = function toWriter(bw) {
return this.toRaw(writer); this.writeRaw(bw);
return bw;
};
/**
* Write the transaction to a buffer writer.
* Uses non-witness serialization.
* @param {BufferWriter} bw
*/
TX.prototype.toNormalWriter = function toNormalWriter(bw) {
if (this.hasWitness()) {
this.frameNormalWriter(bw);
return bw;
}
return this.toWriter(bw);
}; };
/** /**
@ -323,17 +318,26 @@ TX.prototype.toWitness = function toWitness(writer) {
* that this is cached. This will use * that this is cached. This will use
* the witness serialization if a * the witness serialization if a
* witness is present. * witness is present.
* @returns {Buffer} Serialized transaction. * @private
* @returns {RawTX}
*/ */
TX.prototype.getRaw = function getRaw() { TX.prototype.getRaw = function getRaw() {
var raw; var raw;
if (this.mutable) {
assert(!this._raw);
if (this.hasWitness())
return this.frameWitness();
return this.frameNormal();
}
if (this._raw) { if (this._raw) {
assert(this._size > 0); assert(this._size > 0);
assert(this._witnessSize >= 0); assert(this._witnessSize >= 0);
this._lastWitnessSize = this._witnessSize; raw = new RawTX(this._size, this._witnessSize);
return this._raw; raw.data = this._raw;
return raw;
} }
if (this.hasWitness()) if (this.hasWitness())
@ -341,39 +345,43 @@ TX.prototype.getRaw = function getRaw() {
else else
raw = this.frameNormal(); raw = this.frameNormal();
if (!this.mutable) { this._raw = raw.data;
this._raw = raw; this._size = raw.total;
this._size = raw.length; this._witnessSize = raw.witness;
this._witnessSize = this._lastWitnessSize;
}
return raw; return raw;
}; };
/** /**
* Calculate real size and size of the witness bytes. * Write raw transaction to buffer writer.
* @returns {Object} Contains `size` and `witnessSize`. * Cache if possible.
* @returns {RawTX}
*/
TX.prototype.writeRaw = function writeRaw(bw) {
var raw;
if (this.mutable) {
if (this.hasWitness())
return this.frameWitnessWriter(bw);
return this.frameNormalWriter(bw);
}
raw = this.getRaw();
bw.writeBytes(raw.data);
return raw;
};
/**
* Calculate total size and size of the witness bytes.
* @returns {Object} Contains `total` and `witness`.
*/ */
TX.prototype.getSizes = function getSizes() { TX.prototype.getSizes = function getSizes() {
var sizes = new TXSizes(); if (this.mutable)
var writer; return this.writeRaw(new BufferWriter());
return this.getRaw();
if (this.mutable) {
assert(!this._raw);
writer = new BufferWriter();
this.toRaw(writer);
sizes.total = writer.written;
sizes.witness = this._lastWitnessSize;
return sizes;
}
this.getRaw();
sizes.total = this._size;
sizes.witness = this._witnessSize;
return sizes;
}; };
/** /**
@ -394,9 +402,9 @@ TX.prototype.getVirtualSize = function getVirtualSize() {
*/ */
TX.prototype.getWeight = function getWeight() { TX.prototype.getWeight = function getWeight() {
var sizes = this.getSizes(); var raw = this.getSizes();
var base = sizes.total - sizes.witness; var base = raw.total - raw.witness;
return base * (constants.WITNESS_SCALE_FACTOR - 1) + sizes.total; return base * (constants.WITNESS_SCALE_FACTOR - 1) + raw.total;
}; };
/** /**
@ -417,8 +425,8 @@ TX.prototype.getSize = function getSize() {
*/ */
TX.prototype.getBaseSize = function getBaseSize() { TX.prototype.getBaseSize = function getBaseSize() {
var sizes = this.getSizes(); var raw = this.getSizes();
return sizes.total - sizes.witness; return raw.total - raw.witness;
}; };
/** /**
@ -427,13 +435,14 @@ TX.prototype.getBaseSize = function getBaseSize() {
*/ */
TX.prototype.hasWitness = function hasWitness() { TX.prototype.hasWitness = function hasWitness() {
var i; var i, input;
if (this._witnessSize !== -1) if (this._witnessSize !== -1)
return this._witnessSize !== 0; return this._witnessSize !== 0;
for (i = 0; i < this.inputs.length; i++) { for (i = 0; i < this.inputs.length; i++) {
if (this.inputs[i].witness.items.length > 0) input = this.inputs[i];
if (input.witness.items.length > 0)
return true; return true;
} }
@ -452,9 +461,6 @@ TX.prototype.hasWitness = function hasWitness() {
*/ */
TX.prototype.signatureHash = function signatureHash(index, prev, type, version) { TX.prototype.signatureHash = function signatureHash(index, prev, type, version) {
if (typeof index !== 'number')
index = this.inputs.indexOf(index);
if (typeof type === 'string') if (typeof type === 'string')
type = constants.hashType[type.toUpperCase()]; type = constants.hashType[type.toUpperCase()];
@ -506,8 +512,7 @@ TX.prototype.signatureHashV0 = function signatureHashV0(index, prev, type) {
input = this.inputs[index]; input = this.inputs[index];
// Outpoint. // Outpoint.
bw.writeHash(input.prevout.hash); input.prevout.toWriter(bw);
bw.writeU32(input.prevout.index);
// Replace script with previous // Replace script with previous
// output script if current index. // output script if current index.
@ -519,8 +524,7 @@ TX.prototype.signatureHashV0 = function signatureHashV0(index, prev, type) {
input = this.inputs[i]; input = this.inputs[i];
// Outpoint. // Outpoint.
bw.writeHash(input.prevout.hash); input.prevout.toWriter(bw);
bw.writeU32(input.prevout.index);
// Replace script with previous // Replace script with previous
// output script if current index. // output script if current index.
@ -606,7 +610,7 @@ TX.prototype.signatureHashV1 = function signatureHashV1(index, prev, type) {
for (i = 0; i < this.inputs.length; i++) { for (i = 0; i < this.inputs.length; i++) {
input = this.inputs[i]; input = this.inputs[i];
input.prevout.toRaw(bw); input.prevout.toWriter(bw);
} }
prevouts = crypto.hash256(bw.render()); prevouts = crypto.hash256(bw.render());
@ -649,7 +653,7 @@ TX.prototype.signatureHashV1 = function signatureHashV1(index, prev, type) {
for (i = 0; i < this.outputs.length; i++) { for (i = 0; i < this.outputs.length; i++) {
output = this.outputs[i]; output = this.outputs[i];
output.toRaw(bw); output.toWriter(bw);
} }
outputs = crypto.hash256(bw.render()); outputs = crypto.hash256(bw.render());
@ -715,12 +719,7 @@ TX.prototype.verify = function verify(flags) {
*/ */
TX.prototype.verifyInput = function verifyInput(index, flags) { TX.prototype.verifyInput = function verifyInput(index, flags) {
var input; var input = this.inputs[index];
if (typeof index === 'object')
index = this.inputs.indexOf(index);
input = this.inputs[index];
assert(input, 'Input does not exist.'); assert(input, 'Input does not exist.');
@ -753,15 +752,15 @@ TX.prototype.verifyInput = function verifyInput(index, flags) {
* @returns {Boolean} Whether the inputs are valid. * @returns {Boolean} Whether the inputs are valid.
*/ */
TX.prototype.verifyAsync = function verifyAsync(flags) { TX.prototype.verifyAsync = co(function* verifyAsync(flags) {
if (this.inputs.length === 0) if (this.inputs.length === 0)
return Promise.resolve(false); return false;
if (this.isCoinbase()) if (this.isCoinbase())
return Promise.resolve(true); return true;
return workerPool.verify(this, flags); return yield workerPool.verify(this, flags);
}; });
/** /**
* Verify a transaction input asynchronously. * Verify a transaction input asynchronously.
@ -771,18 +770,11 @@ TX.prototype.verifyAsync = function verifyAsync(flags) {
* @returns {Boolean} Whether the input is valid. * @returns {Boolean} Whether the input is valid.
*/ */
TX.prototype.verifyInputAsync = function verifyInputAsync(index, flags) { TX.prototype.verifyInputAsync = co(function* verifyInputAsync(index, flags) {
var input; var input = this.inputs[index];
if (typeof index === 'object')
index = this.inputs.indexOf(index);
input = this.inputs[index];
assert(input, 'Input does not exist.'); assert(input, 'Input does not exist.');
return yield workerPool.verifyInput(this, index, flags);
return workerPool.verifyInput(this, index, flags); });
};
/** /**
* Test whether the transaction is a coinbase * Test whether the transaction is a coinbase
@ -1169,13 +1161,17 @@ TX.prototype.isFinal = function isFinal(height, ts) {
TX.prototype.getLegacySigops = function getLegacySigops() { TX.prototype.getLegacySigops = function getLegacySigops() {
var total = 0; var total = 0;
var i; var i, input, output;
for (i = 0; i < this.inputs.length; i++) for (i = 0; i < this.inputs.length; i++) {
total += this.inputs[i].script.getSigops(false); input = this.inputs[i];
total += input.script.getSigops(false);
}
for (i = 0; i < this.outputs.length; i++) for (i = 0; i < this.outputs.length; i++) {
total += this.outputs[i].script.getSigops(false); output = this.outputs[i];
total += output.script.getSigops(false);
}
return total; return total;
}; };
@ -1187,19 +1183,20 @@ TX.prototype.getLegacySigops = function getLegacySigops() {
TX.prototype.getScripthashSigops = function getScripthashSigops() { TX.prototype.getScripthashSigops = function getScripthashSigops() {
var total = 0; var total = 0;
var i, input; var i, input, coin;
if (this.isCoinbase()) if (this.isCoinbase())
return 0; return 0;
for (i = 0; i < this.inputs.length; i++) { for (i = 0; i < this.inputs.length; i++) {
input = this.inputs[i]; input = this.inputs[i];
coin = input.coin;
if (!input.coin) if (!coin)
continue; continue;
if (input.coin.script.isScripthash()) if (coin.script.isScripthash())
total += input.coin.script.getScripthashSigops(input.script); total += coin.script.getScripthashSigops(input.script);
} }
return total; return total;
@ -1439,34 +1436,26 @@ TX.prototype.isStandard = function isStandard(ret) {
TX.prototype.hasStandardInputs = function hasStandardInputs() { TX.prototype.hasStandardInputs = function hasStandardInputs() {
var maxSigops = constants.script.MAX_SCRIPTHASH_SIGOPS; var maxSigops = constants.script.MAX_SCRIPTHASH_SIGOPS;
var VERIFY_NONE = constants.flags.VERIFY_NONE; var i, input, coin, redeem;
var i, input, stack, redeem;
if (this.isCoinbase()) if (this.isCoinbase())
return true; return true;
for (i = 0; i < this.inputs.length; i++) { for (i = 0; i < this.inputs.length; i++) {
input = this.inputs[i]; input = this.inputs[i];
coin = input.coin;
if (!input.coin) if (!coin)
return false; return false;
if (input.coin.script.isUnknown()) if (coin.script.isUnknown())
return false; return false;
if (input.coin.script.isScripthash()) { if (coin.script.isScripthash()) {
stack = new Stack(); redeem = input.script.getRedeem();
try { if (!redeem)
input.script.execute(stack, VERIFY_NONE, this, i, 0);
} catch (e) {
return false; return false;
}
if (stack.length === 0)
return false;
redeem = Script.fromRaw(stack.top(-1));
if (redeem.getSigops(true) > maxSigops) if (redeem.getSigops(true) > maxSigops)
return false; return false;
@ -1737,13 +1726,14 @@ TX.prototype.maxSize = function maxSize() {
*/ */
TX.prototype.getModifiedSize = function getModifiedSize(size) { TX.prototype.getModifiedSize = function getModifiedSize(size) {
var i, offset; var i, input, offset;
if (size == null) if (size == null)
size = this.maxSize(); size = this.maxSize();
for (i = 0; i < this.inputs.length; i++) { for (i = 0; i < this.inputs.length; i++) {
offset = 41 + Math.min(110, this.inputs[i].script.getSize()); input = this.inputs[i];
offset = 41 + Math.min(110, input.script.getSize());
if (size > offset) if (size > offset)
size -= offset; size -= offset;
} }
@ -1940,9 +1930,6 @@ TX.prototype.isWatched = function isWatched(filter) {
var found = false; var found = false;
var i, input, output, prevout; var i, input, output, prevout;
if (!filter)
return false;
// 1. Test the tx hash // 1. Test the tx hash
if (filter.test(this.hash())) if (filter.test(this.hash()))
found = true; found = true;
@ -2195,32 +2182,51 @@ TX.fromRaw = function fromRaw(data, enc) {
return new TX().fromRaw(data); return new TX().fromRaw(data);
}; };
/**
* Instantiate a transaction from a buffer reader.
* @param {BufferReader} br
* @returns {TX}
*/
TX.fromReader = function fromReader(br) {
return new TX().fromReader(br);
};
/** /**
* Inject properties from serialized data. * Inject properties from serialized data.
* @private * @private
* @param {Buffer|BufferReader} data * @param {Buffer} data
*/ */
TX.prototype.fromRaw = function fromRaw(data) { TX.prototype.fromRaw = function fromRaw(data) {
var br, i, count; return this.fromReader(new BufferReader(data));
};
if (TX.isWitness(data)) /**
return this.fromWitness(data); * Inject properties from buffer reader.
* @private
* @param {BufferReader} br
*/
TX.prototype.fromReader = function fromReader(br) {
var i, count;
if (TX.isWitness(br))
return this.fromWitnessReader(br);
br = BufferReader(data);
br.start(); br.start();
this.version = br.readU32(); // Technically signed this.version = br.readU32();
count = br.readVarint(); count = br.readVarint();
for (i = 0; i < count; i++) for (i = 0; i < count; i++)
this.inputs.push(Input.fromRaw(br)); this.inputs.push(Input.fromReader(br));
count = br.readVarint(); count = br.readVarint();
for (i = 0; i < count; i++) for (i = 0; i < count; i++)
this.outputs.push(Output.fromRaw(br)); this.outputs.push(Output.fromReader(br));
this.locktime = br.readU32(); this.locktime = br.readU32();
@ -2237,13 +2243,12 @@ TX.prototype.fromRaw = function fromRaw(data) {
/** /**
* Inject properties from serialized * Inject properties from serialized
* data (witness serialization). * buffer reader (witness serialization).
* @private * @private
* @param {Buffer|BufferReader} data * @param {BufferReader} br
*/ */
TX.prototype.fromWitness = function fromWitness(data) { TX.prototype.fromWitnessReader = function fromWitnessReader(br) {
var br = BufferReader(data);
var flag = 0; var flag = 0;
var witnessSize = 0; var witnessSize = 0;
var hasWitness = false; var hasWitness = false;
@ -2251,7 +2256,7 @@ TX.prototype.fromWitness = function fromWitness(data) {
br.start(); br.start();
this.version = br.readU32(); // Technically signed this.version = br.readU32();
assert(br.readU8() === 0, 'Non-zero marker.'); assert(br.readU8() === 0, 'Non-zero marker.');
@ -2264,12 +2269,12 @@ TX.prototype.fromWitness = function fromWitness(data) {
count = br.readVarint(); count = br.readVarint();
for (i = 0; i < count; i++) for (i = 0; i < count; i++)
this.inputs.push(Input.fromRaw(br)); this.inputs.push(Input.fromReader(br));
count = br.readVarint(); count = br.readVarint();
for (i = 0; i < count; i++) for (i = 0; i < count; i++)
this.outputs.push(Output.fromRaw(br)); this.outputs.push(Output.fromReader(br));
if (flag & 1) { if (flag & 1) {
flag ^= 1; flag ^= 1;
@ -2278,7 +2283,7 @@ TX.prototype.fromWitness = function fromWitness(data) {
for (i = 0; i < this.inputs.length; i++) { for (i = 0; i < this.inputs.length; i++) {
input = this.inputs[i]; input = this.inputs[i];
input.witness.fromRaw(br); input.witness.fromReader(br);
if (input.witness.items.length > 0) if (input.witness.items.length > 0)
hasWitness = true; hasWitness = true;
} }
@ -2311,12 +2316,39 @@ TX.prototype.fromWitness = function fromWitness(data) {
/** /**
* Serialize transaction without witness. * Serialize transaction without witness.
* @private * @private
* @param {BufferWriter?} writer - A buffer writer to continue writing from. * @returns {RawTX}
* @returns {Buffer} Returns a BufferWriter if `writer` was passed in.
*/ */
TX.prototype.frameNormal = function frameNormal(writer) { TX.prototype.frameNormal = function frameNormal() {
var bw = BufferWriter(writer); var bw = new BufferWriter();
var raw = this.frameNormalWriter(bw);
raw.data = bw.render();
return raw;
};
/**
* Serialize transaction with witness. Calculates the witness
* size as it is framing (exposed on return value as `witness`).
* @private
* @returns {RawTX}
*/
TX.prototype.frameWitness = function frameWitness() {
var bw = new BufferWriter();
var raw = this.frameWitnessWriter(bw);
raw.data = bw.render();
return raw;
};
/**
* Serialize transaction without witness.
* @private
* @param {BufferWriter} writer
* @returns {RawTX}
*/
TX.prototype.frameNormalWriter = function frameNormalWriter(bw) {
var offset = bw.written;
var i; var i;
if (this.inputs.length === 0 && this.outputs.length !== 0) if (this.inputs.length === 0 && this.outputs.length !== 0)
@ -2327,33 +2359,28 @@ TX.prototype.frameNormal = function frameNormal(writer) {
bw.writeVarint(this.inputs.length); bw.writeVarint(this.inputs.length);
for (i = 0; i < this.inputs.length; i++) for (i = 0; i < this.inputs.length; i++)
this.inputs[i].toRaw(bw); this.inputs[i].toWriter(bw);
bw.writeVarint(this.outputs.length); bw.writeVarint(this.outputs.length);
for (i = 0; i < this.outputs.length; i++) for (i = 0; i < this.outputs.length; i++)
this.outputs[i].toRaw(bw); this.outputs[i].toWriter(bw);
bw.writeU32(this.locktime); bw.writeU32(this.locktime);
if (!writer) return new RawTX(bw.written - offset, 0);
bw = bw.render();
this._lastWitnessSize = 0;
return bw;
}; };
/** /**
* Serialize transaction with witness. Calculates the witness * Serialize transaction with witness. Calculates the witness
* size as it is framing (exposed on return value as `_witnessSize`). * size as it is framing (exposed on return value as `witness`).
* @private * @private
* @param {BufferWriter?} writer - A buffer writer to continue writing from. * @param {BufferWriter} bw
* @returns {Buffer} Returns a BufferWriter if `writer` was passed in. * @returns {RawTX}
*/ */
TX.prototype.frameWitness = function frameWitness(writer) { TX.prototype.frameWitnessWriter = function frameWitnessWriter(bw) {
var bw = BufferWriter(writer); var offset = bw.written;
var witnessSize = 0; var witnessSize = 0;
var i, start; var i, start;
@ -2367,17 +2394,17 @@ TX.prototype.frameWitness = function frameWitness(writer) {
bw.writeVarint(this.inputs.length); bw.writeVarint(this.inputs.length);
for (i = 0; i < this.inputs.length; i++) for (i = 0; i < this.inputs.length; i++)
this.inputs[i].toRaw(bw); this.inputs[i].toWriter(bw);
bw.writeVarint(this.outputs.length); bw.writeVarint(this.outputs.length);
for (i = 0; i < this.outputs.length; i++) for (i = 0; i < this.outputs.length; i++)
this.outputs[i].toRaw(bw); this.outputs[i].toWriter(bw);
start = bw.written; start = bw.written;
for (i = 0; i < this.inputs.length; i++) for (i = 0; i < this.inputs.length; i++)
this.inputs[i].witness.toRaw(bw); this.inputs[i].witness.toWriter(bw);
witnessSize += bw.written - start; witnessSize += bw.written - start;
@ -2386,12 +2413,7 @@ TX.prototype.frameWitness = function frameWitness(writer) {
if (witnessSize === this.inputs.length) if (witnessSize === this.inputs.length)
throw new Error('Cannot serialize empty-witness tx.'); throw new Error('Cannot serialize empty-witness tx.');
this._lastWitnessSize = witnessSize + 2; return new RawTX(bw.written - offset, witnessSize + 2);
if (!writer)
bw = bw.render();
return bw;
}; };
/** /**
@ -2400,19 +2422,12 @@ TX.prototype.frameWitness = function frameWitness(writer) {
* @returns {Boolean} * @returns {Boolean}
*/ */
TX.isWitness = function isWitness(data) { TX.isWitness = function isWitness(br) {
if (Buffer.isBuffer(data)) { if (br.left() < 6)
if (data.length < 6)
return false;
return data[4] === 0 && data[5] !== 0;
}
if (data.left() < 6)
return false; return false;
return data.data[data.offset + 4] === 0 return br.data[br.offset + 4] === 0
&& data.data[data.offset + 5] !== 0; && br.data[br.offset + 5] !== 0;
}; };
/** /**
@ -2426,13 +2441,13 @@ TX.isWitness = function isWitness(data) {
* @returns {Buffer} * @returns {Buffer}
*/ */
TX.prototype.toExtended = function toExtended(saveCoins, writer) { TX.prototype.toExtended = function toExtended(saveCoins) {
var bw = BufferWriter(writer); var bw = new BufferWriter();
var height = this.height; var height = this.height;
var index = this.index; var index = this.index;
var i, input, field, bit, oct; var i, input, field, bit, oct;
this.toRaw(bw); this.toWriter(bw);
bw.writeU32(this.ps); bw.writeU32(this.ps);
@ -2469,14 +2484,11 @@ TX.prototype.toExtended = function toExtended(saveCoins, writer) {
continue; continue;
} }
input.coin.toRaw(bw); input.coin.toWriter(bw);
} }
} }
if (!writer) return bw.render();
bw = bw.render();
return bw;
}; };
/** /**
@ -2487,10 +2499,10 @@ TX.prototype.toExtended = function toExtended(saveCoins, writer) {
*/ */
TX.prototype.fromExtended = function fromExtended(data, saveCoins) { TX.prototype.fromExtended = function fromExtended(data, saveCoins) {
var br = BufferReader(data); var br = new BufferReader(data);
var i, input, coin, field, bit, oct, spent; var i, input, coin, field, bit, oct, spent;
this.fromRaw(br); this.fromReader(br);
this.ps = br.readU32(); this.ps = br.readU32();
@ -2520,7 +2532,7 @@ TX.prototype.fromExtended = function fromExtended(data, saveCoins) {
if (spent) if (spent)
continue; continue;
coin = Coin.fromRaw(br); coin = Coin.fromReader(br);
coin.hash = input.prevout.hash; coin.hash = input.prevout.hash;
coin.index = input.prevout.index; coin.index = input.prevout.index;
@ -2570,9 +2582,10 @@ TX.isTX = function isTX(obj) {
* Helpers * Helpers
*/ */
function TXSizes() { function RawTX(total, witness) {
this.total = 0; this.data = null;
this.witness = 0; this.total = total;
this.witness = witness;
} }
/* /*

View File

@ -7,12 +7,13 @@
'use strict'; 'use strict';
var assert = require('assert');
var BN = require('bn.js'); var BN = require('bn.js');
var constants = require('../protocol/constants'); var constants = require('../protocol/constants');
var util = require('../utils/util'); var util = require('../utils/util');
var encoding = require('./encoding'); var encoding = require('./encoding');
var BufferReader = require('../utils/reader');
var BufferWriter = require('../utils/writer'); var BufferWriter = require('../utils/writer');
var assert = require('assert');
var opcodes = constants.opcodes; var opcodes = constants.opcodes;
/** /**
@ -30,45 +31,160 @@ function Opcode(value, data) {
if (!(this instanceof Opcode)) if (!(this instanceof Opcode))
return new Opcode(value, data); return new Opcode(value, data);
this.value = value; this.value = value || 0;
this.data = data || null; this.data = data || null;
} }
/**
* Encode the opcode to a buffer writer.
* @param {BufferWriter} bw
*/
Opcode.prototype.toWriter = function toWriter(bw) {
if (this.value === -1)
throw new Error('Cannot reserialize a parse error.');
if (!this.data) {
bw.writeU8(this.value);
return bw;
}
if (this.value <= 0x4b) {
assert(this.value === this.data.length);
bw.writeU8(this.value);
bw.writeBytes(this.data);
return bw;
}
switch (this.value) {
case opcodes.OP_PUSHDATA1:
bw.writeU8(this.value);
bw.writeU8(this.data.length);
bw.writeBytes(this.data);
break;
case opcodes.OP_PUSHDATA2:
bw.writeU8(this.value);
bw.writeU16(this.data.length);
bw.writeBytes(this.data);
break;
case opcodes.OP_PUSHDATA4:
bw.writeU8(this.value);
bw.writeU32(this.data.length);
bw.writeBytes(this.data);
break;
default:
throw new Error('Unknown pushdata opcode.');
}
return bw;
};
/** /**
* Encode the opcode. * Encode the opcode.
* @returns {Buffer} * @returns {Buffer}
*/ */
Opcode.prototype.toRaw = function toRaw() { Opcode.prototype.toRaw = function toRaw() {
var bw = new BufferWriter(); return this.toWriter(new BufferWriter()).render();
};
if (this.value === -1) /**
throw new Error('Cannot reserialize a parse error.'); * Inject properties from buffer reader.
* @param {BufferReader} br
* @private
*/
if (this.data) { Opcode.prototype.fromReader = function fromReader(br) {
if (this.value <= 0x4b) { var op = br.readU8();
bw.writeU8(this.data.length); var size;
bw.writeBytes(this.data);
} else if (this.value === opcodes.OP_PUSHDATA1) { if (op >= 0x01 && op <= 0x4b) {
bw.writeU8(opcodes.OP_PUSHDATA1); if (br.left() < op) {
bw.writeU8(this.data.length); this.value = -1;
bw.writeBytes(this.data); return this;
} else if (this.value === opcodes.OP_PUSHDATA2) {
bw.writeU8(opcodes.OP_PUSHDATA2);
bw.writeU16(this.data.length);
bw.writeBytes(this.data);
} else if (this.value === opcodes.OP_PUSHDATA4) {
bw.writeU8(opcodes.OP_PUSHDATA4);
bw.writeU32(this.data.length);
bw.writeBytes(this.data);
} else {
throw new Error('Unknown pushdata opcode.');
} }
} else { this.value = op;
bw.writeU8(this.value); this.data = br.readBytes(op);
return this;
} }
return bw.render(); switch (op) {
case opcodes.OP_PUSHDATA1:
if (br.left() < 1) {
this.value = -1;
break;
}
size = br.readU8();
if (br.left() < size) {
this.value = -1;
break;
}
this.value = op;
this.data = br.readBytes(size);
break;
case opcodes.OP_PUSHDATA2:
if (br.left() < 2) {
this.value = -1;
break;
}
size = br.readU16();
if (br.left() < size) {
this.value = -1;
break;
}
this.value = op;
this.data = br.readBytes(size);
break;
case opcodes.OP_PUSHDATA4:
if (br.left() < 4) {
this.value = -1;
break;
}
size = br.readU32();
if (br.left() < size) {
this.value = -1;
break;
}
this.value = op;
this.data = br.readBytes(size);
break;
default:
this.value = op;
break;
}
return this;
};
/**
* Inject properties from serialized data.
* @private
* @param {Buffer} data
* @returns {Opcode}
*/
Opcode.prototype.fromRaw = function fromRaw(data) {
return this.fromReader(new BufferReader(data));
};
/**
* Instantiate opcode from buffer reader.
* @param {BufferReader} br
* @returns {Opcode}
*/
Opcode.fromReader = function fromReader(br) {
return new Opcode().fromReader(br);
};
/**
* Instantiate opcode from serialized data.
* @param {Buffer} data
* @returns {Opcode}
*/
Opcode.fromRaw = function fromRaw(data) {
return new Opcode().fromRaw(data);
}; };
/** /**

View File

@ -129,7 +129,7 @@ Script.prototype.toArray = function toArray() {
Script.prototype.fromArray = function fromArray(code) { Script.prototype.fromArray = function fromArray(code) {
assert(Array.isArray(code)); assert(Array.isArray(code));
this.code = Script.parseArray(code); this.code = Script.parseArray(code);
this.raw = Script.encode(this.code); this.compile();
return this; return this;
}; };
@ -186,7 +186,27 @@ Script.prototype.toASM = function toASM(decode) {
*/ */
Script.prototype.compile = function compile() { Script.prototype.compile = function compile() {
this.raw = Script.encode(this.code); var bw = new BufferWriter();
var i, op;
for (i = 0; i < this.code.length; i++) {
op = this.code[i];
op.toWriter(bw);
}
this.raw = bw.render();
return this;
};
/**
* Write the script to a buffer writer.
* @param {BufferWriter} bw
*/
Script.prototype.toWriter = function toWriter(bw) {
bw.writeVarBytes(this.raw);
return bw;
}; };
/** /**
@ -195,11 +215,7 @@ Script.prototype.compile = function compile() {
* @returns {Buffer|String} Serialized script. * @returns {Buffer|String} Serialized script.
*/ */
Script.prototype.toRaw = function toRaw(writer) { Script.prototype.toRaw = function toRaw() {
if (writer) {
writer.writeVarBytes(this.raw);
return writer;
}
return this.raw; return this.raw;
}; };
@ -1401,7 +1417,7 @@ Script.prototype.removeData = function removeData(data) {
for (i = index.length - 1; i >= 0; i--) for (i = index.length - 1; i >= 0; i--)
this.code.splice(index[i], 1); this.code.splice(index[i], 1);
this.raw = Script.encode(this.code); this.compile();
return index.length; return index.length;
}; };
@ -1478,14 +1494,11 @@ Script.isMinimal = function isMinimal(data, opcode, flags) {
*/ */
Script.isCode = function isCode(raw) { Script.isCode = function isCode(raw) {
var i, op, code; var script = Script.fromRaw(raw);
var i, op;
assert(Buffer.isBuffer(raw)); for (i = 0; i < script.code.length; i++) {
op = script.code[i];
code = Script.decode(raw);
for (i = 0; i < code.length; i++) {
op = code[i];
if (op.data) if (op.data)
continue; continue;
@ -2430,7 +2443,8 @@ Script.prototype.getCoinbaseFlags = function getCoinbaseFlags() {
else else
nonce = -1; nonce = -1;
flags = Script.encode(this.code.slice(index)); flags = Script.fromArray(this.code.slice(index));
flags = flags.toRaw();
text = flags.toString('utf8'); text = flags.toString('utf8');
text = text.replace(/[\u0000-\u0019\u007f-\u00ff]/g, ''); text = text.replace(/[\u0000-\u0019\u007f-\u00ff]/g, '');
@ -3439,6 +3453,16 @@ Script.sign = function sign(msg, key, type) {
return bw.render(); return bw.render();
}; };
/**
* Inject properties from buffer reader.
* @private
* @param {BufferReader} br
*/
Script.prototype.fromReader = function fromReader(br) {
return this.fromRaw(br.readVarBytes());
};
/** /**
* Inject properties from serialized data. * Inject properties from serialized data.
* @private * @private
@ -3446,15 +3470,27 @@ Script.sign = function sign(msg, key, type) {
*/ */
Script.prototype.fromRaw = function fromRaw(data) { Script.prototype.fromRaw = function fromRaw(data) {
if (data instanceof BufferReader) var br = new BufferReader(data, true);
data = data.readVarBytes();
this.raw = data; this.raw = data;
this.code = Script.decode(data);
while (br.left())
this.code.push(Opcode.fromReader(br));
return this; return this;
}; };
/**
* Create a script from buffer reader.
* @param {BufferReader} br
* @param {String?} enc - Either `"hex"` or `null`.
* @returns {Script}
*/
Script.fromReader = function fromReader(br) {
return new Script().fromReader(br);
};
/** /**
* Create a script from a serialized buffer. * Create a script from a serialized buffer.
* @param {Buffer|String} data - Serialized script. * @param {Buffer|String} data - Serialized script.
@ -3468,127 +3504,6 @@ Script.fromRaw = function fromRaw(data, enc) {
return new Script().fromRaw(data); return new Script().fromRaw(data);
}; };
/**
* Decode a serialized script into script code.
* Note that the serialized script must _not_
* include the varint size before it. Parse
* errors will output an opcode with a value
* of -1.
*
* @param {Buffer} raw - Serialized script.
* @returns {Opcode[]} Script code.
*/
Script.decode = function decode(raw) {
var br = new BufferReader(raw, true);
var code = [];
var op, size, data;
assert(Buffer.isBuffer(raw));
while (br.left()) {
op = br.readU8();
if (op >= 0x01 && op <= 0x4b) {
if (br.left() < op) {
code.push(new Opcode(-1));
break;
}
data = br.readBytes(op);
code.push(new Opcode(op, data));
} else if (op === opcodes.OP_PUSHDATA1) {
if (br.left() < 1) {
code.push(new Opcode(-1));
break;
}
size = br.readU8();
if (br.left() < size) {
code.push(new Opcode(-1));
break;
}
data = br.readBytes(size);
code.push(new Opcode(op, data));
} else if (op === opcodes.OP_PUSHDATA2) {
if (br.left() < 2) {
code.push(new Opcode(-1));
break;
}
size = br.readU16();
if (br.left() < size) {
code.push(new Opcode(-1));
break;
}
data = br.readBytes(size);
code.push(new Opcode(op, data));
} else if (op === opcodes.OP_PUSHDATA4) {
if (br.left() < 4) {
code.push(new Opcode(-1));
break;
}
size = br.readU32();
if (br.left() < size) {
code.push(new Opcode(-1));
break;
}
data = br.readBytes(size);
code.push(new Opcode(op, data));
} else {
code.push(new Opcode(op));
}
}
return code;
};
/**
* Encode and serialize script code. This will _not_
* include the varint size at the start.
* @param {Array} code - Script code.
* @returns {Buffer} Serialized script.
*/
Script.encode = function encode(code, writer) {
var bw = new BufferWriter(writer);
var i, op;
assert(Array.isArray(code));
for (i = 0; i < code.length; i++) {
op = code[i];
if (op.value === -1)
throw new Error('Cannot reserialize a parse error.');
if (op.data) {
if (op.value <= 0x4b) {
bw.writeU8(op.data.length);
bw.writeBytes(op.data);
} else if (op.value === opcodes.OP_PUSHDATA1) {
bw.writeU8(opcodes.OP_PUSHDATA1);
bw.writeU8(op.data.length);
bw.writeBytes(op.data);
} else if (op.value === opcodes.OP_PUSHDATA2) {
bw.writeU8(opcodes.OP_PUSHDATA2);
bw.writeU16(op.data.length);
bw.writeBytes(op.data);
} else if (op.value === opcodes.OP_PUSHDATA4) {
bw.writeU8(opcodes.OP_PUSHDATA4);
bw.writeU32(op.data.length);
bw.writeBytes(op.data);
} else {
throw new Error('Unknown pushdata opcode.');
}
continue;
}
bw.writeU8(op.value);
}
if (!writer)
bw = bw.render();
return bw;
};
/** /**
* Convert an array of Buffers and * Convert an array of Buffers and
* Numbers into an array of Opcodes. * Numbers into an array of Opcodes.

View File

@ -299,13 +299,11 @@ Witness.prototype.indexOf = function indexOf(data) {
}; };
/** /**
* Encode the witness to a Buffer. * Write witness to a buffer writer.
* @param {String} enc - Encoding, either `'hex'` or `null`. * @param {BufferWriter} bw
* @returns {Buffer|String} Serialized script.
*/ */
Witness.prototype.toRaw = function toRaw(writer) { Witness.prototype.toWriter = function toWriter(bw) {
var bw = BufferWriter(writer);
var i; var i;
bw.writeVarint(this.items.length); bw.writeVarint(this.items.length);
@ -313,12 +311,19 @@ Witness.prototype.toRaw = function toRaw(writer) {
for (i = 0; i < this.items.length; i++) for (i = 0; i < this.items.length; i++)
bw.writeVarBytes(this.items[i]); bw.writeVarBytes(this.items[i]);
if (!writer)
bw = bw.render();
return bw; return bw;
}; };
/**
* Encode the witness to a Buffer.
* @param {String} enc - Encoding, either `'hex'` or `null`.
* @returns {Buffer|String} Serialized script.
*/
Witness.prototype.toRaw = function toRaw() {
return this.toWriter(new BufferWriter()).render();
};
/** /**
* Convert witness to a hex string. * Convert witness to a hex string.
* @returns {String} * @returns {String}
@ -513,13 +518,12 @@ Witness.encodeItem = function encodeItem(data) {
}; };
/** /**
* Inject properties from serialized data. * Inject properties from buffer reader.
* @private * @private
* @param {Buffer} data * @param {BufferReader} br
*/ */
Witness.prototype.fromRaw = function fromRaw(data) { Witness.prototype.fromReader = function fromReader(br) {
var br = BufferReader(data);
var chunkCount = br.readVarint(); var chunkCount = br.readVarint();
var i; var i;
@ -530,7 +534,26 @@ Witness.prototype.fromRaw = function fromRaw(data) {
}; };
/** /**
* Create a Witness from a serialized buffer. * Inject properties from serialized data.
* @private
* @param {Buffer} data
*/
Witness.prototype.fromRaw = function fromRaw(data) {
return this.fromReader(new BufferReader(data));
};
/**
* Create a witness from a buffer reader.
* @param {BufferReader} br
*/
Witness.fromReader = function fromReader(br) {
return new Witness().fromReader(br);
};
/**
* Create a witness from a serialized buffer.
* @param {Buffer|String} data - Serialized witness. * @param {Buffer|String} data - Serialized witness.
* @param {String?} enc - Either `"hex"` or `null`. * @param {String?} enc - Either `"hex"` or `null`.
* @returns {Witness} * @returns {Witness}

View File

@ -29,113 +29,96 @@
'use strict'; 'use strict';
var assert = require('assert');
var BufferReader = require('./reader'); var BufferReader = require('./reader');
var ASN1 = exports; var ASN1 = exports;
ASN1.parseTag = function parseTag(br) { /*
var tag = br.readU8(); * Primitives
var primitive = (tag & 0x20) === 0; */
ASN1.readTag = function readTag(br) {
var type = br.readU8();
var primitive = (type & 0x20) === 0;
var oct; var oct;
if ((tag & 0x1f) === 0x1f) { if ((type & 0x1f) === 0x1f) {
oct = tag; oct = type;
tag = 0; type = 0;
while ((oct & 0x80) === 0x80) { while ((oct & 0x80) === 0x80) {
oct = br.readU8(); oct = br.readU8();
tag <<= 7; type <<= 7;
tag |= oct & 0x7f; type |= oct & 0x7f;
} }
} else { } else {
tag &= 0x1f; type &= 0x1f;
} }
return { return {
type: type,
primitive: primitive, primitive: primitive,
tag: tag, size: ASN1.readSize(br, primitive)
len: ASN1.parseLen(br, primitive)
}; };
}; };
ASN1.parseLen = function parseLen(br, primitive) { ASN1.readSize = function readSize(br, primitive) {
var len = br.readU8(); var size = br.readU8();
var num, i, j; var bytes, i, j;
// Indefinite form // Indefinite form
if (!primitive && len === 0x80) if (!primitive && size === 0x80)
return null; throw new Error('Indefinite size.');
// Definite form // Definite form
if ((len & 0x80) === 0) { if ((size & 0x80) === 0) {
// Short form // Short form
return len; return size;
} }
// Long form // Long form
num = len & 0x7f; bytes = size & 0x7f;
assert(num < 4, 'length octect is too long');
len = 0; if (bytes > 3)
for (i = 0; i < num; i++) { throw new Error('Length octet is too long.');
len <<= 8;
size = 0;
for (i = 0; i < bytes; i++) {
size <<= 8;
j = br.readU8(); j = br.readU8();
len |= j; size |= j;
} }
return len; return size;
}; };
ASN1.parseCert = function parseCert(data) { ASN1.readSeq = function readSeq(br) {
var d = BufferReader(data); var tag = ASN1.implicit(br, 0x10);
var br; return br.readBytes(tag.size);
d.start();
br = BufferReader(ASN1.parseSeq(d));
return {
tbs: ASN1.parseTBS(br),
sigAlg: ASN1.parseAlgIdent(br),
sig: ASN1.parseBitstr(br),
raw: d.endData(true)
};
}; };
ASN1.parseTBS = function parseTBS(data) { ASN1.implicit = function implicit(br, type) {
var d = BufferReader(data); var tag = ASN1.readTag(br);
var br; if (tag.type !== type)
throw new Error('Unexpected tag: ' + tag.type + '.');
d.start(); return tag;
br = BufferReader(ASN1.parseSeq(d));
return {
version: ASN1.parseExplicitInt(br, 0, true),
serial: ASN1.parseInt(br),
sig: ASN1.parseAlgIdent(br),
issuer: ASN1.parseName(br),
validity: ASN1.parseValidity(br),
subject: ASN1.parseName(br),
pubkey: ASN1.parsePubkey(br),
raw: d.endData(true)
};
}; };
ASN1.parseSeq = function parseSeq(data) { ASN1.explicit = function explicit(br, type) {
var br = BufferReader(data); var offset = br.offset;
var tag = ASN1.parseTag(br); var tag = ASN1.readTag(br);
assert.equal(tag.tag, 0x10); // seq if (tag.type !== type) {
return br.readBytes(tag.len, true); br.offset = offset;
return false;
}
return true;
}; };
ASN1.parseInt = function parseInt(data, readNum) { ASN1.seq = function seq(br) {
var br = BufferReader(data); return new BufferReader(ASN1.readSeq(br), true);
var tag = ASN1.parseTag(br); };
var num;
assert.equal(tag.tag, 0x02); // int ASN1.readInt = function readInt(br, readNum) {
var tag = ASN1.implicit(br, 0x02);
num = br.readBytes(tag.len, true); var num = br.readBytes(tag.size);
if (readNum) if (readNum)
return num.readUIntBE(0, num.length); return num.readUIntBE(0, num.length);
@ -143,30 +126,28 @@ ASN1.parseInt = function parseInt(data, readNum) {
return num; return num;
}; };
ASN1.parseExplicitInt = function parseExplicitInt(data, i, readNum) { ASN1.readExplicitInt = function readExplicitInt(br, type, readNum) {
var br = BufferReader(data); if (!ASN1.explicit(br, type))
var off = br.offset;
var tag = ASN1.parseTag(br);
if (tag.tag !== i) {
br.seek(-(br.offset - off));
return -1; return -1;
} return ASN1.readInt(br, readNum);
return ASN1.parseInt(br, readNum);
}; };
ASN1.parseBitstr = function parseBitstr(data) { ASN1.readBitstr = function readBitstr(br) {
var br = BufferReader(data); var tag = ASN1.implicit(br, 0x03);
var tag = ASN1.parseTag(br); var str = br.readBytes(tag.size);
assert.equal(tag.tag, 0x03); // bitstr return ASN1.alignBitstr(str);
return ASN1.alignBitstr(br.readBytes(tag.len, true));
}; };
ASN1.parseString = function parseString(data) { ASN1.readString = function readString(br) {
var br = BufferReader(data); var tag = ASN1.readTag(br);
var tag = ASN1.parseTag(br); var str;
switch (tag.tag) {
switch (tag.type) {
case 0x03: // bitstr case 0x03: // bitstr
return ASN1.alignBitstr(br.readBytes(tag.len, true)); str = br.readBytes(tag.size);
return ASN1.alignBitstr(str);
// Note:
// Fuck all these.
case 0x04: // octstr case 0x04: // octstr
case 0x12: // numstr case 0x12: // numstr
case 0x13: // prinstr case 0x13: // prinstr
@ -180,9 +161,9 @@ ASN1.parseString = function parseString(data) {
case 0x1c: // unistr case 0x1c: // unistr
case 0x1d: // charstr case 0x1d: // charstr
case 0x1e: // bmpstr case 0x1e: // bmpstr
return br.readString('utf8', tag.len); return br.readString('utf8', tag.size);
default: default:
assert(false, 'Bad string.'); throw new Error('Unexpected tag: ' + tag.type + '.');
} }
}; };
@ -207,52 +188,83 @@ ASN1.alignBitstr = function(data) {
return out; return out;
}; };
ASN1.parsePubkey = function parsePubkey(data) { /*
var br = BufferReader(data); * Certificates
br = BufferReader(ASN1.parseSeq(br)); */
ASN1.readCert = function readCert(br) {
var buf = br;
buf.start();
br = ASN1.seq(buf);
return { return {
alg: ASN1.parseAlgIdent(br), tbs: ASN1.readTBS(br),
pubkey: ASN1.parseBitstr(br) sigAlg: ASN1.readAlgIdent(br),
sig: ASN1.readBitstr(br),
raw: buf.endData(true)
}; };
}; };
ASN1.parseName = function parseName(data) { ASN1.readTBS = function readTBS(br) {
var br = BufferReader(data); var buf = br;
var values = [];
var tag;
br = BufferReader(ASN1.parseSeq(br)); buf.start();
br = ASN1.seq(buf);
return {
version: ASN1.readExplicitInt(br, 0x00, true),
serial: ASN1.readInt(br),
sig: ASN1.readAlgIdent(br),
issuer: ASN1.readName(br),
validity: ASN1.readValidity(br),
subject: ASN1.readName(br),
pubkey: ASN1.readPubkey(br),
raw: buf.endData(true)
};
};
ASN1.readPubkey = function readPubkey(br) {
br = ASN1.seq(br);
return {
alg: ASN1.readAlgIdent(br),
pubkey: ASN1.readBitstr(br)
};
};
ASN1.readName = function readName(br) {
var values = [];
br = ASN1.seq(br);
while (br.left()) { while (br.left()) {
tag = ASN1.parseTag(br); ASN1.implicit(br, 0x11); // set
assert.equal(tag.tag, 0x11); // set ASN1.implicit(br, 0x10); // seq
tag = ASN1.parseTag(br);
assert.equal(tag.tag, 0x10); // seq
values.push({ values.push({
type: ASN1.parseOID(br), type: ASN1.readOID(br),
value: ASN1.parseString(br) value: ASN1.readString(br)
}); });
} }
return values; return values;
}; };
ASN1.parseValidity = function parseValidity(data) { ASN1.readValidity = function readValidity(br) {
var br = BufferReader(data); br = ASN1.seq(br);
br = BufferReader(ASN1.parseSeq(br));
return { return {
notBefore: ASN1.parseTime(br), notBefore: ASN1.readTime(br),
notAfter: ASN1.parseTime(br) notAfter: ASN1.readTime(br)
}; };
}; };
ASN1.parseTime = function parseTime(data) { ASN1.readTime = function readTime(br) {
var br = BufferReader(data); var tag = ASN1.readTag(br);
var tag = ASN1.parseTag(br); var str = br.readString('ascii', tag.size);
var str = br.readString('ascii', tag.len);
var year, mon, day, hour, min, sec; var year, mon, day, hour, min, sec;
switch (tag.tag) { switch (tag.type) {
case 0x17: // utctime case 0x17: // utctime
year = str.slice(0, 2) | 0; year = str.slice(0, 2) | 0;
mon = str.slice(2, 4) | 0; mon = str.slice(2, 4) | 0;
@ -274,25 +286,24 @@ ASN1.parseTime = function parseTime(data) {
sec = str.slice(12, 14) | 0; sec = str.slice(12, 14) | 0;
break; break;
default: default:
assert(false); throw new Error('Unexpected tag: ' + tag.type + '.');
break;
} }
return Date.UTC(year, mon - 1, day, hour, min, sec, 0) / 1000; return Date.UTC(year, mon - 1, day, hour, min, sec, 0) / 1000;
}; };
ASN1.parseOID = function parseOID(data) { ASN1.readOID = function readOID(br) {
var br = BufferReader(data); var tag = ASN1.implicit(br, 0x06);
var tag = ASN1.parseTag(br); var data = br.readBytes(tag.size);
return ASN1.formatOID(data);
};
ASN1.formatOID = function formatOID(data) {
var br = new BufferReader(data);
var ids = []; var ids = [];
var ident = 0; var ident = 0;
var subident = 0; var subident = 0;
var objid, result, first, second; var result, first, second;
assert.equal(tag.tag, 0x06); // objid
objid = br.readBytes(tag.len, true);
br = BufferReader(objid);
while (br.left()) { while (br.left()) {
subident = br.readU8(); subident = br.readU8();
@ -314,17 +325,17 @@ ASN1.parseOID = function parseOID(data) {
return result.join('.'); return result.join('.');
}; };
ASN1.parseAlgIdent = function parseAlgIdent(data) { ASN1.readAlgIdent = function readAlgIdent(br) {
var br = BufferReader(data);
var params = null; var params = null;
var alg; var alg, tag;
br = BufferReader(ASN1.parseSeq(br)); br = ASN1.seq(br);
alg = ASN1.parseOID(br); alg = ASN1.readOID(br);
if (br.left() > 0) { if (br.left() > 0) {
params = br.readBytes(ASN1.parseTag(br).len, true); tag = ASN1.readTag(br);
params = br.readBytes(tag.size);
if (params.length === 0) if (params.length === 0)
params = null; params = null;
} }
@ -335,27 +346,49 @@ ASN1.parseAlgIdent = function parseAlgIdent(data) {
}; };
}; };
ASN1.parseRSAPublic = function parseRSAPublic(data) { /*
var br = BufferReader(data); * RSA
br = BufferReader(ASN1.parseSeq(br)); */
ASN1.readRSAPublic = function readRSAPublic(br) {
br = ASN1.seq(br);
return { return {
modulus: ASN1.parseInt(br), modulus: ASN1.readInt(br),
publicExponent: ASN1.parseInt(br) publicExponent: ASN1.readInt(br)
}; };
}; };
ASN1.parseRSAPrivate = function parseRSAPrivate(data) { ASN1.readRSAPrivate = function readRSAPrivate(br) {
var br = BufferReader(data); br = ASN1.seq(br);
br = BufferReader(ASN1.parseSeq(br));
return { return {
version: ASN1.parseInt(br, true), version: ASN1.readInt(br, true),
modulus: ASN1.parseInt(br), modulus: ASN1.readInt(br),
publicExponent: ASN1.parseInt(br), publicExponent: ASN1.readInt(br),
privateExponent: ASN1.parseInt(br), privateExponent: ASN1.readInt(br),
prime1: ASN1.parseInt(br), prime1: ASN1.readInt(br),
prime2: ASN1.parseInt(br), prime2: ASN1.readInt(br),
exponent1: ASN1.parseInt(br), exponent1: ASN1.readInt(br),
exponent2: ASN1.parseInt(br), exponent2: ASN1.readInt(br),
coefficient: ASN1.parseInt(br) coefficient: ASN1.readInt(br)
}; };
}; };
/*
* Public
*/
ASN1.parseRSAPublic = function parseRSAPublic(data) {
return ASN1.readRSAPublic(new BufferReader(data, true));
};
ASN1.parseRSAPrivate = function parseRSAPrivate(data) {
return ASN1.readRSAPrivate(new BufferReader(data, true));
};
ASN1.parseCert = function parseCert(data) {
return ASN1.readCert(new BufferReader(data, true));
};
ASN1.parseTBS = function parseTBS(data) {
return ASN1.readTBS(new BufferReader(data, true));
};

View File

@ -178,18 +178,15 @@ Bloom.fromRate = function fromRate(items, rate, update) {
* @returns {Buffer} * @returns {Buffer}
*/ */
Bloom.prototype.toRaw = function toRaw(writer) { Bloom.prototype.toRaw = function toRaw() {
var bw = BufferWriter(writer); var bw = new BufferWriter();
bw.writeVarBytes(this.filter); bw.writeVarBytes(this.filter);
bw.writeU32(this.n); bw.writeU32(this.n);
bw.writeU32(this.tweak); bw.writeU32(this.tweak);
bw.writeU8(this.update); bw.writeU8(this.update);
if (!writer) return bw.render();
bw = bw.render();
return bw;
}; };
/** /**
@ -199,7 +196,7 @@ Bloom.prototype.toRaw = function toRaw(writer) {
*/ */
Bloom.prototype.fromRaw = function fromRaw(data) { Bloom.prototype.fromRaw = function fromRaw(data) {
var br = BufferReader(data); var br = new BufferReader(data);
this.filter = br.readVarBytes(); this.filter = br.readVarBytes();
this.n = br.readU32(); this.n = br.readU32();

View File

@ -11,6 +11,10 @@ var assert = require('assert');
var BufferReader = require('../utils/reader'); var BufferReader = require('../utils/reader');
var BufferWriter = require('../utils/writer'); var BufferWriter = require('../utils/writer');
/*
* Constants
*/
var wireType = { var wireType = {
VARINT: 0, VARINT: 0,
FIXED64: 1, FIXED64: 1,
@ -20,11 +24,15 @@ var wireType = {
FIXED32: 5 FIXED32: 5
}; };
/**
* ProtoReader
* @constructor
*/
function ProtoReader(data, zeroCopy) { function ProtoReader(data, zeroCopy) {
if (data instanceof ProtoReader)
return data;
if (!(this instanceof ProtoReader)) if (!(this instanceof ProtoReader))
return new ProtoReader(data, zeroCopy); return new ProtoReader(data, zeroCopy);
BufferReader.call(this, data, zeroCopy); BufferReader.call(this, data, zeroCopy);
} }
@ -92,72 +100,105 @@ ProtoReader.prototype.nextTag = function nextTag() {
ProtoReader.prototype.readField = function readField(tag, opt) { ProtoReader.prototype.readField = function readField(tag, opt) {
var offset = this.offset; var offset = this.offset;
var header = this.readVarint(); var header = this.readVarint();
var value, data, group, field; var field = new Field(header);
var inner;
if (tag != null && (header >>> 3) !== tag) { if (tag != null && field.tag !== tag) {
assert(opt, 'Non-optional field not present.'); assert(opt, 'Non-optional field not present.');
this.offset = offset; this.offset = offset;
return; return null;
} }
switch (header & 7) { switch (field.type) {
case wireType.VARINT: case wireType.VARINT:
value = this.readVarint(); field.value = this.readVarint();
break; break;
case wireType.FIXED64: case wireType.FIXED64:
value = this.readU64(); field.value = this.readU64();
break; break;
case wireType.DELIMITED: case wireType.DELIMITED:
data = this.readVarBytes(); field.data = this.readVarBytes();
break; break;
case wireType.START_GROUP: case wireType.START_GROUP:
group = []; field.group = [];
for (;;) { for (;;) {
field = this.readField(); inner = this.readField();
if (field.type === wireType.END_GROUP) if (inner.type === wireType.END_GROUP)
break; break;
group.push(field); field.group.push(inner);
} }
break; break;
case wireType.END_GROUP: case wireType.END_GROUP:
assert(false, 'Unexpected end group.'); assert(false, 'Unexpected end group.');
break; break;
case wireType.FIXED32: case wireType.FIXED32:
value = this.readU32(); field.value = this.readU32();
break; break;
default: default:
assert(false, 'Bad wire type.'); assert(false, 'Bad wire type.');
break; break;
} }
return { field.size = this.offset - offset;
size: this.offset - offset,
header: header, return field;
tag: header >>> 3,
type: header & 7,
value: value,
data: data,
group: group
};
}; };
function ProtoWriter(options) { /**
if (options instanceof ProtoWriter) * ProtoWriter
return options; * @constructor
*/
function ProtoWriter() {
if (!(this instanceof ProtoWriter)) if (!(this instanceof ProtoWriter))
return new ProtoWriter(options); return new ProtoWriter();
BufferWriter.call(this, options); BufferWriter.call(this);
} }
util.inherits(ProtoWriter, BufferWriter); util.inherits(ProtoWriter, BufferWriter);
ProtoWriter.prototype.writeVarint = function writeVarint(num) { ProtoWriter.prototype.writeVarint = function writeVarint(num) {
var size = exports.sizeVarint(num); var size = exports.sizeVarint(num);
var buf = new Buffer(size); var value;
exports.writeVarint(buf, num, 0);
this.writeBytes(buf); // Avoid an extra allocation until
// we make bufferwriter more hackable.
// More insanity here...
switch (size) {
case 6:
value = exports.slipVarint(num);
this.writeU32BE(value / 0x10000 | 0);
this.writeU16BE(value & 0xffff);
break;
case 5:
value = exports.slipVarint(num);
this.writeU32BE(value / 0x100 | 0);
this.writeU8(value & 0xff);
break;
case 4:
value = exports.slipVarint(num);
this.writeU32BE(value);
break;
case 3:
value = exports.slipVarint(num);
this.writeU16BE(value >> 8);
this.writeU8(value & 0xff);
break;
case 2:
value = exports.slipVarint(num);
this.writeU16BE(value);
break;
case 1:
value = exports.slipVarint(num);
this.writeU8(value);
break;
default:
value = new Buffer(size);
exports.writeVarint(value, num, 0);
this.writeBytes(value);
break;
}
}; };
ProtoWriter.prototype.writeFieldVarint = function writeFieldVarint(tag, value) { ProtoWriter.prototype.writeFieldVarint = function writeFieldVarint(tag, value) {
@ -189,6 +230,10 @@ ProtoWriter.prototype.writeFieldString = function writeFieldString(tag, data, en
this.writeFieldBytes(tag, data); this.writeFieldBytes(tag, data);
}; };
/*
* Encoding
*/
exports.readVarint = function readVarint(data, off) { exports.readVarint = function readVarint(data, off) {
var num = 0; var num = 0;
var ch = 0x80; var ch = 0x80;
@ -199,7 +244,9 @@ exports.readVarint = function readVarint(data, off) {
num = 0; num = 0;
break; break;
} }
ch = data[off++]; ch = data[off++];
// Optimization for javascript insanity. // Optimization for javascript insanity.
switch (size) { switch (size) {
case 0: case 0:
@ -215,12 +262,13 @@ exports.readVarint = function readVarint(data, off) {
num += (ch & 0x7f) * Math.pow(2, 7 * size); num += (ch & 0x7f) * Math.pow(2, 7 * size);
break; break;
} }
size++; size++;
assert(size < 7, 'Number exceeds 2^53-1.');
} }
assert(util.isSafeInteger(num), 'Number exceeds 2^53-1.'); return new Varint(size, num);
return { size: size, value: num };
}; };
exports.writeVarint = function writeVarint(data, num, off) { exports.writeVarint = function writeVarint(data, num, off) {
@ -242,6 +290,28 @@ exports.writeVarint = function writeVarint(data, num, off) {
return off; return off;
}; };
exports.slipVarint = function slipVarint(num) {
var data = 0;
var size = 0;
var ch;
assert(util.isSafeInteger(num), 'Number exceeds 2^53-1.');
do {
assert(size < 7);
ch = num & 0x7f;
num -= num % 0x80;
num /= 0x80;
if (num !== 0)
ch |= 0x80;
data *= 256;
data += ch;
size++;
} while (num > 0);
return data;
};
exports.sizeVarint = function sizeVarint(num) { exports.sizeVarint = function sizeVarint(num) {
var size = 0; var size = 0;
@ -256,5 +326,27 @@ exports.sizeVarint = function sizeVarint(num) {
return size; return size;
}; };
/*
* Helpers
*/
function Field(header) {
this.tag = header >>> 3;
this.type = header & 7;
this.size = 0;
this.value = 0;
this.data = null;
this.group = null;
}
function Varint(size, value) {
this.size = size;
this.value = value;
}
/*
* Expose
*/
exports.ProtoReader = ProtoReader; exports.ProtoReader = ProtoReader;
exports.ProtoWriter = ProtoWriter; exports.ProtoWriter = ProtoWriter;

View File

@ -7,9 +7,9 @@
'use strict'; 'use strict';
var assert = require('assert');
var encoding = require('./encoding'); var encoding = require('./encoding');
var crypto = require('../crypto/crypto'); var crypto = require('../crypto/crypto');
var assert = require('assert');
/** /**
* An object that allows reading of buffers in a sane manner. * An object that allows reading of buffers in a sane manner.
@ -22,15 +22,14 @@ var assert = require('assert');
*/ */
function BufferReader(data, zeroCopy) { function BufferReader(data, zeroCopy) {
if (data instanceof BufferReader)
return data;
if (!(this instanceof BufferReader)) if (!(this instanceof BufferReader))
return new BufferReader(data, zeroCopy); return new BufferReader(data, zeroCopy);
assert(Buffer.isBuffer(data), 'Must pass a Buffer.');
this.data = data; this.data = data;
this.offset = 0; this.offset = 0;
this.zeroCopy = zeroCopy; this.zeroCopy = zeroCopy || false;
this.stack = []; this.stack = [];
} }

View File

@ -56,12 +56,9 @@ var FILL = 24;
* @param {(BufferWriter|Object)?} options * @param {(BufferWriter|Object)?} options
*/ */
function BufferWriter(options) { function BufferWriter() {
if (options instanceof BufferWriter)
return options;
if (!(this instanceof BufferWriter)) if (!(this instanceof BufferWriter))
return new BufferWriter(options); return new BufferWriter();
this.ops = []; this.ops = [];
this.written = 0; this.written = 0;

View File

@ -910,8 +910,8 @@ Account.prototype.toJSON = function toJSON(minimal) {
* @returns {Buffer} * @returns {Buffer}
*/ */
Account.prototype.toRaw = function toRaw(writer) { Account.prototype.toRaw = function toRaw() {
var bw = new BufferWriter(writer); var bw = new BufferWriter();
var i, key; var i, key;
bw.writeVarString(this.name, 'ascii'); bw.writeVarString(this.name, 'ascii');
@ -933,10 +933,7 @@ Account.prototype.toRaw = function toRaw(writer) {
bw.writeBytes(key.toRaw()); bw.writeBytes(key.toRaw());
} }
if (!writer) return bw.render();
bw = bw.render();
return bw;
}; };
/** /**

View File

@ -445,8 +445,8 @@ MasterKey.prototype._encrypt = co(function* encrypt(passphrase, aes) {
* @returns {Buffer} * @returns {Buffer}
*/ */
MasterKey.prototype.toRaw = function toRaw(writer) { MasterKey.prototype.toRaw = function toRaw() {
var bw = new BufferWriter(writer); var bw = new BufferWriter();
if (this.encrypted) { if (this.encrypted) {
bw.writeU8(1); bw.writeU8(1);
@ -458,19 +458,13 @@ MasterKey.prototype.toRaw = function toRaw(writer) {
bw.writeU32(this.r); bw.writeU32(this.r);
bw.writeU32(this.p); bw.writeU32(this.p);
if (!writer) return bw.render();
bw = bw.render();
return bw;
} }
bw.writeU8(0); bw.writeU8(0);
bw.writeVarBytes(this.key.toExtended()); bw.writeVarBytes(this.key.toExtended());
if (!writer) return bw.render();
bw = bw.render();
return bw;
}; };
/** /**

View File

@ -175,8 +175,8 @@ Path.fromRaw = function fromRaw(data) {
* @returns {Buffer} * @returns {Buffer}
*/ */
Path.prototype.toRaw = function toRaw(writer) { Path.prototype.toRaw = function toRaw() {
var bw = new BufferWriter(writer); var bw = new BufferWriter();
bw.writeU32(this.account); bw.writeU32(this.account);
bw.writeU8(this.keyType); bw.writeU8(this.keyType);
@ -206,10 +206,7 @@ Path.prototype.toRaw = function toRaw(writer) {
bw.write8(this.version); bw.write8(this.version);
bw.writeU8(this.type); bw.writeU8(this.type);
if (!writer) return bw.render();
bw = bw.render();
return bw;
}; };
/** /**

View File

@ -77,18 +77,15 @@ ChainState.fromRaw = function fromRaw(data) {
* @returns {Buffer} * @returns {Buffer}
*/ */
ChainState.prototype.toRaw = function toRaw(writer) { ChainState.prototype.toRaw = function toRaw() {
var bw = new BufferWriter(writer); var bw = new BufferWriter();
bw.writeU32(this.startHeight); bw.writeU32(this.startHeight);
bw.writeHash(this.startHash); bw.writeHash(this.startHash);
bw.writeU32(this.height); bw.writeU32(this.height);
bw.writeU8(this.marked ? 1 : 0); bw.writeU8(this.marked ? 1 : 0);
if (!writer) return bw.render();
bw = bw.render();
return bw;
}; };
/** /**
@ -202,17 +199,12 @@ BlockMeta.fromRaw = function fromRaw(data) {
* @returns {Buffer} * @returns {Buffer}
*/ */
BlockMeta.prototype.toRaw = function toRaw(writer) { BlockMeta.prototype.toRaw = function toRaw() {
var bw = new BufferWriter(writer); var bw = new BufferWriter();
bw.writeHash(this.hash); bw.writeHash(this.hash);
bw.writeU32(this.height); bw.writeU32(this.height);
bw.writeU32(this.ts); bw.writeU32(this.ts);
return bw.render();
if (!writer)
bw = bw.render();
return bw;
}; };
/** /**
@ -258,7 +250,7 @@ BlockMapRecord.prototype.fromRaw = function fromRaw(data) {
for (i = 0; i < count; i++) { for (i = 0; i < count; i++) {
hash = br.readHash('hex'); hash = br.readHash('hex');
tx = TXMapRecord.fromRaw(hash, br); tx = TXMapRecord.fromReader(hash, br);
this.txs.push(tx); this.txs.push(tx);
this.index[tx.hash] = tx; this.index[tx.hash] = tx;
} }
@ -283,8 +275,8 @@ BlockMapRecord.fromRaw = function fromRaw(height, data) {
* @returns {Buffer} * @returns {Buffer}
*/ */
BlockMapRecord.prototype.toRaw = function toRaw(writer) { BlockMapRecord.prototype.toRaw = function toRaw() {
var bw = new BufferWriter(writer); var bw = new BufferWriter();
var i, tx; var i, tx;
bw.writeU32(this.txs.length); bw.writeU32(this.txs.length);
@ -292,13 +284,10 @@ BlockMapRecord.prototype.toRaw = function toRaw(writer) {
for (i = 0; i < this.txs.length; i++) { for (i = 0; i < this.txs.length; i++) {
tx = this.txs[i]; tx = this.txs[i];
bw.writeHash(tx.hash); bw.writeHash(tx.hash);
tx.toRaw(bw); tx.toWriter(bw);
} }
if (!writer) return bw.render();
bw = bw.render();
return bw;
}; };
/** /**
@ -369,13 +358,25 @@ TXMapRecord.prototype.remove = function remove(wid) {
return util.binaryRemove(this.wids, wid, cmp); return util.binaryRemove(this.wids, wid, cmp);
}; };
TXMapRecord.prototype.toRaw = function toRaw(writer) { TXMapRecord.prototype.toWriter = function toWriter(bw) {
return serializeWallets(this.wids, writer); return serializeWallets(bw, this.wids);
};
TXMapRecord.prototype.toRaw = function toRaw() {
return this.toWriter(new BufferWriter()).render();
};
TXMapRecord.prototype.fromReader = function fromReader(br) {
this.wids = parseWallets(br);
return this;
}; };
TXMapRecord.prototype.fromRaw = function fromRaw(data) { TXMapRecord.prototype.fromRaw = function fromRaw(data) {
this.wids = parseWallets(data); return this.fromReader(new BufferReader(data));
return this; };
TXMapRecord.fromReader = function fromReader(hash, br) {
return new TXMapRecord(hash).fromReader(br);
}; };
TXMapRecord.fromRaw = function fromRaw(hash, data) { TXMapRecord.fromRaw = function fromRaw(hash, data) {
@ -401,13 +402,25 @@ OutpointMapRecord.prototype.remove = function remove(wid) {
return util.binaryRemove(this.wids, wid, cmp); return util.binaryRemove(this.wids, wid, cmp);
}; };
OutpointMapRecord.prototype.toRaw = function toRaw(writer) { OutpointMapRecord.prototype.toWriter = function toWriter(bw) {
return serializeWallets(this.wids, writer); return serializeWallets(bw, this.wids);
};
OutpointMapRecord.prototype.toRaw = function toRaw() {
return this.toWriter(new BufferWriter()).render();
};
OutpointMapRecord.prototype.fromReader = function fromReader(br) {
this.wids = parseWallets(br);
return this;
}; };
OutpointMapRecord.prototype.fromRaw = function fromRaw(data) { OutpointMapRecord.prototype.fromRaw = function fromRaw(data) {
this.wids = parseWallets(data); return this.fromReader(new BufferReader(data));
return this; };
OutpointMapRecord.fromReader = function fromReader(hash, index, br) {
return new OutpointMapRecord(hash, index).fromReader(br);
}; };
OutpointMapRecord.fromRaw = function fromRaw(hash, index, data) { OutpointMapRecord.fromRaw = function fromRaw(hash, index, data) {
@ -432,13 +445,25 @@ PathMapRecord.prototype.remove = function remove(wid) {
return util.binaryRemove(this.wids, wid, cmp); return util.binaryRemove(this.wids, wid, cmp);
}; };
PathMapRecord.prototype.toRaw = function toRaw(writer) { PathMapRecord.prototype.toWriter = function toWriter(bw) {
return serializeWallets(this.wids, writer); return serializeWallets(bw, this.wids);
};
PathMapRecord.prototype.toRaw = function toRaw() {
return this.toWriter(new BufferWriter()).render();
};
PathMapRecord.prototype.fromReader = function fromReader(br) {
this.wids = parseWallets(br);
return this;
}; };
PathMapRecord.prototype.fromRaw = function fromRaw(data) { PathMapRecord.prototype.fromRaw = function fromRaw(data) {
this.wids = parseWallets(data); return this.fromReader(new BufferReader(data));
return this; };
PathMapRecord.fromReader = function fromReader(hash, br) {
return new PathMapRecord(hash).fromReader(br);
}; };
PathMapRecord.fromRaw = function fromRaw(hash, data) { PathMapRecord.fromRaw = function fromRaw(hash, data) {
@ -457,8 +482,7 @@ function cmpid(a, b) {
return a.id - b.id; return a.id - b.id;
} }
function parseWallets(data) { function parseWallets(br) {
var br = new BufferReader(data);
var count = br.readU32(); var count = br.readU32();
var wids = []; var wids = [];
var i; var i;
@ -469,8 +493,7 @@ function parseWallets(data) {
return wids; return wids;
} }
function serializeWallets(wids, writer) { function serializeWallets(bw, wids) {
var bw = new BufferWriter(writer);
var i, wid; var i, wid;
bw.writeU32(wids.length); bw.writeU32(wids.length);
@ -480,9 +503,6 @@ function serializeWallets(wids, writer) {
bw.writeU32(wid); bw.writeU32(wid);
} }
if (!writer)
bw = bw.render();
return bw; return bw;
} }

View File

@ -2895,18 +2895,15 @@ TXDBState.prototype.toBalance = function toBalance() {
* @returns {Buffer} * @returns {Buffer}
*/ */
TXDBState.prototype.toRaw = function toRaw(writer) { TXDBState.prototype.toRaw = function toRaw() {
var bw = new BufferWriter(writer); var bw = new BufferWriter();
bw.writeU64(this.tx); bw.writeU64(this.tx);
bw.writeU64(this.coin); bw.writeU64(this.coin);
bw.writeU64(this.unconfirmed); bw.writeU64(this.unconfirmed);
bw.writeU64(this.confirmed); bw.writeU64(this.confirmed);
if (!writer) return bw.render();
bw = bw.render();
return bw;
}; };
/** /**
@ -2985,8 +2982,8 @@ function Credit(coin, spent) {
*/ */
Credit.prototype.fromRaw = function fromRaw(data) { Credit.prototype.fromRaw = function fromRaw(data) {
var br = BufferReader(data); var br = new BufferReader(data);
this.coin.fromRaw(br); this.coin.fromReader(br);
this.spent = br.readU8() === 1; this.spent = br.readU8() === 1;
return this; return this;
}; };
@ -3006,16 +3003,11 @@ Credit.fromRaw = function fromRaw(data) {
* @returns {Buffer} * @returns {Buffer}
*/ */
Credit.prototype.toRaw = function toRaw(writer) { Credit.prototype.toRaw = function toRaw() {
var bw = BufferWriter(writer); var bw = new BufferWriter();
this.coin.toWriter(bw);
this.coin.toRaw(bw);
bw.writeU8(this.spent ? 1 : 0); bw.writeU8(this.spent ? 1 : 0);
return bw.render();
if (!writer)
bw = bw.render();
return bw;
}; };
/** /**
@ -3377,8 +3369,8 @@ BlockRecord.fromRaw = function fromRaw(data) {
* @returns {Buffer} * @returns {Buffer}
*/ */
BlockRecord.prototype.toRaw = function toRaw(writer) { BlockRecord.prototype.toRaw = function toRaw() {
var bw = new BufferWriter(writer); var bw = new BufferWriter();
var i; var i;
bw.writeHash(this.hash); bw.writeHash(this.hash);
@ -3390,10 +3382,7 @@ BlockRecord.prototype.toRaw = function toRaw(writer) {
for (i = 0; i < this.hashes.length; i++) for (i = 0; i < this.hashes.length; i++)
bw.writeHash(this.hashes[i]); bw.writeHash(this.hashes[i]);
if (!writer) return bw.render();
bw = bw.render();
return bw;
}; };
/** /**

View File

@ -2440,8 +2440,8 @@ Wallet.prototype.toJSON = function toJSON(unsafe) {
* @returns {Buffer} * @returns {Buffer}
*/ */
Wallet.prototype.toRaw = function toRaw(writer) { Wallet.prototype.toRaw = function toRaw() {
var bw = new BufferWriter(writer); var bw = new BufferWriter();
bw.writeU32(this.network.magic); bw.writeU32(this.network.magic);
bw.writeU32(this.wid); bw.writeU32(this.wid);
@ -2453,10 +2453,7 @@ Wallet.prototype.toRaw = function toRaw(writer) {
bw.writeU32(this.tokenDepth); bw.writeU32(this.tokenDepth);
bw.writeVarBytes(this.master.toRaw()); bw.writeVarBytes(this.master.toRaw());
if (!writer) return bw.render();
bw = bw.render();
return bw;
}; };
/** /**

View File

@ -33,7 +33,7 @@ Framer.prototype.packet = function _packet(packet) {
bw.writeU8(packet.cmd); bw.writeU8(packet.cmd);
bw.seek(4); bw.seek(4);
packet.toRaw(bw); packet.toWriter(bw);
bw.writeU8(0x0a); bw.writeU8(0x0a);

View File

@ -53,7 +53,7 @@ Packet.id = 0;
Packet.prototype.cmd = -1; Packet.prototype.cmd = -1;
Packet.prototype.toRaw = function toRaw() { Packet.prototype.toWriter = function toWriter() {
throw new Error('Abstract method.'); throw new Error('Abstract method.');
}; };
@ -71,7 +71,7 @@ util.inherits(EventPacket, Packet);
EventPacket.prototype.cmd = packetTypes.EVENT; EventPacket.prototype.cmd = packetTypes.EVENT;
EventPacket.prototype.toRaw = function toRaw(bw) { EventPacket.prototype.toWriter = function toWriter(bw) {
bw.writeVarString(JSON.stringify(this.items), 'utf8'); bw.writeVarString(JSON.stringify(this.items), 'utf8');
}; };
@ -96,7 +96,7 @@ util.inherits(LogPacket, Packet);
LogPacket.prototype.cmd = packetTypes.LOG; LogPacket.prototype.cmd = packetTypes.LOG;
LogPacket.prototype.toRaw = function toRaw(bw) { LogPacket.prototype.toWriter = function toWriter(bw) {
bw.writeVarString(this.text, 'utf8'); bw.writeVarString(this.text, 'utf8');
}; };
@ -121,7 +121,7 @@ util.inherits(ErrorPacket, Packet);
ErrorPacket.prototype.cmd = packetTypes.ERROR; ErrorPacket.prototype.cmd = packetTypes.ERROR;
ErrorPacket.prototype.toRaw = function toRaw(bw) { ErrorPacket.prototype.toWriter = function toWriter(bw) {
bw.writeVarString(this.error.message + '', 'utf8'); bw.writeVarString(this.error.message + '', 'utf8');
bw.writeVarString(this.error.stack + '', 'utf8'); bw.writeVarString(this.error.stack + '', 'utf8');
bw.writeVarString((this.error.type || ''), 'utf8'); bw.writeVarString((this.error.type || ''), 'utf8');
@ -150,7 +150,7 @@ util.inherits(ErrorResultPacket, Packet);
ErrorResultPacket.prototype.cmd = packetTypes.ERRORRESULT; ErrorResultPacket.prototype.cmd = packetTypes.ERRORRESULT;
ErrorResultPacket.prototype.toRaw = function toRaw(bw) { ErrorResultPacket.prototype.toWriter = function toWriter(bw) {
bw.writeVarString(this.error.message + '', 'utf8'); bw.writeVarString(this.error.message + '', 'utf8');
bw.writeVarString(this.error.stack + '', 'utf8'); bw.writeVarString(this.error.stack + '', 'utf8');
bw.writeVarString((this.error.type || ''), 'utf8'); bw.writeVarString((this.error.type || ''), 'utf8');
@ -180,16 +180,22 @@ util.inherits(VerifyPacket, Packet);
VerifyPacket.prototype.cmd = packetTypes.VERIFY; VerifyPacket.prototype.cmd = packetTypes.VERIFY;
VerifyPacket.prototype.toRaw = function(bw) { VerifyPacket.prototype.toWriter = function(bw) {
frameTX(this.tx, bw); frameTX(this.tx, bw);
bw.writeU32(this.flags); bw.write32(this.flags != null ? this.flags : -1);
}; };
VerifyPacket.fromRaw = function fromRaw(TX, data) { VerifyPacket.fromRaw = function fromRaw(TX, data) {
var br = new BufferReader(data, true); var br = new BufferReader(data, true);
var packet = new VerifyPacket(); var packet = new VerifyPacket();
packet.tx = parseTX(TX, br); packet.tx = parseTX(TX, br);
packet.flags = br.readU32();
packet.flags = br.read32();
if (packet.flags === -1)
packet.flags = null;
return packet; return packet;
}; };
@ -207,7 +213,7 @@ util.inherits(VerifyResultPacket, Packet);
VerifyResultPacket.prototype.cmd = packetTypes.VERIFYRESULT; VerifyResultPacket.prototype.cmd = packetTypes.VERIFYRESULT;
VerifyResultPacket.prototype.toRaw = function toRaw(bw) { VerifyResultPacket.prototype.toWriter = function toWriter(bw) {
bw.writeU8(this.value ? 1 : 0); bw.writeU8(this.value ? 1 : 0);
}; };
@ -234,16 +240,16 @@ util.inherits(SignPacket, Packet);
SignPacket.prototype.cmd = packetTypes.SIGN; SignPacket.prototype.cmd = packetTypes.SIGN;
SignPacket.prototype.toRaw = function toRaw(bw) { SignPacket.prototype.toWriter = function toWriter(bw) {
var i, ring; var i, ring;
frameTX(this.tx, bw); frameTX(this.tx, bw);
bw.writeU32(this.rings.length); bw.writeVarint(this.rings.length);
for (i = 0; i < this.rings.length; i++) { for (i = 0; i < this.rings.length; i++) {
ring = this.rings[i]; ring = this.rings[i];
bw.writeBytes(ring.toRaw()); ring.toWriter(bw);
} }
bw.write8(this.type != null ? this.type : -1); bw.write8(this.type != null ? this.type : -1);
@ -256,10 +262,10 @@ SignPacket.fromRaw = function fromRaw(MTX, KeyRing, data) {
packet.tx = parseTX(MTX, br); packet.tx = parseTX(MTX, br);
count = br.readU32(); count = br.readVarint();
for (i = 0; i < count; i++) { for (i = 0; i < count; i++) {
ring = KeyRing.fromRaw(br); ring = KeyRing.fromReader(br);
packet.rings.push(ring); packet.rings.push(ring);
} }
@ -300,7 +306,7 @@ SignResultPacket.fromTX = function fromTX(tx, total) {
return packet; return packet;
}; };
SignResultPacket.prototype.toRaw = function toRaw(bw) { SignResultPacket.prototype.toWriter = function toWriter(bw) {
var i; var i;
assert(this.script.length === this.witness.length); assert(this.script.length === this.witness.length);
@ -309,8 +315,8 @@ SignResultPacket.prototype.toRaw = function toRaw(bw) {
bw.writeVarint(this.script.length); bw.writeVarint(this.script.length);
for (i = 0; i < this.script.length; i++) { for (i = 0; i < this.script.length; i++) {
this.script[i].toRaw(bw); this.script[i].toWriter(bw);
this.witness[i].toRaw(bw); this.witness[i].toWriter(bw);
} }
}; };
@ -337,8 +343,8 @@ SignResultPacket.fromRaw = function fromRaw(data) {
count = br.readVarint(); count = br.readVarint();
for (i = 0; i < count; i++) { for (i = 0; i < count; i++) {
packet.script.push(Script.fromRaw(br)); packet.script.push(Script.fromReader(br));
packet.witness.push(Witness.fromRaw(br)); packet.witness.push(Witness.fromReader(br));
} }
return packet; return packet;
@ -360,9 +366,9 @@ util.inherits(VerifyInputPacket, Packet);
VerifyInputPacket.prototype.cmd = packetTypes.VERIFYINPUT; VerifyInputPacket.prototype.cmd = packetTypes.VERIFYINPUT;
VerifyInputPacket.prototype.toRaw = function toRaw(bw) { VerifyInputPacket.prototype.toWriter = function toWriter(bw) {
frameTX(this.tx, bw); frameTX(this.tx, bw);
bw.writeU32(this.index); bw.writeVarint(this.index);
bw.write32(this.flags != null ? this.flags : -1); bw.write32(this.flags != null ? this.flags : -1);
}; };
@ -371,7 +377,7 @@ VerifyInputPacket.fromRaw = function fromRaw(TX, data) {
var packet = new VerifyInputPacket(); var packet = new VerifyInputPacket();
packet.tx = parseTX(TX, br); packet.tx = parseTX(TX, br);
packet.index = br.readU32(); packet.index = br.readVarint();
packet.flags = br.read32(); packet.flags = br.read32();
if (packet.flags === -1) if (packet.flags === -1)
@ -394,7 +400,7 @@ util.inherits(VerifyInputResultPacket, Packet);
VerifyInputResultPacket.prototype.cmd = packetTypes.VERIFYINPUTRESULT; VerifyInputResultPacket.prototype.cmd = packetTypes.VERIFYINPUTRESULT;
VerifyInputResultPacket.prototype.toRaw = function toRaw(bw) { VerifyInputResultPacket.prototype.toWriter = function toWriter(bw) {
bw.writeU8(this.value ? 1 : 0); bw.writeU8(this.value ? 1 : 0);
}; };
@ -410,11 +416,11 @@ VerifyInputResultPacket.fromRaw = function fromRaw(data) {
* @constructor * @constructor
*/ */
function SignInputPacket(tx, index, rings, type) { function SignInputPacket(tx, index, ring, type) {
Packet.call(this); Packet.call(this);
this.tx = tx || null; this.tx = tx || null;
this.index = index; this.index = index;
this.rings = rings || []; this.ring = ring || null;
this.type = type != null ? type : null; this.type = type != null ? type : null;
} }
@ -422,18 +428,19 @@ util.inherits(SignInputPacket, Packet);
SignInputPacket.prototype.cmd = packetTypes.SIGNINPUT; SignInputPacket.prototype.cmd = packetTypes.SIGNINPUT;
SignInputPacket.prototype.toRaw = function toRaw(bw) { SignInputPacket.prototype.toWriter = function toWriter(bw) {
var i, ring; var input = this.tx.inputs[this.index];
frameTX(this.tx, bw); assert(input);
bw.writeU32(this.index); assert(input.coin);
bw.writeU32(this.rings.length); this.tx.toWriter(bw);
bw.writeVarint(this.index);
for (i = 0; i < this.rings.length; i++) { bw.writeVarint(input.coin.value);
ring = this.rings[i]; input.coin.script.toWriter(bw);
bw.writeBytes(ring.toRaw());
} this.ring.toWriter(bw);
bw.write8(this.type != null ? this.type : -1); bw.write8(this.type != null ? this.type : -1);
}; };
@ -441,27 +448,33 @@ SignInputPacket.prototype.toRaw = function toRaw(bw) {
SignInputPacket.fromRaw = function fromRaw(MTX, KeyRing, data) { SignInputPacket.fromRaw = function fromRaw(MTX, KeyRing, data) {
var br = new BufferReader(data, true); var br = new BufferReader(data, true);
var packet = new SignInputPacket(); var packet = new SignInputPacket();
var i, count, ring; var coin = new Coin();
var input;
packet.tx = parseTX(MTX, br); packet.tx = parseTX(MTX, br);
packet.index = br.readU32(); packet.index = br.readVarint();
count = br.readU32(); coin.value = br.readVarint();
coin.script.fromReader(br);
for (i = 0; i < count; i++) { packet.ring = KeyRing.fromReader(br);
ring = KeyRing.fromRaw(br);
packet.rings.push(ring);
}
packet.type = br.read8(); packet.type = br.read8();
if (packet.type === -1) if (packet.type === -1)
packet.type = null; packet.type = null;
input = packet.tx.inputs[packet.index];
assert(input);
coin.hash = input.prevout.hash;
coin.index = input.prevout.index;
input.coin = coin;
return packet; return packet;
}; };
/** /**
* SignInputResultPacket * SignInputResultPacket
* @constructor * @constructor
@ -490,10 +503,10 @@ SignInputResultPacket.fromTX = function fromTX(tx, i, value) {
return packet; return packet;
}; };
SignInputResultPacket.prototype.toRaw = function toRaw(bw) { SignInputResultPacket.prototype.toWriter = function toWriter(bw) {
bw.writeU8(this.value ? 1 : 0); bw.writeU8(this.value ? 1 : 0);
this.script.toRaw(bw); this.script.toWriter(bw);
this.witness.toRaw(bw); this.witness.toWriter(bw);
}; };
SignInputResultPacket.prototype.inject = function inject(tx, i) { SignInputResultPacket.prototype.inject = function inject(tx, i) {
@ -507,8 +520,8 @@ SignInputResultPacket.fromRaw = function fromRaw(data) {
var br = new BufferReader(data, true); var br = new BufferReader(data, true);
var packet = new SignInputResultPacket(); var packet = new SignInputResultPacket();
packet.value = br.readU8() === 1; packet.value = br.readU8() === 1;
packet.script = Script.fromRaw(br); packet.script = Script.fromReader(br);
packet.witness = Witness.fromRaw(br); packet.witness = Witness.fromReader(br);
return packet; return packet;
}; };
@ -529,7 +542,7 @@ util.inherits(ECVerifyPacket, Packet);
ECVerifyPacket.prototype.cmd = packetTypes.ECVERIFY; ECVerifyPacket.prototype.cmd = packetTypes.ECVERIFY;
ECVerifyPacket.prototype.toRaw = function(bw) { ECVerifyPacket.prototype.toWriter = function(bw) {
bw.writeVarBytes(this.msg); bw.writeVarBytes(this.msg);
bw.writeVarBytes(this.sig); bw.writeVarBytes(this.sig);
bw.writeVarBytes(this.key); bw.writeVarBytes(this.key);
@ -558,7 +571,7 @@ util.inherits(ECVerifyResultPacket, Packet);
ECVerifyResultPacket.prototype.cmd = packetTypes.ECVERIFYRESULT; ECVerifyResultPacket.prototype.cmd = packetTypes.ECVERIFYRESULT;
ECVerifyResultPacket.prototype.toRaw = function toRaw(bw) { ECVerifyResultPacket.prototype.toWriter = function toWriter(bw) {
bw.writeU8(this.value ? 1 : 0); bw.writeU8(this.value ? 1 : 0);
}; };
@ -584,7 +597,7 @@ util.inherits(ECSignPacket, Packet);
ECSignPacket.prototype.cmd = packetTypes.ECSIGN; ECSignPacket.prototype.cmd = packetTypes.ECSIGN;
ECSignPacket.prototype.toRaw = function(bw) { ECSignPacket.prototype.toWriter = function(bw) {
bw.writeVarBytes(this.msg); bw.writeVarBytes(this.msg);
bw.writeVarBytes(this.key); bw.writeVarBytes(this.key);
}; };
@ -611,7 +624,7 @@ util.inherits(ECSignResultPacket, Packet);
ECSignResultPacket.prototype.cmd = packetTypes.ECSIGNRESULT; ECSignResultPacket.prototype.cmd = packetTypes.ECSIGNRESULT;
ECSignResultPacket.prototype.toRaw = function toRaw(bw) { ECSignResultPacket.prototype.toWriter = function toWriter(bw) {
bw.writeVarBytes(this.sig); bw.writeVarBytes(this.sig);
}; };
@ -639,7 +652,7 @@ util.inherits(MinePacket, Packet);
MinePacket.prototype.cmd = packetTypes.MINE; MinePacket.prototype.cmd = packetTypes.MINE;
MinePacket.prototype.toRaw = function(bw) { MinePacket.prototype.toWriter = function(bw) {
bw.writeBytes(this.data); bw.writeBytes(this.data);
bw.writeBytes(this.target); bw.writeBytes(this.target);
bw.writeU32(this.min); bw.writeU32(this.min);
@ -670,7 +683,7 @@ util.inherits(MineResultPacket, Packet);
MineResultPacket.prototype.cmd = packetTypes.MINERESULT; MineResultPacket.prototype.cmd = packetTypes.MINERESULT;
MineResultPacket.prototype.toRaw = function toRaw(bw) { MineResultPacket.prototype.toWriter = function toWriter(bw) {
bw.writeU32(this.nonce); bw.writeU32(this.nonce);
}; };
@ -702,7 +715,7 @@ util.inherits(ScryptPacket, Packet);
ScryptPacket.prototype.cmd = packetTypes.SCRYPT; ScryptPacket.prototype.cmd = packetTypes.SCRYPT;
ScryptPacket.prototype.toRaw = function(bw) { ScryptPacket.prototype.toWriter = function(bw) {
bw.writeVarBytes(this.passwd); bw.writeVarBytes(this.passwd);
bw.writeVarBytes(this.salt); bw.writeVarBytes(this.salt);
bw.writeU32(this.N); bw.writeU32(this.N);
@ -737,7 +750,7 @@ util.inherits(ScryptResultPacket, Packet);
ScryptResultPacket.prototype.cmd = packetTypes.SCRYPTRESULT; ScryptResultPacket.prototype.cmd = packetTypes.SCRYPTRESULT;
ScryptResultPacket.prototype.toRaw = function toRaw(bw) { ScryptResultPacket.prototype.toWriter = function toWriter(bw) {
bw.writeVarBytes(this.key); bw.writeVarBytes(this.key);
}; };
@ -755,7 +768,7 @@ ScryptResultPacket.fromRaw = function fromRaw(data) {
function frameTX(tx, bw) { function frameTX(tx, bw) {
var i, input; var i, input;
tx.toRaw(bw); tx.toWriter(bw);
for (i = 0; i < tx.inputs.length; i++) { for (i = 0; i < tx.inputs.length; i++) {
input = tx.inputs[i]; input = tx.inputs[i];
@ -767,12 +780,12 @@ function frameTX(tx, bw) {
bw.writeU8(1); bw.writeU8(1);
bw.writeVarint(input.coin.value); bw.writeVarint(input.coin.value);
input.coin.script.toRaw(bw); input.coin.script.toWriter(bw);
} }
} }
function parseTX(TX, br) { function parseTX(TX, br) {
var tx = TX.fromRaw(br); var tx = TX.fromReader(br);
var i, input, prevout, coin; var i, input, prevout, coin;
for (i = 0; i < tx.inputs.length; i++) { for (i = 0; i < tx.inputs.length; i++) {
@ -784,7 +797,7 @@ function parseTX(TX, br) {
coin = new Coin(); coin = new Coin();
coin.value = br.readVarint(); coin.value = br.readVarint();
coin.script.fromRaw(br); coin.script.fromReader(br);
coin.hash = prevout.hash; coin.hash = prevout.hash;
coin.index = prevout.index; coin.index = prevout.index;

View File

@ -317,17 +317,9 @@ WorkerPool.prototype.verifyInput = co(function* verifyInput(tx, index, flags) {
*/ */
WorkerPool.prototype.signInput = co(function* signInput(tx, index, ring, type) { WorkerPool.prototype.signInput = co(function* signInput(tx, index, ring, type) {
var rings = ring; var packet = new packets.SignInputPacket(tx, index, ring, type);
var packet, result; var result = yield this.execute(packet, -1);
if (!Array.isArray(rings))
rings = [rings];
packet = new packets.SignInputPacket(tx, index, rings, type);
result = yield this.execute(packet, -1);
result.inject(tx); result.inject(tx);
return result.value; return result.value;
}); });

View File

@ -188,7 +188,7 @@ var reserializeUndo = co(function* reserializeUndo() {
while (br.left()) { while (br.left()) {
undo.push(null); undo.push(null);
injectCoin(undo.top(), Coin.fromRaw(br)); injectCoin(undo.top(), Coin.fromReader(br));
} }
batch.write(item.key, undo.toRaw()); batch.write(item.key, undo.toRaw());

View File

@ -139,8 +139,8 @@ function parseWallets(data) {
return wids; return wids;
} }
function serializeWallets(wids, writer) { function serializeWallets(wids) {
var p = new BufferWriter(writer); var p = new BufferWriter();
var i, wid; var i, wid;
p.writeU32(wids.length); p.writeU32(wids.length);
@ -150,10 +150,7 @@ function serializeWallets(wids, writer) {
p.writeU32(wid); p.writeU32(wid);
} }
if (!writer) return p.render();
p = p.render();
return p;
} }
function accountToRaw(account) { function accountToRaw(account) {

View File

@ -207,10 +207,9 @@ describe('Protocol', function() {
}); });
it('should parse, reserialize, and verify alert packets', function() { it('should parse, reserialize, and verify alert packets', function() {
var p = new bcoin.reader(alertData); var br = new bcoin.reader(alertData);
p.start(); while (br.left()) {
while (p.left()) { var alert = packets.AlertPacket.fromReader(br);
var alert = packets.AlertPacket.fromRaw(p);
assert(alert.verify(network.alertKey)); assert(alert.verify(network.alertKey));
alert._payload = null; alert._payload = null;
alert._hash = null; alert._hash = null;
@ -218,6 +217,5 @@ describe('Protocol', function() {
alert = packets.AlertPacket.fromRaw(data); alert = packets.AlertPacket.fromRaw(data);
assert(alert.verify(network.alertKey)); assert(alert.verify(network.alertKey));
} }
p.end();
}); });
}); });

View File

@ -19,22 +19,22 @@ describe('Script', function() {
+ '101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f' + '101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f'
+ 'ac'; + 'ac';
var decoded = bcoin.script.decode(new Buffer(src, 'hex')); var decoded = bcoin.script(new Buffer(src, 'hex'));
assert.equal(decoded.length, 3); assert.equal(decoded.code.length, 3);
assert.equal(decoded[0].data.toString('hex'), assert.equal(decoded.code[0].data.toString('hex'),
'000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f'); '000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f');
assert.equal(decoded[1].data.toString('hex'), assert.equal(decoded.code[1].data.toString('hex'),
'101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f'); '101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f');
assert.equal(decoded[2].value, opcodes.OP_CHECKSIG); assert.equal(decoded.code[2].value, opcodes.OP_CHECKSIG);
var dst = bcoin.script.encode(decoded); var dst = decoded.toRaw();
assert.equal(dst.toString('hex'), src); assert.equal(dst.toString('hex'), src);
}); });
it('should encode/decode numbers', function() { it('should encode/decode numbers', function() {
var script = [0, 0x51, 0x52, 0x60]; var script = [0, 0x51, 0x52, 0x60];
var encoded = bcoin.script.fromArray(script).raw; var encoded = bcoin.script.fromArray(script).raw;
var decoded = bcoin.script.decode(encoded).map(function(op) { return op.value; }); var decoded = bcoin.script(encoded).toArray();
assert.deepEqual(decoded, script); assert.deepEqual(decoded, script);
}); });