You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 

434 lines
11 KiB

'use strict';
var _ = require('lodash');
var async = require('async');
var chai = require('chai');
var sinon = require('sinon');
var should = chai.should();
var levelup = require('levelup');
var memdown = require('memdown');
var Storage = require('../lib/storage');
var Wallet = require('../lib/model/wallet');
var Address = require('../lib/model/address');
var Copayer = require('../lib/model/copayer');
var CopayServer = require('../lib/server');
var helpers = {};
helpers.createAndJoinWallet = function (id, m, n, cb) {
var walletOpts = {
id: id,
name: id + ' wallet',
m: m,
n: n,
pubKey: 'dummy',
};
server.createWallet(walletOpts, function(err) {
if (err) return cb(err);
async.each(_.range(1, n + 1), function (i, cb) {
var copayerOpts = {
walletId: id,
id: '' + i,
name: 'copayer ' + i,
xPubKey: 'dummy' + i,
xPubKeySignature: 'dummy',
};
server.joinWallet(copayerOpts, function (err) {
return cb(err);
});
}, function (err) {
if (err) return cb(err);
server.getWallet({ id: id, includeCopayers: true }, function (err, wallet) {
return cb(err, wallet);
});
});
});
};
var db, storage;
var server;
describe('Copay server', function() {
beforeEach(function() {
db = levelup(memdown, { valueEncoding: 'json' });
storage = new Storage({ db: db });
});
describe('#getWallet', function() {
beforeEach(function() {
server = new CopayServer({
storage: storage,
});
});
it('should get existing wallet', function (done) {
var w1 = new Wallet({
id: '123',
name: 'my wallet',
m: 2,
n: 3,
pubKey: 'dummy',
});
var w2 = new Wallet({
id: '234',
name: 'my wallet 2',
m: 3,
n: 4,
pubKey: 'dummy',
});
db.batch([{
type: 'put',
key: 'wallet-123',
value: w1,
}, {
type: 'put',
key: 'wallet-234',
value: w2,
}]);
server.getWallet({ id: '123', includeCopayers: true }, function (err, wallet) {
should.not.exist(err);
wallet.id.should.equal('123');
wallet.name.should.equal('my wallet');
wallet.status.should.equal('pending');
wallet.copayers.length.should.equal(0);
done();
});
});
it('should fail when requesting non-existent wallet', function (done) {
var w1 = new Wallet({
id: '123',
name: 'my wallet',
m: 2,
n: 3,
pubKey: 'dummy',
});
var w2 = new Wallet({
id: '234',
name: 'my wallet 2',
m: 3,
n: 4,
pubKey: 'dummy',
});
db.batch([{
type: 'put',
key: 'wallet-123',
value: w1,
}, {
type: 'put',
key: 'wallet-234',
value: w2,
}]);
server.getWallet({ id: '345' }, function (err, wallet) {
should.exist(err);
err.should.equal('Wallet not found');
done();
});
});
});
describe('#createWallet', function() {
beforeEach(function() {
server = new CopayServer({
storage: storage,
});
});
it('should create and store wallet', function(done) {
var opts = {
id: '123',
name: 'my wallet',
m: 2,
n: 3,
pubKey: 'dummy',
};
server.createWallet(opts, function(err) {
should.not.exist(err);
server.getWallet({ id: '123' }, function (err, wallet) {
should.not.exist(err);
wallet.id.should.equal('123');
wallet.name.should.equal('my wallet');
done();
});
});
});
it('should fail to recreate existing wallet', function(done) {
var opts = {
id: '123',
name: 'my wallet',
m: 2,
n: 3,
pubKey: 'dummy',
};
server.createWallet(opts, function(err) {
should.not.exist(err);
server.getWallet({ id: '123' }, function (err, wallet) {
should.not.exist(err);
wallet.id.should.equal('123');
wallet.name.should.equal('my wallet');
server.createWallet(opts, function(err) {
should.exist(err);
done();
});
});
});
});
});
describe('#joinWallet', function() {
beforeEach(function() {
server = new CopayServer({
storage: storage,
});
});
it('should join existing wallet', function (done) {
var walletOpts = {
id: '123',
name: 'my wallet',
m: 2,
n: 3,
pubKey: 'dummy',
};
server.createWallet(walletOpts, function(err) {
should.not.exist(err);
var copayerOpts = {
walletId: '123',
id: '999',
name: 'me',
xPubKey: 'dummy',
xPubKeySignature: 'dummy',
};
server.joinWallet(copayerOpts, function (err) {
should.not.exist(err);
server.getWallet({ id: '123', includeCopayers: true }, function (err, wallet) {
wallet.id.should.equal('123');
wallet.copayers.length.should.equal(1);
var copayer = wallet.copayers[0];
copayer.id.should.equal('999');
copayer.name.should.equal('me');
done();
});
});
});
});
it('should fail to join non-existent wallet', function (done) {
var walletOpts = {
id: '123',
name: 'my wallet',
m: 2,
n: 3,
pubKey: 'dummy',
};
server.createWallet(walletOpts, function(err) {
should.not.exist(err);
var copayerOpts = {
walletId: '234',
id: '999',
name: 'me',
xPubKey: 'dummy',
xPubKeySignature: 'dummy',
};
server.joinWallet(copayerOpts, function (err) {
should.exist(err);
done();
});
});
});
it('should fail to join full wallet', function (done) {
var walletOpts = {
id: '123',
name: 'my wallet',
m: 1,
n: 1,
pubKey: 'dummy',
};
server.createWallet(walletOpts, function(err) {
should.not.exist(err);
var copayer1Opts = {
walletId: '123',
id: '111',
name: 'me',
xPubKey: 'dummy1',
xPubKeySignature: 'dummy',
};
var copayer2Opts = {
walletId: '123',
id: '222',
name: 'me 2',
xPubKey: 'dummy2',
xPubKeySignature: 'dummy',
};
server.joinWallet(copayer1Opts, function (err) {
should.not.exist(err);
server.getWallet({ id: '123' }, function (err, wallet) {
wallet.status.should.equal('complete');
server.joinWallet(copayer2Opts, function (err) {
should.exist(err);
err.should.equal('Wallet full');
done();
});
});
});
});
});
it('should fail to re-join wallet', function (done) {
var walletOpts = {
id: '123',
name: 'my wallet',
m: 1,
n: 1,
pubKey: 'dummy',
};
server.createWallet(walletOpts, function(err) {
should.not.exist(err);
var copayerOpts = {
walletId: '123',
id: '111',
name: 'me',
xPubKey: 'dummy',
xPubKeySignature: 'dummy',
};
server.joinWallet(copayerOpts, function (err) {
should.not.exist(err);
server.joinWallet(copayerOpts, function (err) {
should.exist(err);
err.should.equal('Copayer already in wallet');
done();
});
});
});
});
it('should set pkr and status = complete on last copayer joining', function (done) {
helpers.createAndJoinWallet('123', 2, 3, function (err, wallet) {
server.getWallet({ id: '123' }, function (err, wallet) {
should.not.exist(err);
wallet.status.should.equal('complete');
wallet.publicKeyRing.length.should.equal(3);
done();
});
});
});
});
describe('#verifyMessageSignature', function() {
beforeEach(function() {
server = new CopayServer({
storage: storage,
});
});
it('should successfully verify message signature', function (done) {
server._doVerifyMessageSignature = sinon.stub().returns(true);
helpers.createAndJoinWallet('123', 2, 2, function (err, wallet) {
var opts = {
walletId: '123',
copayerId: '1',
message: 'hello world',
signature: 'dummy',
};
server.verifyMessageSignature(opts, function (err, isValid) {
should.not.exist(err);
isValid.should.be.true;
done();
});
});
});
it('should fail to verify message signature when copayer does not exist', function (done) {
helpers.createAndJoinWallet('123', 2, 2, function (err, wallet) {
var opts = {
walletId: '123',
copayerId: '999',
message: 'hello world',
signature: 'dummy',
};
server.verifyMessageSignature(opts, function (err, isValid) {
err.should.equal('Copayer not found');
done();
});
});
});
});
describe('#createAddress', function() {
beforeEach(function() {
server = new CopayServer({
storage: storage,
});
});
it('should create address', function (done) {
server._doCreateAddress = sinon.stub().returns(new Address({ address: 'addr1', path: 'path1' }));
helpers.createAndJoinWallet('123', 2, 2, function (err, wallet) {
server.createAddress({ walletId: '123' }, function (err, address) {
should.not.exist(err);
address.should.exist;
address.address.should.equal('addr1');
address.path.should.equal('path1');
done();
});
});
});
});
describe('#createTx', function() {
beforeEach(function(done) {
server = new CopayServer({
storage: storage,
});
server._doCreateAddress = sinon.stub().returns(new Address({ address: 'addr1', path: 'path1' }));
helpers.createAndJoinWallet('123', 2, 2, function (err, wallet) {
server.createAddress({ walletId: '123' }, function (err, address) {
done();
});
});
});
it('should create tx', function (done) {
var bc = sinon.stub();
bc.getUnspentUtxos = sinon.stub().callsArgWith(1, null, ['utxo1', 'utxo2']);
server._getBlockExplorer = sinon.stub().returns(bc);
server._createRawTx = sinon.stub().returns('raw');
var txOpts = {
copayerId: '1',
walletId: '123',
toAddress: 'dummy',
amount: 100,
message: 'some message',
otToken: 'dummy',
requestSignature: 'dummy',
};
server.createTx(txOpts, function (err, tx) {
should.not.exist(err);
tx.should.exist;
tx.rawTx.should.equal('raw');
tx.isAccepted().should.equal.false;
tx.isRejected().should.equal.false;
server.getPendingTxs({ walletId: '123' }, function (err, txs) {
should.not.exist(err);
txs.length.should.equal(1);
});
done();
});
});
});
});