bitcore-wallet-service/test/integration/clientApi.js

692 lines
22 KiB
JavaScript
Raw Normal View History

2015-02-16 10:04:25 -08:00
'use strict';
var _ = require('lodash');
var chai = require('chai');
var sinon = require('sinon');
var should = chai.should();
2015-02-19 06:00:14 -08:00
var levelup = require('levelup');
var memdown = require('memdown');
2015-02-19 07:32:10 -08:00
var async = require('async');
2015-02-19 06:00:14 -08:00
var request = require('supertest');
2015-02-16 10:04:25 -08:00
var Client = require('../../lib/client');
var API = Client.API;
var Bitcore = require('bitcore');
2015-02-16 21:20:04 -08:00
var TestData = require('./clienttestdata');
var WalletUtils = require('../../lib/walletutils');
2015-02-19 06:00:14 -08:00
var ExpressApp = require('../../lib/expressapp');
var Storage = require('../../lib/storage');
2015-02-16 10:04:25 -08:00
2015-02-19 07:32:10 -08:00
var helpers = {};
helpers.getRequest = function(app) {
return function(args, cb) {
var req = request(app);
var r = req[args.method](args.relUrl);
if (args.headers) {
_.each(args.headers, function(v, k) {
r.set(k, v);
})
}
if (!_.isEmpty(args.body)) {
r.send(args.body);
};
r.end(function(err, res) {
return cb(err, res, res.body);
2015-02-16 10:04:25 -08:00
});
2015-02-19 07:32:10 -08:00
};
};
helpers.createAndJoinWallet = function(clients, m, n, cb) {
2015-02-19 12:38:48 -08:00
clients[0].createWallet('wallet name', 'creator', m, n, 'testnet',
2015-02-19 07:32:10 -08:00
function(err, secret) {
if (err) return cb(err);
if (n == 1) return cb();
should.exist(secret);
2015-02-19 07:45:28 -08:00
async.each(_.range(n - 1), function(i, cb) {
2015-02-19 07:32:10 -08:00
clients[i + 1].joinWallet(secret, 'copayer ' + (i + 1), function(err, result) {
should.not.exist(err);
return cb(err);
});
}, function(err) {
2015-02-19 12:38:48 -08:00
if (err) return cb(err);
return cb(null, {
m: m,
n: n,
secret: secret,
});
2015-02-19 07:32:10 -08:00
});
2015-02-16 10:04:25 -08:00
});
2015-02-19 07:32:10 -08:00
};
2015-02-19 06:00:14 -08:00
2015-02-19 12:38:48 -08:00
2015-02-19 07:32:10 -08:00
var fsmock = {};
var content = {};
fsmock.readFile = function(name, enc, cb) {
if (!content || _.isEmpty(content[name]))
return cb('empty');
return cb(null, content[name]);
};
fsmock.writeFile = function(name, data, cb) {
content[name] = data;
return cb();
};
2015-02-19 12:38:48 -08:00
fsmock.reset = function() {
content = {};
};
fsmock._get = function(name) {
return content[name];
};
var blockExplorerMock = {};
2015-02-19 13:11:57 -08:00
blockExplorerMock.utxos = [];
2015-02-19 12:38:48 -08:00
blockExplorerMock.getUnspentUtxos = function(dummy, cb) {
2015-02-19 13:11:57 -08:00
var ret = _.map(blockExplorerMock.utxos || [], function(x) {
2015-02-19 15:19:01 -08:00
var y = _.clone(x);
y.toObject = function() {
2015-02-19 12:38:48 -08:00
return this;
};
2015-02-19 15:19:01 -08:00
return y;
2015-02-19 12:38:48 -08:00
});
return cb(null, ret);
};
blockExplorerMock.setUtxo = function(address, amount, m) {
2015-02-19 13:11:57 -08:00
blockExplorerMock.utxos.push({
2015-02-19 12:38:48 -08:00
txid: Bitcore.crypto.Hash.sha256(new Buffer(Math.random() * 100000)).toString('hex'),
vout: Math.floor((Math.random() * 10) + 1),
amount: amount,
address: address.address,
2015-02-19 13:11:57 -08:00
scriptPubKey: Bitcore.Script.buildMultisigOut(address.publicKeys, m).toScriptHashOut().toString(),
2015-02-19 12:38:48 -08:00
});
};
2015-02-19 13:11:57 -08:00
blockExplorerMock.broadcast = function(raw, cb) {
blockExplorerMock.lastBroadcasted = raw;
return cb(null, (new Bitcore.Transaction(raw)).id);
};
2015-02-19 12:38:48 -08:00
blockExplorerMock.reset = function() {
2015-02-19 13:11:57 -08:00
blockExplorerMock.utxos = [];
2015-02-19 12:38:48 -08:00
};
2015-02-19 07:32:10 -08:00
describe('client API ', function() {
2015-02-19 12:38:48 -08:00
var clients, app;
2015-02-19 07:32:10 -08:00
beforeEach(function() {
clients = [];
2015-02-19 07:45:28 -08:00
var db = levelup(memdown, {
valueEncoding: 'json'
});
var storage = new Storage({
db: db
});
2015-02-19 12:38:48 -08:00
app = ExpressApp.start({
2015-02-19 07:45:28 -08:00
CopayServer: {
2015-02-19 12:38:48 -08:00
storage: storage,
blockExplorer: blockExplorerMock,
2015-02-19 07:45:28 -08:00
}
});
2015-02-19 07:32:10 -08:00
// Generates 5 clients
_.each(_.range(5), function(i) {
var storage = new Client.FileStorage({
filename: 'client' + i,
fs: fsmock,
});
var client = new Client({
storage: storage,
});
2015-02-19 07:45:28 -08:00
2015-02-19 07:32:10 -08:00
client.request = helpers.getRequest(app);
clients.push(client);
2015-02-19 06:00:14 -08:00
});
2015-02-19 12:38:48 -08:00
fsmock.reset();
blockExplorerMock.reset();
2015-02-19 07:32:10 -08:00
});
2015-02-19 12:38:48 -08:00
describe('Wallet Creation', function() {
2015-02-19 07:32:10 -08:00
it('should check balance in a 1-1 ', function(done) {
helpers.createAndJoinWallet(clients, 1, 1, function(err) {
should.not.exist(err);
clients[0].getBalance(function(err, x) {
should.not.exist(err);
done();
})
});
2015-02-19 06:00:14 -08:00
});
2015-02-19 12:38:48 -08:00
it('should be able to complete wallets in copayer that joined later', function(done) {
2015-02-19 07:32:10 -08:00
helpers.createAndJoinWallet(clients, 2, 3, function(err) {
should.not.exist(err);
clients[0].getBalance(function(err, x) {
should.not.exist(err);
clients[1].getBalance(function(err, x) {
should.not.exist(err);
clients[2].getBalance(function(err, x) {
should.not.exist(err);
done();
})
})
})
});
2015-02-19 06:00:14 -08:00
});
2015-02-16 21:20:04 -08:00
2015-02-19 12:38:48 -08:00
it('should not allow to join a full wallet ', function(done) {
helpers.createAndJoinWallet(clients, 2, 2, function(err, w) {
2015-02-16 21:20:04 -08:00
should.not.exist(err);
2015-02-19 12:38:48 -08:00
should.exist(w.secret);
clients[4].joinWallet(w.secret, 'copayer', function(err, result) {
2015-02-19 15:04:05 -08:00
err.code.should.contain('WFULL');
2015-02-19 12:38:48 -08:00
done();
});
});
});
it('should fail with a unknown secret', function(done) {
var oldSecret = '3f8e5acb-ceeb-4aae-134f-692d934e3b1c:L2gohj8s2fLKqVU5cQutAVGciutUxczFxLxxXHFsjzLh71ZjkFQQ:T';
clients[0].joinWallet(oldSecret, 'copayer', function(err, result) {
2015-02-19 15:04:05 -08:00
err.code.should.contain('BADREQUEST');
2015-02-16 21:20:04 -08:00
done();
});
2015-02-17 07:39:11 -08:00
});
2015-02-19 12:38:48 -08:00
it('should reject wallets with bad signatures', function(done) {
helpers.createAndJoinWallet(clients, 2, 3, function(err) {
should.not.exist(err);
2015-02-16 21:20:04 -08:00
2015-02-19 12:38:48 -08:00
// Get right response
2015-02-20 06:23:28 -08:00
clients[0]._load(function(err, data) {
2015-02-19 12:38:48 -08:00
var url = '/v1/wallets/';
clients[0]._doGetRequest(url, data, function(err, x) {
2015-02-16 21:20:04 -08:00
2015-02-19 12:38:48 -08:00
// Tamper data
x.wallet.copayers[0].xPubKey = x.wallet.copayers[1].xPubKey;
2015-02-16 21:20:04 -08:00
2015-02-19 12:38:48 -08:00
// Tamper response
clients[1]._doGetRequest = sinon.stub().yields(null, x);
2015-02-16 21:20:04 -08:00
2015-02-19 12:38:48 -08:00
clients[1].getBalance(function(err, x) {
2015-02-19 15:04:05 -08:00
err.code.should.contain('SERVERCOMPROMISED');
2015-02-19 12:38:48 -08:00
done();
});
});
});
2015-02-16 21:20:04 -08:00
});
2015-02-17 07:39:11 -08:00
});
2015-02-16 21:20:04 -08:00
2015-02-19 12:38:48 -08:00
it('should reject wallets with missing signatures', function(done) {
helpers.createAndJoinWallet(clients, 2, 3, function(err) {
should.not.exist(err);
2015-02-16 21:20:04 -08:00
2015-02-19 12:38:48 -08:00
// Get right response
var data = clients[0]._load(function(err, data) {
var url = '/v1/wallets/';
clients[0]._doGetRequest(url, data, function(err, x) {
// Tamper data
delete x.wallet.copayers[1].xPubKey;
// Tamper response
clients[1]._doGetRequest = sinon.stub().yields(null, x);
clients[1].getBalance(function(err, x) {
2015-02-19 15:04:05 -08:00
err.code.should.contain('SERVERCOMPROMISED');
2015-02-19 12:38:48 -08:00
done();
});
});
});
2015-02-16 21:20:04 -08:00
});
2015-02-17 07:39:11 -08:00
});
2015-02-16 21:20:04 -08:00
2015-02-19 12:38:48 -08:00
it('should reject wallets missing caller"s pubkey', function(done) {
helpers.createAndJoinWallet(clients, 2, 3, function(err) {
should.not.exist(err);
// Get right response
var data = clients[0]._load(function(err, data) {
var url = '/v1/wallets/';
clients[0]._doGetRequest(url, data, function(err, x) {
// Tamper data. Replace caller's pubkey
x.wallet.copayers[1].xPubKey = (new Bitcore.HDPrivateKey()).publicKey;
// Add a correct signature
x.wallet.copayers[1].xPubKeySignature = WalletUtils.signMessage(
x.wallet.copayers[1].xPubKey, data.walletPrivKey),
// Tamper response
clients[1]._doGetRequest = sinon.stub().yields(null, x);
clients[1].getBalance(function(err, x) {
2015-02-19 15:04:05 -08:00
err.code.should.contain('SERVERCOMPROMISED');
2015-02-19 12:38:48 -08:00
done();
});
});
});
2015-02-16 21:20:04 -08:00
});
2015-02-17 07:39:11 -08:00
});
2015-02-19 12:38:48 -08:00
});
2015-02-17 06:48:19 -08:00
2015-02-19 12:38:48 -08:00
describe('Address Creation', function() {
it('should be able to create address in all copayers in a 2-3 wallet', function(done) {
this.timeout(5000);
helpers.createAndJoinWallet(clients, 2, 3, function(err) {
should.not.exist(err);
clients[0].createAddress(function(err, x0) {
should.not.exist(err);
should.exist(x0.address);
clients[1].createAddress(function(err, x1) {
should.not.exist(err);
should.exist(x1.address);
clients[2].createAddress(function(err, x2) {
should.not.exist(err);
should.exist(x2.address);
done();
});
});
});
});
});
it('should see balance on address created by others', function(done) {
helpers.createAndJoinWallet(clients, 2, 2, function(err, w) {
should.not.exist(err);
clients[0].createAddress(function(err, x0) {
should.not.exist(err);
should.exist(x0.address);
blockExplorerMock.setUtxo(x0, 10, w.m);
clients[0].getBalance(function(err, bal0) {
should.not.exist(err);
bal0.totalAmount.should.equal(10 * 1e8);
bal0.lockedAmount.should.equal(0);
clients[1].getBalance(function(err, bal1) {
bal1.totalAmount.should.equal(10 * 1e8);
bal1.lockedAmount.should.equal(0);
done();
});
});
});
2015-02-17 06:48:19 -08:00
});
2015-02-17 07:39:11 -08:00
});
2015-02-20 06:23:28 -08:00
it('should detect fake addresses', function(done) {
helpers.createAndJoinWallet(clients, 2, 2, function(err) {
should.not.exist(err);
// Get right response
clients[0]._load(function(err, data) {
var url = '/v1/addresses/';
clients[0]._doPostRequest(url, {}, data, function(err, address) {
// Tamper data
address.address = '2N86pNEpREGpwZyHVC5vrNUCbF9nM1Geh4K';
// Tamper response
clients[1]._doPostRequest = sinon.stub().yields(null, address);
// Grab real response
clients[1].createAddress(function(err, x0) {
err.code.should.contain('SERVERCOMPROMISED');
done();
});
});
});
});
});
it('should detect fake public keys', function(done) {
helpers.createAndJoinWallet(clients, 2, 2, function(err) {
should.not.exist(err);
// Get right response
clients[0]._load(function(err, data) {
var url = '/v1/addresses/';
clients[0]._doPostRequest(url, {}, data, function(err, address) {
console.log('[clientApi.js.326:address:]', address); //TODO
// Tamper data
address.publicKeys = ['0322defe0c3eb9fcd8bc01878e6dbca7a6846880908d214b50a752445040cc5c54',
'02bf3aadc17131ca8144829fa1883c1ac0a8839067af4bca47a90ccae63d0d8037'];
// Tamper response
clients[1]._doPostRequest = sinon.stub().yields(null, address);
// Grab real response
clients[1].createAddress(function(err, x0) {
err.code.should.contain('SERVERCOMPROMISED');
done();
});
});
});
});
});
2015-02-16 21:20:04 -08:00
});
2015-02-17 06:52:29 -08:00
2015-02-19 12:38:48 -08:00
describe('Wallet Backups and Mobility', function() {
2015-02-17 06:52:29 -08:00
2015-02-19 12:38:48 -08:00
it('round trip #import #export', function(done) {
helpers.createAndJoinWallet(clients, 2, 2, function(err, w) {
should.not.exist(err);
clients[0].export(function(err, str) {
should.not.exist(err);
var original = JSON.parse(fsmock._get('client0'));
clients[2].import(str, function(err, wallet) {
should.not.exist(err);
var clone = JSON.parse(fsmock._get('client2'));
delete original.walletPrivKey; // no need to persist it.
clone.should.deep.equal(original);
done();
});
2015-02-17 06:52:29 -08:00
2015-02-19 12:38:48 -08:00
});
});
});
it('should recreate a wallet, create addresses and receive money', function(done) {
var backup = '["tprv8ZgxMBicQKsPehCdj4HM1MZbKVXBFt5Dj9nQ44M99EdmdiUfGtQBDTSZsKmzdUrB1vEuP6ipuoa39UXwPS2CvnjE1erk5aUjc5vQZkWvH4B",2,["tpubD6NzVbkrYhZ4XCNDPDtyRWPxvJzvTkvUE2cMPB8jcUr9Dkicv6cYQmA18DBAid6eRK1BGCU9nzgxxVdQUGLYJ34XsPXPW4bxnH4PH6oQBF3"],"sd0kzXmlXBgTGHrKaBW4aA=="]';
clients[0].import(backup, function(err, wallet) {
2015-02-17 06:52:29 -08:00
should.not.exist(err);
2015-02-19 12:38:48 -08:00
clients[0].reCreateWallet('pepe', function(err, wallet) {
should.not.exist(err);
clients[0].createAddress(function(err, x0) {
should.not.exist(err);
should.exist(x0.address);
blockExplorerMock.setUtxo(x0, 10, 2);
clients[0].getBalance(function(err, bal0) {
should.not.exist(err);
bal0.totalAmount.should.equal(10 * 1e8);
bal0.lockedAmount.should.equal(0);
done();
});
});
});
2015-02-17 06:52:29 -08:00
});
2015-02-17 07:39:11 -08:00
});
2015-02-19 12:38:48 -08:00
});
2015-02-17 07:39:11 -08:00
2015-02-19 12:38:48 -08:00
2015-02-19 15:04:05 -08:00
describe('Transactions Signatures and Rejection', function() {
2015-02-19 12:38:48 -08:00
it('Send and broadcast in 1-1 wallet', function(done) {
helpers.createAndJoinWallet(clients, 1, 1, function(err, w) {
clients[0].createAddress(function(err, x0) {
should.not.exist(err);
should.exist(x0.address);
2015-02-19 13:11:57 -08:00
blockExplorerMock.setUtxo(x0, 1, 1);
2015-02-19 12:38:48 -08:00
var opts = {
2015-02-19 16:37:13 -08:00
amount: 10000000,
2015-02-19 12:38:48 -08:00
toAddress: 'n2TBMPzPECGUfcT2EByiTJ12TPZkhN2mN5',
message: 'hola 1-1',
};
clients[0].sendTxProposal(opts, function(err, x) {
should.not.exist(err);
2015-02-19 12:47:51 -08:00
x.requiredRejections.should.equal(1);
x.requiredSignatures.should.equal(1);
x.status.should.equal('pending');
x.changeAddress.path.should.equal('m/2147483647/1/0');
2015-02-19 13:11:57 -08:00
clients[0].signTxProposal(x, function(err, tx) {
should.not.exist(err);
tx.status.should.equal('broadcasted');
tx.txid.should.equal((new Bitcore.Transaction(blockExplorerMock.lastBroadcasted)).id);
2015-02-19 12:47:51 -08:00
done();
});
2015-02-19 12:38:48 -08:00
});
});
});
});
2015-02-19 12:47:51 -08:00
it('Send and broadcast in 2-3 wallet', function(done) {
helpers.createAndJoinWallet(clients, 2, 3, function(err, w) {
clients[0].createAddress(function(err, x0) {
should.not.exist(err);
should.exist(x0.address);
blockExplorerMock.setUtxo(x0, 10, 1);
var opts = {
amount: 10000,
toAddress: 'n2TBMPzPECGUfcT2EByiTJ12TPZkhN2mN5',
message: 'hola 1-1',
};
clients[0].sendTxProposal(opts, function(err, x) {
should.not.exist(err);
x.status.should.equal('pending');
x.requiredRejections.should.equal(2);
x.requiredSignatures.should.equal(2);
2015-02-19 13:11:57 -08:00
clients[0].signTxProposal(x, function(err, tx) {
should.not.exist(err, err);
tx.status.should.equal('pending');
clients[1].signTxProposal(x, function(err, tx) {
should.not.exist(err);
tx.status.should.equal('broadcasted');
tx.txid.should.equal((new Bitcore.Transaction(blockExplorerMock.lastBroadcasted)).id);
done();
});
2015-02-19 12:47:51 -08:00
});
});
});
});
});
2015-02-19 13:11:57 -08:00
it('Send, reject, 2 signs and broadcast in 2-3 wallet', function(done) {
helpers.createAndJoinWallet(clients, 2, 3, function(err, w) {
clients[0].createAddress(function(err, x0) {
should.not.exist(err);
should.exist(x0.address);
blockExplorerMock.setUtxo(x0, 10, 1);
var opts = {
amount: 10000,
toAddress: 'n2TBMPzPECGUfcT2EByiTJ12TPZkhN2mN5',
message: 'hola 1-1',
};
clients[0].sendTxProposal(opts, function(err, x) {
should.not.exist(err);
x.status.should.equal('pending');
x.requiredRejections.should.equal(2);
x.requiredSignatures.should.equal(2);
clients[0].rejectTxProposal(x, 'no me gusto', function(err, tx) {
should.not.exist(err, err);
tx.status.should.equal('pending');
clients[1].signTxProposal(x, function(err, tx) {
should.not.exist(err);
clients[2].signTxProposal(x, function(err, tx) {
should.not.exist(err);
tx.status.should.equal('broadcasted');
tx.txid.should.equal((new Bitcore.Transaction(blockExplorerMock.lastBroadcasted)).id);
done();
});
});
});
});
});
});
});
it('Send, reject in 3-4 wallet', function(done) {
helpers.createAndJoinWallet(clients, 3, 4, function(err, w) {
clients[0].createAddress(function(err, x0) {
should.not.exist(err);
should.exist(x0.address);
blockExplorerMock.setUtxo(x0, 10, 1);
var opts = {
amount: 10000,
toAddress: 'n2TBMPzPECGUfcT2EByiTJ12TPZkhN2mN5',
message: 'hola 1-1',
};
clients[0].sendTxProposal(opts, function(err, x) {
should.not.exist(err);
x.status.should.equal('pending');
x.requiredRejections.should.equal(2);
x.requiredSignatures.should.equal(3);
clients[0].rejectTxProposal(x, 'no me gusto', function(err, tx) {
should.not.exist(err, err);
tx.status.should.equal('pending');
clients[1].signTxProposal(x, function(err, tx) {
should.not.exist(err);
tx.status.should.equal('pending');
clients[2].rejectTxProposal(x, 'tampoco me gusto', function(err, tx) {
should.not.exist(err);
tx.status.should.equal('rejected');
done();
});
});
});
});
});
});
});
2015-02-19 13:47:17 -08:00
it('Should not allow to reject or sign twice', function(done) {
helpers.createAndJoinWallet(clients, 2, 3, function(err, w) {
clients[0].createAddress(function(err, x0) {
should.not.exist(err);
should.exist(x0.address);
blockExplorerMock.setUtxo(x0, 10, 1);
var opts = {
amount: 10000,
toAddress: 'n2TBMPzPECGUfcT2EByiTJ12TPZkhN2mN5',
message: 'hola 1-1',
};
clients[0].sendTxProposal(opts, function(err, x) {
should.not.exist(err);
x.status.should.equal('pending');
x.requiredRejections.should.equal(2);
x.requiredSignatures.should.equal(2);
clients[0].signTxProposal(x, function(err, tx) {
should.not.exist(err, err);
tx.status.should.equal('pending');
clients[0].signTxProposal(x, function(err, tx) {
2015-02-19 15:04:05 -08:00
err.code.should.contain('CVOTED');
2015-02-19 13:47:17 -08:00
clients[1].rejectTxProposal(x, 'xx', function(err, tx) {
should.not.exist(err);
clients[1].rejectTxProposal(x, 'xx', function(err, tx) {
2015-02-19 15:04:05 -08:00
err.code.should.contain('CVOTED');
2015-02-19 13:47:17 -08:00
done();
});
});
});
});
});
});
});
});
2015-02-20 06:23:28 -08:00
2015-02-19 15:04:05 -08:00
});
2015-02-19 13:47:17 -08:00
2015-02-20 06:23:28 -08:00
describe('Send Transaction Troposals and Locked funds', function() {
2015-02-19 15:19:01 -08:00
it('Should lock and release funds', function(done) {
2015-02-19 15:04:05 -08:00
helpers.createAndJoinWallet(clients, 2, 2, function(err, w) {
clients[0].createAddress(function(err, x0) {
should.not.exist(err);
should.exist(x0.address);
blockExplorerMock.setUtxo(x0, 1, 2);
blockExplorerMock.setUtxo(x0, 1, 2);
var opts = {
2015-02-19 16:37:13 -08:00
amount: 120000000,
2015-02-19 15:04:05 -08:00
toAddress: 'n2TBMPzPECGUfcT2EByiTJ12TPZkhN2mN5',
message: 'hola 1-1',
};
clients[0].sendTxProposal(opts, function(err, x) {
should.not.exist(err);
2015-02-19 15:19:01 -08:00
clients[0].sendTxProposal(opts, function(err, y) {
2015-02-19 15:04:05 -08:00
err.code.should.contain('INSUFFICIENTFUNDS');
2015-02-19 15:19:01 -08:00
clients[0].rejectTxProposal(x, 'no', function(err, z) {
should.not.exist(err);
z.status.should.equal('rejected');
clients[0].sendTxProposal(opts, function(err, x) {
should.not.exist(err);
done();
});
});
2015-02-19 15:04:05 -08:00
});
});
});
});
});
2015-02-20 06:23:28 -08:00
it('Should keep message and refusal texts', function(done) {
var msg = 'abcdefg';
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: msg,
};
clients[0].sendTxProposal(opts, function(err, x) {
should.not.exist(err);
clients[1].rejectTxProposal(x, 'xx', function(err, tx1) {
should.not.exist(err);
clients[2].getTxProposals({}, function(err, txs) {
should.not.exist(err);
txs[0].decryptedMessage.should.equal(msg);
_.values(txs[0].actions)[0].comment.should.equal('xx');
done();
});
});
});
});
2015-02-17 06:52:29 -08:00
});
2015-02-17 07:39:11 -08:00
});
});
2015-02-16 10:04:25 -08:00
2015-02-17 13:04:13 -08:00
2015-02-18 10:44:34 -08:00
2015-02-20 06:23:28 -08:00
/*
2015-02-17 07:39:11 -08:00
describe('#signTxProposal ', function() {
it.skip('should sign tx proposal', function(done) {});
it('should detect fake tx proposal signature', function(done) {
2015-02-19 05:33:59 -08:00
client.storage.fs.readFile = sinon.stub().yields(null, JSON.stringify(TestData.storage.complete11));
2015-02-17 07:39:11 -08:00
var txp = {
2015-02-19 05:33:59 -08:00
creatorId: '56cb00afd85f4f37fa900ac4e367676f2eb6189a773633eb9f119eb21a22ba44',
2015-02-17 07:39:11 -08:00
toAddress: '2N3fA6wDtnebzywPkGuNK9KkFaEzgbPRRTq',
amount: 100000,
message: 'some message',
proposalSignature: 'dummy',
changeAddress: {
address: '2N3fA6wDtnebzywPkGuNK9KkFaEzgbPRRTq',
path: 'm/2147483647/0/7',
publicKeys: ['03f6a5fe8db51bfbaf26ece22a3e3bc242891a47d3048fc70bc0e8c03a071ad76f']
},
2015-02-16 10:04:25 -08:00
};
2015-02-17 07:39:11 -08:00
client.signTxProposal(txp, function(err) {
err.code.should.equal('SERVERCOMPROMISED');
err.message.should.contain('fake transaction proposal');
2015-02-16 10:04:25 -08:00
done();
});
2015-02-17 07:39:11 -08:00
});
it('should detect fake tx proposal change address', function(done) {
var txp = {
toAddress: '2N3fA6wDtnebzywPkGuNK9KkFaEzgbPRRTq',
amount: 100000,
message: 'some message',
proposalSignature: '3045022100e2d9ef7ed592217ab2256fdcf9627075f35ecdf431dde8c9a9c9422b7b1fb00f02202bc8ce066db4401bdbafb2492c3138debbc69c4c01db50d8c22a227e744c8906',
changeAddress: {
address: '2N3fA6wDtnebzywPkGuNK9KkFaEzgbPRRTq',
path: 'm/2147483647/0/8',
publicKeys: ['03f6a5fe8db51bfbaf26ece22a3e3bc242891a47d3048fc70bc0e8c03a071ad76f']
},
2015-02-16 10:04:25 -08:00
};
2015-02-17 07:39:11 -08:00
client.signTxProposal(txp, function(err) {
2015-02-16 11:23:42 -08:00
err.code.should.equal('SERVERCOMPROMISED');
2015-02-17 07:39:11 -08:00
err.message.should.contain('fake transaction proposal');
2015-02-16 10:04:25 -08:00
done();
});
2015-02-17 07:39:11 -08:00
});
});
2015-02-19 12:38:48 -08:00
*/
2015-02-16 10:04:25 -08:00
});