Add `PublicKeyHashInput` and `ScriptHashInput`.

Remove `_outpoints`, `_utxos` from Transaction, as that info
can be efficiently retrieved from the inputs
This commit is contained in:
Esteban Ordano 2014-12-11 11:44:42 -03:00
parent 264a239e5a
commit af43228daf
6 changed files with 99 additions and 36 deletions

View File

@ -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]',

View File

@ -2,4 +2,7 @@
var Input = require('./input');
Input.PublicKeyHash = require('./publicKeyHash');
Input.ScriptHash = require('./scriptHash');
module.exports = Input;

View File

@ -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;

View File

@ -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;

View File

@ -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;

View File

@ -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;
};