add api tests
This commit is contained in:
parent
83f59ddfbb
commit
ce8aeee3a9
|
@ -35,7 +35,8 @@ Verifier.checkCopayers = function(copayers, walletPrivKey, myXPrivKey, n) {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Not signed pub keys
|
// Not signed pub keys
|
||||||
if (!WalletUtils.verifyMessage(copayer.xPubKey, copayer.xPubKeySignature, walletPubKey)) {
|
if (!copayer.xPubKey || !copayer.xPubKeySignature ||
|
||||||
|
!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;
|
||||||
}
|
}
|
||||||
|
|
|
@ -420,7 +420,7 @@ API.prototype.import = function(str, cb) {
|
||||||
|
|
||||||
var xPubKey = (new Bitcore.HDPublicKey(data.xPrivKey)).toString();
|
var xPubKey = (new Bitcore.HDPublicKey(data.xPrivKey)).toString();
|
||||||
|
|
||||||
data.publicKeyRing.push(xPubKey);
|
data.publicKeyRing.unshift(xPubKey);
|
||||||
data.copayerId = WalletUtils.xPubToCopayerId(xPubKey);
|
data.copayerId = WalletUtils.xPubToCopayerId(xPubKey);
|
||||||
data.n = data.publicKeyRing.length;
|
data.n = data.publicKeyRing.length;
|
||||||
data.signingPrivKey = (new Bitcore.HDPrivateKey(data.xPrivKey)).derive('m/1/0').privateKey.toWIF();
|
data.signingPrivKey = (new Bitcore.HDPrivateKey(data.xPrivKey)).derive('m/1/0').privateKey.toWIF();
|
||||||
|
|
|
@ -26,15 +26,18 @@ var TxProposal = require('./model/txproposal');
|
||||||
var Notification = require('./model/notification');
|
var Notification = require('./model/notification');
|
||||||
|
|
||||||
var initialized = false;
|
var initialized = false;
|
||||||
var storage;
|
var storage, blockExplorer;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Creates an instance of the Copay server.
|
* Creates an instance of the Copay server.
|
||||||
* @constructor
|
* @constructor
|
||||||
*/
|
*/
|
||||||
function CopayServer() {
|
function CopayServer() {
|
||||||
if (!initialized) throw new Error('Server not initialized');
|
if (!initialized)
|
||||||
|
throw new Error('Server not initialized');
|
||||||
|
|
||||||
this.storage = storage;
|
this.storage = storage;
|
||||||
|
this.blockExplorer = blockExplorer;
|
||||||
this.notifyTicker = 0;
|
this.notifyTicker = 0;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -45,10 +48,12 @@ nodeutil.inherits(CopayServer, events.EventEmitter);
|
||||||
* Initializes global settings for all instances.
|
* Initializes global settings for all instances.
|
||||||
* @param {Object} opts
|
* @param {Object} opts
|
||||||
* @param {Storage} [opts.storage] - The storage provider.
|
* @param {Storage} [opts.storage] - The storage provider.
|
||||||
|
* @param {Storage} [opts.blockExplorer] - The blockExporer provider.
|
||||||
*/
|
*/
|
||||||
CopayServer.initialize = function(opts) {
|
CopayServer.initialize = function(opts) {
|
||||||
opts = opts || {};
|
opts = opts || {};
|
||||||
storage = opts.storage || new Storage();
|
storage = opts.storage || new Storage();
|
||||||
|
blockExplorer = opts.blockExplorer;
|
||||||
initialized = true;
|
initialized = true;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -311,6 +316,9 @@ CopayServer.prototype.verifyMessageSignature = function(opts, cb) {
|
||||||
CopayServer.prototype._getBlockExplorer = function(provider, network) {
|
CopayServer.prototype._getBlockExplorer = function(provider, network) {
|
||||||
var url;
|
var url;
|
||||||
|
|
||||||
|
if (this.blockExplorer)
|
||||||
|
return this.blockExplorer;
|
||||||
|
|
||||||
switch (provider) {
|
switch (provider) {
|
||||||
default:
|
default:
|
||||||
case 'insight':
|
case 'insight':
|
||||||
|
@ -352,7 +360,6 @@ CopayServer.prototype._getUtxos = function(cb) {
|
||||||
var utxos = _.map(inutxos, function(i) {
|
var utxos = _.map(inutxos, function(i) {
|
||||||
return i.toObject();
|
return i.toObject();
|
||||||
});
|
});
|
||||||
|
|
||||||
self.getPendingTxs({}, function(err, txps) {
|
self.getPendingTxs({}, function(err, txps) {
|
||||||
if (err) return cb(err);
|
if (err) return cb(err);
|
||||||
|
|
||||||
|
|
|
@ -1,4 +1,5 @@
|
||||||
var _ = require('lodash');
|
var _ = require('lodash');
|
||||||
|
var $ = require('preconditions').singleton();
|
||||||
var sjcl = require('sjcl');
|
var sjcl = require('sjcl');
|
||||||
|
|
||||||
var Bitcore = require('bitcore');
|
var Bitcore = require('bitcore');
|
||||||
|
@ -14,6 +15,7 @@ function WalletUtils() {};
|
||||||
/* TODO: It would be nice to be compatible with bitcoind signmessage. How
|
/* TODO: It would be nice to be compatible with bitcoind signmessage. How
|
||||||
* the hash is calculated there? */
|
* the hash is calculated there? */
|
||||||
WalletUtils.hashMessage = function(text) {
|
WalletUtils.hashMessage = function(text) {
|
||||||
|
$.checkArgument(text);
|
||||||
var buf = new Buffer(text);
|
var buf = new Buffer(text);
|
||||||
var ret = crypto.Hash.sha256sha256(buf);
|
var ret = crypto.Hash.sha256sha256(buf);
|
||||||
ret = new Bitcore.encoding.BufferReader(ret).readReverse();
|
ret = new Bitcore.encoding.BufferReader(ret).readReverse();
|
||||||
|
@ -22,6 +24,7 @@ WalletUtils.hashMessage = function(text) {
|
||||||
|
|
||||||
|
|
||||||
WalletUtils.signMessage = function(text, privKey) {
|
WalletUtils.signMessage = function(text, privKey) {
|
||||||
|
$.checkArgument(text);
|
||||||
var priv = new PrivateKey(privKey);
|
var priv = new PrivateKey(privKey);
|
||||||
var hash = WalletUtils.hashMessage(text);
|
var hash = WalletUtils.hashMessage(text);
|
||||||
return crypto.ECDSA.sign(hash, priv, 'little').toString();
|
return crypto.ECDSA.sign(hash, priv, 'little').toString();
|
||||||
|
@ -29,6 +32,7 @@ WalletUtils.signMessage = function(text, privKey) {
|
||||||
|
|
||||||
|
|
||||||
WalletUtils.verifyMessage = function(text, signature, pubKey) {
|
WalletUtils.verifyMessage = function(text, signature, pubKey) {
|
||||||
|
$.checkArgument(signature, text, pubKey);
|
||||||
var pub = new PublicKey(pubKey);
|
var pub = new PublicKey(pubKey);
|
||||||
var hash = WalletUtils.hashMessage(text);
|
var hash = WalletUtils.hashMessage(text);
|
||||||
|
|
||||||
|
@ -69,6 +73,7 @@ WalletUtils.toSecret = function(walletId, walletPrivKey, network) {
|
||||||
};
|
};
|
||||||
|
|
||||||
WalletUtils.fromSecret = function(secret) {
|
WalletUtils.fromSecret = function(secret) {
|
||||||
|
$.checkArgument(secret);
|
||||||
var secretSplit = secret.split(':');
|
var secretSplit = secret.split(':');
|
||||||
var walletId = secretSplit[0];
|
var walletId = secretSplit[0];
|
||||||
var walletPrivKey = Bitcore.PrivateKey.fromString(secretSplit[1]);
|
var walletPrivKey = Bitcore.PrivateKey.fromString(secretSplit[1]);
|
||||||
|
@ -105,7 +110,6 @@ WalletUtils.UNITS = {
|
||||||
|
|
||||||
WalletUtils.parseAmount = function(text) {
|
WalletUtils.parseAmount = function(text) {
|
||||||
var regex = '^(\\d*(\\.\\d{0,8})?)\\s*(' + _.keys(WalletUtils.UNITS).join('|') + ')?$';
|
var regex = '^(\\d*(\\.\\d{0,8})?)\\s*(' + _.keys(WalletUtils.UNITS).join('|') + ')?$';
|
||||||
|
|
||||||
var match = new RegExp(regex, 'i').exec(text.trim());
|
var match = new RegExp(regex, 'i').exec(text.trim());
|
||||||
|
|
||||||
if (!match || match.length === 0) throw new Error('Invalid amount');
|
if (!match || match.length === 0) throw new Error('Invalid amount');
|
||||||
|
|
|
@ -39,7 +39,7 @@ helpers.getRequest = function(app) {
|
||||||
};
|
};
|
||||||
|
|
||||||
helpers.createAndJoinWallet = function(clients, m, n, cb) {
|
helpers.createAndJoinWallet = function(clients, m, n, cb) {
|
||||||
clients[0].createWallet('wallet name', 'creator copayer', m, n, 'testnet',
|
clients[0].createWallet('wallet name', 'creator', m, n, 'testnet',
|
||||||
function(err, secret) {
|
function(err, secret) {
|
||||||
if (err) return cb(err);
|
if (err) return cb(err);
|
||||||
if (n == 1) return cb();
|
if (n == 1) return cb();
|
||||||
|
@ -51,12 +51,17 @@ helpers.createAndJoinWallet = function(clients, m, n, cb) {
|
||||||
return cb(err);
|
return cb(err);
|
||||||
});
|
});
|
||||||
}, function(err) {
|
}, function(err) {
|
||||||
if (err) return new Error('Could not generate wallet');
|
if (err) return cb(err);
|
||||||
return cb();
|
return cb(null, {
|
||||||
|
m: m,
|
||||||
|
n: n,
|
||||||
|
secret: secret,
|
||||||
|
});
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
var fsmock = {};
|
var fsmock = {};
|
||||||
var content = {};
|
var content = {};
|
||||||
fsmock.readFile = function(name, enc, cb) {
|
fsmock.readFile = function(name, enc, cb) {
|
||||||
|
@ -69,9 +74,47 @@ fsmock.writeFile = function(name, data, cb) {
|
||||||
content[name] = data;
|
content[name] = data;
|
||||||
return cb();
|
return cb();
|
||||||
};
|
};
|
||||||
|
fsmock.reset = function() {
|
||||||
|
content = {};
|
||||||
|
};
|
||||||
|
|
||||||
|
fsmock._get = function(name) {
|
||||||
|
return content[name];
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
var utxos = [];
|
||||||
|
var blockExplorerMock = {};
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
blockExplorerMock.getUnspentUtxos = function(dummy, cb) {
|
||||||
|
var ret = _.map(utxos || [], function(x) {
|
||||||
|
x.toObject = function() {
|
||||||
|
return this;
|
||||||
|
};
|
||||||
|
return x;
|
||||||
|
});
|
||||||
|
return cb(null, ret);
|
||||||
|
};
|
||||||
|
|
||||||
|
blockExplorerMock.setUtxo = function(address, amount, m) {
|
||||||
|
utxos.push({
|
||||||
|
txid: Bitcore.crypto.Hash.sha256(new Buffer(Math.random() * 100000)).toString('hex'),
|
||||||
|
vout: Math.floor((Math.random() * 10) + 1),
|
||||||
|
amount: amount,
|
||||||
|
address: address.address,
|
||||||
|
scriptPubKey: Bitcore.Script.buildMultisigOut(address.publicKeys, m).toScriptHashOut(),
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
blockExplorerMock.reset = function() {
|
||||||
|
utxos = [];
|
||||||
|
};
|
||||||
|
|
||||||
describe('client API ', function() {
|
describe('client API ', function() {
|
||||||
var clients;
|
var clients, app;
|
||||||
|
|
||||||
beforeEach(function() {
|
beforeEach(function() {
|
||||||
clients = [];
|
clients = [];
|
||||||
|
@ -81,9 +124,10 @@ describe('client API ', function() {
|
||||||
var storage = new Storage({
|
var storage = new Storage({
|
||||||
db: db
|
db: db
|
||||||
});
|
});
|
||||||
var app = ExpressApp.start({
|
app = ExpressApp.start({
|
||||||
CopayServer: {
|
CopayServer: {
|
||||||
storage: storage
|
storage: storage,
|
||||||
|
blockExplorer: blockExplorerMock,
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
// Generates 5 clients
|
// Generates 5 clients
|
||||||
|
@ -99,10 +143,11 @@ describe('client API ', function() {
|
||||||
client.request = helpers.getRequest(app);
|
client.request = helpers.getRequest(app);
|
||||||
clients.push(client);
|
clients.push(client);
|
||||||
});
|
});
|
||||||
content = {};
|
fsmock.reset();
|
||||||
|
blockExplorerMock.reset();
|
||||||
});
|
});
|
||||||
|
|
||||||
describe.only('#getBalance', function() {
|
describe('Wallet Creation', function() {
|
||||||
it('should check balance in a 1-1 ', function(done) {
|
it('should check balance in a 1-1 ', function(done) {
|
||||||
helpers.createAndJoinWallet(clients, 1, 1, function(err) {
|
helpers.createAndJoinWallet(clients, 1, 1, function(err) {
|
||||||
should.not.exist(err);
|
should.not.exist(err);
|
||||||
|
@ -112,7 +157,7 @@ describe('client API ', function() {
|
||||||
})
|
})
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
it('should be able to check balance in a 2-3 wallet ', function(done) {
|
it('should be able to complete wallets in copayer that joined later', function(done) {
|
||||||
helpers.createAndJoinWallet(clients, 2, 3, function(err) {
|
helpers.createAndJoinWallet(clients, 2, 3, function(err) {
|
||||||
should.not.exist(err);
|
should.not.exist(err);
|
||||||
clients[0].getBalance(function(err, x) {
|
clients[0].getBalance(function(err, x) {
|
||||||
|
@ -127,105 +172,212 @@ describe('client API ', function() {
|
||||||
})
|
})
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
});
|
|
||||||
|
|
||||||
describe('#_tryToComplete ', function() {
|
it('should not allow to join a full wallet ', function(done) {
|
||||||
it('should complete a wallet ', function(done) {
|
helpers.createAndJoinWallet(clients, 2, 2, function(err, w) {
|
||||||
client.storage.fs.readFile =
|
|
||||||
sinon.stub().yields(null, JSON.stringify(TestData.storage.incompleteWallet22));
|
|
||||||
|
|
||||||
|
|
||||||
client.getBalance(function(err, x) {
|
|
||||||
should.not.exist(err);
|
should.not.exist(err);
|
||||||
|
should.exist(w.secret);
|
||||||
|
clients[4].joinWallet(w.secret, 'copayer', function(err, result) {
|
||||||
|
err.should.contain('Request error');
|
||||||
|
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) {
|
||||||
|
err.should.contain('Request error');
|
||||||
done();
|
done();
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
||||||
it('should handle incomple wallets', function(done) {
|
|
||||||
var request = sinon.stub();
|
|
||||||
|
|
||||||
// Wallet request
|
|
||||||
request.onCall(0).yields(null, {
|
|
||||||
statusCode: 200,
|
|
||||||
}, TestData.serverResponse.incompleteWallet);
|
|
||||||
|
|
||||||
client.request = request;
|
|
||||||
client.storage.fs.readFile = sinon.stub().yields(null, JSON.stringify(TestData.storage.incompleteWallet22));
|
|
||||||
client.createAddress(function(err, x) {
|
|
||||||
err.should.contain('Incomplete');
|
|
||||||
done();
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
it('should reject wallets with bad signatures', function(done) {
|
it('should reject wallets with bad signatures', function(done) {
|
||||||
var request = sinon.stub();
|
helpers.createAndJoinWallet(clients, 2, 3, function(err) {
|
||||||
// Wallet request
|
should.not.exist(err);
|
||||||
request.onCall(0).yields(null, {
|
|
||||||
statusCode: 200,
|
|
||||||
}, TestData.serverResponse.corruptWallet22);
|
|
||||||
|
|
||||||
client.request = request;
|
// Get right response
|
||||||
client.storage.fs.readFile = sinon.stub().yields(null, JSON.stringify(TestData.storage.incompleteWallet22));
|
var data = clients[0]._load(function(err, data) {
|
||||||
client.createAddress(function(err, x) {
|
var url = '/v1/wallets/';
|
||||||
err.should.contain('verified');
|
clients[0]._doGetRequest(url, data, function(err, x) {
|
||||||
done();
|
|
||||||
|
// Tamper data
|
||||||
|
x.wallet.copayers[0].xPubKey = x.wallet.copayers[1].xPubKey;
|
||||||
|
|
||||||
|
// Tamper response
|
||||||
|
clients[1]._doGetRequest = sinon.stub().yields(null, x);
|
||||||
|
|
||||||
|
clients[1].getBalance(function(err, x) {
|
||||||
|
err.should.contain('verified');
|
||||||
|
done();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should reject wallets with missing signatures ', function(done) {
|
it('should reject wallets with missing signatures', function(done) {
|
||||||
var request = sinon.stub();
|
helpers.createAndJoinWallet(clients, 2, 3, function(err) {
|
||||||
// Wallet request
|
should.not.exist(err);
|
||||||
request.onCall(0).yields(null, {
|
|
||||||
statusCode: 200,
|
|
||||||
}, TestData.serverResponse.corruptWallet222);
|
|
||||||
|
|
||||||
client.request = request;
|
// Get right response
|
||||||
client.storage.fs.readFile = sinon.stub().yields(null, JSON.stringify(TestData.storage.incompleteWallet22));
|
var data = clients[0]._load(function(err, data) {
|
||||||
client.createAddress(function(err, x) {
|
var url = '/v1/wallets/';
|
||||||
err.should.contain('verified');
|
clients[0]._doGetRequest(url, data, function(err, x) {
|
||||||
done();
|
|
||||||
|
// Tamper data
|
||||||
|
delete x.wallet.copayers[1].xPubKey;
|
||||||
|
|
||||||
|
// Tamper response
|
||||||
|
clients[1]._doGetRequest = sinon.stub().yields(null, x);
|
||||||
|
|
||||||
|
clients[1].getBalance(function(err, x) {
|
||||||
|
err.should.contain('verified');
|
||||||
|
done();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
||||||
it('should reject wallets missing caller"s pubkey', function(done) {
|
it('should reject wallets missing caller"s pubkey', function(done) {
|
||||||
var request = sinon.stub();
|
helpers.createAndJoinWallet(clients, 2, 3, function(err) {
|
||||||
// Wallet request
|
should.not.exist(err);
|
||||||
request.onCall(0).yields(null, {
|
|
||||||
statusCode: 200,
|
|
||||||
}, TestData.serverResponse.missingMyPubKey);
|
|
||||||
|
|
||||||
client.request = request;
|
// Get right response
|
||||||
client.storage.fs.readFile = sinon.stub().yields(null, JSON.stringify(TestData.storage.incompleteWallet22));
|
var data = clients[0]._load(function(err, data) {
|
||||||
client.createAddress(function(err, x) {
|
var url = '/v1/wallets/';
|
||||||
err.should.contain('verified');
|
clients[0]._doGetRequest(url, data, function(err, x) {
|
||||||
done();
|
|
||||||
|
// 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) {
|
||||||
|
err.should.contain('verified');
|
||||||
|
done();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
describe('#createAddress ', function() {
|
|
||||||
it('should check address ', function(done) {
|
|
||||||
|
|
||||||
var response = {
|
describe('Address Creation', function() {
|
||||||
createdOn: 1424105995,
|
it('should be able to create address in all copayers in a 2-3 wallet', function(done) {
|
||||||
address: '2N3fA6wDtnebzywPkGuNK9KkFaEzgbPRRTq',
|
this.timeout(5000);
|
||||||
path: 'm/2147483647/0/7',
|
helpers.createAndJoinWallet(clients, 2, 3, function(err) {
|
||||||
publicKeys: ['03f6a5fe8db51bfbaf26ece22a3e3bc242891a47d3048fc70bc0e8c03a071ad76f']
|
|
||||||
};
|
|
||||||
var request = sinon.mock().yields(null, {
|
|
||||||
statusCode: 200
|
|
||||||
}, response);
|
|
||||||
client.request = request;
|
|
||||||
|
|
||||||
|
|
||||||
client.createAddress(function(err, x) {
|
|
||||||
should.not.exist(err);
|
should.not.exist(err);
|
||||||
x.address.should.equal('2N3fA6wDtnebzywPkGuNK9KkFaEzgbPRRTq');
|
clients[0].createAddress(function(err, x0) {
|
||||||
done();
|
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();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
|
||||||
|
describe('Wallet Backups and Mobility', function() {
|
||||||
|
|
||||||
|
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();
|
||||||
|
});
|
||||||
|
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
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) {
|
||||||
|
should.not.exist(err);
|
||||||
|
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();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
|
||||||
|
describe.only('Send TXs', function() {
|
||||||
|
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);
|
||||||
|
blockExplorerMock.setUtxo(x0, 10, 1);
|
||||||
|
var opts = {
|
||||||
|
amount: 1000,
|
||||||
|
toAddress: 'n2TBMPzPECGUfcT2EByiTJ12TPZkhN2mN5',
|
||||||
|
message: 'hola 1-1',
|
||||||
|
};
|
||||||
|
clients[0].sendTxProposal(opts, function(err, x) {
|
||||||
|
should.not.exist(err);
|
||||||
|
console.log('[clientApi.js.372]',x); //TODO
|
||||||
|
done();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
/*
|
||||||
|
describe('TODO', function(x) {
|
||||||
it('should detect fake addresses ', function(done) {
|
it('should detect fake addresses ', function(done) {
|
||||||
var response = {
|
var response = {
|
||||||
createdOn: 1424105995,
|
createdOn: 1424105995,
|
||||||
|
@ -246,25 +398,6 @@ describe('client API ', function() {
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
||||||
describe('#export & #import 2-2 wallet', function() {
|
|
||||||
it('round trip ', function(done) {
|
|
||||||
client.storage.fs.readFile = sinon.stub().yields(null, JSON.stringify(TestData.storage.complete22));
|
|
||||||
client.export(function(err, str) {
|
|
||||||
should.not.exist(err);
|
|
||||||
|
|
||||||
client.storage.fs.readFile = sinon.stub().yields(null);
|
|
||||||
client.import(str, function(err, wallet) {
|
|
||||||
should.not.exist(err);
|
|
||||||
var wallet = JSON.parse(client.storage.fs.writeFile.getCall(0).args[1]);
|
|
||||||
TestData.storage.complete22.should.deep.equal(wallet);
|
|
||||||
|
|
||||||
done();
|
|
||||||
});
|
|
||||||
});
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
|
|
||||||
describe('#getTxProposals', function() {
|
describe('#getTxProposals', function() {
|
||||||
it('should return tx proposals and decrypt message', function(done) {
|
it('should return tx proposals and decrypt message', function(done) {
|
||||||
client.storage.fs.readFile = sinon.stub().yields(null, JSON.stringify(TestData.storage.complete11));
|
client.storage.fs.readFile = sinon.stub().yields(null, JSON.stringify(TestData.storage.complete11));
|
||||||
|
@ -283,10 +416,6 @@ describe('client API ', function() {
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
describe('#recreate', function() {
|
|
||||||
it.skip('Should recreate a wallet acording stored data', function(done) {});
|
|
||||||
});
|
|
||||||
|
|
||||||
describe('#sendTxProposal ', function() {
|
describe('#sendTxProposal ', function() {
|
||||||
it('should send tx proposal with encrypted message', function(done) {
|
it('should send tx proposal with encrypted message', function(done) {
|
||||||
client.storage.fs.readFile = sinon.stub().yields(null, JSON.stringify(TestData.storage.complete11));
|
client.storage.fs.readFile = sinon.stub().yields(null, JSON.stringify(TestData.storage.complete11));
|
||||||
|
@ -356,4 +485,5 @@ describe('client API ', function() {
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
*/
|
||||||
});
|
});
|
||||||
|
|
Loading…
Reference in New Issue