new way of handling script parsing.

This commit is contained in:
Christopher Jeffrey 2016-04-20 09:17:58 -07:00
parent 91acf2a607
commit 1d8a86838d
No known key found for this signature in database
GPG Key ID: 8962AB9DE6666BBD

View File

@ -1047,8 +1047,6 @@ Script.prototype.execute = function execute(stack, flags, tx, index, version) {
op = this.code[ip];
if (Buffer.isBuffer(op)) {
if (!Script.checkPush(op))
throw new ScriptError('BAD_OPCODE', op, ip);
if (op.length > constants.script.MAX_PUSH)
throw new ScriptError('PUSH_SIZE', op, ip);
// Note that minimaldata is not checked
@ -1981,7 +1979,7 @@ Script.array = function(value) {
Script.prototype.removeData = function removeData(data) {
var total = 0;
var pushdata = data.pushdata;
var op = data.op;
var sig, raw, i, a, b;
if (!this.raw)
@ -1989,10 +1987,10 @@ Script.prototype.removeData = function removeData(data) {
// We need to reserialize
// the signature as minimaldata.
delete data.pushdata;
delete data.op;
sig = new Script([data]).encode();
if (pushdata)
utils.hidden(data, 'pushdata', pushdata);
if (op)
utils.hidden(data, 'op', op);
raw = this.encode();
@ -2064,38 +2062,6 @@ Script.prototype.indexOf = function indexOf(data) {
return utils.indexOf(this.code, data);
};
/**
* Test whether an op is a buffer, also
* check for buffer underflows.
* @param {Buffer?} value
* @returns {Boolean}
*/
Script.isPush = function isPush(value) {
return Buffer.isBuffer(value) && Script.checkPush(value);
};
/**
* Perform some range checking on the pushdatas
* (exactly what GetOp2 does). Note that this
* _must_ be done during execution, not parsing.
* @see GetOp2
* @param {Buffer} value - Pushdata op from script code
* (must be from a deserialized script).
* @returns {Boolean}
*/
Script.checkPush = function checkPush(value) {
var pushdata = value.pushdata;
if (!pushdata)
return true;
// The pushdata size can never
// be greater than the buffer.
return pushdata.size === value.length;
};
/**
* Check to see if a pushdata Buffer abides by minimaldata.
* @param {Buffer} value - Pushdata op from script code
@ -2105,15 +2071,13 @@ Script.checkPush = function checkPush(value) {
*/
Script.checkMinimal = function checkMinimal(value, flags) {
var pushdata = value.pushdata;
if (flags == null)
flags = constants.flags.STANDARD_VERIFY_FLAGS;
if (!(flags & constants.flags.VERIFY_MINIMALDATA))
return true;
if (!pushdata)
if (value.op == null)
return true;
if (value.length === 1 && value[0] >= 1 && value[0] <= 16)
@ -2123,13 +2087,13 @@ Script.checkMinimal = function checkMinimal(value, flags) {
return false;
if (value.length <= 75)
return pushdata.opcode == null && pushdata.size === value.length;
return value.op === value.length;
if (value.length <= 255)
return pushdata.opcode === opcodes.OP_PUSHDATA1;
return value.op === opcodes.OP_PUSHDATA1;
if (value.length <= 65535)
return pushdata.opcode === opcodes.OP_PUSHDATA2;
return value.op === opcodes.OP_PUSHDATA2;
return true;
};
@ -2155,7 +2119,7 @@ Script.isCode = function isCode(buf) {
op = code[i];
if (Buffer.isBuffer(op))
continue;
if (op >= opcodes.OP_PUSHDATA1 && op <= opcodes.OP_PUSHDATA4)
if (Script.isBadPush(op))
return false;
if (constants.opcodesByVal[op] == null)
return false;
@ -2312,7 +2276,7 @@ Script.prototype.getRedeem = function getRedeem() {
Script.getRedeem = function getRedeem(code) {
var redeem = code[code.length - 1];
if (!Script.isPush(redeem))
if (!Buffer.isBuffer(redeem))
return;
return new Script(redeem);
@ -2662,14 +2626,11 @@ Script.prototype.isNulldata = function isNulldata() {
for (i = 1; i < this.code.length; i++) {
op = this.code[i];
if (Buffer.isBuffer(op)) {
if (!Script.checkPush(op))
return false;
if (Buffer.isBuffer(op))
continue;
}
if (op > opcodes.OP_16)
return false;
if (op >= opcodes.OP_PUSHDATA1 && op <= opcodes.OP_PUSHDATA4)
if (Script.isBadPush(op))
return false;
}
@ -2699,7 +2660,7 @@ Script.prototype.isCommitment = function isCommitment() {
}
return this.code.length >= 2
&& this.code[0] === opcodes.OP_RETURN
&& Script.isPush(this.code[1])
&& Buffer.isBuffer(this.code[1])
&& this.code[1].length === 36
&& utils.readU32BE(this.code[1], 0) === 0xaa21a9ed;
};
@ -2746,7 +2707,7 @@ Script.prototype.isWitnessProgram = function isWitnessProgram() {
if (typeof this.code[0] !== 'number')
return false;
if (!Script.isPush(this.code[1]))
if (!Buffer.isBuffer(this.code[1]))
return false;
return (this.code[0] === opcodes.OP_0
@ -3044,7 +3005,7 @@ Script.isScripthashInput = function isScripthashInput(code, isWitness) {
// Last data element should be an array
// for the redeem script.
if (!Script.isPush(raw))
if (!Buffer.isBuffer(raw))
return false;
// Testing for scripthash inputs requires
@ -3101,9 +3062,6 @@ Script.getCoinbaseHeight = function getCoinbaseHeight(code) {
if (!Buffer.isBuffer(code[0]))
return -1;
if (!Script.checkPush(code[0]))
return -1;
if (!Script.checkMinimal(code[0]))
return -1;
@ -3152,7 +3110,7 @@ Script.prototype.getCoinbaseData = function getCoinbaseData() {
*/
Script.isHash = function isHash(hash) {
return Script.isPush(hash) && hash.length === 20;
return Buffer.isBuffer(hash) && hash.length === 20;
};
/**
@ -3163,7 +3121,7 @@ Script.isHash = function isHash(hash) {
*/
Script.isKey = function isKey(key) {
return Script.isPush(key) && key.length >= 33 && key.length <= 65;
return Buffer.isBuffer(key) && key.length >= 33 && key.length <= 65;
};
/**
@ -3174,7 +3132,7 @@ Script.isKey = function isKey(key) {
*/
Script.isSignature = function isSignature(sig) {
return Script.isPush(sig) && sig.length >= 9 && sig.length <= 73;
return Buffer.isBuffer(sig) && sig.length >= 9 && sig.length <= 73;
};
/**
@ -3184,7 +3142,7 @@ Script.isSignature = function isSignature(sig) {
*/
Script.isDummy = function isDummy(data) {
return Script.isPush(data) && data.length === 0;
return Buffer.isBuffer(data) && data.length === 0;
};
/**
@ -3213,7 +3171,7 @@ Script.validateKey = function validateKey(key, flags) {
if (flags == null)
flags = constants.flags.STANDARD_VERIFY_FLAGS;
if (!Script.isPush(key))
if (!Buffer.isBuffer(key))
throw new ScriptError('BAD_OPCODE');
if (flags & constants.flags.VERIFY_STRICTENC) {
@ -3231,7 +3189,7 @@ Script.validateKey = function validateKey(key, flags) {
*/
Script.isKeyEncoding = function isKeyEncoding(key) {
if (!Script.isPush(key))
if (!Buffer.isBuffer(key))
return false;
if (key.length < 33)
@ -3266,7 +3224,7 @@ Script.validateSignature = function validateSignature(sig, flags) {
if (flags == null)
flags = constants.flags.STANDARD_VERIFY_FLAGS;
if (!Script.isPush(sig))
if (!Buffer.isBuffer(sig))
throw new ScriptError('BAD_OPCODE');
// Allow empty sigs
@ -3303,7 +3261,7 @@ Script.validateSignature = function validateSignature(sig, flags) {
Script.isSignatureEncoding = function isSignatureEncoding(sig) {
var lenR, lenS;
if (!Script.isPush(sig))
if (!Buffer.isBuffer(sig))
return false;
// Format: 0x30 [total-length] 0x02 [R-length] [R] 0x02 [S-length] [S] [sighash]
@ -3394,7 +3352,7 @@ Script.isSignatureEncoding = function isSignatureEncoding(sig) {
Script.isHashType = function isHashType(sig) {
var type;
if (!Script.isPush(sig))
if (!Buffer.isBuffer(sig))
return false;
if (sig.length === 0)
@ -3416,7 +3374,7 @@ Script.isHashType = function isHashType(sig) {
Script.isLowDER = function isLowDER(sig) {
if (!sig.s) {
if (!Script.isPush(sig))
if (!Buffer.isBuffer(sig))
return false;
if (!Script.isSignatureEncoding(sig))
@ -3485,14 +3443,11 @@ Script.prototype.isPushOnly = function isPushOnly() {
var i, op;
for (i = 0; i < this.code.length; i++) {
op = this.code[i];
if (Buffer.isBuffer(op)) {
if (!Script.checkPush(op))
return false;
if (Buffer.isBuffer(op))
continue;
}
if (op > opcodes.OP_16)
return false;
if (op >= opcodes.OP_PUSHDATA1 && op <= opcodes.OP_PUSHDATA4)
if (Script.isBadPush(op))
return false;
}
return true;
@ -3513,13 +3468,10 @@ Script.prototype.getSigops = function getSigops(accurate) {
for (i = 0; i < this.code.length; i++) {
op = this.code[i];
if (Script.isPush(op))
if (Buffer.isBuffer(op))
continue;
if (op >= opcodes.OP_PUSHDATA1 && op <= opcodes.OP_PUSHDATA4)
return 0;
if (constants.opcodesByVal[op] == null)
if (Script.isBadPush(op))
return 0;
if (op === opcodes.OP_CHECKSIG || op === opcodes.OP_CHECKSIGVERIFY) {
@ -4085,72 +4037,14 @@ Script.fromRaw = function fromRaw(data, enc) {
* @returns {Array} Script code.
*/
Script.isPushOp = function isPushOp(op) {
if (Buffer.isBuffer(op)) {
if (!Script.checkPush(op))
return false;
Script.isBadPush = function isBadPush(op) {
if (Buffer.isBuffer(op))
return false;
if (op >= 0x01 && op <= 0x4b)
return true;
}
if (op > opcodes.OP_16)
return false;
if (op >= opcodes.OP_PUSHDATA1 && op <= opcodes.OP_PUSHDATA4)
return false;
return true;
};
Script.decode = function decode(buf) {
var code = [];
var off = 0;
var op, size;
assert(Buffer.isBuffer(buf));
while (off < buf.length) {
op = buf[off++];
if (op >= 0x01 && op <= 0x4b) {
code.push(buf.slice(off, off + op));
off += op;
// if (off > buf.length) {
utils.hidden(code[code.length - 1], 'pushdata', {
opcode: null,
size: op
});
} else if (op === opcodes.OP_PUSHDATA1) {
size = buf[off];
off += 1;
code.push(buf.slice(off, off + size));
off += size;
// if (size <= 0x4b || off > buf.length) {
utils.hidden(code[code.length - 1], 'pushdata', {
opcode: op,
size: size
});
} else if (op === opcodes.OP_PUSHDATA2) {
size = utils.readU16(buf, off);
off += 2;
code.push(buf.slice(off, off + size));
off += size;
// if (size <= 0xff || off > buf.length) {
utils.hidden(code[code.length - 1], 'pushdata', {
opcode: op,
size: size
});
} else if (op === opcodes.OP_PUSHDATA4) {
size = utils.readU32(buf, off);
off += 4;
code.push(buf.slice(off, off + size));
off += size;
// if (size <= 0xffff || off > buf.length) {
utils.hidden(code[code.length - 1], 'pushdata', {
opcode: op,
size: size
});
} else {
code.push(op);
}
}
return code;
return true;
return false;
};
Script.decode = function decode(buf) {
@ -4164,11 +4058,14 @@ Script.decode = function decode(buf) {
while (p.left()) {
op = p.readU8();
if (op >= 0x01 && op <= 0x4b) {
data = p.readBytes(Math.min(p.left(), op));
utils.hidden(data, 'pushdata', {
opcode: null,
size: op
});
if (p.left() < op) {
code.push(op);
while (p.left())
code.push(p.readU8());
continue;
}
data = p.readBytes(op);
utils.hidden(data, 'op', op);
code.push(data);
} else if (op === opcodes.OP_PUSHDATA1) {
if (p.left() < 1) {
@ -4185,11 +4082,8 @@ Script.decode = function decode(buf) {
code.push(p.readU8());
continue;
}
data = p.readBytes(Math.min(p.left(), size));
utils.hidden(data, 'pushdata', {
opcode: op,
size: size
});
data = p.readBytes(size);
utils.hidden(data, 'op', op);
code.push(data);
} else if (op === opcodes.OP_PUSHDATA2) {
if (p.left() < 2) {
@ -4207,11 +4101,8 @@ Script.decode = function decode(buf) {
code.push(p.readU8());
continue;
}
data = p.readBytes(Math.min(p.left(), size));
utils.hidden(data, 'pushdata', {
opcode: op,
size: size
});
data = p.readBytes(size);
utils.hidden(data, 'op', op);
code.push(data);
} else if (op === opcodes.OP_PUSHDATA4) {
if (p.left() < 4) {
@ -4231,11 +4122,8 @@ Script.decode = function decode(buf) {
code.push(p.readU8());
continue;
}
data = p.readBytes(Math.min(p.left(), size));
utils.hidden(data, 'pushdata', {
opcode: op,
size: size
});
data = p.readBytes(size);
utils.hidden(data, 'op', op);
code.push(data);
} else {
code.push(op);
@ -4271,21 +4159,21 @@ Script.encode = function encode(code, writer) {
if (Buffer.isBuffer(op)) {
// Check for nonstandard pushdatas that
// may have been decoded from before.
if (op.pushdata) {
if (op.pushdata.opcode === null) {
p.writeU8(op.pushdata.size);
if (op.op != null) {
if (op.op <= 0x4b) {
p.writeU8(op.length);
p.writeBytes(op);
} else if (op.pushdata.opcode === opcodes.OP_PUSHDATA1) {
} else if (op.op === opcodes.OP_PUSHDATA1) {
p.writeU8(opcodes.OP_PUSHDATA1);
p.writeU8(op.pushdata.size);
p.writeU8(op.length);
p.writeBytes(op);
} else if (op.pushdata.opcode === opcodes.OP_PUSHDATA2) {
} else if (op.op === opcodes.OP_PUSHDATA2) {
p.writeU8(opcodes.OP_PUSHDATA2);
p.writeU16(op.pushdata.size);
p.writeU16(op.length);
p.writeBytes(op);
} else if (op.pushdata.opcode === opcodes.OP_PUSHDATA4) {
} else if (op.op === opcodes.OP_PUSHDATA4) {
p.writeU8(opcodes.OP_PUSHDATA4);
p.writeU32(op.pushdata.size);
p.writeU32(op.length);
p.writeBytes(op);
} else {
assert(false, 'Bad pushdata op.');