mirror of https://github.com/BTCPrivate/copay.git
commit
20b49e8823
|
@ -328,6 +328,8 @@ PublicKeyRing.prototype.copayersForPubkeys = function(pubkeys, paths) {
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
for(var i in inKeyMap)
|
||||
throw new Error('Pubkey not identified')
|
||||
|
||||
|
|
|
@ -25,7 +25,7 @@ function TxProposal(opts) {
|
|||
this.builder = opts.builder;
|
||||
this.createdTs = opts.createdTs;
|
||||
this.createdTs = opts.createdTs;
|
||||
this._inputSignatures = [];
|
||||
this._inputSigners = [];
|
||||
|
||||
// CopayerIds
|
||||
this.creator = opts.creator;
|
||||
|
@ -80,21 +80,20 @@ TxProposal.prototype.isPending = function(maxRejectCount) {
|
|||
|
||||
|
||||
TxProposal.prototype._updateSignedBy = function() {
|
||||
this._inputSignatures = [];
|
||||
this._inputSigners = [];
|
||||
|
||||
var tx = this.builder.build();
|
||||
for (var i in tx.ins) {
|
||||
var scriptSig = new Script(tx.ins[i].s);
|
||||
var signatureCount = scriptSig.countSignatures();
|
||||
|
||||
var info = TxProposal._infoFromRedeemScript(scriptSig);
|
||||
var txSigHash = tx.hashForSignature(info.script, parseInt(i), Transaction.SIGHASH_ALL);
|
||||
var signatureIndexes = TxProposal._verifySignatures(info.keys, scriptSig, txSigHash);
|
||||
if (signatureIndexes.length !== signatureCount)
|
||||
var signersPubKey = TxProposal._verifySignatures(info.keys, scriptSig, txSigHash);
|
||||
if (signersPubKey.length !== signatureCount)
|
||||
throw new Error('Invalid signature');
|
||||
this._inputSignatures[i] = signatureIndexes.map(function(i) {
|
||||
var r = info.keys[i].toString('hex');
|
||||
return r;
|
||||
});
|
||||
|
||||
this._inputSigners[i] = signersPubKey;
|
||||
};
|
||||
};
|
||||
|
||||
|
@ -163,8 +162,11 @@ TxProposal._formatKeys = function(keys) {
|
|||
|
||||
var k = new Key();
|
||||
k.public = keys[i];
|
||||
ret.push(k);
|
||||
};
|
||||
ret.push({
|
||||
keyObj: k,
|
||||
keyHex: keys[i].toString('hex'),
|
||||
});
|
||||
}
|
||||
return ret;
|
||||
};
|
||||
|
||||
|
@ -183,8 +185,8 @@ TxProposal._verifySignatures = function(inKeys, scriptSig, txSigHash) {
|
|||
var sigRaw = new Buffer(chunk.slice(0, chunk.length - 1));
|
||||
for (var j in keys) {
|
||||
var k = keys[j];
|
||||
if (k.verifySignatureSync(txSigHash, sigRaw)) {
|
||||
ret.push(parseInt(j));
|
||||
if (k.keyObj.verifySignatureSync(txSigHash, sigRaw)) {
|
||||
ret.push(k.keyHex);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
@ -241,9 +243,9 @@ TxProposal.prototype.setSent = function(sentTxid) {
|
|||
|
||||
TxProposal.prototype._allSignatures = function() {
|
||||
var ret = {};
|
||||
for (var i in this._inputSignatures)
|
||||
for (var j in this._inputSignatures[i])
|
||||
ret[this._inputSignatures[i][j]] = true;
|
||||
for (var i in this._inputSigners)
|
||||
for (var j in this._inputSigners[i])
|
||||
ret[this._inputSigners[i][j]] = true;
|
||||
|
||||
return ret;
|
||||
};
|
||||
|
@ -274,9 +276,10 @@ TxProposal.prototype.setCopayers = function(senderId, keyMap, readOnlyPeers) {
|
|||
}
|
||||
|
||||
|
||||
var iSig = this._inputSignatures[0];
|
||||
var iSig = this._inputSigners[0];
|
||||
for (var i in iSig) {
|
||||
var copayerId = keyMap[iSig[i]];
|
||||
|
||||
if (!copayerId)
|
||||
throw new Error('Found unknown signature')
|
||||
|
||||
|
|
|
@ -173,24 +173,32 @@ txId: ntxid
|
|||
*/
|
||||
Wallet.prototype._getKeyMap = function(txp) {
|
||||
preconditions.checkArgument(txp);
|
||||
var inSig0, keyMapAll = {};
|
||||
|
||||
var keyMap = this.publicKeyRing.copayersForPubkeys(txp._inputSignatures[0], txp.inputChainPaths);
|
||||
for (var i in txp._inputSigners) {
|
||||
var keyMap = this.publicKeyRing.copayersForPubkeys(txp._inputSigners[i], txp.inputChainPaths);
|
||||
|
||||
var inSig = JSON.stringify(txp._inputSignatures[0].sort());
|
||||
if (Object.keys(keyMap).length !== txp._inputSigners[i].length)
|
||||
throw new Error('Signature does not match known copayers');
|
||||
|
||||
if (JSON.stringify(Object.keys(keyMap).sort()) !== inSig) {
|
||||
throw new Error('inputSignatures dont match know copayers pubkeys');
|
||||
for (var j in keyMap) {
|
||||
keyMapAll[j] = keyMap[j];
|
||||
}
|
||||
|
||||
var keyMapStr = JSON.stringify(keyMap);
|
||||
// All inputs must be signed with the same copayers
|
||||
for (var i in txp._inputSignatures) {
|
||||
if (!i) continue;
|
||||
var inSigX = JSON.stringify(txp._inputSignatures[i].sort());
|
||||
if (inSigX !== inSig)
|
||||
throw new Error('found inputs with different signatures:');
|
||||
// From here -> only to check that all inputs have the same sigs
|
||||
var inSigArr = [];
|
||||
Object.keys(keyMap).forEach(function(k) {
|
||||
inSigArr.push(keyMap[k]);
|
||||
});
|
||||
var inSig = JSON.stringify(inSigArr.sort());
|
||||
if (i === '0') {
|
||||
inSig0 = inSig;
|
||||
continue;
|
||||
}
|
||||
return keyMap;
|
||||
if (inSig !== inSig0)
|
||||
throw new Error('found inputs with different signatures');
|
||||
}
|
||||
return keyMapAll;
|
||||
};
|
||||
|
||||
|
||||
|
@ -717,7 +725,7 @@ Wallet.prototype.purgeTxProposals = function(deleteAll) {
|
|||
this.store();
|
||||
|
||||
var n = this.txProposals.length();
|
||||
return m-n;
|
||||
return m - n;
|
||||
};
|
||||
|
||||
Wallet.prototype.reject = function(ntxid) {
|
||||
|
|
|
@ -189,7 +189,7 @@ describe('TxProposal', function() {
|
|||
var txp = dummyProposal;
|
||||
var tx = dummyProposal.builder.build();
|
||||
var ret = TxProposal._verifySignatures(pubkeys, validScriptSig, tx.hashForSignature());
|
||||
ret.should.deep.equal([0, 3]);
|
||||
ret.should.deep.equal(['03197599f6e209cefef07da2fddc6fe47715a70162c531ffff8e611cef23dfb70d', '03a94351fecc4328bb683bf93a1aa67378374904eac5980c7966723a51897c56e3']);
|
||||
});
|
||||
it('#_infoFromRedeemScript', function() {
|
||||
var info = TxProposal._infoFromRedeemScript(validScriptSig);
|
||||
|
@ -202,7 +202,7 @@ describe('TxProposal', function() {
|
|||
});
|
||||
it('#_updateSignedBy', function() {
|
||||
var txp = dummyProposal;
|
||||
txp._inputSignatures.should.deep.equal([
|
||||
txp._inputSigners.should.deep.equal([
|
||||
['03197599f6e209cefef07da2fddc6fe47715a70162c531ffff8e611cef23dfb70d', '03a94351fecc4328bb683bf93a1aa67378374904eac5980c7966723a51897c56e3']
|
||||
]);
|
||||
});
|
||||
|
@ -302,7 +302,7 @@ describe('TxProposal', function() {
|
|||
txp.signedBy = {
|
||||
'hugo': 1
|
||||
};
|
||||
txp._inputSignatures = [
|
||||
txp._inputSigners = [
|
||||
['pkX']
|
||||
];
|
||||
(function() {
|
||||
|
@ -319,7 +319,7 @@ describe('TxProposal', function() {
|
|||
txp.signedBy = {
|
||||
creator: 1
|
||||
};
|
||||
txp._inputSignatures = [
|
||||
txp._inputSigners = [
|
||||
['pk0', 'pkX']
|
||||
];
|
||||
(function() {
|
||||
|
@ -333,7 +333,7 @@ describe('TxProposal', function() {
|
|||
it.skip("should be signed by sender", function() {
|
||||
var txp = dummyProposal;
|
||||
var ts = Date.now();
|
||||
txp._inputSignatures = [
|
||||
txp._inputSigners = [
|
||||
['pk1', 'pk0']
|
||||
];
|
||||
txp.signedBy = {
|
||||
|
@ -352,7 +352,7 @@ describe('TxProposal', function() {
|
|||
it("should set signedBy (trivial case)", function() {
|
||||
var txp = dummyProposal;
|
||||
var ts = Date.now();
|
||||
txp._inputSignatures = [
|
||||
txp._inputSigners = [
|
||||
['pk1', 'pk0']
|
||||
];
|
||||
txp.signedBy = {
|
||||
|
@ -370,7 +370,7 @@ describe('TxProposal', function() {
|
|||
it("should assign creator", function() {
|
||||
var txp = dummyProposal;
|
||||
var ts = Date.now();
|
||||
txp._inputSignatures = [
|
||||
txp._inputSigners = [
|
||||
['pk0']
|
||||
];
|
||||
txp.signedBy = {};
|
||||
|
@ -392,7 +392,7 @@ describe('TxProposal', function() {
|
|||
txp.signedBy = {};
|
||||
delete txp['creator'];
|
||||
delete txp['creatorTs'];
|
||||
txp._inputSignatures = [
|
||||
txp._inputSigners = [
|
||||
['pk0', 'pk1']
|
||||
];
|
||||
(function() {
|
||||
|
@ -411,7 +411,7 @@ describe('TxProposal', function() {
|
|||
it("if signed, should not change ts", function() {
|
||||
var txp = dummyProposal;
|
||||
var ts = Date.now();
|
||||
txp._inputSignatures = [
|
||||
txp._inputSigners = [
|
||||
['pk0', 'pk1']
|
||||
];
|
||||
txp.creator = 'creator';
|
||||
|
|
|
@ -219,7 +219,7 @@ describe('Wallet model', function() {
|
|||
|
||||
var t = w.txProposals;
|
||||
var txp = t.txps[ntxid];
|
||||
Object.keys(txp._inputSignatures).length.should.equal(1);
|
||||
Object.keys(txp._inputSigners).length.should.equal(1);
|
||||
var tx = txp.builder.build();
|
||||
should.exist(tx);
|
||||
chai.expect(txp.comment).to.be.null;
|
||||
|
@ -509,9 +509,9 @@ describe('Wallet model', function() {
|
|||
}
|
||||
};
|
||||
|
||||
var stub = sinon.stub(w.publicKeyRing,'copayersForPubkeys').returns(
|
||||
{'027445ab3a935dce7aee1dadb0d103ed6147a0f83deb80474a04538b2c5bc4d509':'pepe'}
|
||||
);
|
||||
var stub = sinon.stub(w.publicKeyRing, 'copayersForPubkeys').returns({
|
||||
'027445ab3a935dce7aee1dadb0d103ed6147a0f83deb80474a04538b2c5bc4d509': 'pepe'
|
||||
});
|
||||
w._handleTxProposal('senderID', txp, true);
|
||||
Object.keys(w.txProposals.txps).length.should.equal(1);
|
||||
w.getTxProposals().length.should.equal(1);
|
||||
|
@ -765,7 +765,7 @@ describe('Wallet model', function() {
|
|||
});
|
||||
});
|
||||
|
||||
describe('#createTxSync', function () {
|
||||
describe('#createTxSync', function() {
|
||||
it('should fail if amount below min value', function() {
|
||||
var w = cachedCreateW2();
|
||||
var utxo = createUTXO(w);
|
||||
|
@ -872,9 +872,9 @@ describe('Wallet model', function() {
|
|||
});
|
||||
|
||||
sinon.assert.callCount(updateIndex, 4);
|
||||
sinon.assert.calledWith(updateIndex, w.publicKeyRing.indexes[0] );
|
||||
sinon.assert.calledWith(updateIndex, w.publicKeyRing.indexes[1] );
|
||||
sinon.assert.calledWith(updateIndex, w.publicKeyRing.indexes[2] );
|
||||
sinon.assert.calledWith(updateIndex, w.publicKeyRing.indexes[0]);
|
||||
sinon.assert.calledWith(updateIndex, w.publicKeyRing.indexes[1]);
|
||||
sinon.assert.calledWith(updateIndex, w.publicKeyRing.indexes[2]);
|
||||
w.updateIndex.restore();
|
||||
done();
|
||||
});
|
||||
|
@ -898,8 +898,8 @@ describe('Wallet model', function() {
|
|||
index.receiveIndex.should.equal(9);
|
||||
index.changeIndex.should.equal(9);
|
||||
indexDiscovery.callCount.should.equal(2);
|
||||
sinon.assert.calledWith(indexDiscovery, 1, true, 2, 20 );
|
||||
sinon.assert.calledWith(indexDiscovery, 2, false, 2, 20 );
|
||||
sinon.assert.calledWith(indexDiscovery, 1, true, 2, 20);
|
||||
sinon.assert.calledWith(indexDiscovery, 2, false, 2, 20);
|
||||
w.indexDiscovery.restore();
|
||||
done();
|
||||
});
|
||||
|
@ -1108,7 +1108,7 @@ describe('Wallet model', function() {
|
|||
};
|
||||
});
|
||||
var txp = {
|
||||
_inputSignatures: [
|
||||
_inputSigners: [
|
||||
['123']
|
||||
],
|
||||
inputChainPaths: ['/m/1'],
|
||||
|
@ -1121,19 +1121,34 @@ describe('Wallet model', function() {
|
|||
|
||||
it('should throw if unmatched sigs', function() {
|
||||
var stub = sinon.stub(w.publicKeyRing, 'copayersForPubkeys', function() {
|
||||
return {
|
||||
'123': 'juan'
|
||||
};
|
||||
return {};
|
||||
});
|
||||
var txp = {
|
||||
_inputSignatures: [
|
||||
_inputSigners: [
|
||||
['234']
|
||||
],
|
||||
inputChainPaths: ['/m/1'],
|
||||
};
|
||||
(function() {
|
||||
w._getKeyMap(txp);
|
||||
}).should.throw('dont match know copayers');
|
||||
}).should.throw('does not match known copayers');
|
||||
stub.restore();
|
||||
});
|
||||
|
||||
it('should throw if unmatched sigs (case 2)', function() {
|
||||
var stub = sinon.stub(w.publicKeyRing, 'copayersForPubkeys', function() {
|
||||
return {};
|
||||
});
|
||||
var txp = {
|
||||
_inputSigners: [
|
||||
['234', '321'],
|
||||
['234', '322']
|
||||
],
|
||||
inputChainPaths: ['/m/1'],
|
||||
};
|
||||
(function() {
|
||||
w._getKeyMap(txp);
|
||||
}).should.throw('does not match known copayers');
|
||||
stub.restore();
|
||||
});
|
||||
|
||||
|
@ -1145,7 +1160,7 @@ describe('Wallet model', function() {
|
|||
};
|
||||
});
|
||||
var txp = {
|
||||
_inputSignatures: [
|
||||
_inputSigners: [
|
||||
['234', '123']
|
||||
],
|
||||
inputChainPaths: ['/m/1'],
|
||||
|
@ -1157,17 +1172,20 @@ describe('Wallet model', function() {
|
|||
stub.restore();
|
||||
});
|
||||
|
||||
it('should throw is one inputs has missing sigs', function() {
|
||||
it('should throw if one inputs has missing sigs', function() {
|
||||
var call = 0;
|
||||
var stub = sinon.stub(w.publicKeyRing, 'copayersForPubkeys', function() {
|
||||
return {
|
||||
return call++ ? {
|
||||
'555': 'pepe',
|
||||
} : {
|
||||
'123': 'juan',
|
||||
'234': 'pepe',
|
||||
};
|
||||
});
|
||||
var txp = {
|
||||
_inputSignatures: [
|
||||
_inputSigners: [
|
||||
['234', '123'],
|
||||
['234']
|
||||
['555']
|
||||
],
|
||||
inputChainPaths: ['/m/1'],
|
||||
};
|
||||
|
@ -1176,6 +1194,60 @@ describe('Wallet model', function() {
|
|||
}).should.throw('different sig');
|
||||
stub.restore();
|
||||
});
|
||||
|
||||
|
||||
it('should throw if one inputs has different sigs', function() {
|
||||
var call = 0;
|
||||
var stub = sinon.stub(w.publicKeyRing, 'copayersForPubkeys', function() {
|
||||
return call++ ? {
|
||||
'555': 'pepe',
|
||||
'666': 'pedro',
|
||||
} : {
|
||||
'123': 'juan',
|
||||
'234': 'pepe',
|
||||
};
|
||||
});
|
||||
var txp = {
|
||||
_inputSigners: [
|
||||
['234', '123'],
|
||||
['555', '666']
|
||||
],
|
||||
inputChainPaths: ['/m/1'],
|
||||
};
|
||||
(function() {
|
||||
w._getKeyMap(txp);
|
||||
}).should.throw('different sig');
|
||||
stub.restore();
|
||||
});
|
||||
|
||||
|
||||
it('should not throw if 2 inputs has different pubs, same copayers', function() {
|
||||
var call = 0;
|
||||
var stub = sinon.stub(w.publicKeyRing, 'copayersForPubkeys', function() {
|
||||
return call++ ? {
|
||||
'555': 'pepe',
|
||||
'666': 'pedro',
|
||||
} : {
|
||||
'123': 'pedro',
|
||||
'234': 'pepe',
|
||||
};
|
||||
});
|
||||
var txp = {
|
||||
_inputSigners: [
|
||||
['234', '123'],
|
||||
['555', '666']
|
||||
],
|
||||
inputChainPaths: ['/m/1'],
|
||||
};
|
||||
var gk = w._getKeyMap(txp);
|
||||
gk.should.deep.equal({
|
||||
'123': 'pedro',
|
||||
'234': 'pepe',
|
||||
'555': 'pepe',
|
||||
'666': 'pedro'
|
||||
});
|
||||
stub.restore();
|
||||
});
|
||||
});
|
||||
|
||||
|
||||
|
|
Loading…
Reference in New Issue