Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
61 changes: 30 additions & 31 deletions lib/script/script.js
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
'use strict';


var BufferReader = require('../encoding/bufferreader');
var BufferWriter = require('../encoding/bufferwriter');
var Hash = require('../crypto/hash');
Expand All @@ -14,7 +13,6 @@ var _ = require('lodash');
var errors = require('../errors');
var buffer = require('buffer');
var BufferUtil = require('../util/buffer');
var JSUtil = require('../util/js');

/**
* A bitcoin transaction script. Each transaction's inputs and outputs
Expand Down Expand Up @@ -134,44 +132,44 @@ Script.prototype.toBuffer = function() {
return bw.concat();
};

Script.fromHexString = function(hexStr) {
return new Script(new buffer.Buffer(hexStr, 'hex'));
};

Script.fromString = function(str) {
if (JSUtil.isHexa(str) || str.length === 0) {
return new Script(new buffer.Buffer(str, 'hex'));
}
var script = new Script();
script.chunks = [];

if (str.length === 0) {
return script;
}

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)) {
opcodenum = parseInt(token);
if (opcodenum > 0 && opcodenum < Opcode.OP_PUSHDATA1) {
script.chunks.push({
buf: new Buffer(tokens[i + 1].slice(2), 'hex'),
len: opcodenum,
opcodenum: opcodenum
});
i = i + 2;
} else {
throw new Error('Invalid script: ' + JSON.stringify(str));
}
var buf = new Buffer(tokens[i], 'hex');
script.chunks.push({
buf: buf,
len: buf.length,
opcodenum: buf.length // todo: fix serialization so that opcodenum isn't the length
});
i = i + 1;
} else if (opcodenum === Opcode.OP_PUSHDATA1 ||
opcodenum === Opcode.OP_PUSHDATA2 ||
opcodenum === Opcode.OP_PUSHDATA4) {
if (tokens[i + 2].slice(0, 2) !== '0x') {
throw new Error('Pushdata data must start with 0x');
}
var pushBuf = new Buffer(tokens[i + 1], 'hex');
script.chunks.push({
buf: new Buffer(tokens[i + 2].slice(2), 'hex'),
len: parseInt(tokens[i + 1]),
buf: pushBuf,
len: pushBuf.length,
opcodenum: opcodenum
});
i = i + 3;
i = i + 2;
} else {
script.chunks.push({
opcodenum: opcodenum
Expand All @@ -194,7 +192,7 @@ Script.prototype._chunkToString = function(chunk) {
if (numstr.length % 2 !== 0) {
numstr = '0' + numstr;
}
str = str + ' ' + '0x' + numstr;
str = str + ' ' + numstr;
}
} else {
// data chunk
Expand All @@ -203,9 +201,8 @@ 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');
str = str + ' ' + chunk.buf.toString('hex');
}
}
return str;
Expand Down Expand Up @@ -290,7 +287,7 @@ Script.prototype.isScriptHashOut = function() {
buf[buf.length - 1] === Opcode.OP_EQUAL);
};

/**
/**
* @returns {boolean} if this is a p2sh input script
* Note that these are frequently indistinguishable from pubkeyhashin
*/
Expand All @@ -303,7 +300,6 @@ Script.prototype.isScriptHashIn = function() {
if (!redeemBuf) {
return false;
}

var redeemScript;
try {
redeemScript = Script.fromBuffer(redeemBuf);
Expand Down Expand Up @@ -340,7 +336,9 @@ Script.prototype.isMultisigIn = function() {
this.chunks.slice(1, this.chunks.length).every(function(obj) {
return obj.buf &&
BufferUtil.isBuffer(obj.buf) &&
obj.buf.length === 0x47;
obj.buf.length <= 0x49;
// todo: check for signature encoding
// https://github.com/bitcoin/bips/blob/master/bip-0062.mediawiki#der-encoding
});
};

Expand Down Expand Up @@ -655,12 +653,13 @@ Script.buildPublicKeyOut = function(pubkey) {

/**
* @returns {Script} a new OP_RETURN script with data
* @param {(string|Buffer)} to - the data to embed in the output
* @param {(string|Buffer)} data - the data to embed in the output
* @param {(string)} encoding - the type of encoding of a string
*/
Script.buildDataOut = function(data) {
Script.buildDataOut = function(data, encoding) {
$.checkArgument(_.isUndefined(data) || _.isString(data) || BufferUtil.isBuffer(data));
if (typeof data === 'string') {
data = new Buffer(data);
data = new Buffer(data, encoding);
}
var s = new Script();
s.add(Opcode.OP_RETURN);
Expand Down
7 changes: 5 additions & 2 deletions lib/transaction/input/input.js
Original file line number Diff line number Diff line change
Expand Up @@ -40,12 +40,15 @@ Object.defineProperty(Input.prototype, 'script', {
});

Input.prototype._fromObject = function(params) {
var prevTxId;
if (_.isString(params.prevTxId) && JSUtil.isHexa(params.prevTxId)) {
params.prevTxId = new buffer.Buffer(params.prevTxId, 'hex');
prevTxId = new buffer.Buffer(params.prevTxId, 'hex');
} else {
prevTxId = params.prevTxId;
}
this.output = params.output ?
(params.output instanceof Output ? params.output : new Output(params.output)) : undefined;
this.prevTxId = params.prevTxId || params.txidbuf;
this.prevTxId = prevTxId || params.txidbuf;
this.outputIndex = _.isUndefined(params.outputIndex) ? params.txoutnum : params.outputIndex;
this.sequenceNumber = _.isUndefined(params.sequenceNumber) ?
(_.isUndefined(params.seqnum) ? DEFAULT_SEQNUMBER : params.seqnum) : params.sequenceNumber;
Expand Down
9 changes: 6 additions & 3 deletions lib/transaction/output.js
Original file line number Diff line number Diff line change
Expand Up @@ -21,10 +21,13 @@ function Output(args) {
if (bufferUtil.isBuffer(args.script)) {
this._scriptBuffer = args.script;
} else {
var script;
if (_.isString(args.script) && JSUtil.isHexa(args.script)) {
args.script = new buffer.Buffer(args.script, 'hex');
script = new buffer.Buffer(args.script, 'hex');
} else {
script = args.script;
}
this.setScript(args.script);
this.setScript(script);
}
} else if (JSUtil.isValidJSON(args)) {
return Output.fromJSON(args);
Expand Down Expand Up @@ -105,7 +108,7 @@ Output.fromJSON = function(data) {
var json = JSON.parse(data);
return new Output({
satoshis: Number(json.satoshis),
script: new Script(json.script)
script: Script.fromHexString(json.script)
});
};

Expand Down
8 changes: 4 additions & 4 deletions lib/transaction/transaction.js
Original file line number Diff line number Diff line change
Expand Up @@ -358,16 +358,16 @@ Transaction.prototype.fromObject = function(transaction) {
self.uncheckedAddInput(new Input(input));
return;
}
input.output.script = new Script(input.output.script);
var script = Script.fromHexString(input.output.script);
var txin;
if (input.output.script.isPublicKeyHashOut()) {
if (script.isPublicKeyHashOut()) {
txin = new Input.PublicKeyHash(input);
} else if (input.output.script.isScriptHashOut() && input.publicKeys && input.threshold) {
} else if (script.isScriptHashOut() && input.publicKeys && input.threshold) {
txin = new Input.MultiSigScriptHash(
input, input.publicKeys, input.threshold, input.signatures
);
} else {
throw new errors.Transaction.Input.UnsupportedScript(input.output.script);
throw new errors.Transaction.Input.UnsupportedScript(script);
}
self.addInput(txin);
});
Expand Down
7 changes: 6 additions & 1 deletion lib/transaction/unspentoutput.js
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,12 @@ function UnspentOutput(data) {
}
$.checkArgument(!_.isUndefined(data.scriptPubKey) || !_.isUndefined(data.script),
'Must provide the scriptPubKey for that output!');
var script = new Script(data.scriptPubKey || data.script);
var script;
if (data.scriptPubKey) {
script = Script.fromHexString(data.scriptPubKey);
} else {
script = new Script(data.script);
}
$.checkArgument(!_.isUndefined(data.amount) || !_.isUndefined(data.satoshis),
'Must provide an amount for the output');
var amount = !_.isUndefined(data.amount) ? new Unit.fromBTC(data.amount).toSatoshis() : data.satoshis;
Expand Down
6 changes: 3 additions & 3 deletions test/address.js
Original file line number Diff line number Diff line change
Expand Up @@ -378,8 +378,8 @@ describe('Address', function() {
}).should.throw('needs to be p2pkh in, p2pkh out, p2sh in, or p2sh out');
});
it('should make this address from a p2pkh output script', function() {
var s = new Script('OP_DUP OP_HASH160 20 ' +
'0xc8e11b0eb0d2ad5362d894f048908341fa61b6e1 OP_EQUALVERIFY OP_CHECKSIG');
var s = new Script('OP_DUP OP_HASH160 ' +
'c8e11b0eb0d2ad5362d894f048908341fa61b6e1 OP_EQUALVERIFY OP_CHECKSIG');
var buf = s.toBuffer();
var a = Address.fromScript(s, 'livenet');
a.toString().should.equal('1KK9oz4bFH8c1t6LmighHaoSEGx3P3FEmc');
Expand All @@ -388,7 +388,7 @@ describe('Address', function() {
});

it('should make this address from a p2sh input script', function() {
var s = Script.fromString('OP_HASH160 20 0xa6ed4af315271e657ee307828f54a4365fa5d20f OP_EQUAL');
var s = Script.fromString('OP_HASH160 a6ed4af315271e657ee307828f54a4365fa5d20f OP_EQUAL');
var a = Address.fromScript(s, 'livenet');
a.toString().should.equal('3GueMn6ruWVfQTN4XKBGEbCbGLwRSUhfnS');
var b = new Address(s, 'livenet');
Expand Down
2 changes: 1 addition & 1 deletion test/data/tx_creation.json
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
"address": "mszYqVnqKoQx4jcTdJXxwKAissE3Jbrrc1",
"txId": "a477af6b2667c29670467e4e0728b685ee07b240235771862318e29ddbe58458",
"outputIndex": 0,
"script": "OP_DUP OP_HASH160 20 0x88d9931ea73d60eaf7e5671efc0552b912911f2a OP_EQUALVERIFY OP_CHECKSIG",
"script": "OP_DUP OP_HASH160 88d9931ea73d60eaf7e5671efc0552b912911f2a OP_EQUALVERIFY OP_CHECKSIG",
"satoshis": 1020000
}],
"to", ["mrU9pEmAx26HcbKVrABvgL7AwA5fjNFoDc", 1010000],
Expand Down
2 changes: 1 addition & 1 deletion test/script/interpreter.js
Original file line number Diff line number Diff line change
Expand Up @@ -114,7 +114,7 @@ describe('Interpreter', function() {
verified.should.equal(true);
verified = Interpreter().verify(Script('OP_1 OP_2'), Script('OP_2 OP_EQUALVERIFY OP_1 OP_EQUAL'));
verified.should.equal(true);
verified = Interpreter().verify(Script('9 0x000000000000000010'), Script(''));
verified = Interpreter().verify(Script('000000000000000010'), Script(''));
verified.should.equal(true);
verified = Interpreter().verify(Script('OP_1'), Script('OP_15 OP_ADD OP_16 OP_EQUAL'));
verified.should.equal(true);
Expand Down
Loading