diff --git a/lib/script/script.js b/lib/script/script.js index 41215b0df..6daeb24e5 100644 --- a/lib/script/script.js +++ b/lib/script/script.js @@ -131,6 +131,48 @@ Script.prototype.toBuffer = function() { return bw.concat(); }; +Script.fromASM = function(str) { + var script = new Script(); + script.chunks = []; + + var tokens = str.split(' '); + var i = 0; + while (i < tokens.length) { + var token = tokens[i]; + var opcode = Opcode(token); + var opcodenum = opcode.toNumber(); + + if (_.isUndefined(opcodenum)) { + var buf = new Buffer(tokens[i], 'hex'); + script.chunks.push({ + buf: buf, + len: buf.length, + opcodenum: buf.length + }); + i = i + 1; + } else if (opcodenum === Opcode.OP_PUSHDATA1 || + opcodenum === Opcode.OP_PUSHDATA2 || + opcodenum === Opcode.OP_PUSHDATA4) { + script.chunks.push({ + buf: new Buffer(tokens[i + 2], 'hex'), + len: parseInt(tokens[i + 1]), + opcodenum: opcodenum + }); + i = i + 3; + } else { + script.chunks.push({ + opcodenum: opcodenum + }); + i = i + 1; + } + } + return script; +}; + +Script.fromHex = function(str) { + return new Script(new buffer.Buffer(str, 'hex')); +}; + Script.fromString = function(str) { if (JSUtil.isHexa(str) || str.length === 0) { return new Script(new buffer.Buffer(str, 'hex')); @@ -179,8 +221,9 @@ Script.fromString = function(str) { return script; }; -Script.prototype._chunkToString = function(chunk) { +Script.prototype._chunkToString = function(chunk, type) { var opcodenum = chunk.opcodenum; + var asm = (type === 'asm'); var str = ''; if (!chunk.buf) { // no data chunk @@ -191,7 +234,11 @@ Script.prototype._chunkToString = function(chunk) { if (numstr.length % 2 !== 0) { numstr = '0' + numstr; } - str = str + ' ' + '0x' + numstr; + if (asm) { + str = str + ' ' + numstr; + } else { + str = str + ' ' + '0x' + numstr; + } } } else { // data chunk @@ -200,14 +247,27 @@ Script.prototype._chunkToString = function(chunk) { opcodenum === Opcode.OP_PUSHDATA4) { str = str + ' ' + Opcode(opcodenum).toString(); } - str = str + ' ' + chunk.len; if (chunk.len > 0) { - str = str + ' ' + '0x' + chunk.buf.toString('hex'); + if (asm) { + str = str + ' ' + chunk.buf.toString('hex'); + } else { + str = str + ' ' + chunk.len + ' ' + '0x' + chunk.buf.toString('hex'); + } } } return str; }; +Script.prototype.toASM = function() { + var str = ''; + for (var i = 0; i < this.chunks.length; i++) { + var chunk = this.chunks[i]; + str += this._chunkToString(chunk, 'asm'); + } + + return str.substr(1); +}; + Script.prototype.toString = function() { var str = ''; for (var i = 0; i < this.chunks.length; i++) { diff --git a/test/script/script.js b/test/script/script.js index 6d16b7710..bbbf94532 100644 --- a/test/script/script.js +++ b/test/script/script.js @@ -159,6 +159,19 @@ describe('Script', function() { }); + describe('#fromASM', function() { + it('should parse this known script in ASM', function() { + var asm = 'OP_DUP OP_HASH160 f4c03610e60ad15100929cc23da2f3a799af1725 OP_EQUALVERIFY OP_CHECKSIG'; + var script = Script.fromASM(asm); + script.chunks[0].opcodenum.should.equal(Opcode.OP_DUP); + script.chunks[1].opcodenum.should.equal(Opcode.OP_HASH160); + script.chunks[2].opcodenum.should.equal(20); + script.chunks[2].buf.toString('hex').should.equal('f4c03610e60ad15100929cc23da2f3a799af1725'); + script.chunks[3].opcodenum.should.equal(Opcode.OP_EQUALVERIFY); + script.chunks[4].opcodenum.should.equal(Opcode.OP_CHECKSIG); + }); + }); + describe('#fromString', function() { it('should parse these known scripts', function() { @@ -191,6 +204,11 @@ describe('Script', function() { script.toString().toString('hex').should.equal('OP_0 OP_PUSHDATA4 3 0x010203 OP_0'); }); + it('should output this known script as ASM', function() { + var script = Script.fromHex('76a914f4c03610e60ad15100929cc23da2f3a799af172588ac'); + script.toASM().should.equal('OP_DUP OP_HASH160 f4c03610e60ad15100929cc23da2f3a799af1725 OP_EQUALVERIFY OP_CHECKSIG'); + }); + }); describe('toHex', function() { @@ -463,7 +481,7 @@ describe('Script', function() { }); it('should work for no data OP_RETURN', function() { - Script().add(Opcode.OP_RETURN).add(new Buffer('')).toString().should.equal('OP_RETURN 0'); + Script().add(Opcode.OP_RETURN).add(new Buffer('')).toString().should.equal('OP_RETURN'); }); it('works with objects', function() { Script().add({ @@ -582,7 +600,7 @@ describe('Script', function() { var data = new Buffer(''); var s = Script.buildDataOut(data); should.exist(s); - s.toString().should.equal('OP_RETURN 0'); + s.toString().should.equal('OP_RETURN'); s.isDataOut().should.equal(true); }); it('should create script from some data', function() {