Merge pull request #142 from isocolsky/ref/shuffle_outputs
Ref/shuffle outputs
This commit is contained in:
commit
3f2575fa2a
|
@ -1,6 +1,6 @@
|
||||||
'use strict';
|
'use strict';
|
||||||
|
|
||||||
var Bitcore = require('bitcore');
|
var Bitcore = require('bitcore-wallet-utils').Bitcore;
|
||||||
|
|
||||||
function Address() {
|
function Address() {
|
||||||
this.version = '1.0.0';
|
this.version = '1.0.0';
|
||||||
|
|
|
@ -4,12 +4,11 @@ var $ = require('preconditions').singleton();
|
||||||
var _ = require('lodash');
|
var _ = require('lodash');
|
||||||
var util = require('util');
|
var util = require('util');
|
||||||
|
|
||||||
var Bitcore = require('bitcore');
|
|
||||||
var HDPublicKey = Bitcore.HDPublicKey;
|
|
||||||
var Uuid = require('uuid');
|
var Uuid = require('uuid');
|
||||||
var AddressManager = require('./addressmanager');
|
var AddressManager = require('./addressmanager');
|
||||||
var WalletUtils = require('bitcore-wallet-utils');
|
var WalletUtils = require('bitcore-wallet-utils');
|
||||||
|
var Bitcore = WalletUtils.Bitcore;
|
||||||
|
var HDPublicKey = Bitcore.HDPublicKey;
|
||||||
|
|
||||||
function Copayer() {
|
function Copayer() {
|
||||||
this.version = '1.0.0';
|
this.version = '1.0.0';
|
||||||
|
|
|
@ -2,7 +2,8 @@
|
||||||
|
|
||||||
var _ = require('lodash');
|
var _ = require('lodash');
|
||||||
var Uuid = require('uuid');
|
var Uuid = require('uuid');
|
||||||
var Bitcore = require('bitcore');
|
var WalletUtils = require('bitcore-wallet-utils');
|
||||||
|
var Bitcore = WalletUtils.Bitcore;
|
||||||
var Address = Bitcore.Address;
|
var Address = Bitcore.Address;
|
||||||
|
|
||||||
var TxProposalAction = require('./txproposalaction');
|
var TxProposalAction = require('./txproposalaction');
|
||||||
|
@ -31,6 +32,7 @@ TxProposal.create = function(opts) {
|
||||||
x.requiredRejections = opts.requiredRejections;
|
x.requiredRejections = opts.requiredRejections;
|
||||||
x.status = 'pending';
|
x.status = 'pending';
|
||||||
x.actions = [];
|
x.actions = [];
|
||||||
|
x.outputOrder = _.shuffle(_.range(2));
|
||||||
|
|
||||||
return x;
|
return x;
|
||||||
};
|
};
|
||||||
|
@ -57,6 +59,7 @@ TxProposal.fromObj = function(obj) {
|
||||||
x.actions = _.map(obj.actions, function(action) {
|
x.actions = _.map(obj.actions, function(action) {
|
||||||
return TxProposalAction.fromObj(action);
|
return TxProposalAction.fromObj(action);
|
||||||
});
|
});
|
||||||
|
x.outputOrder = obj.outputOrder;
|
||||||
|
|
||||||
return x;
|
return x;
|
||||||
};
|
};
|
||||||
|
@ -89,16 +92,7 @@ TxProposal.prototype._getCurrentSignatures = function() {
|
||||||
TxProposal.prototype.getBitcoreTx = function() {
|
TxProposal.prototype.getBitcoreTx = function() {
|
||||||
var self = this;
|
var self = this;
|
||||||
|
|
||||||
var t = new Bitcore.Transaction();
|
var t = WalletUtils.buildTx(this);
|
||||||
|
|
||||||
_.each(this.inputs, function(i) {
|
|
||||||
t.from(i, i.publicKeys, self.requiredSignatures)
|
|
||||||
});
|
|
||||||
|
|
||||||
t.to(this.toAddress, this.amount)
|
|
||||||
.change(this.changeAddress.address);
|
|
||||||
|
|
||||||
t._updateChangeOutput();
|
|
||||||
|
|
||||||
var sigs = this._getCurrentSignatures();
|
var sigs = this._getCurrentSignatures();
|
||||||
_.each(sigs, function(x) {
|
_.each(sigs, function(x) {
|
||||||
|
|
|
@ -8,7 +8,8 @@ var inherits = require('inherits');
|
||||||
var events = require('events');
|
var events = require('events');
|
||||||
var nodeutil = require('util');
|
var nodeutil = require('util');
|
||||||
|
|
||||||
var Bitcore = require('bitcore');
|
var WalletUtils = require('bitcore-wallet-utils');
|
||||||
|
var Bitcore = WalletUtils.Bitcore;
|
||||||
var PublicKey = Bitcore.PublicKey;
|
var PublicKey = Bitcore.PublicKey;
|
||||||
var HDPublicKey = Bitcore.HDPublicKey;
|
var HDPublicKey = Bitcore.HDPublicKey;
|
||||||
var Address = Bitcore.Address;
|
var Address = Bitcore.Address;
|
||||||
|
@ -17,7 +18,6 @@ var Explorers = require('bitcore-explorers');
|
||||||
var ClientError = require('./clienterror');
|
var ClientError = require('./clienterror');
|
||||||
var Utils = require('./utils');
|
var Utils = require('./utils');
|
||||||
var Storage = require('./storage');
|
var Storage = require('./storage');
|
||||||
var WalletUtils = require('bitcore-wallet-utils');
|
|
||||||
|
|
||||||
var Wallet = require('./model/wallet');
|
var Wallet = require('./model/wallet');
|
||||||
var Copayer = require('./model/copayer');
|
var Copayer = require('./model/copayer');
|
||||||
|
|
|
@ -2,7 +2,7 @@
|
||||||
"name": "bitcore-wallet-service",
|
"name": "bitcore-wallet-service",
|
||||||
"description": "A service for Mutisig HD Bitcoin Wallets",
|
"description": "A service for Mutisig HD Bitcoin Wallets",
|
||||||
"author": "BitPay Inc",
|
"author": "BitPay Inc",
|
||||||
"version": "0.0.5",
|
"version": "0.0.6",
|
||||||
"keywords": [
|
"keywords": [
|
||||||
"bitcoin",
|
"bitcoin",
|
||||||
"copay",
|
"copay",
|
||||||
|
@ -19,8 +19,7 @@
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"async": "^0.9.0",
|
"async": "^0.9.0",
|
||||||
"bitcore": "^0.11.2",
|
"bitcore-wallet-utils": "^0.0.4",
|
||||||
"bitcore-wallet-utils": "0.0.3",
|
|
||||||
"bitcore-explorers": "^0.9.1",
|
"bitcore-explorers": "^0.9.1",
|
||||||
"body-parser": "^1.11.0",
|
"body-parser": "^1.11.0",
|
||||||
"coveralls": "^2.11.2",
|
"coveralls": "^2.11.2",
|
||||||
|
|
|
@ -11,10 +11,10 @@ var levelup = require('levelup');
|
||||||
var memdown = require('memdown');
|
var memdown = require('memdown');
|
||||||
var log = require('npmlog');
|
var log = require('npmlog');
|
||||||
log.debug = log.verbose;
|
log.debug = log.verbose;
|
||||||
var Bitcore = require('bitcore');
|
|
||||||
|
|
||||||
var Utils = require('../../lib/utils');
|
var Utils = require('../../lib/utils');
|
||||||
var WalletUtils = require('bitcore-wallet-utils');
|
var WalletUtils = require('bitcore-wallet-utils');
|
||||||
|
var Bitcore = WalletUtils.Bitcore;
|
||||||
var Storage = require('../../lib/storage');
|
var Storage = require('../../lib/storage');
|
||||||
|
|
||||||
var Wallet = require('../../lib/model/wallet');
|
var Wallet = require('../../lib/model/wallet');
|
||||||
|
@ -168,38 +168,7 @@ helpers.stubHistory = function(txs) {
|
||||||
blockExplorer.getTransactions = sinon.stub().callsArgWith(1, null, txs);
|
blockExplorer.getTransactions = sinon.stub().callsArgWith(1, null, txs);
|
||||||
};
|
};
|
||||||
|
|
||||||
helpers.clientSign = function(txp, xprivHex) {
|
helpers.clientSign = WalletUtils.signTxp;
|
||||||
//Derive proper key to sign, for each input
|
|
||||||
var privs = [],
|
|
||||||
derived = {};
|
|
||||||
var xpriv = new Bitcore.HDPrivateKey(xprivHex);
|
|
||||||
|
|
||||||
_.each(txp.inputs, function(i) {
|
|
||||||
if (!derived[i.path]) {
|
|
||||||
derived[i.path] = xpriv.derive(i.path).privateKey;
|
|
||||||
privs.push(derived[i.path]);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
var t = new Bitcore.Transaction();
|
|
||||||
|
|
||||||
_.each(txp.inputs, function(i) {
|
|
||||||
t.from(i, i.publicKeys, txp.requiredSignatures);
|
|
||||||
});
|
|
||||||
|
|
||||||
t.to(txp.toAddress, txp.amount)
|
|
||||||
.change(txp.changeAddress.address);
|
|
||||||
|
|
||||||
var signatures = _.map(privs, function(priv, i) {
|
|
||||||
return t.getSignatures(priv);
|
|
||||||
});
|
|
||||||
|
|
||||||
signatures = _.map(_.sortBy(_.flatten(signatures), 'inputIndex'), function(s) {
|
|
||||||
return s.signature.toDER().toString('hex');
|
|
||||||
});
|
|
||||||
|
|
||||||
return signatures;
|
|
||||||
};
|
|
||||||
|
|
||||||
helpers.createProposalOpts = function(toAddress, amount, message, signingKey) {
|
helpers.createProposalOpts = function(toAddress, amount, message, signingKey) {
|
||||||
var opts = {
|
var opts = {
|
||||||
|
@ -1236,7 +1205,7 @@ describe('Copay server', function() {
|
||||||
var tx = txs[0];
|
var tx = txs[0];
|
||||||
tx.id.should.equal(txid);
|
tx.id.should.equal(txid);
|
||||||
|
|
||||||
var signatures = helpers.clientSign(tx, TestData.copayers[0].xPrivKey_45H);
|
var signatures = helpers.clientSign(tx, TestData.copayers[0].xPrivKey);
|
||||||
server.signTx({
|
server.signTx({
|
||||||
txProposalId: txid,
|
txProposalId: txid,
|
||||||
signatures: signatures,
|
signatures: signatures,
|
||||||
|
@ -1263,7 +1232,7 @@ describe('Copay server', function() {
|
||||||
server.getPendingTxs({}, function(err, txs) {
|
server.getPendingTxs({}, function(err, txs) {
|
||||||
var tx = txs[0];
|
var tx = txs[0];
|
||||||
tx.id.should.equal(txid);
|
tx.id.should.equal(txid);
|
||||||
var signatures = helpers.clientSign(tx, TestData.copayers[1].xPrivKey_45H);
|
var signatures = helpers.clientSign(tx, TestData.copayers[1].xPrivKey);
|
||||||
server.signTx({
|
server.signTx({
|
||||||
txProposalId: txid,
|
txProposalId: txid,
|
||||||
signatures: signatures,
|
signatures: signatures,
|
||||||
|
@ -1279,7 +1248,7 @@ describe('Copay server', function() {
|
||||||
var tx = txs[0];
|
var tx = txs[0];
|
||||||
tx.id.should.equal(txid);
|
tx.id.should.equal(txid);
|
||||||
|
|
||||||
var signatures = helpers.clientSign(tx, TestData.copayers[0].xPrivKey_45H);
|
var signatures = helpers.clientSign(tx, TestData.copayers[0].xPrivKey);
|
||||||
signatures[0] = 1;
|
signatures[0] = 1;
|
||||||
|
|
||||||
server.signTx({
|
server.signTx({
|
||||||
|
@ -1314,7 +1283,7 @@ describe('Copay server', function() {
|
||||||
var tx = txs[0];
|
var tx = txs[0];
|
||||||
tx.id.should.equal(txid);
|
tx.id.should.equal(txid);
|
||||||
|
|
||||||
var signatures = _.take(helpers.clientSign(tx, TestData.copayers[0].xPrivKey_45H), 2);
|
var signatures = _.take(helpers.clientSign(tx, TestData.copayers[0].xPrivKey), 2);
|
||||||
server.signTx({
|
server.signTx({
|
||||||
txProposalId: txid,
|
txProposalId: txid,
|
||||||
signatures: signatures,
|
signatures: signatures,
|
||||||
|
@ -1331,7 +1300,7 @@ describe('Copay server', function() {
|
||||||
var tx = txs[0];
|
var tx = txs[0];
|
||||||
tx.id.should.equal(txid);
|
tx.id.should.equal(txid);
|
||||||
|
|
||||||
var signatures = helpers.clientSign(tx, TestData.copayers[0].xPrivKey_45H);
|
var signatures = helpers.clientSign(tx, TestData.copayers[0].xPrivKey);
|
||||||
server.signTx({
|
server.signTx({
|
||||||
txProposalId: txid,
|
txProposalId: txid,
|
||||||
signatures: signatures,
|
signatures: signatures,
|
||||||
|
@ -1354,7 +1323,7 @@ describe('Copay server', function() {
|
||||||
server.rejectTx({
|
server.rejectTx({
|
||||||
txProposalId: txid,
|
txProposalId: txid,
|
||||||
}, function(err) {
|
}, function(err) {
|
||||||
var signatures = helpers.clientSign(tx, TestData.copayers[0].xPrivKey_45H);
|
var signatures = helpers.clientSign(tx, TestData.copayers[0].xPrivKey);
|
||||||
server.signTx({
|
server.signTx({
|
||||||
txProposalId: txid,
|
txProposalId: txid,
|
||||||
signatures: signatures,
|
signatures: signatures,
|
||||||
|
@ -1402,7 +1371,7 @@ describe('Copay server', function() {
|
||||||
txProposalId: txid
|
txProposalId: txid
|
||||||
}, function(err, tx) {
|
}, function(err, tx) {
|
||||||
should.not.exist(err);
|
should.not.exist(err);
|
||||||
var signatures = helpers.clientSign(tx, TestData.copayers[2].xPrivKey_45H);
|
var signatures = helpers.clientSign(tx, TestData.copayers[2].xPrivKey);
|
||||||
server.signTx({
|
server.signTx({
|
||||||
txProposalId: txid,
|
txProposalId: txid,
|
||||||
signatures: signatures,
|
signatures: signatures,
|
||||||
|
@ -1429,7 +1398,7 @@ describe('Copay server', function() {
|
||||||
server.createTx(txOpts, function(err, txp) {
|
server.createTx(txOpts, function(err, txp) {
|
||||||
should.not.exist(err);
|
should.not.exist(err);
|
||||||
should.exist(txp);
|
should.exist(txp);
|
||||||
var signatures = helpers.clientSign(txp, TestData.copayers[0].xPrivKey_45H);
|
var signatures = helpers.clientSign(txp, TestData.copayers[0].xPrivKey);
|
||||||
server.signTx({
|
server.signTx({
|
||||||
txProposalId: txp.id,
|
txProposalId: txp.id,
|
||||||
signatures: signatures,
|
signatures: signatures,
|
||||||
|
@ -1571,7 +1540,7 @@ describe('Copay server', function() {
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
function(txp, next) {
|
function(txp, next) {
|
||||||
var signatures = helpers.clientSign(txp, TestData.copayers[0].xPrivKey_45H);
|
var signatures = helpers.clientSign(txp, TestData.copayers[0].xPrivKey);
|
||||||
server.signTx({
|
server.signTx({
|
||||||
txProposalId: txpId,
|
txProposalId: txpId,
|
||||||
signatures: signatures,
|
signatures: signatures,
|
||||||
|
@ -1602,7 +1571,7 @@ describe('Copay server', function() {
|
||||||
},
|
},
|
||||||
function(txp, next) {
|
function(txp, next) {
|
||||||
helpers.getAuthServer(wallet.copayers[1].id, function(server, wallet) {
|
helpers.getAuthServer(wallet.copayers[1].id, function(server, wallet) {
|
||||||
var signatures = helpers.clientSign(txp, TestData.copayers[1].xPrivKey_45H);
|
var signatures = helpers.clientSign(txp, TestData.copayers[1].xPrivKey);
|
||||||
server.signTx({
|
server.signTx({
|
||||||
txProposalId: txpId,
|
txProposalId: txpId,
|
||||||
signatures: signatures,
|
signatures: signatures,
|
||||||
|
@ -1917,7 +1886,7 @@ describe('Copay server', function() {
|
||||||
server.getPendingTxs({}, function(err, txs) {
|
server.getPendingTxs({}, function(err, txs) {
|
||||||
helpers.stubBroadcastFail();
|
helpers.stubBroadcastFail();
|
||||||
var tx = txs[0];
|
var tx = txs[0];
|
||||||
var signatures = helpers.clientSign(tx, TestData.copayers[0].xPrivKey_45H);
|
var signatures = helpers.clientSign(tx, TestData.copayers[0].xPrivKey);
|
||||||
server.signTx({
|
server.signTx({
|
||||||
txProposalId: tx.id,
|
txProposalId: tx.id,
|
||||||
signatures: signatures,
|
signatures: signatures,
|
||||||
|
@ -1959,7 +1928,7 @@ describe('Copay server', function() {
|
||||||
it('should notify sign, acceptance, and broadcast, and emit', function(done) {
|
it('should notify sign, acceptance, and broadcast, and emit', function(done) {
|
||||||
server.getPendingTxs({}, function(err, txs) {
|
server.getPendingTxs({}, function(err, txs) {
|
||||||
var tx = txs[2];
|
var tx = txs[2];
|
||||||
var signatures = helpers.clientSign(tx, TestData.copayers[0].xPrivKey_45H);
|
var signatures = helpers.clientSign(tx, TestData.copayers[0].xPrivKey);
|
||||||
sinon.spy(server, 'emit');
|
sinon.spy(server, 'emit');
|
||||||
server.signTx({
|
server.signTx({
|
||||||
txProposalId: tx.id,
|
txProposalId: tx.id,
|
||||||
|
@ -2102,7 +2071,7 @@ describe('Copay server', function() {
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should allow creator to remove an signed TX by himself', function(done) {
|
it('should allow creator to remove an signed TX by himself', function(done) {
|
||||||
var signatures = helpers.clientSign(txp, TestData.copayers[0].xPrivKey_45H);
|
var signatures = helpers.clientSign(txp, TestData.copayers[0].xPrivKey);
|
||||||
server.signTx({
|
server.signTx({
|
||||||
txProposalId: txp.id,
|
txProposalId: txp.id,
|
||||||
signatures: signatures,
|
signatures: signatures,
|
||||||
|
@ -2124,7 +2093,7 @@ describe('Copay server', function() {
|
||||||
async.waterfall([
|
async.waterfall([
|
||||||
|
|
||||||
function(next) {
|
function(next) {
|
||||||
var signatures = helpers.clientSign(txp, TestData.copayers[0].xPrivKey_45H);
|
var signatures = helpers.clientSign(txp, TestData.copayers[0].xPrivKey);
|
||||||
server.signTx({
|
server.signTx({
|
||||||
txProposalId: txp.id,
|
txProposalId: txp.id,
|
||||||
signatures: signatures,
|
signatures: signatures,
|
||||||
|
@ -2188,7 +2157,7 @@ describe('Copay server', function() {
|
||||||
|
|
||||||
it('should not allow creator copayer to remove an TX signed by other copayer', function(done) {
|
it('should not allow creator copayer to remove an TX signed by other copayer', function(done) {
|
||||||
helpers.getAuthServer(wallet.copayers[1].id, function(server2) {
|
helpers.getAuthServer(wallet.copayers[1].id, function(server2) {
|
||||||
var signatures = helpers.clientSign(txp, TestData.copayers[1].xPrivKey_45H);
|
var signatures = helpers.clientSign(txp, TestData.copayers[1].xPrivKey);
|
||||||
server2.signTx({
|
server2.signTx({
|
||||||
txProposalId: txp.id,
|
txProposalId: txp.id,
|
||||||
signatures: signatures,
|
signatures: signatures,
|
||||||
|
@ -2325,7 +2294,7 @@ describe('Copay server', function() {
|
||||||
should.not.exist(err);
|
should.not.exist(err);
|
||||||
should.exist(tx);
|
should.exist(tx);
|
||||||
|
|
||||||
var signatures = helpers.clientSign(tx, TestData.copayers[0].xPrivKey_45H);
|
var signatures = helpers.clientSign(tx, TestData.copayers[0].xPrivKey);
|
||||||
server.signTx({
|
server.signTx({
|
||||||
txProposalId: tx.id,
|
txProposalId: tx.id,
|
||||||
signatures: signatures,
|
signatures: signatures,
|
||||||
|
|
|
@ -5,7 +5,7 @@ var chai = require('chai');
|
||||||
var sinon = require('sinon');
|
var sinon = require('sinon');
|
||||||
var should = chai.should();
|
var should = chai.should();
|
||||||
var TXP = require('../../lib/model/txproposal');
|
var TXP = require('../../lib/model/txproposal');
|
||||||
var Bitcore = require('bitcore');
|
var Bitcore = require('bitcore-wallet-utils').Bitcore;
|
||||||
|
|
||||||
|
|
||||||
describe('TXProposal', function() {
|
describe('TXProposal', function() {
|
||||||
|
@ -22,6 +22,17 @@ describe('TXProposal', function() {
|
||||||
var t = txp.getBitcoreTx();
|
var t = txp.getBitcoreTx();
|
||||||
should.exist(t);
|
should.exist(t);
|
||||||
});
|
});
|
||||||
|
it('should order ouputs as specified by outputOrder', function() {
|
||||||
|
var txp = TXP.fromObj(aTXP());
|
||||||
|
|
||||||
|
txp.outputOrder = [0, 1];
|
||||||
|
var t = txp.getBitcoreTx();
|
||||||
|
t.getChangeOutput().should.deep.equal(t.outputs[1]);
|
||||||
|
|
||||||
|
txp.outputOrder = [1, 0];
|
||||||
|
var t = txp.getBitcoreTx();
|
||||||
|
t.getChangeOutput().should.deep.equal(t.outputs[0]);
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
||||||
|
@ -108,6 +119,7 @@ var aTXP = function() {
|
||||||
"requiredSignatures": 2,
|
"requiredSignatures": 2,
|
||||||
"requiredRejections": 1,
|
"requiredRejections": 1,
|
||||||
"status": "pending",
|
"status": "pending",
|
||||||
"actions": []
|
"actions": [],
|
||||||
|
"outputOrder": [0, 1],
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
Loading…
Reference in New Issue