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) {
|
||||
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
|
||||
|
||||
Loading…
Reference in New Issue
Block a user