diff --git a/lib/script.js b/lib/script.js index a33a999..d884aee 100644 --- a/lib/script.js +++ b/lib/script.js @@ -4,22 +4,19 @@ var BufferReader = require('./encoding/bufferreader'); var BufferWriter = require('./encoding/bufferwriter'); var Opcode = require('./opcode'); -var Script = function Script(buf) { - if (!(this instanceof Script)) - return new Script(buf); - +var Script = function Script(from) { + if (!(this instanceof Script)) { + return new Script(from); + } + this.chunks = []; - if (Buffer.isBuffer(buf)) { - this.fromBuffer(buf); - } - else if (typeof buf === 'string') { - var str = buf; - this.fromString(str); - } - else if (typeof buf !== 'undefined') { - var obj = buf; - this.set(obj); + if (Buffer.isBuffer(from)) { + this.fromBuffer(from); + } else if (typeof from === 'string') { + this.fromString(from); + } else if (typeof from !== 'undefined') { + this.set(from); } }; @@ -28,33 +25,26 @@ Script.prototype.set = function(obj) { return this; }; -Script.prototype.fromJSON = function(json) { - return this.fromString(json); -}; - -Script.prototype.toJSON = function() { - return this.toString(); -}; +Script.fromBuffer = function(buffer) { + var script = new Script(); + script.chunks = []; -Script.prototype.fromBuffer = function(buf) { - this.chunks = []; - - var br = new BufferReader(buf); + var br = new BufferReader(buffer); while (!br.eof()) { var opcodenum = br.readUInt8(); var len, buf; if (opcodenum > 0 && opcodenum < Opcode.map.OP_PUSHDATA1) { len = opcodenum; - this.chunks.push({ + script.chunks.push({ buf: br.read(len), len: len, opcodenum: opcodenum }); } else if (opcodenum === Opcode.map.OP_PUSHDATA1) { len = br.readUInt8(); - var buf = br.read(len); - this.chunks.push({ + buf = br.read(len); + script.chunks.push({ buf: buf, len: len, opcodenum: opcodenum @@ -62,7 +52,7 @@ Script.prototype.fromBuffer = function(buf) { } else if (opcodenum === Opcode.map.OP_PUSHDATA2) { len = br.readUInt16LE(); buf = br.read(len); - this.chunks.push({ + script.chunks.push({ buf: buf, len: len, opcodenum: opcodenum @@ -70,17 +60,17 @@ Script.prototype.fromBuffer = function(buf) { } else if (opcodenum === Opcode.map.OP_PUSHDATA4) { len = br.readUInt32LE(); buf = br.read(len); - this.chunks.push({ + script.chunks.push({ buf: buf, len: len, opcodenum: opcodenum }); } else { - this.chunks.push(opcodenum); + script.chunks.push(opcodenum); } } - return this; + return script; }; Script.prototype.toBuffer = function() { @@ -88,24 +78,22 @@ Script.prototype.toBuffer = function() { for (var i = 0; i < this.chunks.length; i++) { var chunk = this.chunks[i]; + var opcodenum; if (typeof chunk === 'number') { - var opcodenum = chunk; + opcodenum = chunk; bw.writeUInt8(opcodenum); } else { - var opcodenum = chunk.opcodenum; + opcodenum = chunk.opcodenum; bw.writeUInt8(chunk.opcodenum); if (opcodenum < Opcode.map.OP_PUSHDATA1) { bw.write(chunk.buf); - } - else if (opcodenum === Opcode.map.OP_PUSHDATA1) { + } else if (opcodenum === Opcode.map.OP_PUSHDATA1) { bw.writeUInt8(chunk.len); bw.write(chunk.buf); - } - else if (opcodenum === Opcode.map.OP_PUSHDATA2) { + } else if (opcodenum === Opcode.map.OP_PUSHDATA2) { bw.writeUInt16LE(chunk.len); bw.write(chunk.buf); - } - else if (opcodenum === Opcode.map.OP_PUSHDATA4) { + } else if (opcodenum === Opcode.map.OP_PUSHDATA4) { bw.writeUInt32LE(chunk.len); bw.write(chunk.buf); } @@ -134,13 +122,13 @@ Script.prototype.fromString = function(str) { opcodenum: opcodenum }); i = i + 2; - } - else { + } else { throw new Error('Invalid script'); } } else if (opcodenum === Opcode.map.OP_PUSHDATA1 || opcodenum === Opcode.map.OP_PUSHDATA2 || opcodenum === Opcode.map.OP_PUSHDATA4) { - if (tokens[i + 2].slice(0, 2) != '0x') + if (tokens[i + 2].slice(0, 2) !== '0x') { throw new Error('Pushdata data must start with 0x'); + } this.chunks.push({ buf: new Buffer(tokens[i + 2].slice(2), 'hex'), len: parseInt(tokens[i + 1]), @@ -156,19 +144,23 @@ Script.prototype.fromString = function(str) { }; Script.prototype.toString = function() { - var str = ""; + var str = ''; for (var i = 0; i < this.chunks.length; i++) { var chunk = this.chunks[i]; + var opcodenum; if (typeof chunk === 'number') { - var opcodenum = chunk; - str = str + Opcode(opcodenum).toString() + " "; + opcodenum = chunk; + str = str + Opcode(opcodenum).toString() + ' '; } else { - var opcodenum = chunk.opcodenum; - if (opcodenum === Opcode.map.OP_PUSHDATA1 || opcodenum === Opcode.map.OP_PUSHDATA2 || opcodenum === Opcode.map.OP_PUSHDATA4) - str = str + Opcode(opcodenum).toString() + " " ; - str = str + chunk.len + " " ; - str = str + "0x" + chunk.buf.toString('hex') + " "; + opcodenum = chunk.opcodenum; + if (opcodenum === Opcode.map.OP_PUSHDATA1 || + opcodenum === Opcode.map.OP_PUSHDATA2 || + opcodenum === Opcode.map.OP_PUSHDATA4) { + str = str + Opcode(opcodenum).toString() + ' '; + } + str = str + chunk.len + ' '; + str = str + '0x' + chunk.buf.toString('hex') + ' '; } } @@ -176,14 +168,9 @@ Script.prototype.toString = function() { }; Script.prototype.isOpReturn = function() { - if (this.chunks[0] === Opcode('OP_RETURN').toNumber() - && - (this.chunks.length === 1 - || - (this.chunks.length === 2 - && this.chunks[1].buf - && this.chunks[1].buf.length <= 40 - && this.chunks[1].length === this.chunks.len))) { + if (this.chunks[0] === Opcode('OP_RETURN').toNumber() && + (this.chunks.length === 1 || + (this.chunks.length === 2 && this.chunks[1].buf && this.chunks[1].buf.length <= 40 && this.chunks[1].length === this.chunks.len))) { return true; } else { return false; @@ -191,11 +178,7 @@ Script.prototype.isOpReturn = function() { }; Script.prototype.isPublicKeyHashOut = function() { - if (this.chunks[0] === Opcode('OP_DUP').toNumber() - && this.chunks[1] === Opcode('OP_HASH160').toNumber() - && this.chunks[2].buf - && this.chunks[3] === Opcode('OP_EQUALVERIFY').toNumber() - && this.chunks[4] === Opcode('OP_CHECKSIG').toNumber()) { + if (this.chunks[0] === Opcode('OP_DUP').toNumber() && this.chunks[1] === Opcode('OP_HASH160').toNumber() && this.chunks[2].buf && this.chunks[3] === Opcode('OP_EQUALVERIFY').toNumber() && this.chunks[4] === Opcode('OP_CHECKSIG').toNumber()) { return true; } else { return false; @@ -203,9 +186,7 @@ Script.prototype.isPublicKeyHashOut = function() { }; Script.prototype.isPublicKeyHashIn = function() { - if (this.chunks.length === 2 - && this.chunks[0].buf - && this.chunks[1].buf) { + if (this.chunks.length === 2 && this.chunks[0].buf && this.chunks[1].buf) { return true; } else { return false; @@ -213,11 +194,7 @@ Script.prototype.isPublicKeyHashIn = function() { }; Script.prototype.isScriptHashOut = function() { - if (this.chunks.length === 3 - && this.chunks[0] === Opcode('OP_HASH160').toNumber() - && this.chunks[1].buf - && this.chunks[1].buf.length === 20 - && this.chunks[2] === Opcode('OP_EQUAL').toNumber()) { + if (this.chunks.length === 3 && this.chunks[0] === Opcode('OP_HASH160').toNumber() && this.chunks[1].buf && this.chunks[1].buf.length === 20 && this.chunks[2] === Opcode('OP_EQUAL').toNumber()) { return true; } else { return false; @@ -236,29 +213,35 @@ Script.prototype.isScriptHashIn = function() { } }; -Script.prototype.write = function(obj) { - if (typeof obj === 'string') - this.writeOp(obj); - else if (typeof obj === 'number') - this.writeOp(obj); - else if (Buffer.isBuffer(obj)) - this.writeBuffer(obj); - else if (typeof obj === 'object') +Script.prototype.add = function(obj) { + if (typeof obj === 'string') { + this._addOpcode(obj); + } else if (typeof obj === 'number') { + this._addOpcode(obj); + } else if (obj.constructor && obj.constructor.name && obj.constructor.name === 'Opcode') { + this._addOpcode(obj); + } else if (Buffer.isBuffer(obj)) { + this._addBuffer(obj); + } else if (typeof obj === 'object') { this.chunks.push(obj); - else + } else { throw new Error('Invalid script chunk'); + } return this; }; -Script.prototype.writeOp = function(str) { - if (typeof str === 'number') - this.chunks.push(str); - else - this.chunks.push(Opcode(str).toNumber()); +Script.prototype._addOpcode = function(opcode) { + if (typeof opcode === 'number') { + this.chunks.push(opcode); + } else if (opcode.constructor && opcode.constructor.name && opcode.constructor.name === 'Opcode') { + this.chunks.push(opcode.toNumber()); + } else { + this.chunks.push(Opcode(opcode).toNumber()); + } return this; }; -Script.prototype.writeBuffer = function(buf) { +Script.prototype._addBuffer = function(buf) { var opcodenum; var len = buf.length; if (buf.length > 0 && buf.length < Opcode.map.OP_PUSHDATA1) { @@ -270,7 +253,7 @@ Script.prototype.writeBuffer = function(buf) { } else if (buf.length < Math.pow(2, 32)) { opcodenum = Opcode.map.OP_PUSHDATA4; } else { - throw new Error("You can't push that much data"); + throw new Error('You can\'t push that much data'); } this.chunks.push({ buf: buf,