diff --git a/lib/bcoin/mtx.js b/lib/bcoin/mtx.js index d62bb3f0..080d2076 100644 --- a/lib/bcoin/mtx.js +++ b/lib/bcoin/mtx.js @@ -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] ... diff --git a/lib/bcoin/script.js b/lib/bcoin/script.js index cf1ce5c7..075f20bc 100644 --- a/lib/bcoin/script.js +++ b/lib/bcoin/script.js @@ -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(); diff --git a/test/node-test.js b/test/node-test.js index c5441e62..ea6b2355 100644 --- a/test/node-test.js +++ b/test/node-test.js @@ -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, diff --git a/test/script-test.js b/test/script-test.js index 84b05d76..e297fe1b 100644 --- a/test/script-test.js +++ b/test/script-test.js @@ -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);