diff --git a/lib/bcoin/protocol/constants.js b/lib/bcoin/protocol/constants.js index e22dcb83..ba25f547 100644 --- a/lib/bcoin/protocol/constants.js +++ b/lib/bcoin/protocol/constants.js @@ -59,7 +59,7 @@ exports.opcodes = { pushdata4: 0x4e, negate1: 0x4f, - nop: 0x61, + nop1: 0x61, if_: 0x63, notif: 0x64, else_: 0x67, @@ -144,8 +144,14 @@ exports.opcodes = { for (var i = 1; i <= 16; i++) exports.opcodes[i] = 0x50 + i; -exports.opcodes['false'] = exports.opcodes['0']; -exports.opcodes['true'] = exports.opcodes['1']; +for (var i = 0; i <= 7; i++) + exports.opcodes['nop' + (i + 3)] = 0xb2 + i; + +// exports.opcodes['false'] = exports.opcodes['0']; +// exports.opcodes['true'] = exports.opcodes['1']; + +// exports.opcodes['if'] = exports.opcodes.if_; +// exports.opcodes['else'] = exports.opcodes.else_; exports.opcodesByVal = new Array(256); Object.keys(exports.opcodes).forEach(function(name) { diff --git a/lib/bcoin/script.js b/lib/bcoin/script.js index dd1eb65f..b2501be7 100644 --- a/lib/bcoin/script.js +++ b/lib/bcoin/script.js @@ -135,9 +135,15 @@ script.execute = function execute(s, stack, tx, index) { return false; var input = tx.inputs[index]; + var lastSep = -1; + + stack.alt = stack.alt || []; + + // TODO: if statements for (var pc = 0; pc < s.length; pc++) { var o = s[pc]; + if (Array.isArray(o)) { stack.push(o); } else if (typeof o === 'number' && o >= 1 && o <= 16) { @@ -148,7 +154,287 @@ script.execute = function execute(s, stack, tx, index) { stack.push(stack[stack.length - 1]); } else if (o === 'drop') { + if (stack.length === 0) + return false; + stack.pop(); + } else if (o === 'nop1' || o === 'nop3' || o === 'nop4' + || o === 'nop5' || o === 'nop6' || o === 'nop7' + || o === 'nop8' || o === 'nop9' || o === 'nop10') { + ; + // OP_EVAL + // if (o === 'nop1') { + // var evalScript = script.decode(stack.pop()); + // var res = script.execute(evalScript, stack, tx, index); + // if (!res) + // return false; + // } + } else if (o === 'verify') { + if (stack.length === 0) + return false; + if (new bn(stack[stack.length - 1]).cmp(0) === 0) + return false; + } else if (o === 'return') { + return false; + } else if (o === 'toaltstack') { + if (stack.length === 0) + return false; + stack.alt.push(stack.pop()); + } else if (o === 'fromaltstack') { + if (stack.alt.length === 0) + return false; + stack.push(stack.alt.pop()); + } else if (o === 'ifdup') { + if (stack.length === 0) + return false; + if (new bn(stack[stack.length - 1]).cmp(0) !== 0) + stack.push(new bn(stack[stack.length - 1]).toArray()); + } else if (o === 'depth') { + stack.push(new bn(stack.length).toArray()); + } else if (o === 'nip') { + if (stack.length < 2) + return false; + stack.splice(stack.length - 2, 1); + } else if (o === 'over') { + if (stack.length < 2) + return false; + stack.push(stack[stack.length - 2]); + } else if (o === 'pick' || o === 'roll') { + if (stack.length < 2) + return false; + var n = new bn(stack.pop()).toNumber(); + if (n < 0 || n >= stack.length) + return false; + var v = stack[-n - 1]; + if (o === 'roll') + stack.splice(stack.length - n - 1, 1); + stack.push(v); + } else if (o === 'rot') { + if (stack.length < 3) + return false; + var v3 = stack[stack.length - 3]; + var v2 = stack[stack.length - 2]; + var v1 = stack[stack.length - 1]; + stack[stack.length - 3] = v2; + stack[stack.length - 2] = v3; + + v2 = stack[stack.length - 2]; + stack[stack.length - 2] = v1; + stack[stack.length - 1] = v2; + } else if (o === 'swap') { + if (stack.length < 2) + return false; + var v2 = stack[stack.length - 2]; + var v1 = stack[stack.length - 1]; + stack[stack.length - 2] = v1; + stack[stack.length - 1] = v2; + } else if (o === 'tuck') { + if (stack.length < 2) + return false; + stack.splice(stack.length - 2, 0, stack[stack.length - 1]); + } else if (o === 'drop2') { + if (stack.length < 2) + return false; + stack.pop(); + stack.pop(); + } else if (o === 'dup2') { + if (stack.length < 2) + return false; + var v1 = stack[stack.length - 1]; + var v2 = stack[stack.length - 2]; + stack.push(v1); + stack.push(v2); + } else if (o === 'dup3') { + if (stack.length < 3) + return false; + var v1 = stack[stack.length - 1]; + var v2 = stack[stack.length - 2]; + var v3 = stack[stack.length - 3]; + stack.push(v1); + stack.push(v2); + stack.push(v3); + } else if (o === 'over2') { + if (stack.length < 4) + return false; + var v1 = stack[stack.length - 4]; + var v2 = stack[stack.length - 3]; + stack.push(v1); + stack.push(v2); + } else if (o === 'rot2') { + if (stack.length < 6) + return false; + var v1 = stack[stack.length - 6]; + var v2 = stack[stack.length - 5]; + stack.splice(stack.length - 6, 2); + stack.push(v1); + stack.push(v2); + } else if (o === 'swap2') { + if (stack.length < 4) + return false; + var v4 = stack[stack.length - 4]; + var v3 = stack[stack.length - 3]; + var v2 = stack[stack.length - 2]; + var v1 = stack[stack.length - 1]; + stack[stack.length - 4] = v2; + stack[stack.length - 2] = v4; + stack[stack.length - 3] = v1; + stack[stack.length - 1] = v3; + } else if (o === 'size') { + if (stack.length < 1) + return false; + stack.push(new bn(stack[stack.length - 1].length || 0).toArray()); + } else if (o === 'add1' + || o === 'sub1' + || o === 'negate' + || o === 'abs' + || o === 'not' + || o === 'noteq0') { + if (stack.length < 1) + return false; + var n = new bn(stack.pop()); + switch (o) { + case 'add1': + n.iadd(1); + break; + case 'sub1': + n.isub(1); + break; + case 'negate': + n = n.neg(); + break; + case 'abs': + if (n.cmp(0) < 0) + n = n.neg(); + break; + case 'not': + n = n.cmp(0) === 0; + break; + case 'noteq0': + n = n.cmp(0) !== 0; + break; + default: + return false; + } + stack.push(n.toArray()); + } else if (o === 'add' + || o === 'sub' + || o === 'booland' + || o === 'boolor' + || o === 'numeq' + || o === 'numeqverify' + || o === 'numneq' + || o === 'lt' + || o === 'gt' + || o === 'lte' + || o === 'gte' + || o === 'min' + || o === 'max') { + switch (o) { + case 'add': + case 'sub': + case 'booland': + case 'boolor': + case 'numeq': + case 'numeqverify': + case 'numneq': + case 'lt': + case 'gt': + case 'lte': + case 'gte': + case 'min': + case 'max': + if (stack.length < 2) + return false; + var n2 = new bn(stack.pop()); + var n1 = new bn(stack.pop()); + var n = new bn(0); + switch (o) { + case 'add': + n = n1.add(b2); + break; + case 'sub': + n = n1.sub(n2); + break; + case 'booland': + n = n1.cmp(0) !== 0 && n2.cmp(0) !== 0; + break; + case 'boolor': + n = n1.cmp(0) !== 0 || n2.cmp(0) !== 0; + break; + case 'numeq': + n = n1.cmp(n2) === 0; + break; + case 'numeqverify': + n = n1.cmp(n2) === 0; + break; + case 'numneq': + n = n1.cmp(n2) !== 0; + break; + case 'lt': + n = n1.cmp(n2) < 0; + break; + case 'gt': + n = n1.cmp(n2) > 0; + break; + case 'lte': + n = n1.cmp(n2) <= 0; + break; + case 'gte': + n = n1.cmp(n2) >= 0; + break; + case 'min': + n = n1.cmp(n2) < 0 ? n1 : n2; + break; + case 'max': + n = n1.cmp(n2) > 0 ? n1 : n2; + break; + default: + return false; + } + var res = n.cmp(0) !== 0; + if (o === 'numeqverify') { + if (!res) + return false; + } else { + stack.push(n.toArray()); + // stack.push(res ? [ 1 ] : []); + } + // stack.push(n.toArray()); + // if (op == 'numeqverify') { + // if (n.cmp(0) !== 0) + // stack.pop(); + // else + // return false; + // } + break; + case 'within': + if (stack.length < 3) + return false; + var n3 = new bn(stack.pop()); + var n2 = new bn(stack.pop()); + var n1 = new bn(stack.pop()); + var val = n2.cmp(n1) <= 0 && n1.cmp(n3) < 0; + stack.push(val.cmp(0) !== 0 ? [ 1 ] : []); + break; + } + } else if (o === 'codesep') { + lastSep = pc; + } else if (o === 'ripemd160') { + if (stack.length === 0) + return false; + stack.push(utils.ripemd160(stack.pop())); + } else if (o === 'sha1') { + if (stack.length === 0) + return false; + stack.push(utils.sha1(stack.pop())); + } else if (o === 'sha256') { + if (stack.length === 0) + return false; + stack.push(utils.sha256(stack.pop())); + } else if (o === 'hash256') { + if (stack.length === 0) + return false; + stack.push(utils.dsha256(stack.pop())); } else if (o === 'hash160') { if (stack.length === 0) return false; @@ -165,7 +451,6 @@ script.execute = function execute(s, stack, tx, index) { } else { stack.push(res ? [ 1 ] : []); } - } else if (o === 'checksigverify' || o === 'checksig') { if (!tx || stack.length < 2) return false; @@ -179,7 +464,8 @@ script.execute = function execute(s, stack, tx, index) { if (!script.isValidSig(sig)) return false; - var subscript = input.out.tx.getSubscript(input.out.index); + // var subscript = input.out.tx.getSubscript(input.out.index); + var subscript = s.slice(lastSep + 1); var hash = tx.subscriptHash(index, subscript, type); var res = script.verify(hash, sig.slice(0, -1), pub); @@ -227,7 +513,8 @@ script.execute = function execute(s, stack, tx, index) { if (!constants.rhashType[type & 0x7f]) return false; - var subscript = input.out.tx.getSubscript(input.out.index); + // var subscript = input.out.tx.getSubscript(input.out.index); + var subscript = s.slice(lastSep + 1); var hash = tx.subscriptHash(index, subscript, type); if (!script.isValidSig(sig)) @@ -260,11 +547,7 @@ script.execute = function execute(s, stack, tx, index) { if (stack.length === 0) return false; - var lock = stack[stack.length - 1]; - if (lock.length !== 1) - return false; - - lock = lock[0]; + var lock = new bn(stack[stack.length - 1]).toNumber(); if (lock < 0) return false; @@ -288,7 +571,7 @@ script.execute = function execute(s, stack, tx, index) { } } - if (stack.length > 1000) + if (stack.length + stack.alt.length > 1000) return false; return true; diff --git a/lib/bcoin/utils.js b/lib/bcoin/utils.js index f96ded1c..d4566c6e 100644 --- a/lib/bcoin/utils.js +++ b/lib/bcoin/utils.js @@ -118,6 +118,14 @@ utils.fromBase58 = function fromBase58(str) { return z.concat(res.toArray()); }; +utils.ripemd160 = function ripemd160(data, enc) { + return hash.ripemd160().update(data, enc).digest(); +}; + +utils.sha1 = function sha1(data, enc) { + return hash.sha1().update(data, enc).digest(); +}; + utils.ripesha = function ripesha(data, enc) { return hash.ripemd160().update(utils.sha256(data, enc)).digest(); };