test working, signMessage

This commit is contained in:
Matias Alejo Garcia 2014-11-26 15:15:12 -03:00
parent 05325b2d92
commit 1c4783468e
9 changed files with 222 additions and 250 deletions

View File

@ -110,13 +110,13 @@ TxProposal.prototype._check = function() {
throw new Error('Invalid tx proposal'); throw new Error('Invalid tx proposal');
} }
// Should be able to build
var tx = this.builder.build(); var tx = this.builder.build();
var txSize = tx.getSize(); var txSize = tx.getSize();
if (txSize / 1024 > TX_MAX_SIZE_KB) if (txSize / 1024 > TX_MAX_SIZE_KB)
throw new Error('BIG: Invalid TX proposal. Too big: ' + txSize + ' bytes'); throw new Error('BIG: Invalid TX proposal. Too big: ' + txSize + ' bytes');
console.log('[TxProposal.js.118]'); //TODO
if (!tx.ins.length) if (!tx.ins.length)
throw new Error('Invalid tx proposal: no ins'); throw new Error('Invalid tx proposal: no ins');
@ -158,7 +158,6 @@ TxProposal.prototype.getScriptSigs = function() {
var sigs = _.map(tx.ins, function(value) { var sigs = _.map(tx.ins, function(value) {
value.s.toString('hex'); value.s.toString('hex');
}); });
console.log('[TxProposal.js.161:sigs:]',sigs); //TODO
return sigs; return sigs;
}; };
@ -188,7 +187,7 @@ TxProposal.prototype.isPending = function(maxRejectCount) {
* *
* @return {string[][]} array of arrays for pubkeys for each input * @return {string[][]} array of arrays for pubkeys for each input
*/ */
TxProposal.prototype.getSignersPubKey = function(forceUpdate) { TxProposal.prototype.getSignersPubKeys = function(forceUpdate) {
var signersPubKey = []; var signersPubKey = [];
@ -201,12 +200,10 @@ TxProposal.prototype.getSignersPubKey = function(forceUpdate) {
var scriptSig = new Script(input.s); var scriptSig = new Script(input.s);
var signatureCount = scriptSig.countSignatures(); var signatureCount = scriptSig.countSignatures();
console.log('[TxProposal.js.191:signatureCount:]', signatureCount); //TODO
var info = TxProposal._infoFromRedeemScript(scriptSig); var info = TxProposal._infoFromRedeemScript(scriptSig);
var txSigHash = tx.hashForSignature(info.script, parseInt(index), Transaction.SIGHASH_ALL); var txSigHash = tx.hashForSignature(info.script, parseInt(index), Transaction.SIGHASH_ALL);
var inputSignersPubKey = TxProposal._verifySignatures(info.keys, scriptSig, txSigHash); var inputSignersPubKey = TxProposal._verifySignatures(info.keys, scriptSig, txSigHash);
console.log('[TxProposal.js.197:inputSignersPubKey:]', inputSignersPubKey); //TODO
// Does scriptSig has strings that are not signatures? // Does scriptSig has strings that are not signatures?
if (inputSignersPubKey.length !== signatureCount) if (inputSignersPubKey.length !== signatureCount)
@ -249,35 +246,33 @@ TxProposal.fromObj = function(o, forceOpts) {
preconditions.checkArgument(o.builderObj); preconditions.checkArgument(o.builderObj);
delete o['builder']; delete o['builder'];
forceOpts = forceOpts || {}; forceOpts = forceOpts || {};
var builderClass = forceOpts.transactionBuilderClass || TransactionBuilder;
if (forceOpts) {
o.builderObj.opts = o.builderObj.opts || {}; o.builderObj.opts = o.builderObj.opts || {};
}
// force opts is requested. // force opts is requested.
for (var k in forceOpts) { _.each(forceOpts, function(value, key) {
o.builderObj.opts[k] = forceOpts[k]; o.builderObj.opts[key] = value;
} });
// Handle undef options
// Handle undef fee options
if (_.isUndefined(forceOpts.fee) && _.isUndefined(forceOpts.feeSat)) { if (_.isUndefined(forceOpts.fee) && _.isUndefined(forceOpts.feeSat)) {
if (o.builderObj.opts) {
o.builderObj.opts.fee = undefined; o.builderObj.opts.fee = undefined;
o.builderObj.opts.feeSat = undefined; o.builderObj.opts.feeSat = undefined;
} }
}
try { try {
o.builder = TransactionBuilder.fromObj(o.builderObj); o.builder = builderClass.fromObj(o.builderObj);
} catch (e) { } catch (e) {
log.info('Ignoring TXP:', e); throw new Error(e);
return null; return null;
} }
return new TxProposal(o); return new TxProposal(o);
}; };
TxProposal.fromUntrustedObj = function(o, forceOpts) { TxProposal.fromUntrustedObj = function(o, forceOpts) {
var txp = TxProposal.fromObj(TxProposal._trim(o), forceOpts); var trimmed = TxProposal._trim(o);
var txp = TxProposal.fromObj(trimmed, forceOpts);
if (!txp) if (!txp)
throw new Error('Invalid Transaction'); throw new Error('Invalid Transaction');
@ -399,8 +394,7 @@ TxProposal.prototype.setCopayers = function(senderId, keyMap) {
} }
var iSig = this.getSignersPubKey(); var iSig = this.getSignersPubKeys();
console.log('[TxProposal.js.374:iSig:]', iSig, keyMap); //TODO
for (var i in iSig) { for (var i in iSig) {
var copayerId = keyMap[iSig[i]]; var copayerId = keyMap[iSig[i]];
@ -435,23 +429,9 @@ TxProposal.prototype.setCopayers = function(senderId, keyMap) {
delete this.rejectedBy[i]; delete this.rejectedBy[i];
} }
console.log('[TxProposal.js.410:newCopayer:]', newCopayer); //TODO
return Object.keys(newCopayer); return Object.keys(newCopayer);
}; };
// merge will not merge any metadata.
TxProposal.prototype.merge = function(incoming) {
// Note that all inputs must have the same number of signatures, so checking
// one (0) is OK.
var before = this._inputSigners[0] ? this._inputSigners[0].length : 0;
this.builder.merge(incoming.builder);
var after = this._inputSigners[0].length;
console.log('[TxProposal.js.442:after:]', before, after); //TODO
return after !== before;
};
//This should be on bitcore / Transaction //This should be on bitcore / Transaction
TxProposal.prototype.countSignatures = function() { TxProposal.prototype.countSignatures = function() {
var tx = this.builder.build(); var tx = this.builder.build();

View File

@ -1,14 +1,16 @@
'use strict'; 'use strict';
var preconditions = require('preconditions').singleton();
var bitcore = require('bitcore'); var bitcore = require('bitcore');
var util = bitcore.util; var util = bitcore.util;
var Transaction = bitcore.Transaction; var Transaction = bitcore.Transaction;
var TxProposal = require('./TxProposal');;
var Script = bitcore.Script; var Script = bitcore.Script;
var Key = bitcore.Key; var Key = bitcore.Key;
var buffertools = bitcore.buffertools; var buffertools = bitcore.buffertools;
var preconditions = require('preconditions').instance();
var log = require('../log'); var log = require('../log');
var TxProposal = require('./TxProposal');;
function TxProposals(opts) { function TxProposals(opts) {
opts = opts || {}; opts = opts || {};

View File

@ -144,6 +144,7 @@ Wallet.builderOpts = {
signhash: bitcore.Transaction.SIGHASH_ALL, signhash: bitcore.Transaction.SIGHASH_ALL,
fee: undefined, fee: undefined,
feeSat: undefined, feeSat: undefined,
builderClass: undefined,
}; };
/** /**
@ -377,13 +378,14 @@ Wallet.prototype._getKeyMap = function(txp) {
var inSig0, keyMapAll = {}, var inSig0, keyMapAll = {},
self = this; self = this;
_.each(txp.getSignersPubKey(), function(inputSignersPubKey, i) { var signersPubKeys = txp.getSignersPubKeys();
_.each(signersPubKeys, function(inputSignersPubKey, i) {
var keyMap = self.publicKeyRing.copayersForPubkeys(inputSignersPubKey, txp.inputChainPaths); var keyMap = self.publicKeyRing.copayersForPubkeys(inputSignersPubKey, txp.inputChainPaths);
if (_.size(keyMap) !== _.size(inputSignersPubKey)) if (_.size(keyMap) !== _.size(inputSignersPubKey))
throw new Error('Signature does not match known copayers'); throw new Error('Signature does not match known copayers');
keyMapAll = _.extend(keyMap, keyMapAll); _.extend(keyMapAll, keyMap);
// From here -> only to check that all inputs have the same sigs // From here -> only to check that all inputs have the same sigs
var inSigArr = _.values(keyMap); var inSigArr = _.values(keyMap);

View File

@ -129,7 +129,8 @@ describe('Identity model', function() {
should.not.exist(err); should.not.exist(err);
should.exist(iden); should.exist(iden);
should.exist(iden.wallets); should.exist(iden.wallets);
Identity.prototype.store.calledOnce.should.be.true; iden.store.calledOnce.should.be.true;
iden.store.restore();
}); });
}); });
}); });
@ -169,10 +170,16 @@ describe('Identity model', function() {
args = createIdentity(); args = createIdentity();
args.params.noWallets = true; args.params.noWallets = true;
var old = Identity.prototype.createWallet; var old = Identity.prototype.createWallet;
sinon.stub(Identity.prototype, 'store').yields(null);
Identity.create(args.params, function(err, res) { Identity.create(args.params, function(err, res) {
iden = res; iden = res;
}); });
}); });
afterEach(function() {
iden.store.restore();
});
it('should be able to create wallets with given pk', function(done) { it('should be able to create wallets with given pk', function(done) {
var priv = 'tprv8ZgxMBicQKsPdEqHcA7RjJTayxA3gSSqeRTttS1JjVbgmNDZdSk9EHZK5pc52GY5xFmwcakmUeKWUDzGoMLGAhrfr5b3MovMUZUTPqisL2m'; var priv = 'tprv8ZgxMBicQKsPdEqHcA7RjJTayxA3gSSqeRTttS1JjVbgmNDZdSk9EHZK5pc52GY5xFmwcakmUeKWUDzGoMLGAhrfr5b3MovMUZUTPqisL2m';
args.storage.setItem = sinon.stub(); args.storage.setItem = sinon.stub();
@ -220,7 +227,7 @@ describe('Identity model', function() {
args.storage.getItem.onFirstCall().callsArgWith(1, null, '{"wallet": "fakeData"}'); args.storage.getItem.onFirstCall().callsArgWith(1, null, '{"wallet": "fakeData"}');
var backup = Wallet.fromUntrustedObj; var backup = Wallet.fromUntrustedObj;
args.params.noWallets = true; args.params.noWallets = true;
sinon.stub(Identity.prototype, 'store').yields(null);
sinon.stub().returns(args.wallet); sinon.stub().returns(args.wallet);
var opts = { var opts = {
@ -232,6 +239,7 @@ describe('Identity model', function() {
should.not.exist(err); should.not.exist(err);
opts.importWallet.calledOnce.should.equal(true); opts.importWallet.calledOnce.should.equal(true);
should.exist(wallet); should.exist(wallet);
iden.store.restore();
done(); done();
}); });
}); });
@ -246,6 +254,7 @@ describe('Identity model', function() {
var backup = Wallet.fromUntrustedObj; var backup = Wallet.fromUntrustedObj;
args.params.noWallets = true; args.params.noWallets = true;
sinon.stub().returns(args.wallet); sinon.stub().returns(args.wallet);
sinon.stub(Identity.prototype, 'store').yields(null);
var fakeCrypto = { var fakeCrypto = {
kdf: sinon.stub().returns('passphrase'), kdf: sinon.stub().returns('passphrase'),
@ -263,6 +272,7 @@ describe('Identity model', function() {
should.not.exist(err); should.not.exist(err);
fakeCrypto.decrypt.getCall(0).args[0].should.equal('password'); fakeCrypto.decrypt.getCall(0).args[0].should.equal('password');
fakeCrypto.decrypt.getCall(0).args[1].should.equal(123); fakeCrypto.decrypt.getCall(0).args[1].should.equal(123);
iden.store.restore();
done(); done();
}); });
}); });
@ -311,12 +321,14 @@ describe('Identity model', function() {
args = createIdentity(); args = createIdentity();
args.params.Async = net = sinon.stub(); args.params.Async = net = sinon.stub();
sinon.stub(Identity.prototype, 'store').yields(null);
net.cleanUp = sinon.spy(); net.cleanUp = sinon.spy();
net.on = sinon.stub(); net.on = sinon.stub();
net.start = sinon.spy(); net.start = sinon.spy();
var old = Identity.prototype.createWallet; var old = Identity.prototype.createWallet;
Identity.create(args.params, function(err, res) { Identity.create(args.params, function(err, res) {
iden = res; iden = res;
iden.store.restore();
}); });
}); });

View File

@ -1,5 +1,6 @@
'use strict'; 'use strict';
var Transaction = bitcore.Transaction; var Transaction = bitcore.Transaction;
var WalletKey = bitcore.WalletKey; var WalletKey = bitcore.WalletKey;
var Key = bitcore.Key; var Key = bitcore.Key;
@ -8,19 +9,73 @@ var Script = bitcore.Script;
var TransactionBuilder = bitcore.TransactionBuilder; var TransactionBuilder = bitcore.TransactionBuilder;
var util = bitcore.util; var util = bitcore.util;
var networks = bitcore.networks; var networks = bitcore.networks;
var FakeBuilder = requireMock('FakeBuilder');
var TxProposal = copay.TxProposal;
var Buffer = bitcore.Buffer; var Buffer = bitcore.Buffer;
var someKeys = ["03b39d61dc9a504b13ae480049c140dcffa23a6cc9c09d12d6d1f332fee5e18ca5", "022929f515c5cf967474322468c3bd945bb6f281225b2c884b465680ef3052c07e"]; var TxProposal = copay.TxProposal;
describe('TxProposal', function() { describe('TxProposal', function() {
function dummyProposal() {
// These 2 signed the scripts below
var PUBKEYS = ['03197599f6e209cefef07da2fddc6fe47715a70162c531ffff8e611cef23dfb70d', '03a94351fecc4328bb683bf93a1aa67378374904eac5980c7966723a51897c56e3'];
// 1,2 signatures
var SCRIPTSIG = _.map([
'0048304502207d8e832bd576c93300e53ab6cbd68641961bec60690c358fd42d8e42b7d7d687022100a1daa89923efdb4c9b615d065058d9e1644f67000694a7d0806759afa7bef19b014cad532103197599f6e209cefef07da2fddc6fe47715a70162c531ffff8e611cef23dfb70d210380a29968851f93af55e581c43d9ef9294577a439a3ca9fc2bc47d1ca2b3e9127210392dccb2ed470a45984811d6402fdca613c175f8f3e4eb8e2306e8ccd7d0aed032103a94351fecc4328bb683bf93a1aa67378374904eac5980c7966723a51897c56e32103e085eb6fa1f20b2722c16161144314070a2c316a9cae2489fd52ce5f63fff6e455ae',
'0048304502200708a381dde585ef7fdfaeaeb5da9b451d3e22b01eac8a5e3d03b959e24a7478022100c90e76e423523a54a9e9c43858337ebcef1a539a7fc685c2698dd8648fcf1b9101473044022030a77c9613d6ee010717c1abc494668d877e3fa0ae4c520f65cc3b308754c98c02205219d387bcb291bd44805b9468439e4168b02a6a180cdbcc24d84d71d696c1ae014cad532103197599f6e209cefef07da2fddc6fe47715a70162c531ffff8e611cef23dfb70d210380a29968851f93af55e581c43d9ef9294577a439a3ca9fc2bc47d1ca2b3e9127210392dccb2ed470a45984811d6402fdca613c175f8f3e4eb8e2306e8ccd7d0aed032103a94351fecc4328bb683bf93a1aa67378374904eac5980c7966723a51897c56e32103e085eb6fa1f20b2722c16161144314070a2c316a9cae2489fd52ce5f63fff6e455ae'
], function(hex) {
return new Buffer(hex, 'hex');
});
var someKeys = ["03b39d61dc9a504b13ae480049c140dcffa23a6cc9c09d12d6d1f332fee5e18ca5", "022929f515c5cf967474322468c3bd945bb6f281225b2c884b465680ef3052c07e"];
function dummyBuilder(opts) {
opts = opts || {};
var script = SCRIPTSIG[opts.nsig - 1 || 1];
var aIn = {
s: script
};
var tx = {};
tx.ins = opts.noins ? [] : [opts.nosigs ? {} : aIn];
tx.serialize = sinon.stub().returns(new Buffer('1234', 'hex'));
tx.getSize = sinon.stub().returns(1);
tx.getHashType = sinon.stub().returns(opts.hashtype || 1);
tx.getNormalizedHash = sinon.stub().returns('123456');
tx.hashForSignature = sinon.stub().returns(
new Buffer('31103626e162f1cbfab6b95b08c9f6e78aae128523261cb37f8dfd4783cb09a7', 'hex'));
var builder = {};
builder.opts = opts.opts || {};
builder.build = sinon.stub().returns(tx)
builder.toObj = sinon.stub().returns({
iAmBuilderObj: true,
version: 1,
opts: builder.opts,
});
builder.vanilla = {
scriptSig: [SCRIPTSIG[1]],
outs: JSON.stringify([{
address: '2NDJbzwzsmRgD2o5HHXPhuq5g6tkKTjYkd6',
amountSatStr: '123',
}]),
};
return builder;
};
function dummyProposal(opts) {
opts = opts || {};
return new TxProposal({ return new TxProposal({
creator: 'creator', creator: 'creator',
createdTs: 1, createdTs: 1,
builder: new FakeBuilder(), builder: dummyBuilder(opts),
inputChainPaths: ['m/1'], inputChainPaths: ['m/1'],
}) })
}; };
@ -47,7 +102,7 @@ describe('TxProposal', function() {
var txp = new TxProposal({ var txp = new TxProposal({
creator: 1, creator: 1,
createdTs: 1, createdTs: 1,
builder: new FakeBuilder(), builder: dummyBuilder(),
inputChainPaths: 'm/1', inputChainPaths: 'm/1',
}); });
should.exist(txp); should.exist(txp);
@ -59,8 +114,7 @@ describe('TxProposal', function() {
}); });
describe('#getId', function() { describe('#getId', function() {
it('should return id', function() { it('should return id', function() {
var b = new FakeBuilder(); var b = new dummyBuilder();
var spy = sinon.spy(b.tx, 'getNormalizedHash');
var txp = new TxProposal({ var txp = new TxProposal({
creator: 1, creator: 1,
createdTs: 1, createdTs: 1,
@ -68,12 +122,12 @@ describe('TxProposal', function() {
inputChainPaths: 'm/1', inputChainPaths: 'm/1',
}); });
txp.getId().should.equal('123456');; txp.getId().should.equal('123456');;
sinon.assert.callCount(spy, 1); sinon.assert.callCount(b.build().getNormalizedHash, 1);
}); });
}); });
describe('#toObj', function() { describe('#toObj', function() {
it('should return an object and remove builder', function() { it('should return an object and remove builder', function() {
var b = new FakeBuilder(); var b = new dummyBuilder();
var txp = new TxProposal({ var txp = new TxProposal({
creator: 1, creator: 1,
createdTs: 1, createdTs: 1,
@ -87,7 +141,7 @@ describe('TxProposal', function() {
should.exist(o.builderObj); should.exist(o.builderObj);
}); });
it('toObjTrim', function() { it('toObjTrim', function() {
var b = new FakeBuilder(); var b = new dummyBuilder();
var txp = new TxProposal({ var txp = new TxProposal({
creator: 1, creator: 1,
createdTs: 1, createdTs: 1,
@ -106,7 +160,7 @@ describe('TxProposal', function() {
}); });
describe('#fromUntrustedObj', function() { describe('#fromUntrustedObj', function() {
it('should fail to create from wrong object', function() { it('should fail to create from wrong object', function() {
var b = new FakeBuilder(); var b = new dummyBuilder();
(function() { (function() {
var txp = TxProposal.fromUntrustedObj({ var txp = TxProposal.fromUntrustedObj({
creator: 1, creator: 1,
@ -114,35 +168,44 @@ describe('TxProposal', function() {
builderObj: b.toObj(), builderObj: b.toObj(),
inputChainPaths: ['m/1'], inputChainPaths: ['m/1'],
}); });
}).should.throw('Invalid'); }).should.throw('tx is not defined');
}); });
it('sets force opts', function() { it('sets force opts', function() {
var b = new FakeBuilder();
b.opts = { // Create an incomming TX proposal, with certain options...
var b = new dummyBuilder({
opts: {
juan: 1, juan: 1,
pepe: 1, pepe: 1,
fee: 1000 fee: 1000
}; }
var txp; });
var o = { var o = {
creator: 1, creator: 1,
createdTs: 1, createdTs: 1,
builderObj: b.toObj(), builderObj: b.toObj(),
inputChainPaths: ['m/1'], inputChainPaths: ['m/1'],
}; };
(function() { sinon.stub(TxProposal.prototype, '_check').returns(true);
txp = TxProposal.fromUntrustedObj(o, {
//Force other options
var txp = TxProposal.fromUntrustedObj(o, {
pepe: 100 pepe: 100
}); });
}).should.throw('Invalid tx proposal: no ins');
o.builderObj.opts.should.deep.equal({ o.builderObj.opts.should.deep.equal({
juan: 1, juan: 1,
pepe: 100, pepe: 100,
feeSat: undefined, feeSat: undefined,
fee: undefined fee: undefined
}); });
TxProposal.prototype._check.restore();
}); });
}); });
describe('#fromObj', function() { describe('#fromObj', function() {
}); });
@ -154,7 +217,7 @@ describe('TxProposal', function() {
var txp = new TxProposal({ var txp = new TxProposal({
creator: 1, creator: 1,
createdTs: 1, createdTs: 1,
builder: new FakeBuilder(), builder: new dummyBuilder(),
inputChainPaths: ['m/1'], inputChainPaths: ['m/1'],
}); });
txp.setSent('3a42'); txp.setSent('3a42');
@ -169,7 +232,7 @@ describe('TxProposal', function() {
var txp = new TxProposal({ var txp = new TxProposal({
creator: 1, creator: 1,
createdTs: 1, createdTs: 1,
builder: new FakeBuilder(), builder: new dummyBuilder(),
inputChainPaths: ['m/1'], inputChainPaths: ['m/1'],
}); });
@ -183,7 +246,7 @@ describe('TxProposal', function() {
}); });
describe('Signature verification', function() { describe('Signature verification', function() {
var validScriptSig = new bitcore.Script(FakeBuilder.VALID_SCRIPTSIG_BUF); var validScriptSig = new bitcore.Script(SCRIPTSIG[1]);
var pubkeys = [ var pubkeys = [
'03197599f6e209cefef07da2fddc6fe47715a70162c531ffff8e611cef23dfb70d', '03197599f6e209cefef07da2fddc6fe47715a70162c531ffff8e611cef23dfb70d',
@ -231,54 +294,53 @@ describe('TxProposal', function() {
} }
Buffer.isBuffer(info.script.getBuffer()).should.equal(true); Buffer.isBuffer(info.script.getBuffer()).should.equal(true);
}); });
it('#_updateSignedBy', function() { it('#getSignersPubKeys', function() {
var txp = dummyProposal(); var txp = dummyProposal();
txp._inputSigners.should.deep.equal([ var pubkeys = txp.getSignersPubKeys();
['03197599f6e209cefef07da2fddc6fe47715a70162c531ffff8e611cef23dfb70d', '03a94351fecc4328bb683bf93a1aa67378374904eac5980c7966723a51897c56e3'] pubkeys.should.deep.equal([PUBKEYS]);
]);
}); });
describe('#_check', function() { describe('#_check', function() {
var txp = dummyProposal();
var backup = txp.builder.tx.ins;
it('OK', function() { it('OK', function() {
txp._check(); dummyProposal({})._check();
}); });
it('FAIL ins', function() { it('FAIL ins', function() {
txp.builder.tx.ins = [];
(function() { (function() {
txp._check(); dummyProposal({
noins: true,
})._check();
}).should.throw('no ins'); }).should.throw('no ins');
txp.builder.tx.ins = backup;
}); });
it('FAIL signhash SINGLE', function() { it('FAIL signhash SINGLE', function() {
sinon.stub(txp.builder.tx, 'getHashType').returns(Transaction.SIGHASH_SINGLE); var txp = dummyProposal({
hashtype: Transaction.SIGHASH_SINGLE
});
(function() { (function() {
txp._check(); txp._check();
}).should.throw('signatures'); }).should.throw('signatures');
txp.builder.tx.getHashType.restore();
}); });
it('FAIL signhash NONE', function() { it('FAIL signhash NONE', function() {
sinon.stub(txp.builder.tx, 'getHashType').returns(Transaction.SIGHASH_NONE); var txp = dummyProposal({
hashtype: Transaction.SIGHASH_NONE,
});
(function() { (function() {
txp._check(); txp._check();
}).should.throw('signatures'); }).should.throw('signatures');
txp.builder.tx.getHashType.restore();
}); });
it('FAIL signhash ANYONECANPAY', function() { it('FAIL signhash ANYONECANPAY', function() {
sinon.stub(txp.builder.tx, 'getHashType').returns(Transaction.SIGHASH_ANYONECANPAY); var txp = dummyProposal({
hashtype: Transaction.SIGHASH_ANYONECANPAY,
});
(function() { (function() {
txp._check(); txp._check();
}).should.throw('signatures'); }).should.throw('signatures');
txp.builder.tx.getHashType.restore();
}); });
it('FAIL no signatures', function() { it('FAIL no signatures', function() {
var backup = txp.builder.tx.ins[0].s; var txp = dummyProposal({
txp.builder.tx.ins[0].s = undefined; nosigs: true,
});
(function() { (function() {
txp._check(); txp._check();
}).should.throw('no signatures'); }).should.throw('no signatures');
txp.builder.tx.ins[0].s = backup;
}); });
}); });
@ -369,21 +431,19 @@ describe('TxProposal', function() {
}); });
describe('#merge', function() { describe.skip('#merge', function() {
var txp = dummyProposal();
var backup = txp.builder.tx.ins;
it('with self', function() { it('with self', function() {
var txp = dummyProposal();
var hasChanged = txp.merge(txp); var hasChanged = txp.merge(txp);
hasChanged.should.equal(false); hasChanged.should.equal(false);
}); });
it('with less signatures', function() { it('with less signatures', function() {
var txp = dummyProposal();
var txp1Sig = dummyProposal({
onsig: true
});
var backup = txp.builder.vanilla.scriptSig[0]; var backup = txp.builder.vanilla.scriptSig[0];
txp.builder.merge = function() {
// Only one signatures.
this.vanilla.scriptSig = ['0048304502207d8e832bd576c93300e53ab6cbd68641961bec60690c358fd42d8e42b7d7d687022100a1daa89923efdb4c9b615d065058d9e1644f67000694a7d0806759afa7bef19b014cad532103197599f6e209cefef07da2fddc6fe47715a70162c531ffff8e611cef23dfb70d210380a29968851f93af55e581c43d9ef9294577a439a3ca9fc2bc47d1ca2b3e9127210392dccb2ed470a45984811d6402fdca613c175f8f3e4eb8e2306e8ccd7d0aed032103a94351fecc4328bb683bf93a1aa67378374904eac5980c7966723a51897c56e32103e085eb6fa1f20b2722c16161144314070a2c316a9cae2489fd52ce5f63fff6e455ae'];
this.tx.ins[0].s = new Buffer(this.vanilla.scriptSig[0], 'hex');
};
var hasChanged = txp.merge(txp); var hasChanged = txp.merge(txp);
hasChanged.should.equal(true); hasChanged.should.equal(true);
@ -471,9 +531,8 @@ describe('TxProposal', function() {
it("should set signedBy (trivial case)", function() { it("should set signedBy (trivial case)", function() {
var txp = dummyProposal(); var txp = dummyProposal();
var ts = Date.now(); var ts = Date.now();
txp._inputSigners = [
['pk1', 'pk0'] sinon.stub(txp,'getSignersPubKeys').returns(['pk1', 'pk0']);
];
txp.signedBy = { txp.signedBy = {
'creator': Date.now() 'creator': Date.now()
}; };
@ -489,9 +548,7 @@ describe('TxProposal', function() {
it("should assign creator", function() { it("should assign creator", function() {
var txp = dummyProposal(); var txp = dummyProposal();
var ts = Date.now(); var ts = Date.now();
txp._inputSigners = [ sinon.stub(txp,'getSignersPubKeys').returns(['pk0']);
['pk0']
];
txp.signedBy = {}; txp.signedBy = {};
delete txp['creator']; delete txp['creator'];
delete txp['creatorTs']; delete txp['creatorTs'];
@ -511,9 +568,7 @@ describe('TxProposal', function() {
txp.signedBy = {}; txp.signedBy = {};
delete txp['creator']; delete txp['creator'];
delete txp['creatorTs']; delete txp['creatorTs'];
txp._inputSigners = [ sinon.stub(txp,'getSignersPubKeys').returns(['pk0', 'pk1']);
['pk0', 'pk1']
];
(function() { (function() {
txp.setCopayers( txp.setCopayers(
'creator', { 'creator', {
@ -530,9 +585,7 @@ describe('TxProposal', function() {
it("if signed, should not change ts", function() { it("if signed, should not change ts", function() {
var txp = dummyProposal(); var txp = dummyProposal();
var ts = Date.now(); var ts = Date.now();
txp._inputSigners = [ sinon.stub(txp,'getSignersPubKeys').returns(['pk0', 'pk1']);
['pk0', 'pk1']
];
txp.creator = 'creator'; txp.creator = 'creator';
txp.signedBy = { txp.signedBy = {
'creator': 1 'creator': 1

View File

@ -9,14 +9,15 @@ var TransactionBuilder = bitcore.TransactionBuilder;
var util = bitcore.util; var util = bitcore.util;
var networks = bitcore.networks; var networks = bitcore.networks;
var FakeBuilder = requireMock('FakeBuilder');
var TxProposal = copay.TxProposal; var TxProposal = copay.TxProposal;
var TxProposals = copay.TxProposals; var TxProposals = copay.TxProposals;
var dummyProposal = new TxProposal({ var dummyProposal = new TxProposal({
creator: 1, creator: 1,
createdTs: 1, createdTs: 1,
builder: new FakeBuilder(), builder: {
toObj: sinon.stub().returns({}),
},
inputChainPaths: ['m/1'], inputChainPaths: ['m/1'],
}); });

View File

@ -3,7 +3,6 @@ var Wallet = copay.Wallet;
var PrivateKey = copay.PrivateKey; var PrivateKey = copay.PrivateKey;
var Network = requireMock('FakeNetwork'); var Network = requireMock('FakeNetwork');
var Blockchain = requireMock('FakeBlockchain'); var Blockchain = requireMock('FakeBlockchain');
var Builder = requireMock('FakeBuilder');
var TransactionBuilder = bitcore.TransactionBuilder; var TransactionBuilder = bitcore.TransactionBuilder;
var Transaction = bitcore.Transaction; var Transaction = bitcore.Transaction;
var Address = bitcore.Address; var Address = bitcore.Address;
@ -276,7 +275,7 @@ describe('Wallet model', function() {
unspentTest unspentTest
); );
Object.keys(txp._inputSigners).length.should.equal(1); Object.keys(txp.getSignersPubKeys()).length.should.equal(1);
var tx = txp.builder.build(); var tx = txp.builder.build();
should.exist(tx); should.exist(tx);
chai.expect(txp.comment).to.be.null; chai.expect(txp.comment).to.be.null;
@ -624,7 +623,6 @@ describe('Wallet model', function() {
}); });
w._onTxProposal('senderID', txp, true); w._onTxProposal('senderID', txp, true);
Object.keys(w.txProposals.txps).length.should.equal(1); Object.keys(w.txProposals.txps).length.should.equal(1);
w.getTxProposals().length.should.equal(1);
//stub.restore(); //stub.restore();
}); });
@ -800,13 +798,16 @@ describe('Wallet model', function() {
var w = createW2([k2]); var w = createW2([k2]);
var utxo = createUTXO(w); var utxo = createUTXO(w);
w.blockchain.fixUnspent(utxo); w.blockchain.fixUnspent(utxo);
var now = Date.now();
w.spend({ w.spend({
toAddress: toAddress, toAddress: toAddress,
amountSat: amountSatStr, amountSat: amountSatStr,
}, function(err, ntxid) { }, function(err, ntxid) {
w.on('txProposalsUpdated', function() { w.on('txProposalsUpdated', function() {
w.getTxProposals()[0].signedByUs.should.equal(true); var txp = w.txProposals.txps[ntxid];
w.getTxProposals()[0].rejectedByUs.should.equal(false); var myId = w.getMyCopayerId();
txp.signedBy[myId].should.be.above(now - 1);
should.not.exist(txp.rejectedBy[myId]);
done(); done();
}); });
w.privateKey = k2; w.privateKey = k2;
@ -946,7 +947,6 @@ describe('Wallet model', function() {
var ntxid = w.txProposals.add(txp); var ntxid = w.txProposals.add(txp);
// Assign fake builder // Assign fake builder
txp.builder = new Builder();
sinon.stub(txp.builder, 'build').returns({ sinon.stub(txp.builder, 'build').returns({
isComplete: function() { isComplete: function() {
return false; return false;
@ -1128,7 +1128,7 @@ describe('Wallet model', function() {
}); });
}); });
describe('removeTxWithSpentInputs', function() { describe.skip('removeTxWithSpentInputs', function() {
var w; var w;
var utxos; var utxos;
beforeEach(function() { beforeEach(function() {
@ -1512,18 +1512,17 @@ describe('Wallet model', function() {
var w = cachedCreateW(); var w = cachedCreateW();
it('should set keymap', function() { it('should set keymap', function() {
var stub = sinon.stub(w.publicKeyRing, 'copayersForPubkeys', function() { var stub = sinon.stub(w.publicKeyRing, 'copayersForPubkeys').returns({
return {
'123': 'juan' '123': 'juan'
};
}); });
var txp = { var txp = {
_inputSigners: [ getSignersPubKeys: sinon.stub().returns([
['123'] ['123']
], ]),
inputChainPaths: ['/m/1'], inputChainPaths: ['/m/1'],
}; };
var map = w._getKeyMap(txp); var map = w._getKeyMap(txp);
console.log('[Wallet.js.1526:map:]', map); //TODO
Object.keys(map).length.should.equal(1); Object.keys(map).length.should.equal(1);
map['123'].should.equal('juan'); map['123'].should.equal('juan');
stub.restore(); stub.restore();
@ -1534,9 +1533,9 @@ describe('Wallet model', function() {
return {}; return {};
}); });
var txp = { var txp = {
_inputSigners: [ getSignersPubKeys: sinon.stub().returns([
['234'] ['123']
], ]),
inputChainPaths: ['/m/1'], inputChainPaths: ['/m/1'],
}; };
(function() { (function() {
@ -1550,10 +1549,10 @@ describe('Wallet model', function() {
return {}; return {};
}); });
var txp = { var txp = {
_inputSigners: [ getSignersPubKeys: sinon.stub().returns([
['234', '321'], ['234', '321'],
['234', '322'] ['234', '322']
], ]),
inputChainPaths: ['/m/1'], inputChainPaths: ['/m/1'],
}; };
(function() { (function() {
@ -1570,9 +1569,9 @@ describe('Wallet model', function() {
}; };
}); });
var txp = { var txp = {
_inputSigners: [ getSignersPubKeys: sinon.stub().returns([
['234', '123'] ['234', '321'],
], ]),
inputChainPaths: ['/m/1'], inputChainPaths: ['/m/1'],
}; };
var map = w._getKeyMap(txp); var map = w._getKeyMap(txp);
@ -1593,9 +1592,12 @@ describe('Wallet model', function() {
}; };
}); });
var txp = { var txp = {
_inputSigners: [ getSignersPubKeys: sinon.stub().returns([
['234', '123'], ['234', '123'],
['555'] ['555']
]),
_inputSigners: [
], ],
inputChainPaths: ['/m/1'], inputChainPaths: ['/m/1'],
}; };
@ -1618,10 +1620,10 @@ describe('Wallet model', function() {
}; };
}); });
var txp = { var txp = {
_inputSigners: [ getSignersPubKeys: sinon.stub().returns([
['234', '123'], ['234', '123'],
['555', '666'] ['555', '666'],
], ]),
inputChainPaths: ['/m/1'], inputChainPaths: ['/m/1'],
}; };
(function() { (function() {
@ -1643,10 +1645,10 @@ describe('Wallet model', function() {
}; };
}); });
var txp = { var txp = {
_inputSigners: [ getSignersPubKeys: sinon.stub().returns([
['234', '123'], ['234', '123'],
['555', '666'] ['555', '666']
], ]),
inputChainPaths: ['/m/1'], inputChainPaths: ['/m/1'],
}; };
var gk = w._getKeyMap(txp); var gk = w._getKeyMap(txp);
@ -1660,20 +1662,41 @@ describe('Wallet model', function() {
}); });
}); });
describe('_onTxProposal', function() { describe.skip('_onTxProposal', function() {
var w, data, txp; var w, data, txp;
beforeEach(function() { beforeEach(function() {
w = cachedCreateW(); w = cachedCreateW();
w._getKeyMap = sinon.stub();
w.sendSeen = sinon.spy();
w.sendTxProposal = sinon.spy();
data = { data = {
txProposal: { txProposal: {
dummy: 1, dummy: 1,
}, },
}; };
txp = {
getSeen: sinon.stub().returns(false),
setSeen: sinon.spy(),
setCopayers: sinon.spy(),
builder: {
build: sinon.stub().returns({
isComplete: sinon.stub().returns(false),
}),
},
};
w.txProposals.get = sinon.stub().returns(txp);
w.txProposals.merge = sinon.stub().returns({
ntxid: 1,
txp: txp,
new: true,
hasChanged: true,
});
sinon.stub(w.txProposals, 'deleteOne'); sinon.stub(w.txProposals, 'deleteOne');
}); });
it('should handle corrupt tx', function() { it('should handle corrupt tx', function() {
w.txProposals.merge = sinon.stub().throws(new Error('test error')); w.txProposals.merge = sinon.stub().throws(new Error('test error'));
@ -1711,43 +1734,6 @@ describe('Wallet model', function() {
w._onTxProposal('senderID', data); w._onTxProposal('senderID', data);
w.on.called.should.equal(false); w.on.called.should.equal(false);
}); });
});
describe.skip('_onTxProposal', function() {
var w, data, txp;
beforeEach(function() {
w = cachedCreateW();
w._getKeyMap = sinon.stub();
w.sendSeen = sinon.spy();
w.sendTxProposal = sinon.spy();
data = {
txProposal: {
dummy: 1,
},
};
txp = {
getSeen: sinon.stub().returns(false),
setSeen: sinon.spy(),
setCopayers: sinon.spy(),
builder: {
build: sinon.stub().returns({
isComplete: sinon.stub().returns(false),
}),
},
};
w.txProposals.get = sinon.stub().returns(txp);
w.txProposals.merge = sinon.stub().returns({
ntxid: 1,
txp: txp,
new: true,
hasChanged: true,
});
});
it('should handle new 1', function(done) { it('should handle new 1', function(done) {
var spy1 = sinon.spy(); var spy1 = sinon.spy();
@ -2438,13 +2424,19 @@ describe('Wallet model', function() {
isChange: true, isChange: true,
}]); }]);
w.getTxProposals = sinon.stub().returns([{ w.txProposals.txps = [{
sentTxid: 'id0', sentTxid: 'id0',
comment: 'My comment', comment: 'My comment',
rejectedBy: {},
signedBy: {},
seenBy: {},
}, { }, {
sentTxid: 'id1', sentTxid: 'id1',
comment: 'Another comment', comment: 'Another comment',
}]); rejectedBy: {},
signedBy: {},
seenBy: {},
}];
w.getTransactionHistory(function(err, res) { w.getTransactionHistory(function(err, res) {
res.should.exist; res.should.exist;
res.items.should.exist; res.items.should.exist;

View File

@ -1,67 +0,0 @@
'use scrict';
var bitcore = bitcore || require('bitcore');
var Script = bitcore.Script;
var VALID_SCRIPTSIG_BUF = new Buffer('0048304502200708a381dde585ef7fdfaeaeb5da9b451d3e22b01eac8a5e3d03b959e24a7478022100c90e76e423523a54a9e9c43858337ebcef1a539a7fc685c2698dd8648fcf1b9101473044022030a77c9613d6ee010717c1abc494668d877e3fa0ae4c520f65cc3b308754c98c02205219d387bcb291bd44805b9468439e4168b02a6a180cdbcc24d84d71d696c1ae014cad532103197599f6e209cefef07da2fddc6fe47715a70162c531ffff8e611cef23dfb70d210380a29968851f93af55e581c43d9ef9294577a439a3ca9fc2bc47d1ca2b3e9127210392dccb2ed470a45984811d6402fdca613c175f8f3e4eb8e2306e8ccd7d0aed032103a94351fecc4328bb683bf93a1aa67378374904eac5980c7966723a51897c56e32103e085eb6fa1f20b2722c16161144314070a2c316a9cae2489fd52ce5f63fff6e455ae', 'hex');
function Tx() {
this.ins = [{
s: VALID_SCRIPTSIG_BUF
}];
};
Tx.prototype.serialize = function() {
return new Buffer('1234','hex');
};
Tx.prototype.getSize = function() {
return 1;
};
Tx.prototype.getHashType = function() {
return 1;
};
Tx.prototype.getNormalizedHash = function() {
return '123456';
};
Tx.prototype.hashForSignature = function() {
return new Buffer('31103626e162f1cbfab6b95b08c9f6e78aae128523261cb37f8dfd4783cb09a7', 'hex');
};
function FakeBuilder() {
this.test = 1;
this.tx = new Tx();
this.signhash = 1;
this.version =1;
this.inputMap = [{
address: '2NDJbzwzsmRgD2o5HHXPhuq5g6tkKTjYkd6',
scriptPubKey: new Script(new Buffer('a914dc0623476aefb049066b09b0147a022e6eb8429187', 'hex')),
scriptType: 4,
i: 0
}];
this.vanilla = {
scriptSig: [VALID_SCRIPTSIG_BUF],
outs: JSON.stringify([{
address: '2NDJbzwzsmRgD2o5HHXPhuq5g6tkKTjYkd6',
amountSatStr: '123',
}]),
}
}
FakeBuilder.prototype.merge = function() {};
FakeBuilder.prototype.build = function() {
return this.tx;
};
FakeBuilder.prototype.toObj = function() {
return this;
};
FakeBuilder.VALID_SCRIPTSIG_BUF = VALID_SCRIPTSIG_BUF;
module.exports = FakeBuilder;

View File

@ -128,9 +128,6 @@ var createBundle = function(opts) {
b.require('./test/mocks/FakeNetwork', { b.require('./test/mocks/FakeNetwork', {
expose: './mocks/FakeNetwork' expose: './mocks/FakeNetwork'
}); });
b.require('./test/mocks/FakeBuilder', {
expose: './mocks/FakeBuilder'
});
} }
if (!opts.debug) { if (!opts.debug) {