Browse Source

Merge pull request #51 from isocolsky/ref/actions

Ref/actions
activeAddress
Matias Alejo Garcia 10 years ago
parent
commit
a85fe27987
  1. 2
      bit-wallet/bit-status
  2. 38
      lib/client/api.js
  3. 8
      lib/client/verifier.js
  4. 23
      lib/model/txproposal.js
  5. 2
      lib/storage.js
  6. 75
      test/integration/clientApi.js
  7. 23
      test/integration/server.js
  8. 2
      test/txproposal.js

2
bit-wallet/bit-status

@ -30,7 +30,7 @@ client.getStatus(function(err, res) {
if (!_.isEmpty(res.pendingTxps)) { if (!_.isEmpty(res.pendingTxps)) {
console.log("* TX Proposals:") console.log("* TX Proposals:")
_.each(res.pendingTxps, function(x) { _.each(res.pendingTxps, function(x) {
console.log("\t%s [%s by %s] %dSAT => %s", utils.shortID(x.id), x.decryptedMessage, x.creatorName, x.amount, x.toAddress); console.log("\t%s [%s by %s] %dSAT => %s", utils.shortID(x.id), x.message, x.creatorName, x.amount, x.toAddress);
if (!_.isEmpty(x.actions)) { if (!_.isEmpty(x.actions)) {
console.log('\t\t * Actions'); console.log('\t\t * Actions');

38
lib/client/api.js

@ -17,12 +17,12 @@ var BASE_URL = 'http://localhost:3001/copay/api';
var WALLET_CRITICAL_DATA = ['xPrivKey', 'm', 'publicKeyRing', 'sharedEncryptingKey']; var WALLET_CRITICAL_DATA = ['xPrivKey', 'm', 'publicKeyRing', 'sharedEncryptingKey'];
function _encryptProposalMessage(message, encryptingKey) { function _encryptMessage(message, encryptingKey) {
if (!message) return null; if (!message) return null;
return WalletUtils.encryptMessage(message, encryptingKey); return WalletUtils.encryptMessage(message, encryptingKey);
}; };
function _decryptProposalMessage(message, encryptingKey) { function _decryptMessage(message, encryptingKey) {
if (!message) return ''; if (!message) return '';
try { try {
return WalletUtils.decryptMessage(message, encryptingKey); return WalletUtils.decryptMessage(message, encryptingKey);
@ -31,6 +31,16 @@ function _decryptProposalMessage(message, encryptingKey) {
} }
}; };
function _processTxps(txps, encryptingKey) {
_.each([].concat(txps), function(txp) {
txp.encryptedMessage = txp.message;
txp.message = _decryptMessage(txp.message, encryptingKey);
_.each(txp.actions, function(action) {
action.comment = _decryptMessage(action.comment, encryptingKey);
});
});
};
function _parseError(body) { function _parseError(body) {
if (_.isString(body)) { if (_.isString(body)) {
try { try {
@ -305,12 +315,9 @@ API.prototype.getStatus = function(cb) {
if (err) return cb(err); if (err) return cb(err);
var url = '/v1/wallets/'; var url = '/v1/wallets/';
self._doGetRequest(url, data, function(err, body) { self._doGetRequest(url, data, function(err, result) {
_.each(body.pendingTxps, function(txp) { _processTxps(result.pendingTxps, data.sharedEncryptingKey);
txp.decryptedMessage = _decryptProposalMessage(txp.message, data.sharedEncryptingKey); return cb(err, result, data.copayerId);
});
return cb(err, body, data.copayerId);
}); });
}); });
}; };
@ -335,7 +342,7 @@ API.prototype.sendTxProposal = function(opts, cb) {
var args = { var args = {
toAddress: opts.toAddress, toAddress: opts.toAddress,
amount: opts.amount, amount: opts.amount,
message: _encryptProposalMessage(opts.message, data.sharedEncryptingKey), message: _encryptMessage(opts.message, data.sharedEncryptingKey),
}; };
var hash = WalletUtils.getProposalHash(args.toAddress, args.amount, args.message); var hash = WalletUtils.getProposalHash(args.toAddress, args.amount, args.message);
args.proposalSignature = WalletUtils.signMessage(hash, data.signingPrivKey); args.proposalSignature = WalletUtils.signMessage(hash, data.signingPrivKey);
@ -431,7 +438,7 @@ API.prototype.import = function(str, cb) {
}; };
/** /**
* *
* opts.doNotVerify * opts.doNotVerify
* @return {undefined} * @return {undefined}
*/ */
@ -444,14 +451,11 @@ API.prototype.getTxProposals = function(opts, cb) {
var url = '/v1/txproposals/'; var url = '/v1/txproposals/';
self._doGetRequest(url, data, function(err, txps) { self._doGetRequest(url, data, function(err, txps) {
if (err) return cb(err); if (err) return cb(err);
var fake = false;
_.each(txps, function(txp) { _processTxps(txps, data.sharedEncryptingKey);
txp.decryptedMessage = _decryptProposalMessage(txp.message, data.sharedEncryptingKey);
if (!opts.doNotVerify var fake = _.any(txps, function(txp) {
&& !Verifier.checkTxProposal(data, txp)) return (!opts.doNotVerify && !Verifier.checkTxProposal(data, txp));
fake = true;
}); });
if (fake) if (fake)
@ -523,7 +527,7 @@ API.prototype.rejectTxProposal = function(txp, reason, cb) {
var url = '/v1/txproposals/' + txp.id + '/rejections/'; var url = '/v1/txproposals/' + txp.id + '/rejections/';
var args = { var args = {
reason: reason || '', reason: _encryptMessage(reason, data.sharedEncryptingKey) || '',
}; };
self._doPostRequest(url, args, data, cb); self._doPostRequest(url, args, data, cb);
}); });

8
lib/client/verifier.js

@ -35,8 +35,8 @@ Verifier.checkCopayers = function(copayers, walletPrivKey, myXPrivKey, n) {
} }
// Not signed pub keys // Not signed pub keys
if (!copayer.xPubKey || !copayer.xPubKeySignature || if (!copayer.xPubKey || !copayer.xPubKeySignature ||
!WalletUtils.verifyMessage(copayer.xPubKey, copayer.xPubKeySignature, walletPubKey)) { !WalletUtils.verifyMessage(copayer.xPubKey, copayer.xPubKeySignature, walletPubKey)) {
log.error('Invalid signatures in server response'); log.error('Invalid signatures in server response');
error = true; error = true;
} }
@ -62,9 +62,9 @@ Verifier.checkTxProposal = function(data, txp) {
if (!creatorXPubKey) return false; if (!creatorXPubKey) return false;
var creatorSigningPubKey = (new Bitcore.HDPublicKey(creatorXPubKey)).derive('m/1/0').publicKey.toString(); var creatorSigningPubKey = (new Bitcore.HDPublicKey(creatorXPubKey)).derive('m/1/0').publicKey.toString();
var hash = WalletUtils.getProposalHash(txp.toAddress, txp.amount, txp.message); var hash = WalletUtils.getProposalHash(txp.toAddress, txp.amount, txp.encryptedMessage || txp.message);
log.debug('Regenerating & verifying tx proposal hash -> Hash: ', hash, ' Signature: ', txp.proposalSignature); log.debug('Regenerating & verifying tx proposal hash -> Hash: ', hash, ' Signature: ', txp.proposalSignature);
if (!WalletUtils.verifyMessage(hash, txp.proposalSignature, creatorSigningPubKey)) if (!WalletUtils.verifyMessage(hash, txp.proposalSignature, creatorSigningPubKey))
return false; return false;
return Verifier.checkAddress(data, txp.changeAddress); return Verifier.checkAddress(data, txp.changeAddress);

23
lib/model/txproposal.js

@ -30,7 +30,7 @@ TxProposal.create = function(opts) {
x.requiredSignatures = opts.requiredSignatures; x.requiredSignatures = opts.requiredSignatures;
x.requiredRejections = opts.requiredRejections; x.requiredRejections = opts.requiredRejections;
x.status = 'pending'; x.status = 'pending';
x.actions = {}; x.actions = [];
return x; return x;
}; };
@ -53,9 +53,8 @@ TxProposal.fromObj = function(obj) {
x.status = obj.status; x.status = obj.status;
x.txid = obj.txid; x.txid = obj.txid;
x.inputPaths = obj.inputPaths; x.inputPaths = obj.inputPaths;
x.actions = obj.actions; x.actions = _.map(obj.actions, function(action) {
_.each(x.actions, function(action, copayerId) { return TxProposalAction.fromObj(action);
x.actions[copayerId] = TxProposalAction.fromObj(action);
}); });
return x; return x;
@ -74,8 +73,8 @@ TxProposal.prototype._updateStatus = function() {
TxProposal.prototype._getCurrentSignatures = function() { TxProposal.prototype._getCurrentSignatures = function() {
var acceptedActions = _.filter(this.actions, function(x) { var acceptedActions = _.filter(this.actions, {
return x && x.type == 'accept'; type: 'accept'
}); });
return _.map(acceptedActions, function(x) { return _.map(acceptedActions, function(x) {
@ -125,7 +124,7 @@ TxProposal.prototype.getRawTx = function() {
* @return {String[]} copayerIds that performed actions in this proposal (accept / reject) * @return {String[]} copayerIds that performed actions in this proposal (accept / reject)
*/ */
TxProposal.prototype.getActors = function() { TxProposal.prototype.getActors = function() {
return _.keys(this.actions); return _.pluck(this.actions, 'copayerId');
}; };
@ -136,7 +135,9 @@ TxProposal.prototype.getActors = function() {
* @return {Object} type / createdOn * @return {Object} type / createdOn
*/ */
TxProposal.prototype.getActionBy = function(copayerId) { TxProposal.prototype.getActionBy = function(copayerId) {
return this.actions[copayerId]; return _.find(this.actions, {
copayerId: copayerId
});
}; };
TxProposal.prototype.addAction = function(copayerId, type, comment, signatures, xpub) { TxProposal.prototype.addAction = function(copayerId, type, comment, signatures, xpub) {
@ -147,7 +148,7 @@ TxProposal.prototype.addAction = function(copayerId, type, comment, signatures,
xpub: xpub, xpub: xpub,
comment: comment, comment: comment,
}); });
this.actions[copayerId] = action; this.actions.push(action);
this._updateStatus(); this._updateStatus();
}; };
@ -206,12 +207,12 @@ TxProposal.prototype.isPending = function() {
}; };
TxProposal.prototype.isAccepted = function() { TxProposal.prototype.isAccepted = function() {
var votes = _.countBy(_.values(this.actions), 'type'); var votes = _.countBy(this.actions, 'type');
return votes['accept'] >= this.requiredSignatures; return votes['accept'] >= this.requiredSignatures;
}; };
TxProposal.prototype.isRejected = function() { TxProposal.prototype.isRejected = function() {
var votes = _.countBy(_.values(this.actions), 'type'); var votes = _.countBy(this.actions, 'type');
return votes['reject'] >= this.requiredRejections; return votes['reject'] >= this.requiredRejections;
}; };

2
lib/storage.js

@ -121,7 +121,7 @@ Storage.prototype._completeTxData = function(walletId, txs, cb) {
if (err) return cb(err); if (err) return cb(err);
_.each(txList, function(tx) { _.each(txList, function(tx) {
tx.creatorName = wallet.getCopayer(tx.creatorId).name; tx.creatorName = wallet.getCopayer(tx.creatorId).name;
_.each(_.values(tx.actions), function(action) { _.each(tx.actions, function(action) {
action.copayerName = wallet.getCopayer(action.copayerId).name; action.copayerName = wallet.getCopayer(action.copayerId).name;
}); });
}); });

75
test/integration/clientApi.js

@ -425,7 +425,7 @@ describe('client API ', function() {
var opts = { var opts = {
amount: 120000000, amount: 120000000,
toAddress: 'n2TBMPzPECGUfcT2EByiTJ12TPZkhN2mN5', toAddress: 'n2TBMPzPECGUfcT2EByiTJ12TPZkhN2mN5',
message: 'hola 1-1', message: 'hello 1-1',
}; };
clients[0].sendTxProposal(opts, function(err, x) { clients[0].sendTxProposal(opts, function(err, x) {
should.not.exist(err); should.not.exist(err);
@ -447,7 +447,6 @@ describe('client API ', function() {
}); });
}); });
it('Should keep message and refusal texts', function(done) { it('Should keep message and refusal texts', function(done) {
var msg = 'abcdefg';
helpers.createAndJoinWallet(clients, 2, 3, function(err, w) { helpers.createAndJoinWallet(clients, 2, 3, function(err, w) {
clients[0].createAddress(function(err, x0) { clients[0].createAddress(function(err, x0) {
should.not.exist(err); should.not.exist(err);
@ -455,16 +454,16 @@ describe('client API ', function() {
var opts = { var opts = {
amount: 10000, amount: 10000,
toAddress: 'n2TBMPzPECGUfcT2EByiTJ12TPZkhN2mN5', toAddress: 'n2TBMPzPECGUfcT2EByiTJ12TPZkhN2mN5',
message: msg, message: 'some message',
}; };
clients[0].sendTxProposal(opts, function(err, x) { clients[0].sendTxProposal(opts, function(err, x) {
should.not.exist(err); should.not.exist(err);
clients[1].rejectTxProposal(x, 'xx', function(err, tx1) { clients[1].rejectTxProposal(x, 'rejection comment', function(err, tx1) {
should.not.exist(err); should.not.exist(err);
clients[2].getTxProposals({}, function(err, txs) { clients[2].getTxProposals({}, function(err, txs) {
should.not.exist(err); should.not.exist(err);
txs[0].decryptedMessage.should.equal(msg); txs[0].message.should.equal('some message');
_.values(txs[0].actions)[0].comment.should.equal('xx'); txs[0].actions[0].comment.should.equal('rejection comment');
done(); done();
}); });
}); });
@ -472,6 +471,48 @@ describe('client API ', function() {
}); });
}); });
}); });
it('Should encrypt proposal message', function(done) {
helpers.createAndJoinWallet(clients, 2, 3, function(err, w) {
clients[0].createAddress(function(err, x0) {
should.not.exist(err);
blockExplorerMock.setUtxo(x0, 10, 2);
var opts = {
amount: 10000,
toAddress: 'n2TBMPzPECGUfcT2EByiTJ12TPZkhN2mN5',
message: 'some message',
};
var spy = sinon.spy(clients[0], '_doPostRequest');
clients[0].sendTxProposal(opts, function(err, x) {
should.not.exist(err);
spy.calledOnce.should.be.true;
JSON.stringify(spy.getCall(0).args).should.not.contain('some message');
done();
});
});
});
});
it('Should encrypt proposal refusal comment', function(done) {
helpers.createAndJoinWallet(clients, 2, 3, function(err, w) {
clients[0].createAddress(function(err, x0) {
should.not.exist(err);
blockExplorerMock.setUtxo(x0, 10, 2);
var opts = {
amount: 10000,
toAddress: 'n2TBMPzPECGUfcT2EByiTJ12TPZkhN2mN5',
};
clients[0].sendTxProposal(opts, function(err, x) {
should.not.exist(err);
var spy = sinon.spy(clients[1], '_doPostRequest');
clients[1].rejectTxProposal(x, 'rejection comment', function(err, tx1) {
should.not.exist(err);
spy.calledOnce.should.be.true;
JSON.stringify(spy.getCall(0).args).should.not.contain('rejection comment');
done();
});
});
});
});
});
it('should detect fake tx proposals (wrong signature)', function(done) { it('should detect fake tx proposals (wrong signature)', function(done) {
helpers.createAndJoinWallet(clients, 2, 2, function(err) { helpers.createAndJoinWallet(clients, 2, 2, function(err) {
should.not.exist(err); should.not.exist(err);
@ -482,7 +523,7 @@ describe('client API ', function() {
var opts = { var opts = {
amount: 10000, amount: 10000,
toAddress: 'n2TBMPzPECGUfcT2EByiTJ12TPZkhN2mN5', toAddress: 'n2TBMPzPECGUfcT2EByiTJ12TPZkhN2mN5',
message: 'hola', message: 'hello',
}; };
clients[0].sendTxProposal(opts, function(err, x) { clients[0].sendTxProposal(opts, function(err, x) {
should.not.exist(err); should.not.exist(err);
@ -521,7 +562,7 @@ describe('client API ', function() {
var opts = { var opts = {
amount: 10000, amount: 10000,
toAddress: 'n2TBMPzPECGUfcT2EByiTJ12TPZkhN2mN5', toAddress: 'n2TBMPzPECGUfcT2EByiTJ12TPZkhN2mN5',
message: 'hola', message: 'hello',
}; };
clients[0].sendTxProposal(opts, function(err, x) { clients[0].sendTxProposal(opts, function(err, x) {
should.not.exist(err); should.not.exist(err);
@ -560,7 +601,7 @@ describe('client API ', function() {
var opts = { var opts = {
amount: 10000, amount: 10000,
toAddress: 'n2TBMPzPECGUfcT2EByiTJ12TPZkhN2mN5', toAddress: 'n2TBMPzPECGUfcT2EByiTJ12TPZkhN2mN5',
message: 'hola', message: 'hello',
}; };
clients[0].sendTxProposal(opts, function(err, x) { clients[0].sendTxProposal(opts, function(err, x) {
should.not.exist(err); should.not.exist(err);
@ -603,7 +644,7 @@ describe('client API ', function() {
var opts = { var opts = {
amount: 10000000, amount: 10000000,
toAddress: 'n2TBMPzPECGUfcT2EByiTJ12TPZkhN2mN5', toAddress: 'n2TBMPzPECGUfcT2EByiTJ12TPZkhN2mN5',
message: 'hola 1-1', message: 'hello 1-1',
}; };
clients[0].sendTxProposal(opts, function(err, x) { clients[0].sendTxProposal(opts, function(err, x) {
should.not.exist(err); should.not.exist(err);
@ -630,7 +671,7 @@ describe('client API ', function() {
var opts = { var opts = {
amount: 10000, amount: 10000,
toAddress: 'n2TBMPzPECGUfcT2EByiTJ12TPZkhN2mN5', toAddress: 'n2TBMPzPECGUfcT2EByiTJ12TPZkhN2mN5',
message: 'hola 1-1', message: 'hello 1-1',
}; };
clients[0].sendTxProposal(opts, function(err, x) { clients[0].sendTxProposal(opts, function(err, x) {
should.not.exist(err); should.not.exist(err);
@ -661,14 +702,14 @@ describe('client API ', function() {
var opts = { var opts = {
amount: 10000, amount: 10000,
toAddress: 'n2TBMPzPECGUfcT2EByiTJ12TPZkhN2mN5', toAddress: 'n2TBMPzPECGUfcT2EByiTJ12TPZkhN2mN5',
message: 'hola 1-1', message: 'hello 1-1',
}; };
clients[0].sendTxProposal(opts, function(err, x) { clients[0].sendTxProposal(opts, function(err, x) {
should.not.exist(err); should.not.exist(err);
x.status.should.equal('pending'); x.status.should.equal('pending');
x.requiredRejections.should.equal(2); x.requiredRejections.should.equal(2);
x.requiredSignatures.should.equal(2); x.requiredSignatures.should.equal(2);
clients[0].rejectTxProposal(x, 'no me gusto', function(err, tx) { clients[0].rejectTxProposal(x, 'wont sign', function(err, tx) {
should.not.exist(err, err); should.not.exist(err, err);
tx.status.should.equal('pending'); tx.status.should.equal('pending');
clients[1].signTxProposal(x, function(err, tx) { clients[1].signTxProposal(x, function(err, tx) {
@ -695,7 +736,7 @@ describe('client API ', function() {
var opts = { var opts = {
amount: 10000, amount: 10000,
toAddress: 'n2TBMPzPECGUfcT2EByiTJ12TPZkhN2mN5', toAddress: 'n2TBMPzPECGUfcT2EByiTJ12TPZkhN2mN5',
message: 'hola 1-1', message: 'hello 1-1',
}; };
clients[0].sendTxProposal(opts, function(err, x) { clients[0].sendTxProposal(opts, function(err, x) {
should.not.exist(err); should.not.exist(err);
@ -703,13 +744,13 @@ describe('client API ', function() {
x.requiredRejections.should.equal(2); x.requiredRejections.should.equal(2);
x.requiredSignatures.should.equal(3); x.requiredSignatures.should.equal(3);
clients[0].rejectTxProposal(x, 'no me gusto', function(err, tx) { clients[0].rejectTxProposal(x, 'wont sign', function(err, tx) {
should.not.exist(err, err); should.not.exist(err, err);
tx.status.should.equal('pending'); tx.status.should.equal('pending');
clients[1].signTxProposal(x, function(err, tx) { clients[1].signTxProposal(x, function(err, tx) {
should.not.exist(err); should.not.exist(err);
tx.status.should.equal('pending'); tx.status.should.equal('pending');
clients[2].rejectTxProposal(x, 'tampoco me gusto', function(err, tx) { clients[2].rejectTxProposal(x, 'me neither', function(err, tx) {
should.not.exist(err); should.not.exist(err);
tx.status.should.equal('rejected'); tx.status.should.equal('rejected');
done(); done();
@ -730,7 +771,7 @@ describe('client API ', function() {
var opts = { var opts = {
amount: 10000, amount: 10000,
toAddress: 'n2TBMPzPECGUfcT2EByiTJ12TPZkhN2mN5', toAddress: 'n2TBMPzPECGUfcT2EByiTJ12TPZkhN2mN5',
message: 'hola 1-1', message: 'hello 1-1',
}; };
clients[0].sendTxProposal(opts, function(err, x) { clients[0].sendTxProposal(opts, function(err, x) {
should.not.exist(err); should.not.exist(err);

23
test/integration/server.js

@ -1126,10 +1126,9 @@ describe('Copay server', function() {
server.getTx({ server.getTx({
id: txp.id id: txp.id
}, function(err, txp) { }, function(err, txp) {
var actions = _.values(txp.actions); txp.actions.length.should.equal(1);
actions.length.should.equal(1); txp.actions[0].copayerId.should.equal(wallet.copayers[0].id);
actions[0].copayerId.should.equal(wallet.copayers[0].id); txp.actions[0].copayerName.should.equal(wallet.copayers[0].name);
actions[0].copayerName.should.equal(wallet.copayers[0].name);
done(); done();
}); });
}); });
@ -1221,7 +1220,7 @@ describe('Copay server', function() {
should.not.exist(err); should.not.exist(err);
txps.length.should.equal(1); txps.length.should.equal(1);
var txp = txps[0]; var txp = txps[0];
_.keys(txp.actions).should.be.empty; txp.actions.should.be.empty;
next(null, txp); next(null, txp);
}); });
}, },
@ -1243,8 +1242,8 @@ describe('Copay server', function() {
txp.isPending().should.be.true; txp.isPending().should.be.true;
txp.isRejected().should.be.false; txp.isRejected().should.be.false;
txp.isAccepted().should.be.false; txp.isAccepted().should.be.false;
_.keys(txp.actions).length.should.equal(1); txp.actions.length.should.equal(1);
var action = txp.actions[wallet.copayers[0].id]; var action = txp.getActionBy(wallet.copayers[0].id);
action.type.should.equal('accept'); action.type.should.equal('accept');
next(null, txp); next(null, txp);
}); });
@ -1279,7 +1278,7 @@ describe('Copay server', function() {
txp.isAccepted().should.be.true; txp.isAccepted().should.be.true;
txp.isBroadcasted().should.be.true; txp.isBroadcasted().should.be.true;
txp.txid.should.equal('999'); txp.txid.should.equal('999');
_.keys(txp.actions).length.should.equal(2); txp.actions.length.should.equal(2);
done(); done();
}); });
}, },
@ -1304,7 +1303,7 @@ describe('Copay server', function() {
should.not.exist(err); should.not.exist(err);
txps.length.should.equal(1); txps.length.should.equal(1);
var txp = txps[0]; var txp = txps[0];
_.keys(txp.actions).should.be.empty; txp.actions.should.be.empty;
next(); next();
}); });
}, },
@ -1325,8 +1324,8 @@ describe('Copay server', function() {
txp.isPending().should.be.true; txp.isPending().should.be.true;
txp.isRejected().should.be.false; txp.isRejected().should.be.false;
txp.isAccepted().should.be.false; txp.isAccepted().should.be.false;
_.keys(txp.actions).length.should.equal(1); txp.actions.length.should.equal(1);
var action = txp.actions[wallet.copayers[0].id]; var action = txp.getActionBy(wallet.copayers[0].id);
action.type.should.equal('reject'); action.type.should.equal('reject');
action.comment.should.equal('just because'); action.comment.should.equal('just because');
next(); next();
@ -1359,7 +1358,7 @@ describe('Copay server', function() {
txp.isPending().should.be.false; txp.isPending().should.be.false;
txp.isRejected().should.be.true; txp.isRejected().should.be.true;
txp.isAccepted().should.be.false; txp.isAccepted().should.be.false;
_.keys(txp.actions).length.should.equal(2); txp.actions.length.should.equal(2);
done(); done();
}); });
}, },

2
test/txproposal.js

@ -37,7 +37,7 @@ describe('TXProposal', function() {
}); });
}); });
describe.skip('#getRawTx', function() { describe('#getRawTx', function() {
it('should generate correct raw transaction for signed 2-2', function() { it('should generate correct raw transaction for signed 2-2', function() {
var txp = TXP.fromObj(aTXP()); var txp = TXP.fromObj(aTXP());
txp.sign('1', theSignatures, theXPub); txp.sign('1', theSignatures, theXPub);

Loading…
Cancel
Save