no strings in scripting.

This commit is contained in:
Christopher Jeffrey 2016-03-28 16:50:59 -07:00
parent 2c9756f38b
commit a598a4850c
4 changed files with 215 additions and 232 deletions

View File

@ -13,6 +13,7 @@ var constants = bcoin.protocol.constants;
var network = bcoin.protocol.network;
var Script = bcoin.script;
var Witness = bcoin.script.witness;
var opc = constants.opcodes;
/**
* MTX
@ -188,7 +189,7 @@ MTX.prototype.scriptInput = function scriptInput(index, addr) {
redeemScript = addr.program.encode();
vector = input.witness.items;
dummy = new Buffer([]);
assert(addr.program.code[0] === 0, 'Non-zero version passed to address.');
assert(addr.program.code[0] === opc['0'], 'Non-zero version passed to address.');
if (addr.program.code[1].length === 32) {
// P2WSH nested within pay-to-scripthash
// (it had to be this complicated, didn't it?)
@ -205,7 +206,7 @@ MTX.prototype.scriptInput = function scriptInput(index, addr) {
redeemScript = addr.script.encode();
vector = input.script.code;
prev = addr.script;
dummy = 0;
dummy = opc['0'];
} else {
return false;
}
@ -214,7 +215,7 @@ MTX.prototype.scriptInput = function scriptInput(index, addr) {
vector = input.witness.items;
dummy = new Buffer([]);
if (prev.code[0] !== 0)
if (prev.code[0] !== opc['0'])
return false;
if (prev.code[1].length === 32) {
@ -237,7 +238,7 @@ MTX.prototype.scriptInput = function scriptInput(index, addr) {
} else {
// Wow, a normal output! Praise be to Jengus and Gord.
vector = input.script.code;
dummy = 0;
dummy = opc['0'];
}
if (prev.isPubkey()) {
@ -276,7 +277,7 @@ MTX.prototype.scriptInput = function scriptInput(index, addr) {
vector[0] = dummy;
// Grab `n` value (number of keys).
n = prev.code[prev.code.length - 2];
n = prev.code[prev.code.length - 2] - 0x50;
// Fill script with `n` signature slots.
for (i = 0; i < n; i++)
@ -359,7 +360,7 @@ MTX.prototype.signInput = function signInput(index, addr, type) {
vector = input.script.code;
len = vector.length;
dummy = 0;
dummy = opc['0'];
version = 0;
// We need to grab the redeem script when
@ -433,10 +434,10 @@ MTX.prototype.signInput = function signInput(index, addr, type) {
keys = prev.code.slice(1, -2);
// Grab `m` value (number of sigs required).
m = prev.code[0];
m = prev.code[0] - 0x50;
// Grab `n` value (number of keys).
n = prev.code[prev.code.length - 2];
n = prev.code[prev.code.length - 2] - 0x50;
} else {
// Only allow non-standard signing for
// scripthash.
@ -583,9 +584,7 @@ MTX.prototype.isSigned = function isSigned(m) {
return false;
} else if (prev.isMultisig()) {
// Grab `m` value (number of required sigs).
m = prev.code[0];
if (Buffer.isBuffer(m))
m = m[0] || 0;
m = prev.code[0] - 0x50;
// Ensure all members are signatures.
for (j = 1; j < len; j++) {
@ -738,7 +737,7 @@ MTX.prototype.maxSize = function maxSize(maxM, maxN) {
} else if (prev.isMultisig()) {
// Bare Multisig
// Get the previous m value:
m = prev.code[0];
m = prev.code[0] - 0x50;
// OP_0
size += 1;
// OP_PUSHDATA0 [signature] ...

View File

@ -10,6 +10,7 @@ var constants = bcoin.protocol.constants;
var utils = require('./utils');
var assert = utils.assert;
var BufferWriter = require('./writer');
var opc = constants.opcodes;
function Witness(items) {
if (!(this instanceof Witness))
@ -221,21 +222,21 @@ Stack.prototype._swap = function _swap(i1, i2) {
Stack.prototype.toalt = function toalt() {
if (this.length === 0)
throw new ScriptError('Stack too small.', 'toaltstack');
throw new ScriptError('Stack too small.', opc.toaltstack);
this.alt.push(this.pop());
};
Stack.prototype.fromalt = function fromalt() {
if (this.alt.length === 0)
throw new ScriptError('Stack too small.', 'fromaltstack');
throw new ScriptError('Stack too small.', opc.fromaltstack);
this.push(this.alt.pop());
};
Stack.prototype.ifdup = function ifdup() {
if (this.length === 0)
throw new ScriptError('Stack too small.', 'ifdup');
throw new ScriptError('Stack too small.', opc.ifdup);
if (Script.bool(this.top(-1)))
this.push(Script.array(this.top(-1)));
@ -247,38 +248,38 @@ Stack.prototype.depth = function depth() {
Stack.prototype.drop = function drop() {
if (this.length === 0)
throw new ScriptError('Stack too small.', 'drop');
throw new ScriptError('Stack too small.', opc.drop);
this.pop();
};
Stack.prototype.dup = function dup() {
if (this.length === 0)
throw new ScriptError('Stack too small.', 'dup');
throw new ScriptError('Stack too small.', opc.dup);
this.push(this.top(-1));
};
Stack.prototype.nip = function nip() {
if (this.length < 2)
throw new ScriptError('Stack too small.', 'nip');
throw new ScriptError('Stack too small.', opc.nip);
this.splice(this.length - 2, 1);
};
Stack.prototype.over = function over() {
if (this.length < 2)
throw new ScriptError('Stack too small.', 'over');
throw new ScriptError('Stack too small.', opc.over);
this.push(this.top(-2));
};
Stack.prototype.pick = function pick(flags) {
return this._pickroll('pick', flags);
return this._pickroll(opc.pick, flags);
};
Stack.prototype.roll = function roll(flags) {
return this._pickroll('roll', flags);
return this._pickroll(opc.roll, flags);
};
Stack.prototype._pickroll = function pickroll(op, flags) {
@ -295,7 +296,7 @@ Stack.prototype._pickroll = function pickroll(op, flags) {
val = this.get(-n - 1);
if (op === 'roll')
if (op === opc.roll)
this.splice(this.length - n - 1, 1);
this.push(val);
@ -303,7 +304,7 @@ Stack.prototype._pickroll = function pickroll(op, flags) {
Stack.prototype.rot = function rot() {
if (this.length < 3)
throw new ScriptError('Stack too small.', 'rot');
throw new ScriptError('Stack too small.', opc.rot);
this._swap(-3, -2);
this._swap(-2, -1);
@ -311,21 +312,21 @@ Stack.prototype.rot = function rot() {
Stack.prototype.swap = function swap() {
if (this.length < 2)
throw new ScriptError('Stack too small.', 'swap');
throw new ScriptError('Stack too small.', opc.swap);
this._swap(-2, -1);
};
Stack.prototype.tuck = function tuck() {
if (this.length < 2)
throw new ScriptError('Stack too small.', 'tuck');
throw new ScriptError('Stack too small.', opc.tuck);
this.splice(this.length - 2, 0, this.top(-1));
};
Stack.prototype.drop2 = function drop2() {
if (this.length < 2)
throw new ScriptError('Stack too small.', '2drop');
throw new ScriptError('Stack too small.', opc['2drop']);
this.pop();
this.pop();
@ -335,7 +336,7 @@ Stack.prototype.dup2 = function dup2() {
var v1, v2;
if (this.length < 2)
throw new ScriptError('Stack too small.', '2dup');
throw new ScriptError('Stack too small.', opc['2dup']);
v1 = this.top(-2);
v2 = this.top(-1);
@ -348,7 +349,7 @@ Stack.prototype.dup3 = function dup3() {
var v1, v2, v3;
if (this.length < 3)
throw new ScriptError('Stack too small.', '3dup');
throw new ScriptError('Stack too small.', opc['3dup']);
v1 = this.top(-3);
v2 = this.top(-2);
@ -363,7 +364,7 @@ Stack.prototype.over2 = function over2() {
var v1, v2;
if (this.length < 4)
throw new ScriptError('Stack too small.', '2over');
throw new ScriptError('Stack too small.', opc['2over']);
v1 = this.top(-4);
v2 = this.top(-3);
@ -376,7 +377,7 @@ Stack.prototype.rot2 = function rot2() {
var v1, v2;
if (this.length < 6)
throw new ScriptError('Stack too small.', '2rot');
throw new ScriptError('Stack too small.', opc['2rot']);
v1 = this.top(-6);
v2 = this.top(-5);
@ -393,7 +394,7 @@ Stack.prototype.swap2 = function swap2() {
Stack.prototype.size = function size() {
if (this.length < 1)
throw new ScriptError('Stack too small.', 'size');
throw new ScriptError('Stack too small.', opc.size);
this.push(Script.array(this.top(-1).length));
};
@ -445,10 +446,10 @@ Script.prototype.getSubscript = function getSubscript(lastSep) {
if (lastSep == null)
lastSep = -1;
assert(lastSep <= 0 || this.code[lastSep] === 'codeseparator');
assert(lastSep <= 0 || this.code[lastSep] === opc.codeseparator);
for (i = lastSep + 1; i < this.code.length; i++) {
if (this.code[i] !== 'codeseparator')
if (this.code[i] !== opc.codeseparator)
res.push(this.code[i]);
}
@ -470,11 +471,11 @@ Script.prototype._next = function _next(to, code, ip) {
while (code[ip]) {
op = code[ip];
if (op === 'if' || op === 'notif')
if (op === opc['if'] || op === opc.notif)
depth++;
else if (op === 'else')
else if (op === opc['else'])
depth--;
else if (op === 'endif')
else if (op === opc.endif)
depth--;
if (depth < 0)
@ -483,7 +484,7 @@ Script.prototype._next = function _next(to, code, ip) {
if (depth === 0 && op === to)
return ip;
if (op === 'else')
if (op === opc['else'])
depth++;
ip++;
@ -537,44 +538,44 @@ Script.prototype.interpret = function interpret(stack, flags, tx, index, version
continue;
}
if (op === 0) {
if (op === opc['0']) {
stack.push(new Buffer([]));
continue;
}
if (op >= 1 && op <= 16) {
stack.push(new Buffer([op]));
if (op >= opc['1'] && op <= opc['16']) {
stack.push(new Buffer([op - 0x50]));
continue;
}
switch (op) {
case 'nop':
case 'nop1':
case 'nop4':
case 'nop5':
case 'nop6':
case 'nop7':
case 'nop8':
case 'nop9':
case 'nop10': {
case opc.nop:
case opc.nop1:
case opc.nop4:
case opc.nop5:
case opc.nop6:
case opc.nop7:
case opc.nop8:
case opc.nop9:
case opc.nop10: {
if (flags & constants.flags.VERIFY_DISCOURAGE_UPGRADABLE_NOPS)
throw new ScriptError('Upgradable NOP used.', op, ip);
break;
}
case '1negate': {
case opc['1negate']: {
stack.push(new Buffer([0xff]));
break;
}
case 'if':
case 'notif': {
case opc['if']:
case opc.notif: {
if (stack.length < 1)
throw new ScriptError('Stack too small.', op, ip);
val = Script.bool(stack.pop());
if (op === 'notif')
if (op === opc.notif)
val = !val;
if_ = ip;
else_ = this._next('else', code, ip);
endif = this._next('endif', code, ip);
else_ = this._next(opc['else'], code, ip);
endif = this._next(opc.endif, code, ip);
// Splice out the statement blocks we don't need
if (val) {
if (endif === -1)
@ -600,129 +601,129 @@ Script.prototype.interpret = function interpret(stack, flags, tx, index, version
ip--;
break;
}
case 'else': {
case opc['else']: {
throw new ScriptError('Unexpected else.', op, ip);
}
case 'endif': {
case opc.endif: {
throw new ScriptError('Unexpected endif.', op, ip);
}
case 'verify': {
case opc.verify: {
if (stack.length === 0)
throw new ScriptError('Stack too small.', op, ip);
if (!Script.bool(stack.pop()))
throw new ScriptError('Verification failed.', op, ip);
break;
}
case 'return': {
case opc['return']: {
throw new ScriptError('Script returned.', op, ip);
}
case 'toaltstack': {
case opc.toaltstack: {
stack.toalt();
break;
}
case 'fromaltstack': {
case opc.fromaltstack: {
stack.fromalt();
break;
}
case 'ifdup': {
case opc.ifdup: {
stack.ifdup();
break;
}
case 'depth': {
case opc.depth: {
stack.depth();
break;
}
case 'drop': {
case opc.drop: {
stack.drop();
break;
}
case 'dup': {
case opc.dup: {
stack.dup();
break;
}
case 'nip': {
case opc.nip: {
stack.nip();
break;
}
case 'over': {
case opc.over: {
stack.over();
break;
}
case 'pick': {
case opc.pick: {
stack.pick(flags);
break;
}
case 'roll': {
case opc.roll: {
stack.roll(flags);
break;
}
case 'rot': {
case opc.rot: {
stack.rot();
break;
}
case 'swap': {
case opc.swap: {
stack.swap();
break;
}
case 'tuck': {
case opc.tuck: {
stack.tuck();
break;
}
case '2drop': {
case opc['2drop']: {
stack.drop2();
break;
}
case '2dup': {
case opc['2dup']: {
stack.dup2();
break;
}
case '3dup': {
case opc['3dup']: {
stack.dup3();
break;
}
case '2over': {
case opc['2over']: {
stack.over2();
break;
}
case '2rot': {
case opc['2rot']: {
stack.rot2();
break;
}
case '2swap': {
case opc['2swap']: {
stack.swap2();
break;
}
case 'size': {
case opc.size: {
stack.size();
break;
}
case '1add':
case '1sub':
case 'negate':
case 'abs':
case 'not':
case '0notequal': {
case opc['1add']:
case opc['1sub']:
case opc.negate:
case opc.abs:
case opc.not:
case opc['0notequal']: {
if (stack.length < 1)
throw new ScriptError('Stack too small.', op, ip);
n = Script.num(stack.pop(), flags);
switch (op) {
case '1add':
case opc['1add']:
n.iadd(1);
break;
case '1sub':
case opc['1sub']:
n.isub(1);
break;
case 'negate':
case opc.negate:
n = n.neg();
break;
case 'abs':
case opc.abs:
if (n.cmpn(0) < 0)
n = n.neg();
break;
case 'not':
case opc.not:
n = n.cmpn(0) === 0;
break;
case '0notequal':
case opc['0notequal']:
n = n.cmpn(0) !== 0;
break;
default:
@ -733,76 +734,76 @@ Script.prototype.interpret = function interpret(stack, flags, tx, index, version
stack.push(Script.array(n));
break;
}
case 'add':
case 'sub':
case 'booland':
case 'boolor':
case 'numequal':
case 'numequalverify':
case 'numnotequal':
case 'lessthan':
case 'greaterthan':
case 'lessthanorequal':
case 'greaterthanorequal':
case 'min':
case 'max': {
case opc.add:
case opc.sub:
case opc.booland:
case opc.boolor:
case opc.numequal:
case opc.numequalverify:
case opc.numnotequal:
case opc.lessthan:
case opc.greaterthan:
case opc.lessthanorequal:
case opc.greaterthanorequal:
case opc.min:
case opc.max: {
switch (op) {
case 'add':
case 'sub':
case 'booland':
case 'boolor':
case 'numequal':
case 'numequalverify':
case 'numnotequal':
case 'lessthan':
case 'greaterthan':
case 'lessthanorequal':
case 'greaterthanorequal':
case 'min':
case 'max':
case opc.add:
case opc.sub:
case opc.booland:
case opc.boolor:
case opc.numequal:
case opc.numequalverify:
case opc.numnotequal:
case opc.lessthan:
case opc.greaterthan:
case opc.lessthanorequal:
case opc.greaterthanorequal:
case opc.min:
case opc.max:
if (stack.length < 2)
throw new ScriptError('Stack too small.', op, ip);
n2 = Script.num(stack.pop(), flags);
n1 = Script.num(stack.pop(), flags);
n = new bn(0, 'le');
switch (op) {
case 'add':
case opc.add:
n = n1.add(n2);
break;
case 'sub':
case opc.sub:
n = n1.sub(n2);
break;
case 'booland':
case opc.booland:
n = n1.cmpn(0) !== 0 && n2.cmpn(0) !== 0;
break;
case 'boolor':
case opc.boolor:
n = n1.cmpn(0) !== 0 || n2.cmpn(0) !== 0;
break;
case 'numequal':
case opc.numequal:
n = n1.cmp(n2) === 0;
break;
case 'numequalverify':
case opc.numequalverify:
n = n1.cmp(n2) === 0;
break;
case 'numnotequal':
case opc.numnotequal:
n = n1.cmp(n2) !== 0;
break;
case 'lessthan':
case opc.lessthan:
n = n1.cmp(n2) < 0;
break;
case 'greaterthan':
case opc.greaterthan:
n = n1.cmp(n2) > 0;
break;
case 'lessthanorequal':
case opc.lessthanorequal:
n = n1.cmp(n2) <= 0;
break;
case 'greaterthanorequal':
case opc.greaterthanorequal:
n = n1.cmp(n2) >= 0;
break;
case 'min':
case opc.min:
n = n1.cmp(n2) < 0 ? n1 : n2;
break;
case 'max':
case opc.max:
n = n1.cmp(n2) > 0 ? n1 : n2;
break;
default:
@ -811,14 +812,14 @@ Script.prototype.interpret = function interpret(stack, flags, tx, index, version
if (typeof n === 'boolean')
n = new bn(n ? 1 : 0, 'le');
res = Script.bool(n);
if (op === 'numequalverify') {
if (op === opc.numequalverify) {
if (!res)
return false;
} else {
stack.push(Script.array(n));
}
break;
case 'within':
case opc.within:
if (stack.length < 3)
throw new ScriptError('Stack too small.', op, ip);
n3 = Script.num(stack.pop(), flags);
@ -831,46 +832,46 @@ Script.prototype.interpret = function interpret(stack, flags, tx, index, version
break;
}
case 'codeseparator': {
case opc.codeseparator: {
lastSep = ip;
break;
}
case 'ripemd160': {
case opc.ripemd160: {
if (stack.length === 0)
throw new ScriptError('Stack too small.', op, ip);
stack.push(utils.ripemd160(stack.pop()));
break;
}
case 'sha1': {
case opc.sha1: {
if (stack.length === 0)
throw new ScriptError('Stack too small.', op, ip);
stack.push(utils.sha1(stack.pop()));
break;
}
case 'sha256': {
case opc.sha256: {
if (stack.length === 0)
throw new ScriptError('Stack too small.', op, ip);
stack.push(utils.sha256(stack.pop()));
break;
}
case 'hash256': {
case opc.hash256: {
if (stack.length === 0)
throw new ScriptError('Stack too small.', op, ip);
stack.push(utils.dsha256(stack.pop()));
break;
}
case 'hash160': {
case opc.hash160: {
if (stack.length === 0)
throw new ScriptError('Stack too small.', op, ip);
stack.push(utils.ripesha(stack.pop()));
break;
}
case 'equalverify':
case 'equal': {
case opc.equalverify:
case opc.equal: {
if (stack.length < 2)
throw new ScriptError('Stack too small.', op, ip);
res = utils.isEqual(stack.pop(), stack.pop());
if (op === 'equalverify') {
if (op === opc.equalverify) {
if (!res)
throw new ScriptError('Equal verification failed.', op, ip);
} else {
@ -878,8 +879,8 @@ Script.prototype.interpret = function interpret(stack, flags, tx, index, version
}
break;
}
case 'checksigverify':
case 'checksig': {
case opc.checksigverify:
case opc.checksig: {
if (!tx)
throw new ScriptError('No TX passed in.', op, ip);
@ -903,7 +904,7 @@ Script.prototype.interpret = function interpret(stack, flags, tx, index, version
hash = tx.signatureHash(index, subscript, type, version);
res = Script.checksig(hash, sig, key, flags);
if (op === 'checksigverify') {
if (op === opc.checksigverify) {
if (!res)
throw new ScriptError('Signature verification failed.', op, ip);
} else {
@ -912,8 +913,8 @@ Script.prototype.interpret = function interpret(stack, flags, tx, index, version
break;
}
case 'checkmultisigverify':
case 'checkmultisig': {
case opc.checkmultisigverify:
case opc.checkmultisig: {
if (!tx)
throw new ScriptError('No TX passed in.', op, ip);
@ -984,7 +985,7 @@ Script.prototype.interpret = function interpret(stack, flags, tx, index, version
res = succ >= m;
if (op === 'checkmultisigverify') {
if (op === opc.checkmultisigverify) {
if (!res)
throw new ScriptError('Signature verification failed.', op, ip);
} else {
@ -993,7 +994,7 @@ Script.prototype.interpret = function interpret(stack, flags, tx, index, version
break;
}
case 'checklocktimeverify': {
case opc.checklocktimeverify: {
// OP_CHECKLOCKTIMEVERIFY = OP_NOP2
if (!(flags & constants.flags.VERIFY_CHECKLOCKTIMEVERIFY)) {
if (flags & constants.flags.VERIFY_DISCOURAGE_UPGRADABLE_NOPS)
@ -1019,7 +1020,7 @@ Script.prototype.interpret = function interpret(stack, flags, tx, index, version
break;
}
case 'checksequenceverify': {
case opc.checksequenceverify: {
// OP_CHECKSEQUENCEVERIFY = OP_NOP3
if (!(flags & constants.flags.VERIFY_CHECKSEQUENCEVERIFY)) {
if (flags & constants.flags.VERIFY_DISCOURAGE_UPGRADABLE_NOPS)
@ -1274,16 +1275,16 @@ Script.prototype.concat = function concat(scripts) {
};
Script.createPubkey = function createPubkey(key) {
return new Script([key, 'checksig']);
return new Script([key, opc.checksig]);
};
Script.createPubkeyhash = function createPubkeyhash(hash) {
return new Script([
'dup',
'hash160',
opc.dup,
opc.hash160,
hash,
'equalverify',
'checksig'
opc.equalverify,
opc.checksig
]);
};
@ -1294,23 +1295,23 @@ Script.createMultisig = function createMultisig(keys, m, n) {
assert(m >= 1 && m <= n);
assert(n >= 1 && n <= 15);
return new Script([m].concat(
return new Script([m + 0x50].concat(
utils.sortKeys(keys),
[n, 'checkmultisig']
[n + 0x50, opc.checkmultisig]
));
};
Script.createScripthash = function createScripthash(hash) {
return new Script([
'hash160',
opc.hash160,
hash,
'equal'
opc.equal
]);
};
Script.createNulldata = function createNulldata(flags) {
return new Script([
'return',
opc['return'],
flags
]);
};
@ -1356,8 +1357,8 @@ Script.prototype.isStandard = function isStandard() {
var m, n;
if (type === 'multisig') {
m = this.code[0];
n = this.code[this.code.length - 2];
m = this.code[0] - 0x50;
n = this.code[this.code.length - 2] - 0x50;
if (n < 1 || n > 3)
return false;
@ -1479,7 +1480,7 @@ Script.prototype.isPubkey = function isPubkey(key) {
if (this.code.length !== 2)
return false;
res = Script.isKey(this.code[0]) && this.code[1] === 'checksig';
res = Script.isKey(this.code[0]) && this.code[1] === opc.checksig;
if (!res)
return false;
@ -1498,11 +1499,11 @@ Script.prototype.isPubkeyhash = function isPubkeyhash(hash) {
if (this.code.length !== 5)
return false;
res = this.code[0] === 'dup'
&& this.code[1] === 'hash160'
res = this.code[0] === opc.dup
&& this.code[1] === opc.hash160
&& Script.isHash(this.code[2])
&& this.code[3] === 'equalverify'
&& this.code[4] === 'checksig';
&& this.code[3] === opc.equalverify
&& this.code[4] === opc.checksig;
if (!res)
return false;
@ -1522,20 +1523,16 @@ Script.prototype.isMultisig = function isMultisig(keys) {
if (this.code.length < 4)
return false;
if (this.code[this.code.length - 1] !== 'checkmultisig')
if (this.code[this.code.length - 1] !== opc.checkmultisig)
return false;
n = this.code[this.code.length - 2];
if (Buffer.isBuffer(n)) {
if (n.length !== 0)
return false;
n = 0;
}
if (typeof n !== 'number')
if (!(n >= opc['1'] && n <= opc['16']))
return false;
n -= 0x50;
// Bitcoind technically doesn't check for the
// 15 limit here. It just counts the sigops
// later.
@ -1544,15 +1541,11 @@ Script.prototype.isMultisig = function isMultisig(keys) {
m = this.code[0];
if (Buffer.isBuffer(m)) {
if (m.length !== 0)
return false;
m = 0;
}
if (typeof m !== 'number')
if (!(m >= opc['1'] && m <= opc['16']))
return false;
m -= 0x50;
if (!(m >= 1 && m <= n))
return false;
@ -1587,9 +1580,9 @@ Script.prototype.isScripthash = function isScripthash(hash) {
if (this.code.length !== 3)
return false;
res = this.code[0] === 'hash160'
res = this.code[0] === opc.hash160
&& Script.isHash(this.code[1])
&& this.code[2] === 'equal';
&& this.code[2] === opc.equal;
if (!res)
return false;
@ -1608,7 +1601,7 @@ Script.prototype.isNulldata = function isNulldata() {
if (this.code.length !== 2)
return false;
res = this.code[0] === 'return' && Script.isData(this.code[1]);
res = this.code[0] === opc['return'] && Script.isData(this.code[1]);
if (!res)
return false;
@ -1618,7 +1611,7 @@ Script.prototype.isNulldata = function isNulldata() {
Script.prototype.isCommitment = function isCommitment() {
return this.code.length >= 2
&& this.code[0] === 'return'
&& this.code[0] === opc['return']
&& Buffer.isBuffer(this.code[1])
&& this.code[1].length === 36
&& utils.readU32BE(this.code[1], 0) === 0xaa21a9ed;
@ -1641,7 +1634,7 @@ Script.prototype.isWitnessProgram = function isWitnessProgram() {
if (!Buffer.isBuffer(this.code[1]))
return false;
return this.code[0] >= 0 && this.code[0] <= 16
return this.code[0] >= opc['0'] && this.code[0] <= opc['16']
&& this.code[1].length >= 2 && this.code[1].length <= 32;
};
@ -1657,9 +1650,9 @@ Script.prototype.getWitnessProgram = function getWitnessProgram() {
if (version > 0) {
// No interpretation of script (anyone can spend)
type = 'unknown';
} else if (version === 0 && data.length === 20) {
} else if (version === opc['0'] && data.length === 20) {
type = 'witnesspubkeyhash';
} else if (version === 0 && data.length === 32) {
} else if (version === opc['0'] && data.length === 32) {
type = 'witnessscripthash';
} else {
// Fail on bad version=0
@ -1667,7 +1660,7 @@ Script.prototype.getWitnessProgram = function getWitnessProgram() {
}
return {
version: version,
version: version === opc['0'] ? 0 : version - 0x50,
type: type,
data: data
};
@ -1677,21 +1670,21 @@ Script.prototype.isWitnessPubkeyhash = function isWitnessPubkeyhash() {
if (!this.isWitnessProgram())
return false;
return this.code[0] === 0 && this.code[1].length === 20;
return this.code[0] === opc['0'] && this.code[1].length === 20;
};
Script.prototype.isWitnessScripthash = function isWitnessScripthash() {
if (!this.isWitnessProgram())
return false;
return this.code[0] === 0 && this.code[1].length === 32;
return this.code[0] === opc['0'] && this.code[1].length === 32;
};
Script.createWitnessProgram = function createWitnessProgram(version, data) {
assert(typeof version === 'number' && version >= 0 && version <= 16);
assert(Buffer.isBuffer(data));
assert(data.length === 20 || data.length === 32);
return new Script([version, data]);
return new Script([opc[version], data]);
};
Script.prototype.getInputType = function getInputType(prev) {
@ -1769,8 +1762,8 @@ Script.createOutputScript = function(options) {
if (options.locktime != null) {
script = new Script([
Script.array(options.locktime),
'checklocktimeverify',
'drop'
opc.checklocktimeverify,
opc.drop
].concat(script.code));
}
redeem = script;
@ -2217,7 +2210,7 @@ Script.format = function format(code) {
return '[' + utils.toHex(chunk) + ']';
if (typeof chunk === 'number')
return chunk + '';
return constants.opcodesByVal[chunk] || chunk;
return chunk;
}).join(' ');
@ -2227,7 +2220,7 @@ Script.prototype.isPushOnly = function isPushOnly() {
var i, op;
for (i = 0; i < this.code.length; i++) {
op = this.code[i];
if (Buffer.isBuffer(op) || op === '1negate' || (op >= 0 && op <= 16))
if (Buffer.isBuffer(op) || op === opc['1negate'] || op === opc['0'] || (op >= opc['1'] && op <= opc['16']))
continue;
return false;
}
@ -2248,10 +2241,10 @@ Script.prototype.getSigops = function getSigops(accurate) {
if (constants.opcodes[op] == null)
return 0;
if (op === 'checksig' || op === 'checksigverify') {
if (op === opc.checksig || op === opc.checksigverify) {
total++;
} else if (op === 'checkmultisig' || op === 'checkmultisigverify') {
if (accurate && lastOp >= 1 && lastOp <= 16)
} else if (op === opc.checkmultisig || op === opc.checkmultisigverify) {
if (accurate && lastOp >= opc['1'] && lastOp <= opc['16'])
total += lastOp;
else
total += constants.script.maxPubkeysPerMultisig;
@ -2274,7 +2267,7 @@ Script.prototype.getArgs = function getArgs() {
if (this.isMultisig()) {
keys = this.code.slice(1, -2);
m = this.code[0];
m = this.code[0] - 0x50;
if (keys.length < 1 || m < 1)
return -1;
return m + 1;
@ -2332,9 +2325,11 @@ Script.fromString = function fromString(code) {
op = op.substring(2);
assert(utils.isHex(op), 'Non hex-string.');
op = new Buffer(op, 'hex');
code[i] = op;
continue;
}
code[i] = op;
code[i] = constants.opcodes[op];
}
return new Script(code);
@ -2517,7 +2512,7 @@ Script.concat = function concat(scripts) {
s = s.concat(scripts[0].code);
for (i = 1; i < scripts.length; i++) {
s.push('codeseparator');
s.push(opc.codeseparator);
s = s.concat(scripts[i].code);
}
@ -2575,12 +2570,6 @@ Script.decode = function decode(buf) {
while (off < buf.length) {
b = buf[off++];
// OP_0, OP_FALSE
if (b === 0x00) {
code.push(0);
continue;
}
// Direct Push
// Next `b` bytes should be pushed to stack
if (b >= 0x01 && b <= 0x4b) {
@ -2595,16 +2584,8 @@ Script.decode = function decode(buf) {
continue;
}
// OP_1, OP_TRUE, OP_2-OP_16
// Special case: these get to be number
// literals. Note: 1negate is not included.
if (b >= 0x51 && b <= 0x60) {
code.push(b - 0x50);
continue;
}
if (off >= buf.length) {
code.push(constants.opcodesByVal[b] || b);
code.push(b);
continue;
}
@ -2642,7 +2623,7 @@ Script.decode = function decode(buf) {
});
}
} else {
code.push(constants.opcodesByVal[b] || b);
code.push(b);
}
}
@ -2705,9 +2686,9 @@ Script.encode = function encode(code) {
continue;
}
assert(opcodes[op] != null || typeof op === 'number');
assert(typeof op === 'number');
p.writeU8(opcodes[op] || op);
p.writeU8(op);
}
return p.render();

View File

@ -3,6 +3,7 @@ var bcoin = require('../');
var constants = bcoin.protocol.constants;
var utils = bcoin.utils;
var assert = utils.assert;
var opc = constants.opcodes;
describe('Wallet', function() {
process.env.BCOIN_DB = 'memdown';
@ -30,7 +31,7 @@ describe('Wallet', function() {
// Coinbase
var t1 = bcoin.mtx().addOutput(w, 50000).addOutput(w, 10000); // 10000 instead of 1000
var prev = new bcoin.script([w.publicKey, 'checksig']);
var prev = new bcoin.script([w.publicKey, opc['checksig']]);
var dummyInput = {
prevout: {
hash: constants.oneHash,

View File

@ -2,6 +2,7 @@ var assert = require('assert');
var bcoin = require('../');
var Script = bcoin.script;
var Stack = bcoin.script.stack;
var opc = bcoin.protocol.constants.opcodes;
describe('Script', function() {
it('should encode/decode script', function() {
@ -19,12 +20,13 @@ describe('Script', function() {
assert.equal(
bcoin.utils.toHex(decoded[1]),
'101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f');
assert.equal(decoded[2], 'checksig');
assert.equal(decoded[2], opc['checksig']);
var dst = bcoin.script.encode(decoded);
assert.equal(bcoin.utils.toHex(dst), src);
});
if (0)
it('should encode/decode numbers', function() {
var script = [ 0, 1, 2, 16 ];
var encoded = bcoin.script.encode(script);
@ -48,40 +50,40 @@ describe('Script', function() {
});
it('should handle if statements correctly', function () {
var inputScript = new Script([1, 2]);
var prevOutScript = new Script([2, 'equal', 'if', 3, 'else', 4, 'endif', 5]);
var inputScript = new Script([opc['1'], opc['2']]);
var prevOutScript = new Script([opc['2'], opc.equal, opc['if'], opc[3], opc['else'], opc[4], opc.endif, opc[5]]);
var stack = new Stack();
inputScript.execute(stack);
var res = prevOutScript.execute(stack);
assert(res);
assert.deepEqual(stack.slice(), [[1], [3], [5]]);
var inputScript = new Script([1, 2]);
var prevOutScript = new Script([9, 'equal', 'if', 3, 'else', 4, 'endif', 5]);
var inputScript = new Script([opc[1], opc[2]]);
var prevOutScript = new Script([opc[9], opc['equal'], opc['if'], opc[3], opc['else'], opc[4], opc['endif'], opc[5]]);
var stack = new Stack();
inputScript.execute(stack);
var res = prevOutScript.execute(stack);
assert(res);
assert.deepEqual(stack.slice(), [[1], [4], [5]]);
var inputScript = new Script([1, 2]);
var prevOutScript = new Script([2, 'equal', 'if', 3, 'endif', 5]);
var inputScript = new Script([opc[1], opc[2]]);
var prevOutScript = new Script([opc[2], opc['equal'], opc['if'], opc[3], opc['endif'], opc[5]]);
var stack = new Stack();
inputScript.execute(stack);
var res = prevOutScript.execute(stack);
assert(res);
assert.deepEqual(stack.slice(), [[1], [3], [5]]);
var inputScript = new Script([1, 2]);
var prevOutScript = new Script([9, 'equal', 'if', 3, 'endif', 5]);
var inputScript = new Script([opc[1], opc[2]]);
var prevOutScript = new Script([opc[9], opc['equal'], opc['if'], opc[3], opc['endif'], opc[5]]);
var stack = new Stack();
inputScript.execute(stack);
var res = prevOutScript.execute(stack);
assert(res);
assert.deepEqual(stack.slice(), [[1], [5]]);
var inputScript = new Script([1, 2]);
var prevOutScript = new Script([9, 'equal', 'notif', 3, 'endif', 5]);
var inputScript = new Script([opc[1], opc[2]]);
var prevOutScript = new Script([opc[9], opc['equal'], opc['notif'], opc[3], opc['endif'], opc[5]]);
var stack = new Stack();
inputScript.execute(stack);
var res = prevOutScript.execute(stack);