UNPKG

@dashevo/dashcore-lib

Version:

A pure and powerful JavaScript Dash library.

215 lines (193 loc) 6.04 kB
/* eslint-disable */ // TODO: Remove previous line and work through linting issues at next edit 'use strict'; var _ = require('lodash'); var inherits = require('inherits'); var Input = require('./input'); var Output = require('../output'); var $ = require('../../util/preconditions'); var Script = require('../../script'); var Signature = require('../../crypto/signature'); var Sighash = require('../sighash'); var PublicKey = require('../../publickey'); var BufferUtil = require('../../util/buffer'); var TransactionSignature = require('../signature'); /** * @constructor */ function MultiSigScriptHashInput(input, pubkeys, threshold, signatures) { Input.apply(this, arguments); var self = this; pubkeys = pubkeys || input.publicKeys; threshold = threshold || input.threshold; signatures = signatures || input.signatures; this.publicKeys = _.sortBy(pubkeys, function (publicKey) { return publicKey.toString('hex'); }); this.redeemScript = Script.buildMultisigOut(this.publicKeys, threshold); $.checkState( Script.buildScriptHashOut(this.redeemScript).equals(this.output.script), "Provided public keys don't hash to the provided output" ); this.publicKeyIndex = {}; _.each(this.publicKeys, function (publicKey, index) { self.publicKeyIndex[publicKey.toString()] = index; }); this.threshold = threshold; // Empty array of signatures this.signatures = signatures ? this._deserializeSignatures(signatures) : new Array(this.publicKeys.length); } inherits(MultiSigScriptHashInput, Input); MultiSigScriptHashInput.prototype.toObject = function () { var obj = Input.prototype.toObject.apply(this, arguments); obj.threshold = this.threshold; obj.publicKeys = _.map(this.publicKeys, function (publicKey) { return publicKey.toString(); }); obj.signatures = this._serializeSignatures(); return obj; }; MultiSigScriptHashInput.prototype._deserializeSignatures = function ( signatures ) { return _.map(signatures, function (signature) { if (!signature) { return undefined; } return new TransactionSignature(signature); }); }; MultiSigScriptHashInput.prototype._serializeSignatures = function () { return _.map(this.signatures, function (signature) { if (!signature) { return undefined; } return signature.toObject(); }); }; MultiSigScriptHashInput.prototype.getSignatures = function ( transaction, privateKey, index, sigtype ) { $.checkState(this.output instanceof Output); sigtype = sigtype || Signature.SIGHASH_ALL; var self = this; var results = []; _.each(this.publicKeys, function (publicKey) { if (publicKey.toString() === privateKey.publicKey.toString()) { results.push( new TransactionSignature({ publicKey: privateKey.publicKey, prevTxId: self.prevTxId, outputIndex: self.outputIndex, inputIndex: index, signature: Sighash.sign( transaction, privateKey, sigtype, index, self.redeemScript ), sigtype: sigtype, }) ); } }); return results; }; MultiSigScriptHashInput.prototype.addSignature = function ( transaction, signature ) { $.checkState( !this.isFullySigned(), 'All needed signatures have already been added' ); $.checkArgument( !_.isUndefined(this.publicKeyIndex[signature.publicKey.toString()]), 'Signature has no matching public key' ); $.checkState(this.isValidSignature(transaction, signature)); this.signatures[this.publicKeyIndex[signature.publicKey.toString()]] = signature; this._updateScript(); return this; }; MultiSigScriptHashInput.prototype._updateScript = function () { this.setScript( Script.buildP2SHMultisigIn( this.publicKeys, this.threshold, this._createSignatures(), { cachedMultisig: this.redeemScript } ) ); return this; }; MultiSigScriptHashInput.prototype._createSignatures = function () { return _.map( _.filter(this.signatures, function (signature) { return !_.isUndefined(signature); }), function (signature) { return BufferUtil.concat([ signature.signature.toDER(), BufferUtil.integerAsSingleByteBuffer(signature.sigtype), ]); } ); }; MultiSigScriptHashInput.prototype.clearSignatures = function () { this.signatures = new Array(this.publicKeys.length); this._updateScript(); }; MultiSigScriptHashInput.prototype.isFullySigned = function () { return this.countSignatures() === this.threshold; }; MultiSigScriptHashInput.prototype.countMissingSignatures = function () { return this.threshold - this.countSignatures(); }; MultiSigScriptHashInput.prototype.countSignatures = function () { return _.reduce( this.signatures, function (sum, signature) { return sum + !!signature; }, 0 ); }; MultiSigScriptHashInput.prototype.publicKeysWithoutSignature = function () { var self = this; return _.filter(this.publicKeys, function (publicKey) { return !self.signatures[self.publicKeyIndex[publicKey.toString()]]; }); }; MultiSigScriptHashInput.prototype.isValidSignature = function ( transaction, signature ) { // FIXME: Refactor signature so this is not necessary signature.signature.nhashtype = signature.sigtype; return Sighash.verify( transaction, signature.signature, signature.publicKey, signature.inputIndex, this.redeemScript ); }; MultiSigScriptHashInput.OPCODES_SIZE = 7; // serialized size (<=3) + 0 .. N .. M OP_CHECKMULTISIG MultiSigScriptHashInput.SIGNATURE_SIZE = 74; // size (1) + DER (<=72) + sighash (1) MultiSigScriptHashInput.PUBKEY_SIZE = 34; // size (1) + DER (<=33) MultiSigScriptHashInput.prototype._estimateSize = function () { return ( MultiSigScriptHashInput.OPCODES_SIZE + this.threshold * MultiSigScriptHashInput.SIGNATURE_SIZE + this.publicKeys.length * MultiSigScriptHashInput.PUBKEY_SIZE ); }; module.exports = MultiSigScriptHashInput;