require('classtool'); function spec(b) { var config = b.config || require('./config'); var log = b.log || require('./util/log')(config); var Opcode = require('./opcode').class(); // Make opcodes available as pseudo-constants for (var i in Opcode.map) { eval(i + " = " + Opcode.map[i] + ";"); } var util = b.util || require('./util/util'); var Parser = b.Parser || require('./util/BinaryParser').class(); var Put = b.Put || require('bufferput'); function Script(buffer) { if(buffer) { this.buffer = buffer; } else { this.buffer = util.EMPTY_BUFFER; } this.chunks = []; this.parse(); }; this.class = Script; Script.prototype.parse = function () { this.chunks = []; var parser = new Parser(this.buffer); while (!parser.eof()) { var opcode = parser.word8(); var len; if (opcode > 0 && opcode < OP_PUSHDATA1) { // Read some bytes of data, opcode value is the length of data this.chunks.push(parser.buffer(opcode)); } else if (opcode == OP_PUSHDATA1) { len = parser.word8(); this.chunks.push(parser.buffer(len)); } else if (opcode == OP_PUSHDATA2) { len = parser.word16le(); this.chunks.push(parser.buffer(len)); } else if (opcode == OP_PUSHDATA4) { len = parser.word32le(); this.chunks.push(parser.buffer(len)); } else { this.chunks.push(opcode); } } }; Script.prototype.isSentToIP = function () { if (this.chunks.length != 2) { return false; } return this.chunks[1] == OP_CHECKSIG && Buffer.isBuffer(this.chunks[0]); }; Script.prototype.getOutType = function () { if (this.chunks.length == 5 && this.chunks[0] == OP_DUP && this.chunks[1] == OP_HASH160 && this.chunks[3] == OP_EQUALVERIFY && this.chunks[4] == OP_CHECKSIG) { // Transfer to Bitcoin address return 'Address'; } else if (this.chunks.length == 2 && this.chunks[1] == OP_CHECKSIG) { // Transfer to IP address return 'Pubkey'; } else { return 'Strange'; } }; Script.prototype.simpleOutHash = function () { switch (this.getOutType()) { case 'Address': return this.chunks[2]; case 'Pubkey': return util.sha256ripe160(this.chunks[0]); default: log.debug("Encountered non-standard scriptPubKey"); log.debug("Strange script was: " + this.toString()); return null; } }; Script.prototype.getInType = function () { if (this.chunks.length == 1) { // Direct IP to IP transactions only have the public key in their scriptSig. return 'Pubkey'; } else if (this.chunks.length == 2 && Buffer.isBuffer(this.chunks[0]) && Buffer.isBuffer(this.chunks[1])) { return 'Address'; } else { return 'Strange'; } }; Script.prototype.simpleInPubKey = function () { switch (this.getInType()) { case 'Address': return this.chunks[1]; case 'Pubkey': return null; default: log.debug("Encountered non-standard scriptSig"); log.debug("Strange script was: " + this.toString()); return null; } }; Script.prototype.getBuffer = function () { return this.buffer; }; Script.prototype.getStringContent = function (truncate, maxEl) { if (truncate === null) { truncate = true; } if ("undefined" === typeof maxEl) { maxEl = 15; } var script = ''; for (var i = 0, l = this.chunks.length; i < l; i++) { var chunk = this.chunks[i]; if (i > 0) { script += " "; } if (Buffer.isBuffer(chunk)) { script += "0x"+util.formatBuffer(chunk, truncate ? null : 0); } else { script += Opcode.reverseMap[chunk]; } if (maxEl && i > maxEl) { script += " ..."; break; } } return script; }; Script.prototype.toString = function (truncate, maxEl) { var script = "