Browse Source

Merge pull request #1296 from braydonf/script-optimizations

Optimizations for `script.toAddress()`
patch-2
Patrick Nagurny 10 years ago
parent
commit
1a809cbeec
  1. 6
      benchmark/script.js
  2. 3
      lib/address.js
  3. 11
      lib/crypto/hash.js
  4. 55
      lib/script/script.js
  5. 3
      lib/transaction/input/input.js
  6. 3
      lib/transaction/output.js
  7. 4
      test/transaction/transaction.js

6
benchmark/script.js

@ -24,6 +24,12 @@ async.series([
scripts.push(input.script); scripts.push(input.script);
} }
} }
for (var k = 0; k < tx.outputs.length; k++) {
var output = tx.outputs[k];
if (output.script) {
scripts.push(output.script);
}
}
} }
function isPublicKeyHashIn() { function isPublicKeyHashIn() {

3
lib/address.js

@ -7,7 +7,6 @@ var Base58Check = require('./encoding/base58check');
var Networks = require('./networks'); var Networks = require('./networks');
var Hash = require('./crypto/hash'); var Hash = require('./crypto/hash');
var JSUtil = require('./util/js'); var JSUtil = require('./util/js');
var Script = require('./script');
var PublicKey = require('./publickey'); var PublicKey = require('./publickey');
/** /**
@ -505,3 +504,5 @@ Address.prototype.inspect = function() {
}; };
module.exports = Address; module.exports = Address;
var Script = require('./script');

11
lib/crypto/hash.js

@ -28,10 +28,19 @@ Hash.sha256sha256 = function(buf) {
}; };
Hash.ripemd160 = function(buf) { Hash.ripemd160 = function(buf) {
$.checkArgument(BufferUtil.isBuffer(buf));
return crypto.createHash('ripemd160').update(buf).digest();
};
// Node.js crypto ripemd160 hashes are not supported in a browser
// We'll replace with a (slower) version that does.
if (global.window) {
Hash.ripemd160 = function(buf) {
$.checkArgument(BufferUtil.isBuffer(buf)); $.checkArgument(BufferUtil.isBuffer(buf));
var hash = (new hashjs.ripemd160()).update(buf).digest(); var hash = (new hashjs.ripemd160()).update(buf).digest();
return new Buffer(hash); return new Buffer(hash);
}; };
}
Hash.sha256ripemd160 = function(buf) { Hash.sha256ripemd160 = function(buf) {
$.checkArgument(BufferUtil.isBuffer(buf)); $.checkArgument(BufferUtil.isBuffer(buf));

55
lib/script/script.js

@ -1,6 +1,6 @@
'use strict'; 'use strict';
var Address = require('../address');
var BufferReader = require('../encoding/bufferreader'); var BufferReader = require('../encoding/bufferreader');
var BufferWriter = require('../encoding/bufferwriter'); var BufferWriter = require('../encoding/bufferwriter');
var Hash = require('../crypto/hash'); var Hash = require('../crypto/hash');
@ -8,7 +8,6 @@ var Opcode = require('../opcode');
var PublicKey = require('../publickey'); var PublicKey = require('../publickey');
var Signature = require('../crypto/signature'); var Signature = require('../crypto/signature');
var Networks = require('../networks'); var Networks = require('../networks');
var $ = require('../util/preconditions'); var $ = require('../util/preconditions');
var _ = require('lodash'); var _ = require('lodash');
var errors = require('../errors'); var errors = require('../errors');
@ -29,8 +28,6 @@ var Script = function Script(from) {
if (!(this instanceof Script)) { if (!(this instanceof Script)) {
return new Script(from); return new Script(from);
} }
var Address = require('../address');
this.chunks = []; this.chunks = [];
if (BufferUtil.isBuffer(from)) { if (BufferUtil.isBuffer(from)) {
@ -639,7 +636,6 @@ Script.buildP2SHMultisigIn = function(pubkeys, threshold, signatures, opts) {
* @param {(Address|PublicKey)} to - destination address or public key * @param {(Address|PublicKey)} to - destination address or public key
*/ */
Script.buildPublicKeyHashOut = function(to) { Script.buildPublicKeyHashOut = function(to) {
var Address = require('../address');
$.checkArgument(!_.isUndefined(to)); $.checkArgument(!_.isUndefined(to));
$.checkArgument(to instanceof PublicKey || to instanceof Address || _.isString(to)); $.checkArgument(to instanceof PublicKey || to instanceof Address || _.isString(to));
if (to instanceof PublicKey) { if (to instanceof PublicKey) {
@ -692,7 +688,6 @@ Script.buildDataOut = function(data) {
* @returns {Script} new pay to script hash script for given script * @returns {Script} new pay to script hash script for given script
*/ */
Script.buildScriptHashOut = function(script) { Script.buildScriptHashOut = function(script) {
var Address = require('../address');
$.checkArgument(script instanceof Script || $.checkArgument(script instanceof Script ||
(script instanceof Address && script.isPayToScriptHash())); (script instanceof Address && script.isPayToScriptHash()));
var s = new Script(); var s = new Script();
@ -745,7 +740,6 @@ Script.prototype.toScriptHashOut = function() {
* @return {Script} an output script built from the address * @return {Script} an output script built from the address
*/ */
Script.fromAddress = function(address) { Script.fromAddress = function(address) {
var Address = require('../address');
address = Address(address); address = Address(address);
if (address.isPayToScriptHash()) { if (address.isPayToScriptHash()) {
return Script.buildScriptHashOut(address); return Script.buildScriptHashOut(address);
@ -756,12 +750,29 @@ Script.fromAddress = function(address) {
}; };
/** /**
* @param {Network=} network * Will return the associated address information object
* @return {Address|boolean} the associated address information object * @return {Address|boolean}
* for this script if any, or false
*/ */
Script.prototype.getAddressInfo = function() { Script.prototype.getAddressInfo = function(opts) {
var Address = require('../address'); if (this._isInput) {
return this._getInputAddressInfo();
} else if (this._isOutput) {
return this._getOutputAddressInfo();
} else {
var info = this._getOutputAddressInfo();
if (!info) {
return this._getInputAddressInfo();
}
return info;
}
};
/**
* Will return the associated output scriptPubKey address information object
* @return {Address|boolean}
* @private
*/
Script.prototype._getOutputAddressInfo = function() {
var info = {}; var info = {};
if (this.isScriptHashOut()) { if (this.isScriptHashOut()) {
info.hashBuffer = this.getData(); info.hashBuffer = this.getData();
@ -769,7 +780,20 @@ Script.prototype.getAddressInfo = function() {
} else if (this.isPublicKeyHashOut()) { } else if (this.isPublicKeyHashOut()) {
info.hashBuffer = this.getData(); info.hashBuffer = this.getData();
info.type = Address.PayToPublicKeyHash; info.type = Address.PayToPublicKeyHash;
} else if (this.isPublicKeyHashIn()) { } else {
return false;
}
return info;
};
/**
* Will return the associated input scriptSig address information object
* @return {Address|boolean}
* @private
*/
Script.prototype._getInputAddressInfo = function() {
var info = {};
if (this.isPublicKeyHashIn()) {
// hash the publickey found in the scriptSig // hash the publickey found in the scriptSig
info.hashBuffer = Hash.sha256ripemd160(this.chunks[1].buf); info.hashBuffer = Hash.sha256ripemd160(this.chunks[1].buf);
info.type = Address.PayToPublicKeyHash; info.type = Address.PayToPublicKeyHash;
@ -782,18 +806,17 @@ Script.prototype.getAddressInfo = function() {
} }
return info; return info;
}; };
/** /**
* @param {Network=} network * @param {Network=} network
* @return {Address|boolean} the associated address for this script if possible, or false * @return {Address|boolean} the associated address for this script if possible, or false
*/ */
Script.prototype.toAddress = function(network) { Script.prototype.toAddress = function(network) {
var Address = require('../address');
network = Networks.get(network) || this._network || Networks.defaultNetwork;
var info = this.getAddressInfo(); var info = this.getAddressInfo();
if (!info) { if (!info) {
return false; return false;
} }
info.network = Networks.get(network) || Networks.defaultNetwork; info.network = Networks.get(network) || this._network || Networks.defaultNetwork;
return new Address(info); return new Address(info);
}; };

3
lib/transaction/input/input.js

@ -34,6 +34,7 @@ Object.defineProperty(Input.prototype, 'script', {
} }
if (!this._script) { if (!this._script) {
this._script = new Script(this._scriptBuffer); this._script = new Script(this._scriptBuffer);
this._script._isInput = true;
} }
return this._script; return this._script;
} }
@ -116,6 +117,7 @@ Input.prototype.setScript = function(script) {
this._script = null; this._script = null;
if (script instanceof Script) { if (script instanceof Script) {
this._script = script; this._script = script;
this._script._isInput = true;
this._scriptBuffer = script.toBuffer(); this._scriptBuffer = script.toBuffer();
} else if (JSUtil.isHexa(script)) { } else if (JSUtil.isHexa(script)) {
// hex string script // hex string script
@ -123,6 +125,7 @@ Input.prototype.setScript = function(script) {
} else if (_.isString(script)) { } else if (_.isString(script)) {
// human readable string script // human readable string script
this._script = new Script(script); this._script = new Script(script);
this._script._isInput = true;
this._scriptBuffer = this._script.toBuffer(); this._scriptBuffer = this._script.toBuffer();
} else if (BufferUtil.isBuffer(script)) { } else if (BufferUtil.isBuffer(script)) {
// buffer script // buffer script

3
lib/transaction/output.js

@ -113,6 +113,7 @@ Output.prototype.setScriptFromBuffer = function(buffer) {
this._scriptBuffer = buffer; this._scriptBuffer = buffer;
try { try {
this._script = Script.fromBuffer(this._scriptBuffer); this._script = Script.fromBuffer(this._scriptBuffer);
this._script._isOutput = true;
} catch(e) { } catch(e) {
if (e instanceof errors.Script.InvalidBuffer) { if (e instanceof errors.Script.InvalidBuffer) {
this._script = null; this._script = null;
@ -126,9 +127,11 @@ Output.prototype.setScript = function(script) {
if (script instanceof Script) { if (script instanceof Script) {
this._scriptBuffer = script.toBuffer(); this._scriptBuffer = script.toBuffer();
this._script = script; this._script = script;
this._script._isOutput = true;
} else if (_.isString(script)) { } else if (_.isString(script)) {
this._script = Script.fromString(script); this._script = Script.fromString(script);
this._scriptBuffer = this._script.toBuffer(); this._scriptBuffer = this._script.toBuffer();
this._script._isOutput = true;
} else if (bufferUtil.isBuffer(script)) { } else if (bufferUtil.isBuffer(script)) {
this.setScriptFromBuffer(script); this.setScriptFromBuffer(script);
} else { } else {

4
test/transaction/transaction.js

@ -202,7 +202,9 @@ describe('Transaction', function() {
transaction.outputs[1].satoshis.should.equal(40000); transaction.outputs[1].satoshis.should.equal(40000);
transaction.outputs[1].script.toString() transaction.outputs[1].script.toString()
.should.equal(Script.fromAddress(changeAddress).toString()); .should.equal(Script.fromAddress(changeAddress).toString());
transaction.getChangeOutput().script.should.deep.equal(Script.fromAddress(changeAddress)); var actual = transaction.getChangeOutput().script.toString();
var expected = Script.fromAddress(changeAddress).toString();
actual.should.equal(expected);
}); });
it('accepts a P2SH address for change', function() { it('accepts a P2SH address for change', function() {
var transaction = new Transaction() var transaction = new Transaction()

Loading…
Cancel
Save