tx: refactor sighashing and hasStandardWitness.
This commit is contained in:
parent
ff856fd6c2
commit
47adb5a5a7
@ -25,6 +25,7 @@ const Bloom = require('../utils/bloom');
|
||||
const consensus = require('../protocol/consensus');
|
||||
const policy = require('../protocol/policy');
|
||||
const {ScriptError} = require('../script/common');
|
||||
const hashType = Script.hashType;
|
||||
|
||||
/**
|
||||
* A static transaction object.
|
||||
@ -444,10 +445,9 @@ TX.prototype.signatureHash = function signatureHash(index, prev, value, type, ve
|
||||
*/
|
||||
|
||||
TX.prototype.signatureHashV0 = function signatureHashV0(index, prev, type) {
|
||||
let i, size, bw, input, output;
|
||||
let hashType = type & 0x1f;
|
||||
let size, bw;
|
||||
|
||||
if (hashType === Script.hashType.SINGLE) {
|
||||
if ((type & 0x1f) === hashType.SINGLE) {
|
||||
// Bitcoind used to return 1 as an error code:
|
||||
// it ended up being treated like a hash.
|
||||
if (index >= this.outputs.length)
|
||||
@ -465,12 +465,13 @@ TX.prototype.signatureHashV0 = function signatureHashV0(index, prev, type) {
|
||||
bw.writeU32(this.version);
|
||||
|
||||
// Serialize inputs.
|
||||
if (type & Script.hashType.ANYONECANPAY) {
|
||||
bw.writeVarint(1);
|
||||
|
||||
if (type & hashType.ANYONECANPAY) {
|
||||
// Serialize only the current
|
||||
// input if ANYONECANPAY.
|
||||
input = this.inputs[index];
|
||||
let input = this.inputs[index];
|
||||
|
||||
// Count.
|
||||
bw.writeVarint(1);
|
||||
|
||||
// Outpoint.
|
||||
input.prevout.toWriter(bw);
|
||||
@ -481,8 +482,8 @@ TX.prototype.signatureHashV0 = function signatureHashV0(index, prev, type) {
|
||||
bw.writeU32(input.sequence);
|
||||
} else {
|
||||
bw.writeVarint(this.inputs.length);
|
||||
for (i = 0; i < this.inputs.length; i++) {
|
||||
input = this.inputs[i];
|
||||
for (let i = 0; i < this.inputs.length; i++) {
|
||||
let input = this.inputs[i];
|
||||
|
||||
// Outpoint.
|
||||
input.prevout.toWriter(bw);
|
||||
@ -499,9 +500,9 @@ TX.prototype.signatureHashV0 = function signatureHashV0(index, prev, type) {
|
||||
bw.writeVarint(0);
|
||||
|
||||
// Sequences are 0 if NONE or SINGLE.
|
||||
switch (hashType) {
|
||||
case Script.hashType.NONE:
|
||||
case Script.hashType.SINGLE:
|
||||
switch (type & 0x1f) {
|
||||
case hashType.NONE:
|
||||
case hashType.SINGLE:
|
||||
bw.writeU32(0);
|
||||
break;
|
||||
default:
|
||||
@ -512,17 +513,20 @@ TX.prototype.signatureHashV0 = function signatureHashV0(index, prev, type) {
|
||||
}
|
||||
|
||||
// Serialize outputs.
|
||||
switch (hashType) {
|
||||
case Script.hashType.NONE:
|
||||
switch (type & 0x1f) {
|
||||
case hashType.NONE: {
|
||||
// No outputs if NONE.
|
||||
bw.writeVarint(0);
|
||||
break;
|
||||
case Script.hashType.SINGLE:
|
||||
}
|
||||
case hashType.SINGLE: {
|
||||
let output = this.outputs[index];
|
||||
|
||||
// Drop all outputs after the
|
||||
// current input index if SINGLE.
|
||||
bw.writeVarint(index + 1);
|
||||
|
||||
for (i = 0; i < index; i++) {
|
||||
for (let i = 0; i < index; i++) {
|
||||
// Null all outputs not at
|
||||
// current input index.
|
||||
bw.write64(-1);
|
||||
@ -531,16 +535,17 @@ TX.prototype.signatureHashV0 = function signatureHashV0(index, prev, type) {
|
||||
|
||||
// Regular serialization
|
||||
// at current input index.
|
||||
output = this.outputs[index];
|
||||
output.toWriter(bw);
|
||||
|
||||
break;
|
||||
default:
|
||||
}
|
||||
default: {
|
||||
// Regular output serialization if ALL.
|
||||
bw.writeVarint(this.outputs.length);
|
||||
for (output of this.outputs)
|
||||
for (let output of this.outputs)
|
||||
output.toWriter(bw);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
bw.writeU32(this.locktime);
|
||||
@ -565,7 +570,7 @@ TX.prototype.hashSize = function hashSize(index, prev, type) {
|
||||
|
||||
size += 4;
|
||||
|
||||
if (type & Script.hashType.ANYONECANPAY) {
|
||||
if (type & hashType.ANYONECANPAY) {
|
||||
size += 1;
|
||||
size += 36;
|
||||
size += prev.getVarSize();
|
||||
@ -579,10 +584,10 @@ TX.prototype.hashSize = function hashSize(index, prev, type) {
|
||||
}
|
||||
|
||||
switch (type & 0x1f) {
|
||||
case Script.hashType.NONE:
|
||||
case hashType.NONE:
|
||||
size += 1;
|
||||
break;
|
||||
case Script.hashType.SINGLE:
|
||||
case hashType.SINGLE:
|
||||
size += encoding.sizeVarint(index + 1);
|
||||
size += 9 * index;
|
||||
size += this.outputs[index].getSize();
|
||||
@ -613,15 +618,16 @@ TX.prototype.signatureHashV1 = function signatureHashV1(index, prev, value, type
|
||||
let prevouts = encoding.ZERO_HASH;
|
||||
let sequences = encoding.ZERO_HASH;
|
||||
let outputs = encoding.ZERO_HASH;
|
||||
let bw, size, input, output;
|
||||
let input = this.inputs[index];
|
||||
let bw, size;
|
||||
|
||||
if (!(type & Script.hashType.ANYONECANPAY)) {
|
||||
if (!(type & hashType.ANYONECANPAY)) {
|
||||
if (this._hashPrevouts) {
|
||||
prevouts = this._hashPrevouts;
|
||||
} else {
|
||||
bw = new StaticWriter(this.inputs.length * 36);
|
||||
let bw = new StaticWriter(this.inputs.length * 36);
|
||||
|
||||
for (input of this.inputs)
|
||||
for (let input of this.inputs)
|
||||
input.prevout.toWriter(bw);
|
||||
|
||||
prevouts = digest.hash256(bw.render());
|
||||
@ -631,15 +637,15 @@ TX.prototype.signatureHashV1 = function signatureHashV1(index, prev, value, type
|
||||
}
|
||||
}
|
||||
|
||||
if (!(type & Script.hashType.ANYONECANPAY)
|
||||
&& (type & 0x1f) !== Script.hashType.SINGLE
|
||||
&& (type & 0x1f) !== Script.hashType.NONE) {
|
||||
if (!(type & hashType.ANYONECANPAY)
|
||||
&& (type & 0x1f) !== hashType.SINGLE
|
||||
&& (type & 0x1f) !== hashType.NONE) {
|
||||
if (this._hashSequence) {
|
||||
sequences = this._hashSequence;
|
||||
} else {
|
||||
bw = new StaticWriter(this.inputs.length * 4);
|
||||
let bw = new StaticWriter(this.inputs.length * 4);
|
||||
|
||||
for (input of this.inputs)
|
||||
for (let input of this.inputs)
|
||||
bw.writeU32(input.sequence);
|
||||
|
||||
sequences = digest.hash256(bw.render());
|
||||
@ -649,19 +655,20 @@ TX.prototype.signatureHashV1 = function signatureHashV1(index, prev, value, type
|
||||
}
|
||||
}
|
||||
|
||||
if ((type & 0x1f) !== Script.hashType.SINGLE
|
||||
&& (type & 0x1f) !== Script.hashType.NONE) {
|
||||
if ((type & 0x1f) !== hashType.SINGLE
|
||||
&& (type & 0x1f) !== hashType.NONE) {
|
||||
if (this._hashOutputs) {
|
||||
outputs = this._hashOutputs;
|
||||
} else {
|
||||
size = 0;
|
||||
let size = 0;
|
||||
let bw;
|
||||
|
||||
for (output of this.outputs)
|
||||
for (let output of this.outputs)
|
||||
size += output.getSize();
|
||||
|
||||
bw = new StaticWriter(size);
|
||||
|
||||
for (output of this.outputs)
|
||||
for (let output of this.outputs)
|
||||
output.toWriter(bw);
|
||||
|
||||
outputs = digest.hash256(bw.render());
|
||||
@ -669,13 +676,11 @@ TX.prototype.signatureHashV1 = function signatureHashV1(index, prev, value, type
|
||||
if (!this.mutable)
|
||||
this._hashOutputs = outputs;
|
||||
}
|
||||
} else if ((type & 0x1f) === Script.hashType.SINGLE && index < this.outputs.length) {
|
||||
output = this.outputs[index];
|
||||
} else if ((type & 0x1f) === hashType.SINGLE && index < this.outputs.length) {
|
||||
let output = this.outputs[index];
|
||||
outputs = digest.hash256(output.toRaw());
|
||||
}
|
||||
|
||||
input = this.inputs[index];
|
||||
|
||||
size = 156 + prev.getVarSize();
|
||||
bw = new StaticWriter(size);
|
||||
|
||||
@ -734,7 +739,7 @@ TX.prototype.signature = function signature(index, prev, value, key, type, versi
|
||||
let hash, sig, bw;
|
||||
|
||||
if (type == null)
|
||||
type = Script.hashType.ALL;
|
||||
type = hashType.ALL;
|
||||
|
||||
if (version == null)
|
||||
version = 0;
|
||||
@ -1453,9 +1458,8 @@ TX.prototype.checkStandard = function checkStandard() {
|
||||
if (this.version < 1 || this.version > policy.MAX_TX_VERSION)
|
||||
return [false, 'version', 0];
|
||||
|
||||
if (this.getWeight() >= policy.MAX_TX_WEIGHT) {
|
||||
if (this.getWeight() >= policy.MAX_TX_WEIGHT)
|
||||
return [false, 'tx-size', 0];
|
||||
}
|
||||
|
||||
for (let input of this.inputs) {
|
||||
if (input.script.getSize() > 1650)
|
||||
@ -1536,14 +1540,13 @@ TX.prototype.hasStandardInputs = function hasStandardInputs(view) {
|
||||
*/
|
||||
|
||||
TX.prototype.hasStandardWitness = function hasStandardWitness(view) {
|
||||
|
||||
if (this.isCoinbase())
|
||||
return true;
|
||||
|
||||
for (let input of this.inputs) {
|
||||
let witness = input.witness;
|
||||
let coin = view.getOutput(input);
|
||||
let prev, redeem, m;
|
||||
let prev;
|
||||
|
||||
if (!coin)
|
||||
continue;
|
||||
@ -1576,11 +1579,14 @@ TX.prototype.hasStandardWitness = function hasStandardWitness(view) {
|
||||
}
|
||||
|
||||
if (prev.isWitnessScripthash()) {
|
||||
let redeem;
|
||||
|
||||
if (witness.items.length - 1 > policy.MAX_P2WSH_STACK)
|
||||
return false;
|
||||
|
||||
for (let i = 0; i < witness.items.length - 1; i++) {
|
||||
if (witness.items[i].length > policy.MAX_P2WSH_PUSH)
|
||||
let item = witness.items[i];
|
||||
if (item.length > policy.MAX_P2WSH_PUSH)
|
||||
return false;
|
||||
}
|
||||
|
||||
@ -1615,7 +1621,7 @@ TX.prototype.hasStandardWitness = function hasStandardWitness(view) {
|
||||
}
|
||||
|
||||
if (prev.isMultisig()) {
|
||||
m = prev.getSmall(0);
|
||||
let m = prev.getSmall(0);
|
||||
|
||||
if (witness.items.length - 1 !== m + 1)
|
||||
return false;
|
||||
@ -1624,7 +1630,8 @@ TX.prototype.hasStandardWitness = function hasStandardWitness(view) {
|
||||
return false;
|
||||
|
||||
for (let i = 1; i < witness.items.length - 1; i++) {
|
||||
if (witness.items[i].length > 73)
|
||||
let item = witness.items[i];
|
||||
if (item.length > 73)
|
||||
return false;
|
||||
}
|
||||
}
|
||||
@ -1635,8 +1642,8 @@ TX.prototype.hasStandardWitness = function hasStandardWitness(view) {
|
||||
if (witness.items.length > policy.MAX_P2WSH_STACK)
|
||||
return false;
|
||||
|
||||
for (let i = 0; i < witness.items.length; i++) {
|
||||
if (witness.items[i].length > policy.MAX_P2WSH_PUSH)
|
||||
for (let item of witness.items) {
|
||||
if (item.length > policy.MAX_P2WSH_PUSH)
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
Loading…
Reference in New Issue
Block a user