Browse Source

initial Script refactor

patch-2
Manuel Araoz 10 years ago
parent
commit
87f6651554
  1. 159
      lib/script.js

159
lib/script.js

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

Loading…
Cancel
Save