tx: improve witness parsing.
This commit is contained in:
parent
32a2e119e1
commit
476cc48702
@ -2128,7 +2128,7 @@ TX.fromRaw = function fromRaw(data, enc) {
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
TX.prototype.fromRaw = function fromRaw(data) {
|
TX.prototype.fromRaw = function fromRaw(data) {
|
||||||
var p, i, inCount, outCount;
|
var p, i, count;
|
||||||
|
|
||||||
if (TX.isWitness(data))
|
if (TX.isWitness(data))
|
||||||
return this.fromWitness(data);
|
return this.fromWitness(data);
|
||||||
@ -2138,14 +2138,14 @@ TX.prototype.fromRaw = function fromRaw(data) {
|
|||||||
|
|
||||||
this.version = p.readU32(); // Technically signed
|
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));
|
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.outputs.push(Output.fromRaw(p));
|
||||||
|
|
||||||
this.locktime = p.readU32();
|
this.locktime = p.readU32();
|
||||||
@ -2170,48 +2170,60 @@ TX.prototype.fromRaw = function fromRaw(data) {
|
|||||||
|
|
||||||
TX.prototype.fromWitness = function fromWitness(data) {
|
TX.prototype.fromWitness = function fromWitness(data) {
|
||||||
var p = BufferReader(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();
|
p.start();
|
||||||
|
|
||||||
this.version = p.readU32(); // Technically signed
|
this.version = p.readU32(); // Technically signed
|
||||||
|
|
||||||
marker = p.readU8();
|
assert(p.readU8() === 0, 'Non-zero marker.');
|
||||||
this.flag = p.readU8();
|
|
||||||
|
|
||||||
if (marker !== 0)
|
flag = p.readU8();
|
||||||
throw new Error('Invalid witness tx (marker != 0)');
|
|
||||||
|
|
||||||
if (this.flag === 0)
|
assert(flag !== 0, 'Flag byte is zero.');
|
||||||
throw new Error('Invalid witness tx (flag == 0)');
|
|
||||||
|
|
||||||
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));
|
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.outputs.push(Output.fromRaw(p));
|
||||||
|
|
||||||
p.start();
|
if (flag & 1) {
|
||||||
|
flag ^= 1;
|
||||||
|
|
||||||
for (i = 0; i < inCount; i++) {
|
p.start();
|
||||||
input = this.inputs[i];
|
|
||||||
input.witness.fromRaw(p);
|
for (i = 0; i < this.inputs.length; i++) {
|
||||||
if (input.witness.items.length > 0)
|
input = this.inputs[i];
|
||||||
hasWitness = true;
|
input.witness.fromRaw(p);
|
||||||
|
if (input.witness.items.length > 0)
|
||||||
|
hasWitness = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
witnessSize = p.end() + 2;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!hasWitness)
|
if (flag !== 0)
|
||||||
throw new Error('Witness tx has an empty witness.');
|
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();
|
this.locktime = p.readU32();
|
||||||
|
|
||||||
if (!this.mutable) {
|
if (!this.mutable && hasWitness) {
|
||||||
this._raw = p.endData();
|
this._raw = p.endData();
|
||||||
this._size = this._raw.length;
|
this._size = this._raw.length;
|
||||||
this._witnessSize = witnessSize;
|
this._witnessSize = witnessSize;
|
||||||
@ -2222,27 +2234,6 @@ TX.prototype.fromWitness = function fromWitness(data) {
|
|||||||
return this;
|
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.
|
* Serialize transaction without witness.
|
||||||
* @private
|
* @private
|
||||||
@ -2254,7 +2245,7 @@ TX.prototype.frameNormal = function frameNormal(writer) {
|
|||||||
var p = BufferWriter(writer);
|
var p = BufferWriter(writer);
|
||||||
var i;
|
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.');
|
throw new Error('Cannot serialize zero-input tx.');
|
||||||
|
|
||||||
p.write32(this.version);
|
p.write32(this.version);
|
||||||
@ -2292,6 +2283,9 @@ TX.prototype.frameWitness = function frameWitness(writer) {
|
|||||||
var witnessSize = 0;
|
var witnessSize = 0;
|
||||||
var i, start;
|
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.write32(this.version);
|
||||||
p.writeU8(0);
|
p.writeU8(0);
|
||||||
p.writeU8(this.flag);
|
p.writeU8(this.flag);
|
||||||
@ -2326,6 +2320,27 @@ TX.prototype.frameWitness = function frameWitness(writer) {
|
|||||||
return p;
|
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".
|
* Serialize a transaction to BCoin "extended format".
|
||||||
* This is the serialization format BCoin uses internally
|
* This is the serialization format BCoin uses internally
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user