restore legacy txproposal model
This commit is contained in:
parent
61ffe309f8
commit
827bb03d0c
|
@ -13,6 +13,7 @@ var Common = require('../common');
|
||||||
var Constants = Common.Constants;
|
var Constants = Common.Constants;
|
||||||
var Defaults = Common.Defaults;
|
var Defaults = Common.Defaults;
|
||||||
|
|
||||||
|
var TxProposalLegacy = require('./txproposal_legacy');
|
||||||
var TxProposalAction = require('./txproposalaction');
|
var TxProposalAction = require('./txproposalaction');
|
||||||
|
|
||||||
function TxProposal() {};
|
function TxProposal() {};
|
||||||
|
@ -67,7 +68,7 @@ TxProposal.create = function(opts) {
|
||||||
|
|
||||||
TxProposal.fromObj = function(obj) {
|
TxProposal.fromObj = function(obj) {
|
||||||
if (!(obj.version >= 3)) {
|
if (!(obj.version >= 3)) {
|
||||||
throw new Error('TxProposal < v3 no longer supported.')
|
return TxProposalLegacy.fromObj(obj);
|
||||||
}
|
}
|
||||||
|
|
||||||
var x = new TxProposal();
|
var x = new TxProposal();
|
||||||
|
|
|
@ -0,0 +1,176 @@
|
||||||
|
'use strict';
|
||||||
|
|
||||||
|
var _ = require('lodash');
|
||||||
|
var $ = require('preconditions').singleton();
|
||||||
|
var log = require('npmlog');
|
||||||
|
log.debug = log.verbose;
|
||||||
|
log.disableColor();
|
||||||
|
|
||||||
|
var Bitcore = require('bitcore-lib');
|
||||||
|
|
||||||
|
var Common = require('../common');
|
||||||
|
var Constants = Common.Constants;
|
||||||
|
var Defaults = Common.Defaults;
|
||||||
|
|
||||||
|
var TxProposalAction = require('./txproposalaction');
|
||||||
|
|
||||||
|
function TxProposal() {};
|
||||||
|
|
||||||
|
TxProposal.Types = {
|
||||||
|
SIMPLE: 'simple',
|
||||||
|
MULTIPLEOUTPUTS: 'multiple_outputs',
|
||||||
|
EXTERNAL: 'external'
|
||||||
|
};
|
||||||
|
|
||||||
|
TxProposal.fromObj = function(obj) {
|
||||||
|
var x = new TxProposal();
|
||||||
|
|
||||||
|
x.version = obj.version;
|
||||||
|
if (obj.version === '1.0.0') {
|
||||||
|
x.type = TxProposal.Types.SIMPLE;
|
||||||
|
} else {
|
||||||
|
x.type = obj.type;
|
||||||
|
}
|
||||||
|
x.createdOn = obj.createdOn;
|
||||||
|
x.id = obj.id;
|
||||||
|
x.walletId = obj.walletId;
|
||||||
|
x.creatorId = obj.creatorId;
|
||||||
|
x.outputs = obj.outputs;
|
||||||
|
x.toAddress = obj.toAddress;
|
||||||
|
x.amount = obj.amount;
|
||||||
|
x.message = obj.message;
|
||||||
|
x.payProUrl = obj.payProUrl;
|
||||||
|
x.proposalSignature = obj.proposalSignature;
|
||||||
|
x.changeAddress = obj.changeAddress;
|
||||||
|
x.inputs = obj.inputs;
|
||||||
|
x.requiredSignatures = obj.requiredSignatures;
|
||||||
|
x.requiredRejections = obj.requiredRejections;
|
||||||
|
x.walletN = obj.walletN;
|
||||||
|
x.status = obj.status;
|
||||||
|
x.txid = obj.txid;
|
||||||
|
x.broadcastedOn = obj.broadcastedOn;
|
||||||
|
x.inputPaths = obj.inputPaths;
|
||||||
|
x.actions = _.map(obj.actions, function(action) {
|
||||||
|
return TxProposalAction.fromObj(action);
|
||||||
|
});
|
||||||
|
x.outputOrder = obj.outputOrder;
|
||||||
|
x.network = obj.network;
|
||||||
|
x.fee = obj.fee;
|
||||||
|
x.feePerKb = obj.feePerKb;
|
||||||
|
x.excludeUnconfirmedUtxos = obj.excludeUnconfirmedUtxos;
|
||||||
|
x.proposalSignaturePubKey = obj.proposalSignaturePubKey;
|
||||||
|
x.proposalSignaturePubKeySig = obj.proposalSignaturePubKeySig;
|
||||||
|
x.addressType = obj.addressType || Constants.SCRIPT_TYPES.P2SH;
|
||||||
|
x.derivationStrategy = obj.derivationStrategy || Constants.DERIVATION_STRATEGIES.BIP45;
|
||||||
|
x.customData = obj.customData;
|
||||||
|
|
||||||
|
return x;
|
||||||
|
};
|
||||||
|
|
||||||
|
function throwUnsupportedError() {
|
||||||
|
var msg = 'Unsupported operation on this transaction proposal';
|
||||||
|
log.warn('DEPRECATED: ' + msg);
|
||||||
|
throw new Error(msg);
|
||||||
|
};
|
||||||
|
|
||||||
|
TxProposal.prototype.toObject = function() {
|
||||||
|
var x = _.cloneDeep(this);
|
||||||
|
x.isPending = this.isPending();
|
||||||
|
return x;
|
||||||
|
};
|
||||||
|
|
||||||
|
TxProposal.prototype._updateStatus = function() {
|
||||||
|
if (this.status != 'pending') return;
|
||||||
|
|
||||||
|
if (this.isRejected()) {
|
||||||
|
this.status = 'rejected';
|
||||||
|
} else if (this.isAccepted()) {
|
||||||
|
this.status = 'accepted';
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
TxProposal.prototype.getBitcoreTx = function() {
|
||||||
|
throwUnsupportedError();
|
||||||
|
};
|
||||||
|
|
||||||
|
TxProposal.prototype.getNetworkName = function() {
|
||||||
|
return Bitcore.Address(this.changeAddress.address).toObject().network;
|
||||||
|
};
|
||||||
|
|
||||||
|
TxProposal.prototype.getRawTx = function() {
|
||||||
|
throwUnsupportedError();
|
||||||
|
};
|
||||||
|
|
||||||
|
TxProposal.prototype.getTotalAmount = function() {
|
||||||
|
if (this.type == TxProposal.Types.MULTIPLEOUTPUTS || this.type == TxProposal.Types.EXTERNAL) {
|
||||||
|
return _.pluck(this.outputs, 'amount')
|
||||||
|
.reduce(function(total, n) {
|
||||||
|
return total + n;
|
||||||
|
}, 0);
|
||||||
|
} else {
|
||||||
|
return this.amount;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
TxProposal.prototype.getActors = function() {
|
||||||
|
return _.pluck(this.actions, 'copayerId');
|
||||||
|
};
|
||||||
|
|
||||||
|
TxProposal.prototype.getApprovers = function() {
|
||||||
|
return _.pluck(
|
||||||
|
_.filter(this.actions, {
|
||||||
|
type: 'accept'
|
||||||
|
}), 'copayerId');
|
||||||
|
};
|
||||||
|
|
||||||
|
TxProposal.prototype.getActionBy = function(copayerId) {
|
||||||
|
return _.find(this.actions, {
|
||||||
|
copayerId: copayerId
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
TxProposal.prototype.addAction = function(copayerId, type, comment, signatures, xpub) {
|
||||||
|
var action = TxProposalAction.create({
|
||||||
|
copayerId: copayerId,
|
||||||
|
type: type,
|
||||||
|
signatures: signatures,
|
||||||
|
xpub: xpub,
|
||||||
|
comment: comment,
|
||||||
|
});
|
||||||
|
this.actions.push(action);
|
||||||
|
this._updateStatus();
|
||||||
|
};
|
||||||
|
|
||||||
|
TxProposal.prototype.sign = function() {
|
||||||
|
throwUnsupportedError();
|
||||||
|
};
|
||||||
|
|
||||||
|
TxProposal.prototype.reject = function(copayerId, reason) {
|
||||||
|
this.addAction(copayerId, 'reject', reason);
|
||||||
|
};
|
||||||
|
|
||||||
|
TxProposal.prototype.isPending = function() {
|
||||||
|
return !_.contains(['broadcasted', 'rejected'], this.status);
|
||||||
|
};
|
||||||
|
|
||||||
|
TxProposal.prototype.isAccepted = function() {
|
||||||
|
var votes = _.countBy(this.actions, 'type');
|
||||||
|
return votes['accept'] >= this.requiredSignatures;
|
||||||
|
};
|
||||||
|
|
||||||
|
TxProposal.prototype.isRejected = function() {
|
||||||
|
var votes = _.countBy(this.actions, 'type');
|
||||||
|
return votes['reject'] >= this.requiredRejections;
|
||||||
|
};
|
||||||
|
|
||||||
|
TxProposal.prototype.isBroadcasted = function() {
|
||||||
|
return this.status == 'broadcasted';
|
||||||
|
};
|
||||||
|
|
||||||
|
TxProposal.prototype.setBroadcasted = function() {
|
||||||
|
$.checkState(this.txid);
|
||||||
|
this.status = 'broadcasted';
|
||||||
|
this.broadcastedOn = Math.floor(Date.now() / 1000);
|
||||||
|
};
|
||||||
|
|
||||||
|
module.exports = TxProposal;
|
|
@ -1330,12 +1330,10 @@ WalletService.prototype._checkTx = function(txp) {
|
||||||
var bitcoreError;
|
var bitcoreError;
|
||||||
|
|
||||||
var serializationOpts = {
|
var serializationOpts = {
|
||||||
disableIsFullySigned: true
|
disableIsFullySigned: true,
|
||||||
|
disableSmallFees: true,
|
||||||
|
disableLargeFees: true,
|
||||||
};
|
};
|
||||||
if (!_.startsWith(txp.version, '1.')) {
|
|
||||||
serializationOpts.disableSmallFees = true;
|
|
||||||
serializationOpts.disableLargeFees = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (txp.getEstimatedSize() / 1000 > Defaults.MAX_TX_SIZE_IN_KB)
|
if (txp.getEstimatedSize() / 1000 > Defaults.MAX_TX_SIZE_IN_KB)
|
||||||
return Errors.TX_MAX_SIZE_EXCEEDED;
|
return Errors.TX_MAX_SIZE_EXCEEDED;
|
||||||
|
@ -1886,7 +1884,12 @@ WalletService.prototype.publishTx = function(opts, cb) {
|
||||||
|
|
||||||
var copayer = wallet.getCopayer(self.copayerId);
|
var copayer = wallet.getCopayer(self.copayerId);
|
||||||
|
|
||||||
var raw = txp.getRawTx();
|
var raw;
|
||||||
|
try {
|
||||||
|
raw = txp.getRawTx();
|
||||||
|
} catch (ex) {
|
||||||
|
return cb(ex);
|
||||||
|
}
|
||||||
var signingKey = self._getSigningKey(raw, opts.proposalSignature, copayer.requestPubKeys);
|
var signingKey = self._getSigningKey(raw, opts.proposalSignature, copayer.requestPubKeys);
|
||||||
if (!signingKey) {
|
if (!signingKey) {
|
||||||
return cb(new ClientError('Invalid proposal signature'));
|
return cb(new ClientError('Invalid proposal signature'));
|
||||||
|
@ -2135,6 +2138,7 @@ WalletService.prototype.signTx = function(opts, cb) {
|
||||||
|
|
||||||
var copayer = wallet.getCopayer(self.copayerId);
|
var copayer = wallet.getCopayer(self.copayerId);
|
||||||
|
|
||||||
|
try {
|
||||||
if (!txp.sign(self.copayerId, opts.signatures, copayer.xPubKey)) {
|
if (!txp.sign(self.copayerId, opts.signatures, copayer.xPubKey)) {
|
||||||
log.warn('Error signing transaction (BAD_SIGNATURES)');
|
log.warn('Error signing transaction (BAD_SIGNATURES)');
|
||||||
log.warn('Wallet id:', self.walletId);
|
log.warn('Wallet id:', self.walletId);
|
||||||
|
@ -2146,6 +2150,10 @@ WalletService.prototype.signTx = function(opts, cb) {
|
||||||
log.warn('Raw tx:', raw);
|
log.warn('Raw tx:', raw);
|
||||||
return cb(Errors.BAD_SIGNATURES);
|
return cb(Errors.BAD_SIGNATURES);
|
||||||
}
|
}
|
||||||
|
} catch (ex) {
|
||||||
|
log.error('Error signing transaction proposal', ex);
|
||||||
|
return cb(ex);
|
||||||
|
}
|
||||||
|
|
||||||
self.storage.storeTx(self.walletId, txp, function(err) {
|
self.storage.storeTx(self.walletId, txp, function(err) {
|
||||||
if (err) return cb(err);
|
if (err) return cb(err);
|
||||||
|
|
Loading…
Reference in New Issue