From 4a6755d0d16c501440de4d4cc877594180b47d1c Mon Sep 17 00:00:00 2001 From: Manuel Araoz Date: Fri, 28 Nov 2014 12:57:19 -0300 Subject: [PATCH] add Script#prepend() --- lib/address.js | 2 +- lib/script.js | 61 +++++++++++++++++++++++++++++++++++++------------ test/mocha.opts | 1 + test/script.js | 56 ++++++++++++++++++++++++++------------------- 4 files changed, 81 insertions(+), 39 deletions(-) create mode 100644 test/mocha.opts diff --git a/lib/address.js b/lib/address.js index 295f277..d3159e2 100644 --- a/lib/address.js +++ b/lib/address.js @@ -227,7 +227,7 @@ Address._transformString = function(data, network, type){ * * Instantiate an address from a PublicKey instance * - * @param {String} data - An instance of PublicKey + * @param {PublicKey} data - An instance of PublicKey * @param {String} network - The network: 'livenet' or 'testnet' * @returns {Address} A new valid and frozen instance of an Address */ diff --git a/lib/script.js b/lib/script.js index defee06..e3be402 100644 --- a/lib/script.js +++ b/lib/script.js @@ -208,35 +208,66 @@ Script.prototype.isScriptHashIn = function() { }); }; +/** + * Adds a script element at the start of the script. + * @param {*} obj a string, number, Opcode, Bufer, or object to add + * @returns {Script} this script instance + */ +Script.prototype.prepend = function(obj) { + this._addByType(obj, true); + return this; +}; + +/** + * Adds a script element to the end of the script. + * + * @param {*} obj a string, number, Opcode, Bufer, or object to add + * @returns {Script} this script instance + * + */ Script.prototype.add = function(obj) { + this._addByType(obj, false); + return this; +}; + +Script.prototype._addByType = function(obj, prepend) { if (typeof obj === 'string') { - this._addOpcode(obj); + this._addOpcode(obj, prepend); } else if (typeof obj === 'number') { - this._addOpcode(obj); + this._addOpcode(obj, prepend); } else if (obj.constructor && obj.constructor.name && obj.constructor.name === 'Opcode') { - this._addOpcode(obj); + this._addOpcode(obj, prepend); } else if (Buffer.isBuffer(obj)) { - this._addBuffer(obj); + this._addBuffer(obj, prepend); } else if (typeof obj === 'object') { - this.chunks.push(obj); + this._insertAtPosition(obj, prepend); } else { throw new Error('Invalid script chunk'); } - return this; }; -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()); +Script.prototype._insertAtPosition = function(op, prepend) { + if (prepend) { + this.chunks.unshift(op); } else { - this.chunks.push(Opcode(opcode).toNumber()); + this.chunks.push(op); } +}; + +Script.prototype._addOpcode = function(opcode, prepend) { + var op; + if (typeof opcode === 'number') { + op = opcode; + } else if (opcode.constructor && opcode.constructor.name && opcode.constructor.name === 'Opcode') { + op = opcode.toNumber(); + } else { + op = Opcode(opcode).toNumber(); + } + this._insertAtPosition(op, prepend); return this; }; -Script.prototype._addBuffer = function(buf) { +Script.prototype._addBuffer = function(buf, prepend) { var opcodenum; var len = buf.length; if (buf.length > 0 && buf.length < Opcode.map.OP_PUSHDATA1) { @@ -250,11 +281,11 @@ Script.prototype._addBuffer = function(buf) { } else { throw new Error('You can\'t push that much data'); } - this.chunks.push({ + this._insertAtPosition({ buf: buf, len: len, opcodenum: opcodenum - }); + }, prepend); return this; }; diff --git a/test/mocha.opts b/test/mocha.opts new file mode 100644 index 0000000..4a52320 --- /dev/null +++ b/test/mocha.opts @@ -0,0 +1 @@ +--recursive diff --git a/test/script.js b/test/script.js index 94fccbd..1a3fedf 100644 --- a/test/script.js +++ b/test/script.js @@ -251,37 +251,47 @@ describe('Script', function() { }); - describe('#add', function() { + describe('#add and #prepend', function() { it('should add these ops', function() { Script().add('OP_CHECKMULTISIG').toString().should.equal('OP_CHECKMULTISIG'); + Script().add('OP_1').add('OP_2').toString().should.equal('OP_1 OP_2'); + Script().add(new Opcode('OP_CHECKMULTISIG')).toString().should.equal('OP_CHECKMULTISIG'); Script().add(Opcode.map.OP_CHECKMULTISIG).toString().should.equal('OP_CHECKMULTISIG'); }); - }); + it('should prepend these ops', function() { + Script().prepend('OP_CHECKMULTISIG').toString().should.equal('OP_CHECKMULTISIG'); + Script().prepend('OP_1').prepend('OP_2').toString().should.equal('OP_2 OP_1'); + }); - it('should add these push data', function() { - var buf = new Buffer(1); - buf.fill(0); - Script().add(buf).toString().should.equal('1 0x00'); - buf = new Buffer(255); - buf.fill(0); - Script().add(buf).toString().should.equal('OP_PUSHDATA1 255 0x' + buf.toString('hex')); - buf = new Buffer(256); - buf.fill(0); - Script().add(buf).toString().should.equal('OP_PUSHDATA2 256 0x' + buf.toString('hex')); - buf = new Buffer(Math.pow(2, 16)); - buf.fill(0); - Script().add(buf).toString().should.equal('OP_PUSHDATA4 ' + Math.pow(2, 16) + ' 0x' + buf.toString('hex')); - }); + it('should add and prepend correctly', function() { + Script().add('OP_1').prepend('OP_2').add('OP_3').prepend('OP_4').toString() + .should.equal('OP_4 OP_2 OP_1 OP_3'); + }); - it('should add both pushdata and non-pushdata chunks', function() { - Script().add('OP_CHECKMULTISIG').toString().should.equal('OP_CHECKMULTISIG'); - Script().add(Opcode.map.OP_CHECKMULTISIG).toString().should.equal('OP_CHECKMULTISIG'); - var buf = new Buffer(1); - buf.fill(0); - Script().add(buf).toString().should.equal('1 0x00'); - }); + it('should add these push data', function() { + var buf = new Buffer(1); + buf.fill(0); + Script().add(buf).toString().should.equal('1 0x00'); + buf = new Buffer(255); + buf.fill(0); + Script().add(buf).toString().should.equal('OP_PUSHDATA1 255 0x' + buf.toString('hex')); + buf = new Buffer(256); + buf.fill(0); + Script().add(buf).toString().should.equal('OP_PUSHDATA2 256 0x' + buf.toString('hex')); + buf = new Buffer(Math.pow(2, 16)); + buf.fill(0); + Script().add(buf).toString().should.equal('OP_PUSHDATA4 ' + Math.pow(2, 16) + ' 0x' + buf.toString('hex')); + }); + it('should add both pushdata and non-pushdata chunks', function() { + Script().add('OP_CHECKMULTISIG').toString().should.equal('OP_CHECKMULTISIG'); + Script().add(Opcode.map.OP_CHECKMULTISIG).toString().should.equal('OP_CHECKMULTISIG'); + var buf = new Buffer(1); + buf.fill(0); + Script().add(buf).toString().should.equal('1 0x00'); + }); + }); });