tx: improve witness parsing.

This commit is contained in:
Christopher Jeffrey 2016-10-03 04:55:32 -07:00
parent 32a2e119e1
commit 476cc48702
No known key found for this signature in database
GPG Key ID: 8962AB9DE6666BBD

View File

@ -2128,7 +2128,7 @@ TX.fromRaw = function fromRaw(data, enc) {
*/
TX.prototype.fromRaw = function fromRaw(data) {
var p, i, inCount, outCount;
var p, i, count;
if (TX.isWitness(data))
return this.fromWitness(data);
@ -2138,14 +2138,14 @@ TX.prototype.fromRaw = function fromRaw(data) {
this.version = p.readU32(); // Technically signed
inCount = p.readVarint();
count = p.readVarint();
for (i = 0; i < inCount; i++)
for (i = 0; i < count; i++)
this.inputs.push(Input.fromRaw(p));
outCount = p.readVarint();
count = p.readVarint();
for (i = 0; i < outCount; i++)
for (i = 0; i < count; i++)
this.outputs.push(Output.fromRaw(p));
this.locktime = p.readU32();
@ -2170,48 +2170,60 @@ TX.prototype.fromRaw = function fromRaw(data) {
TX.prototype.fromWitness = function fromWitness(data) {
var p = BufferReader(data);
var i, marker, inCount, outCount, input, hasWitness, witnessSize;
var flag = 0;
var witnessSize = 0;
var hasWitness = false;
var i, count, input;
p.start();
this.version = p.readU32(); // Technically signed
marker = p.readU8();
this.flag = p.readU8();
assert(p.readU8() === 0, 'Non-zero marker.');
if (marker !== 0)
throw new Error('Invalid witness tx (marker != 0)');
flag = p.readU8();
if (this.flag === 0)
throw new Error('Invalid witness tx (flag == 0)');
assert(flag !== 0, 'Flag byte is zero.');
inCount = p.readVarint();
this.flag = flag;
for (i = 0; i < inCount; i++)
count = p.readVarint();
for (i = 0; i < count; i++)
this.inputs.push(Input.fromRaw(p));
outCount = p.readVarint();
count = p.readVarint();
for (i = 0; i < outCount; i++)
for (i = 0; i < count; i++)
this.outputs.push(Output.fromRaw(p));
p.start();
if (flag & 1) {
flag ^= 1;
for (i = 0; i < inCount; i++) {
input = this.inputs[i];
input.witness.fromRaw(p);
if (input.witness.items.length > 0)
hasWitness = true;
p.start();
for (i = 0; i < this.inputs.length; i++) {
input = this.inputs[i];
input.witness.fromRaw(p);
if (input.witness.items.length > 0)
hasWitness = true;
}
witnessSize = p.end() + 2;
}
if (!hasWitness)
throw new Error('Witness tx has an empty witness.');
if (flag !== 0)
throw new Error('Unknown witness flag.');
witnessSize = p.end() + 2;
// We'll never be able to reserialize
// this to get the regular txid, and
// there's no way it's valid anyway.
if (this.inputs.length === 0 && this.outputs.length !== 0)
throw new Error('Zero input witness tx.');
this.locktime = p.readU32();
if (!this.mutable) {
if (!this.mutable && hasWitness) {
this._raw = p.endData();
this._size = this._raw.length;
this._witnessSize = witnessSize;
@ -2222,27 +2234,6 @@ TX.prototype.fromWitness = function fromWitness(data) {
return this;
};
/**
* Test whether data is a witness transaction.
* @param {Buffer|BufferReader} data
* @returns {Boolean}
*/
TX.isWitness = function isWitness(data) {
if (Buffer.isBuffer(data)) {
if (data.length < 12)
return false;
return data[4] === 0 && data[5] !== 0;
}
if (data.left() < 12)
return false;
return data.data[data.offset + 4] === 0
&& data.data[data.offset + 5] !== 0;
};
/**
* Serialize transaction without witness.
* @private
@ -2254,7 +2245,7 @@ TX.prototype.frameNormal = function frameNormal(writer) {
var p = BufferWriter(writer);
var i;
if (this.inputs.length === 0 && this.outputs.length === 1)
if (this.inputs.length === 0 && this.outputs.length !== 0)
throw new Error('Cannot serialize zero-input tx.');
p.write32(this.version);
@ -2292,6 +2283,9 @@ TX.prototype.frameWitness = function frameWitness(writer) {
var witnessSize = 0;
var i, start;
if (this.inputs.length === 0 && this.outputs.length !== 0)
throw new Error('Cannot serialize zero-input tx.');
p.write32(this.version);
p.writeU8(0);
p.writeU8(this.flag);
@ -2326,6 +2320,27 @@ TX.prototype.frameWitness = function frameWitness(writer) {
return p;
};
/**
* Test whether data is a witness transaction.
* @param {Buffer|BufferReader} data
* @returns {Boolean}
*/
TX.isWitness = function isWitness(data) {
if (Buffer.isBuffer(data)) {
if (data.length < 6)
return false;
return data[4] === 0 && data[5] !== 0;
}
if (data.left() < 6)
return false;
return data.data[data.offset + 4] === 0
&& data.data[data.offset + 5] !== 0;
};
/**
* Serialize a transaction to BCoin "extended format".
* This is the serialization format BCoin uses internally