diff --git a/lib/errors/spec.js b/lib/errors/spec.js index 0f8545f..c011378 100644 --- a/lib/errors/spec.js +++ b/lib/errors/spec.js @@ -27,7 +27,10 @@ module.exports = [{ message: format('Invalid network: must be "livenet" or "testnet", got {0}') }, { name: 'InvalidArgument', - message: format('Invalid Argument {0}, {1}'), + message: format('Invalid Argument {0}, {1}') + }, { + name: 'AbstractMethodInvoked', + message: format('Abstract Method Invokation: {0}') }, { name: 'InvalidArgumentType', message: format('Invalid Argument for {2}, expected {1} but got ') + '+ typeof arguments[0]', diff --git a/lib/transaction/input/index.js b/lib/transaction/input/index.js index 2d25901..ee83cb8 100644 --- a/lib/transaction/input/index.js +++ b/lib/transaction/input/index.js @@ -2,4 +2,7 @@ var Input = require('./input'); +Input.PublicKeyHash = require('./publicKeyHash'); +Input.ScriptHash = require('./scriptHash'); + module.exports = Input; diff --git a/lib/transaction/input/input.js b/lib/transaction/input/input.js index fd85364..ad24ca4 100644 --- a/lib/transaction/input/input.js +++ b/lib/transaction/input/input.js @@ -1,6 +1,7 @@ 'use strict'; var _ = require('lodash'); +var errors = require('../../errors'); var BufferWriter = require('../../encoding/bufferwriter'); var buffer = require('buffer'); var bufferUtil = require('../../util/buffer'); @@ -31,6 +32,7 @@ Input.prototype._fromObject = function(params) { if (_.isString(params.prevTxId) && JSUtil.isHexa(params.prevTxId)) { params.prevTxId = new buffer.Buffer(params.prevTxId, 'hex'); } + this.output = params.output; this.prevTxId = params.prevTxId; this.outputIndex = params.outputIndex; this.sequenceNumber = params.sequenceNumber; @@ -106,4 +108,19 @@ Input.prototype.setScript = function(script) { return this; }; +/** + * Retrieve signatures for the provided PrivateKey. + * + * @param {Transaction} transaction - the transaction to be signed + * @param {PrivateKey} privateKey - the private key to use when signing + * @param {number} inputIndex - the index of this input in the provided transaction + * @param {number} sigType - defaults to Signature.SIGHASH_ALL + * @param {Buffer} addressHash - if provided, don't calculate the hash of the + * public key associated with the private key provided + * @abstract + */ +Input.prototype.getSignatures = function() { + throw new errors.AbstractMethodInvoked('Input#getSignatures'); +}; + module.exports = Input; diff --git a/lib/transaction/input/publicKeyHash.js b/lib/transaction/input/publicKeyHash.js new file mode 100644 index 0000000..9e50418 --- /dev/null +++ b/lib/transaction/input/publicKeyHash.js @@ -0,0 +1,31 @@ +'use strict'; + +var inherits = require('inherits'); +var Input = require('./input'); +var Hash = require('../../crypto/hash'); +var Signature = require('../../crypto/signature'); +var Sighash = require('../sighash'); +var BufferUtil = require('../../util/buffer'); + +function PublicKeyHashInput() { +} +inherits(PublicKeyHashInput, Input); + +PublicKeyHashInput.prototype.getSignatures = function(transaction, privateKey, index, sigtype, hashData) { + hashData = hashData || Hash.sha256ripemd160(privateKey.publicKey.toBuffer()); + sigtype = sigtype || Signature.SIGHASH_ALL; + if (BufferUtil.equals(hashData, this.output.script.address.hashData)) { + return [{ + address: this.output.script.address, + publicKey: privateKey.publicKey, + prevTxId: this.txId, + outputIndex: this.outputIndex, + inputIndex: index, + signature: Sighash.sign(transaction, privateKey, sigtype, index, this.output.script), + sigtype: sigtype + }]; + } + return []; +}; + +module.exports = PublicKeyHashInput; diff --git a/lib/transaction/input/scriptHash.js b/lib/transaction/input/scriptHash.js new file mode 100644 index 0000000..c7912b5 --- /dev/null +++ b/lib/transaction/input/scriptHash.js @@ -0,0 +1,31 @@ +'use strict'; + +var inherits = require('inherits'); +var Input = require('./input'); +var Hash = require('../../crypto/hash'); +var Signature = require('../../crypto/signature'); +var Sighash = require('../sighash'); +var BufferUtil = require('../../util/buffer'); + +function ScriptHashInput() { +} +inherits(ScriptHashInput, Input); + +ScriptHashInput.prototype.getSignatures = function(transaction, privateKey, index, sigtype, hashData) { + hashData = hashData || Hash.sha256ripemd160(privateKey.publicKey.toBuffer()); + sigtype = sigtype || Signature.SIGHASH_ALL; + if (BufferUtil.equals(hashData, this.output.script.address.hashData)) { + return [{ + address: this.output.script.address, + publicKey: privateKey.publicKey, + prevTxId: this.txId, + outputIndex: this.outputIndex, + inputIndex: index, + signature: Sighash.sign(transaction, privateKey, sigtype, index, this.output.script), + sigtype: sigtype + }]; + } + return []; +}; + +module.exports = ScriptHashInput; diff --git a/lib/transaction/transaction.js b/lib/transaction/transaction.js index e7ac7d4..36ed537 100644 --- a/lib/transaction/transaction.js +++ b/lib/transaction/transaction.js @@ -33,10 +33,8 @@ function Transaction(serialized) { this.inputs = []; this.outputs = []; this._outpoints = []; - this._utxos = {}; this._inputAmount = 0; this._outputAmount = 0; - this._p2shMap = {}; this._signatures = {}; if (serialized) { @@ -228,12 +226,13 @@ Transaction._isNewUtxo = function(utxo) { }; Transaction.prototype._fromNewUtxo = function(utxo) { - var outpoint = Transaction._makeOutpoint(utxo); utxo.address = utxo.address && new Address(utxo.address); utxo.script = new Script(util.isHexa(utxo.script) ? new buffer.Buffer(utxo.script, 'hex') : utxo.script); - this._utxos[outpoint] = utxo; - this._outpoints.push(outpoint); this.inputs.push(new Input({ + output: new Output({ + script: utxo.script, + satoshis: utxo.satoshis + }), prevTxId: utxo.txId, outputIndex: utxo.outputIndex, sequenceNumber: DEFAULT_SEQNUMBER, @@ -254,9 +253,8 @@ Transaction._makeOutpoint = function(data) { }; Transaction.prototype.hasAllUtxoInfo = function() { - var self = this; - return _.all(this._outpoints.map(function(outpoint) { - return !!self._utxos[outpoint]; + return _.all(this.inputs.map(function(input) { + return !!input.output; })); }; @@ -328,42 +326,22 @@ Transaction.prototype.sign = function(privKey) { return this; }; -Transaction.prototype._getPrivateKeySignatures = function(privKey) { +Transaction.prototype._getPrivateKeySignatures = function(privKey, sigtype) { privKey = new PrivateKey(privKey); + sigtype = sigtype || Signature.SIGHASH_ALL; var transaction = this; var results = []; var hashData = Hash.sha256ripemd160(privKey.publicKey.toBuffer()); - _.each(this._outpoints, function forEachOutput(outpoint, index) { - var utxo = transaction._utxos[outpoint]; - if ((utxo.address && utxo.address.isPayToPublicKeyHash()) || utxo.script.isPublicKeyHashOut()) { - var address = new Address(utxo.address || utxo.script); - if (bufferUtil.equals(hashData, address.hashBuffer)) { - results.push({ - publicKey: privKey.publicKey, - prevTxId: utxo.txId, - outputIndex: utxo.outputIndex, - inputIndex: index, - signature: Sighash.sign(transaction, privKey, Signature.SIGHASH_ALL, index, utxo.script), - sigtype: Signature.SIGHASH_ALL - }); - } else { - ; - } - } else { - ; - } + _.each(this.inputs, function forEachInput(input, index) { + _.each(input.getSignatures(transaction, privKey, index, sigtype, hashData), function(signature) { + results.push(signature); + }); }); return results; }; Transaction.prototype.applySignature = function(signature) { - this.inputs[signature.inputIndex].setScript( - Script.buildPublicKeyHashIn( - signature.publicKey, - signature.signature.toDER(), - signature.sigtype - ) - ); + this.inputs[signature.inputIndex].addSignature(signature); return this; };