From 354d31a297b49a99af2db877fa43b90f7203293a Mon Sep 17 00:00:00 2001
From: Andreas Brekken
Date: Sat, 1 Mar 2014 19:12:50 +0100
Subject: [PATCH 1/2] Clean up script.js formatting. ref #41
---
src/script.js | 394 +++++++++++++++++++++++++-------------------------
1 file changed, 199 insertions(+), 195 deletions(-)
diff --git a/src/script.js b/src/script.js
index 16191fd..7a544bd 100644
--- a/src/script.js
+++ b/src/script.js
@@ -3,100 +3,100 @@ var util = require('./util');
var conv = require('./convert');
var Address = require('./address');
-var Script = function (data) {
- if (!data) {
- this.buffer = [];
- } else if ("string" == typeof data) {
- this.buffer = conv.hexToBytes(data);
- } else if (util.isArray(data)) {
- this.buffer = data;
- } else if (data instanceof Script) {
- this.buffer = data.buffer;
- } else {
- throw new Error("Invalid script");
- }
-
- this.parse();
+var Script = function(data) {
+ if (!data) {
+ this.buffer = [];
+ } else if ('string' == typeof data) {
+ this.buffer = conv.hexToBytes(data);
+ } else if (util.isArray(data)) {
+ this.buffer = data;
+ } else if (data instanceof Script) {
+ this.buffer = data.buffer;
+ } else {
+ throw new Error('Invalid script');
+ }
+
+ this.parse();
};
Script.fromPubKey = function(str) {
- var script = new Script();
- var s = str.split(" ");
- for (var i in s) {
- if (Opcode.map.hasOwnProperty(s[i])){
- script.writeOp(Opcode.map[s[i]]);
- } else {
- script.writeBytes(conv.hexToBytes(s[i]));
+ var script = new Script();
+ var s = str.split(' ');
+ for (var i in s) {
+ if (Opcode.map.hasOwnProperty(s[i])) {
+ script.writeOp(Opcode.map[s[i]]);
+ } else {
+ script.writeBytes(conv.hexToBytes(s[i]));
+ }
}
- }
- return script;
+ return script;
};
Script.fromScriptSig = function(str) {
- var script = new Script();
- var s = str.split(" ");
- for (var i in s) {
- if (Opcode.map.hasOwnProperty(s[i])){
- script.writeOp(Opcode.map[s[i]]);
- } else {
- script.writeBytes(conv.hexToBytes(s[i]));
+ var script = new Script();
+ var s = str.split(' ');
+ for (var i in s) {
+ if (Opcode.map.hasOwnProperty(s[i])) {
+ script.writeOp(Opcode.map[s[i]]);
+ } else {
+ script.writeBytes(conv.hexToBytes(s[i]));
+ }
}
- }
- return script;
+ return script;
};
/**
* Update the parsed script representation.
*
* Each Script object stores the script in two formats. First as a raw byte
- * array and second as an array of "chunks", such as opcodes and pieces of
+ * array and second as an array of 'chunks', such as opcodes and pieces of
* data.
*
* This method updates the chunks cache. Normally this is called by the
* constructor and you don't need to worry about it. However, if you change
* the script buffer manually, you should update the chunks using this method.
*/
-Script.prototype.parse = function () {
- var self = this;
-
- this.chunks = [];
+Script.prototype.parse = function() {
+ var self = this;
- // Cursor
- var i = 0;
+ this.chunks = [];
- // Read n bytes and store result as a chunk
- function readChunk(n) {
- self.chunks.push(self.buffer.slice(i, i + n));
- i += n;
- };
+ // Cursor
+ var i = 0;
- while (i < this.buffer.length) {
- var opcode = this.buffer[i++];
- if (opcode >= 0xF0) {
- // Two byte opcode
- opcode = (opcode << 8) | this.buffer[i++];
+ // Read n bytes and store result as a chunk
+ function readChunk(n) {
+ self.chunks.push(self.buffer.slice(i, i + n));
+ i += n;
}
- var len;
- if (opcode > 0 && opcode < Opcode.map.OP_PUSHDATA1) {
- // Read some bytes of data, opcode value is the length of data
- readChunk(opcode);
- } else if (opcode == Opcode.map.OP_PUSHDATA1) {
- len = this.buffer[i++];
- readChunk(len);
- } else if (opcode == Opcode.map.OP_PUSHDATA2) {
- len = (this.buffer[i++] << 8) | this.buffer[i++];
- readChunk(len);
- } else if (opcode == Opcode.map.OP_PUSHDATA4) {
- len = (this.buffer[i++] << 24) |
- (this.buffer[i++] << 16) |
- (this.buffer[i++] << 8) |
- this.buffer[i++];
- readChunk(len);
- } else {
- this.chunks.push(opcode);
+ while (i < this.buffer.length) {
+ var opcode = this.buffer[i++];
+ if (opcode >= 0xF0) {
+ // Two byte opcode
+ opcode = (opcode << 8) | this.buffer[i++];
+ }
+
+ var len;
+ if (opcode > 0 && opcode < Opcode.map.OP_PUSHDATA1) {
+ // Read some bytes of data, opcode value is the length of data
+ readChunk(opcode);
+ } else if (opcode == Opcode.map.OP_PUSHDATA1) {
+ len = this.buffer[i++];
+ readChunk(len);
+ } else if (opcode == Opcode.map.OP_PUSHDATA2) {
+ len = (this.buffer[i++] << 8) | this.buffer[i++];
+ readChunk(len);
+ } else if (opcode == Opcode.map.OP_PUSHDATA4) {
+ len = (this.buffer[i++] << 24) |
+ (this.buffer[i++] << 16) |
+ (this.buffer[i++] << 8) |
+ this.buffer[i++];
+ readChunk(len);
+ } else {
+ this.chunks.push(opcode);
+ }
}
- }
};
/**
@@ -113,47 +113,58 @@ Script.prototype.parse = function () {
* Pubkey:
* Paying to a public key directly.
* [pubKey] OP_CHECKSIG
- *
+ *
* Strange:
* Any other script (no template matched).
*/
-Script.prototype.getOutType = function () {
- if (this.chunks[this.chunks.length-1] == Opcode.map.OP_EQUAL &&
+Script.prototype.getOutType = function() {
+ if (this.chunks[this.chunks.length - 1] == Opcode.map.OP_EQUAL &&
this.chunks[0] == Opcode.map.OP_HASH160 &&
this.chunks.length == 3) {
// Transfer to M-OF-N
return 'P2SH';
- }
- else if (this.chunks.length == 5 &&
+ } else if (this.chunks.length == 5 &&
this.chunks[0] == Opcode.map.OP_DUP &&
this.chunks[1] == Opcode.map.OP_HASH160 &&
this.chunks[3] == Opcode.map.OP_EQUALVERIFY &&
this.chunks[4] == Opcode.map.OP_CHECKSIG) {
// Transfer to Bitcoin address
return 'Pubkey';
- }
- else {
+ } else {
return 'Strange';
- }
+ }
}
/**
* Returns the address corresponding to this output in hash160 form.
* Assumes strange scripts are P2SH
*/
-Script.prototype.toScriptHash = function () {
+Script.prototype.toScriptHash = function() {
var outType = this.getOutType();
- return outType == 'Pubkey' ? this.chunks[2]
- : outType == 'P2SH' ? util.sha256ripe160(this.buffer)
- : util.sha256ripe160(this.buffer)
-};
+ if (outType == 'Pubkey') {
+ return this.chunks[2]
+ }
+
+ if (outType == 'P2SH') {
+ return util.sha256ripe160(this.buffer)
+ }
+
+ return util.sha256ripe160(this.buffer)
+}
Script.prototype.toAddress = function() {
var outType = this.getOutType();
- return outType == 'Pubkey' ? new Address(this.chunks[2])
- : outType == 'P2SH' ? new Address(this.chunks[1],5)
- : new Address(this.chunks[1],5)
+
+ if (outType == 'Pubkey') {
+ return new Address(this.chunks[2])
+ }
+
+ if (outType == 'P2SH') {
+ return new Address(this.chunks[1], 5)
+ }
+
+ return new Address(this.chunks[1], 5)
}
/**
@@ -177,30 +188,28 @@ Script.prototype.toAddress = function() {
*
* Multisig:
* Paying to M-of-N public keys.
- *
+ *
* Strange:
* Any other script (no template matched).
*/
-Script.prototype.getInType = function ()
-{
- if (this.chunks.length == 1 &&
- util.isArray(this.chunks[0])) {
- // Direct IP to IP transactions only have the signature in their scriptSig.
- // TODO: We could also check that the length of the data is correct.
- return 'Pubkey';
- } else if (this.chunks.length == 2 &&
- util.isArray(this.chunks[0]) &&
- util.isArray(this.chunks[1])) {
- return 'Address';
- } else if (this.chunks[0] == Opcode.map.OP_0 &&
- this.chunks.slice(1).reduce(function(t,chunk,i) {
- return t && util.isArray(chunk)
- && (chunk[0] == 48 || i == this.chunks.length - 1);
- },true)) {
- return 'Multisig';
- } else {
- return 'Strange';
- }
+Script.prototype.getInType = function() {
+ if (this.chunks.length == 1 &&
+ util.isArray(this.chunks[0])) {
+ // Direct IP to IP transactions only have the signature in their scriptSig.
+ // TODO: We could also check that the length of the data is correct.
+ return 'Pubkey';
+ } else if (this.chunks.length == 2 &&
+ util.isArray(this.chunks[0]) &&
+ util.isArray(this.chunks[1])) {
+ return 'Address';
+ } else if (this.chunks[0] == Opcode.map.OP_0 &&
+ this.chunks.slice(1).reduce(function(t, chunk, i) {
+ return t && util.isArray(chunk) && (chunk[0] == 48 || i == this.chunks.length - 1);
+ }, true)) {
+ return 'Multisig';
+ } else {
+ return 'Strange';
+ }
};
/**
@@ -216,18 +225,17 @@ Script.prototype.getInType = function ()
*
* @deprecated
*/
-Script.prototype.simpleInPubKey = function ()
-{
- switch (this.getInType()) {
- case 'Address':
- return this.chunks[1];
- case 'Pubkey':
- // TODO: Theoretically, we could recover the pubkey from the sig here.
- // See https://bitcointalk.org/?topic=6430.0
- throw new Error("Script does not contain pubkey.");
- default:
- throw new Error("Encountered non-standard scriptSig");
- }
+Script.prototype.simpleInPubKey = function() {
+ switch (this.getInType()) {
+ case 'Address':
+ return this.chunks[1];
+ case 'Pubkey':
+ // TODO: Theoretically, we could recover the pubkey from the sig here.
+ // See https://bitcointalk.org/?topic=6430.0
+ throw new Error('Script does not contain pubkey');
+ default:
+ throw new Error('Encountered non-standard scriptSig');
+ }
};
/**
@@ -245,9 +253,8 @@ Script.prototype.simpleInPubKey = function ()
*
* This method is useful for indexing transactions.
*/
-Script.prototype.simpleInHash = function ()
-{
- return util.sha256ripe160(this.simpleInPubKey());
+Script.prototype.simpleInHash = function() {
+ return util.sha256ripe160(this.simpleInPubKey());
};
/**
@@ -260,59 +267,56 @@ Script.prototype.simpleInPubKeyHash = Script.prototype.simpleInHash;
/**
* Add an op code to the script.
*/
-Script.prototype.writeOp = function (opcode)
-{
- this.buffer.push(opcode);
- this.chunks.push(opcode);
+Script.prototype.writeOp = function(opcode) {
+ this.buffer.push(opcode);
+ this.chunks.push(opcode);
};
/**
* Add a data chunk to the script.
*/
-Script.prototype.writeBytes = function (data)
-{
- if (data.length < Opcode.map.OP_PUSHDATA1) {
- this.buffer.push(data.length);
- } else if (data.length <= 0xff) {
- this.buffer.push(Opcode.map.OP_PUSHDATA1);
- this.buffer.push(data.length);
- } else if (data.length <= 0xffff) {
- this.buffer.push(Opcode.map.OP_PUSHDATA2);
- this.buffer.push(data.length & 0xff);
- this.buffer.push((data.length >>> 8) & 0xff);
- } else {
- this.buffer.push(Opcode.map.OP_PUSHDATA4);
- this.buffer.push(data.length & 0xff);
- this.buffer.push((data.length >>> 8) & 0xff);
- this.buffer.push((data.length >>> 16) & 0xff);
- this.buffer.push((data.length >>> 24) & 0xff);
- }
- this.buffer = this.buffer.concat(data);
- this.chunks.push(data);
+Script.prototype.writeBytes = function(data) {
+ if (data.length < Opcode.map.OP_PUSHDATA1) {
+ this.buffer.push(data.length);
+ } else if (data.length <= 0xff) {
+ this.buffer.push(Opcode.map.OP_PUSHDATA1);
+ this.buffer.push(data.length);
+ } else if (data.length <= 0xffff) {
+ this.buffer.push(Opcode.map.OP_PUSHDATA2);
+ this.buffer.push(data.length & 0xff);
+ this.buffer.push((data.length >>> 8) & 0xff);
+ } else {
+ this.buffer.push(Opcode.map.OP_PUSHDATA4);
+ this.buffer.push(data.length & 0xff);
+ this.buffer.push((data.length >>> 8) & 0xff);
+ this.buffer.push((data.length >>> 16) & 0xff);
+ this.buffer.push((data.length >>> 24) & 0xff);
+ }
+ this.buffer = this.buffer.concat(data);
+ this.chunks.push(data);
};
/**
* Create an output for an address
*/
-Script.createOutputScript = function (address)
-{
- var script = new Script();
- address = new Address(address);
- // Standard pay-to-pubkey-hash
- if (!address.version) {
- script.writeOp(Opcode.map.OP_DUP);
- script.writeOp(Opcode.map.OP_HASH160);
- script.writeBytes(address.hash);
- script.writeOp(Opcode.map.OP_EQUALVERIFY);
- script.writeOp(Opcode.map.OP_CHECKSIG);
- }
- // Standard pay-to-script-hash
- else {
- script.writeOp(Opcode.map.OP_HASH160);
- script.writeBytes(address.hash);
- script.writeOp(Opcode.map.OP_EQUAL);
- }
- return script;
+Script.createOutputScript = function(address) {
+ var script = new Script();
+ address = new Address(address);
+ // Standard pay-to-pubkey-hash
+ if (!address.version) {
+ script.writeOp(Opcode.map.OP_DUP);
+ script.writeOp(Opcode.map.OP_HASH160);
+ script.writeBytes(address.hash);
+ script.writeOp(Opcode.map.OP_EQUALVERIFY);
+ script.writeOp(Opcode.map.OP_CHECKSIG);
+ }
+ // Standard pay-to-script-hash
+ else {
+ script.writeOp(Opcode.map.OP_HASH160);
+ script.writeBytes(address.hash);
+ script.writeOp(Opcode.map.OP_EQUAL);
+ }
+ return script;
};
/**
@@ -321,62 +325,62 @@ Script.createOutputScript = function (address)
Script.prototype.extractPubkeys = function() {
return this.chunks.filter(function(chunk) {
- return (chunk[0] == 4 && chunk.length == 65
- || chunk[0] < 4 && chunk.length == 33)
+ return(chunk[0] == 4 && chunk.length == 65 || chunk[0] < 4 && chunk.length == 33)
});
}
/**
* Create an m-of-n output script
*/
-Script.createMultiSigOutputScript = function (m, pubkeys)
-{
- var script = new Script();
-
- pubkeys = pubkeys.sort();
-
- script.writeOp(Opcode.map.OP_1 + m - 1);
-
- for (var i = 0; i < pubkeys.length; ++i) {
- script.writeBytes(pubkeys[i]);
- }
-
- script.writeOp(Opcode.map.OP_1 + pubkeys.length - 1);
-
- script.writeOp(Opcode.map.OP_CHECKMULTISIG);
-
- return script;
+Script.createMultiSigOutputScript = function(m, pubkeys) {
+ var script = new Script();
+
+ pubkeys = pubkeys.sort();
+
+ script.writeOp(Opcode.map.OP_1 + m - 1);
+
+ for (var i = 0; i < pubkeys.length; ++i) {
+ script.writeBytes(pubkeys[i]);
+ }
+
+ script.writeOp(Opcode.map.OP_1 + pubkeys.length - 1);
+
+ script.writeOp(Opcode.map.OP_CHECKMULTISIG);
+
+ return script;
};
/**
* Create a standard payToPubKeyHash input.
*/
-Script.createInputScript = function (signature, pubKey)
-{
- var script = new Script();
- script.writeBytes(signature);
- script.writeBytes(pubKey);
- return script;
+Script.createInputScript = function(signature, pubKey) {
+ var script = new Script();
+ script.writeBytes(signature);
+ script.writeBytes(pubKey);
+ return script;
};
/**
* Create a multisig input
*/
-Script.createMultiSigInputScript = function(signatures, script)
-{
+Script.createMultiSigInputScript = function(signatures, script) {
script = new Script(script);
var k = script.chunks[0][0];
- if (signatures.length < k) return false; //Not enough sigs
+
+ //Not enough sigs
+ if (signatures.length < k) return false;
+
var inScript = new Script();
inScript.writeOp(Opcode.map.OP_0);
- signatures.map(function(sig) { inScript.writeBytes(sig) });
+ signatures.map(function(sig) {
+ inScript.writeBytes(sig)
+ });
inScript.writeBytes(script.buffer);
return inScript;
}
-Script.prototype.clone = function ()
-{
- return new Script(this.buffer);
+Script.prototype.clone = function() {
+ return new Script(this.buffer);
};
module.exports = Script;
From 4a4e75d007291b661ae1df5d85dac48bf650bfea Mon Sep 17 00:00:00 2001
From: Andreas Brekken
Date: Sat, 1 Mar 2014 19:19:27 +0100
Subject: [PATCH 2/2] Simplify Script constructor. close #41
---
src/script.js | 17 +++++------------
1 file changed, 5 insertions(+), 12 deletions(-)
diff --git a/src/script.js b/src/script.js
index 7a544bd..5d04371 100644
--- a/src/script.js
+++ b/src/script.js
@@ -4,21 +4,14 @@ var conv = require('./convert');
var Address = require('./address');
var Script = function(data) {
- if (!data) {
- this.buffer = [];
- } else if ('string' == typeof data) {
- this.buffer = conv.hexToBytes(data);
- } else if (util.isArray(data)) {
- this.buffer = data;
- } else if (data instanceof Script) {
- this.buffer = data.buffer;
- } else {
- throw new Error('Invalid script');
- }
-
+ this.buffer = data || [];
this.parse();
};
+Script.fromHex = function(data) {
+ return new Script(conv.hexToBytes(data))
+};
+
Script.fromPubKey = function(str) {
var script = new Script();
var s = str.split(' ');