new way of handling script parsing.
This commit is contained in:
parent
91acf2a607
commit
1d8a86838d
@ -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.');
|
||||
|
||||
Loading…
Reference in New Issue
Block a user