diff --git a/lib/bcoin/script2.js b/lib/bcoin/script2.js index e8c3134f..173f2069 100644 --- a/lib/bcoin/script2.js +++ b/lib/bcoin/script2.js @@ -2466,25 +2466,16 @@ Script.sign = function sign(msg, key, type) { Script.decode = function decode(buf) { var code = []; - var i = 0; + var off = 0; var b, opcode, len; if (!buf) return []; - while (i < buf.length) { - b = buf[i++]; - - // Next `b` bytes should be pushed to stack - if (b >= 0x01 && b <= 0x4b) { - code.push(utils.slice(buf, i, i + b)); - i += b; - utils.hidden(code[code.length - 1], 'pushdata', { - opcode: null, - len: b - }); - continue; - } + // NOTE: We can't use a BufferReader here since + // script parsing was originally non-strict. + while (off < buf.length) { + b = buf[off++]; // OP_0, OP_FALSE // Special case: this is an empty array @@ -2494,6 +2485,17 @@ Script.decode = function decode(buf) { continue; } + // Next `b` bytes should be pushed to stack + if (b >= 0x01 && b <= 0x4b) { + code.push(utils.slice(buf, off, off + b)); + off += b; + utils.hidden(code[code.length - 1], 'pushdata', { + opcode: null, + len: b + }); + continue; + } + // OP_1, OP_TRUE, OP_2-OP_16 // Special case: these get to be number // literals. Note: 1negate is not included. @@ -2504,34 +2506,34 @@ Script.decode = function decode(buf) { opcode = constants.opcodesByVal[b]; - if (i >= buf.length) { + if (off >= buf.length) { code.push(opcode || b); continue; } if (opcode === 'pushdata1') { - len = buf[i]; - i += 1; - code.push(utils.slice(buf, i, i + len)); - i += len; + len = buf[off]; + off += 1; + code.push(utils.slice(buf, off, off + len)); + off += len; utils.hidden(code[code.length - 1], 'pushdata', { opcode: opcode, len: len }); } else if (opcode === 'pushdata2') { - len = utils.readU16(buf, i); - i += 2; - code.push(utils.slice(buf, i, i + len)); - i += len; + len = utils.readU16(buf, off); + off += 2; + code.push(utils.slice(buf, off, off + len)); + off += len; utils.hidden(code[code.length - 1], 'pushdata', { opcode: opcode, len: len }); } else if (opcode === 'pushdata4') { - len = utils.readU32(buf, i); - i += 4; - code.push(utils.slice(buf, i, i + len)); - i += len; + len = utils.readU32(buf, off); + off += 4; + code.push(utils.slice(buf, off, off + len)); + off += len; utils.hidden(code[code.length - 1], 'pushdata', { opcode: opcode, len: len @@ -2545,111 +2547,65 @@ Script.decode = function decode(buf) { }; Script.encode = function encode(code) { + var p = new bcoin.protocol.framer.BufferWriter(); var opcodes = constants.opcodes; var i = 0; - var instr; - var total = 0; - var off = 0; - var buf; - - if (!code) - return new Buffer([]); - - if (code._raw) - return code._raw; + var op; for (i = 0; i < code.length; i++) { - instr = code[i]; - - if (Buffer.isBuffer(instr)) { - if (instr.pushdata) { - if (instr.pushdata.opcode === null) { - total += 1 + instr.length; - } else if (instr.pushdata.opcode === 'pushdata1') { - total += 1 + 1 + instr.length; - } else if (instr.pushdata.opcode === 'pushdata2') { - total += 1 + 2 + instr.length; - } else if (instr.pushdata.opcode === 'pushdata4') { - total += 1 + 4 + instr.length; - } - continue; - } - if (instr.length === 0) { - total += 1; - } else if (1 <= instr.length && instr.length <= 0x4b) { - total += 1 + instr.length; - } else if (instr.length <= 0xff) { - total += 1 + 1 + instr.length; - } else if (instr.length <= 0xffff) { - total += 1 + 2 + instr.length; - } else { - total += 1 + 4 + instr.length; - } - continue; - } - - total += 1; - } - - buf = new Buffer(total); - - for (i = 0; i < code.length; i++) { - instr = code[i]; - - assert(!Array.isArray(instr)); + op = code[i]; // Push value to stack - if (Buffer.isBuffer(instr)) { + if (Buffer.isBuffer(op)) { // Check for nonstandard pushdatas that // may have been decoded from before. - if (instr.pushdata) { - if (instr.pushdata.opcode === null) { - buf[off++] = instr.pushdata.len; - off += instr.copy(buf, off, 0, instr.length); - } else if (instr.pushdata.opcode === 'pushdata1') { - buf[off++] = opcodes.pushdata1; - buf[off++] = instr.pushdata.len; - off += instr.copy(buf, off, 0, instr.length); - } else if (instr.pushdata.opcode === 'pushdata2') { - buf[off++] = opcodes.pushdata2; - off += utils.writeU16(buf, instr.pushdata.len, off); - off += instr.copy(buf, off, 0, instr.length); - } else if (instr.pushdata.opcode === 'pushdata4') { - buf[off++] = opcodes.pushdata4; - off += utils.writeU32(buf, instr.pushdata.len, off); - off += instr.copy(buf, off, 0, instr.length); + if (op.pushdata) { + if (op.pushdata.opcode === null) { + p.writeU8(op.pushdata.len); + p.writeBytes(op); + } else if (op.pushdata.opcode === 'pushdata1') { + p.writeU8(opcodes.pushdata1); + p.writeU8(op.pushdata.len); + p.writeBytes(op); + } else if (op.pushdata.opcode === 'pushdata2') { + p.writeU8(opcodes.pushdata2); + p.writeU16(op.pushdata.len); + p.writeBytes(op); + } else if (op.pushdata.opcode === 'pushdata4') { + p.writeU8(opcodes.pushdata4); + p.writeU32(op.pushdata.len); + p.writeBytes(op); } continue; } - if (instr.length === 0) { - buf[off++] = opcodes['0']; - } else if (1 <= instr.length && instr.length <= 0x4b) { - buf[off++] = instr.length; - off += instr.copy(buf, off, 0, instr.length); - } else if (instr.length <= 0xff) { - buf[off++] = opcodes.pushdata1; - buf[off++] = instr.length; - off += instr.copy(buf, off, 0, instr.length); - } else if (instr.length <= 0xffff) { - buf[off++] = opcodes.pushdata2; - off += utils.writeU16(buf, instr.length, off); - off += instr.copy(buf, off, 0, instr.length); + // Standard minimaldata encoding + if (op.length === 0) { + p.writeU8(opcodes['0']); + } else if (op.length <= 0x4b) { + p.writeU8(op.length); + p.writeBytes(op); + } else if (op.length <= 0xff) { + p.writeU8(opcodes.pushdata1); + p.writeU8(op.length); + p.writeBytes(op); + } else if (op.length <= 0xffff) { + p.writeU8(opcodes.pushdata2); + p.writeU16(op.length); + p.writeBytes(op); } else { - buf[off++] = opcodes.pushdata4; - off += utils.writeU32(buf, instr.length, off); - off += instr.copy(buf, off, 0, instr.length); + p.writeU8(opcodes.pushdata4); + p.writeU32(op.length); + p.writeBytes(op); } continue; } - assert(opcodes[instr] != null || typeof instr === 'number'); + assert(opcodes[op] != null || typeof op === 'number'); - buf[off++] = opcodes[instr] || instr; + p.writeU8(opcodes[op] || op); } - assert(off === buf.length); - - return buf; + return p.render(); }; Script.witness = Witness;