mirror of https://github.com/BTCPrivate/copay.git
tx proposal test. PrivateKey
This commit is contained in:
parent
f1645945d3
commit
c5b1fca910
|
@ -43,8 +43,6 @@ angular.module('copay.signin').controller('SigninController',
|
||||||
$location.path('peer');
|
$location.path('peer');
|
||||||
$rootScope.$digest();
|
$rootScope.$digest();
|
||||||
}, function() {
|
}, function() {
|
||||||
|
|
||||||
console.log('[signin.js.46] SETTING MESSAGE'); //TODO
|
|
||||||
$rootScope.flashMessage = { message: 'Connection refussed', type: 'error'};
|
$rootScope.flashMessage = { message: 'Connection refussed', type: 'error'};
|
||||||
$location.path('home');
|
$location.path('home');
|
||||||
$rootScope.$digest();
|
$rootScope.$digest();
|
||||||
|
|
|
@ -6,15 +6,19 @@ var bitcore = require('bitcore');
|
||||||
var BIP32 = bitcore.BIP32;
|
var BIP32 = bitcore.BIP32;
|
||||||
var WalletKey = bitcore.WalletKey;
|
var WalletKey = bitcore.WalletKey;
|
||||||
var networks = bitcore.networks;
|
var networks = bitcore.networks;
|
||||||
|
var util = bitcore.util;
|
||||||
var PublicKeyRing = require('./PublicKeyRing');
|
var PublicKeyRing = require('./PublicKeyRing');
|
||||||
|
|
||||||
function PrivateKey(opts) {
|
function PrivateKey(opts) {
|
||||||
this.id = opts.id;
|
|
||||||
this.network = opts.networkName === 'testnet' ?
|
this.network = opts.networkName === 'testnet' ?
|
||||||
networks.testnet : networks.livenet;
|
networks.testnet : networks.livenet;
|
||||||
this.BIP32 = opts.BIP32 || new BIP32(this.network.name);
|
this.BIP32 = opts.BIP32 || new BIP32(opts.extendedPrivateKeyString || this.network.name);
|
||||||
|
this._calcId();
|
||||||
};
|
};
|
||||||
|
|
||||||
|
PrivateKey.prototype._calcId = function() {
|
||||||
|
this.id = util.ripe160(this.BIP32.extendedPublicKey).toString('hex');
|
||||||
|
};
|
||||||
|
|
||||||
PrivateKey.prototype.getBIP32 = function(index,isChange) {
|
PrivateKey.prototype.getBIP32 = function(index,isChange) {
|
||||||
if (typeof index === 'undefined') {
|
if (typeof index === 'undefined') {
|
||||||
|
@ -24,6 +28,21 @@ PrivateKey.prototype.getBIP32 = function(index,isChange) {
|
||||||
PublicKeyRing.ChangeBranch(index):PublicKeyRing.PublicBranch(index) );
|
PublicKeyRing.ChangeBranch(index):PublicKeyRing.PublicBranch(index) );
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
PrivateKey.fromObj = function(o) {
|
||||||
|
return new PrivateKey({
|
||||||
|
extendedPrivateKeyString: o.extendedPrivateKeyString,
|
||||||
|
networkName: o.networkName,
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
PrivateKey.prototype.toObj = function() {
|
||||||
|
return {
|
||||||
|
extendedPrivateKeyString: this.BIP32.extendedPrivateKeyString(),
|
||||||
|
networkName: this.network.name,
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
PrivateKey.prototype.get = function(index,isChange) {
|
PrivateKey.prototype.get = function(index,isChange) {
|
||||||
var derivedBIP32 = this.getBIP32(index,isChange);
|
var derivedBIP32 = this.getBIP32(index,isChange);
|
||||||
var wk = new WalletKey({network: this.network});
|
var wk = new WalletKey({network: this.network});
|
||||||
|
@ -34,6 +53,7 @@ PrivateKey.prototype.get = function(index,isChange) {
|
||||||
|
|
||||||
PrivateKey.prototype.getAll = function(addressIndex, changeAddressIndex) {
|
PrivateKey.prototype.getAll = function(addressIndex, changeAddressIndex) {
|
||||||
var ret = [];
|
var ret = [];
|
||||||
|
|
||||||
for(var i=0;i<addressIndex; i++) {
|
for(var i=0;i<addressIndex; i++) {
|
||||||
ret.push(this.get(i,false));
|
ret.push(this.get(i,false));
|
||||||
}
|
}
|
||||||
|
|
|
@ -13,34 +13,53 @@ var Storage = imports.Storage || require('./Storage');
|
||||||
var storage = Storage.default();
|
var storage = Storage.default();
|
||||||
|
|
||||||
function TxProposal(opts) {
|
function TxProposal(opts) {
|
||||||
this.tx = opts.tx;
|
this.tx = opts.tx;
|
||||||
this.seenBy = {};
|
this.seenBy = opts.seenBy || {};
|
||||||
this.signedBy = {};
|
this.signedBy = opts.signedBy || {};
|
||||||
};
|
};
|
||||||
module.exports = require('soop')(TxProposal);
|
module.exports = require('soop')(TxProposal);
|
||||||
|
|
||||||
|
|
||||||
function TxProposals(opts) {
|
function TxProposals(opts) {
|
||||||
opts = opts || {};
|
opts = opts || {};
|
||||||
|
|
||||||
this.network = opts.networkName === 'livenet' ?
|
this.network = opts.networkName === 'livenet' ?
|
||||||
bitcore.networks.livenet : bitcore.networks.testnet;
|
bitcore.networks.livenet : bitcore.networks.testnet;
|
||||||
|
|
||||||
this.publicKeyRing = opts.publicKeyRing;
|
this.publicKeyRing = opts.publicKeyRing;
|
||||||
this.requiredCopayers = opts.requiredCopayers || 3;
|
|
||||||
this.txs = [];
|
this.txs = [];
|
||||||
this.dirty = 1;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
TxProposals.prototype.list = function() {
|
TxProposals.fromObj = function(o) {
|
||||||
var ret = [];
|
var ret = new TxProposals({
|
||||||
var ret = [];
|
networkName: o.networkName,
|
||||||
|
|
||||||
this.txs.forEach(function(tx) {
|
|
||||||
});
|
});
|
||||||
|
o.txs.forEach(function(t) {
|
||||||
|
var tx = new Transaction;
|
||||||
|
tx.parse(t.txHex);
|
||||||
|
ret.txs.push({
|
||||||
|
seenBy: t.seenBy,
|
||||||
|
signedBy: t.signedBy,
|
||||||
|
tx: tx,
|
||||||
|
});
|
||||||
|
});
|
||||||
|
return ret;
|
||||||
};
|
};
|
||||||
|
|
||||||
TxProposals.prototype.create = function(toAddress, amountSat, utxos, privs) {
|
TxProposals.prototype.toObj = function() {
|
||||||
|
var ret = [];
|
||||||
|
this.txs.forEach(function(t) {
|
||||||
|
ret.push({
|
||||||
|
seenBy: t.seenBy,
|
||||||
|
signedBy: t.signedBy,
|
||||||
|
txHex: t.tx.serialize(),
|
||||||
|
});
|
||||||
|
});
|
||||||
|
return {
|
||||||
|
txs: ret,
|
||||||
|
networkName: this.network.name,
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
TxProposals.prototype.create = function(toAddress, amountSat, utxos, priv) {
|
||||||
var pkr = this.publicKeyRing;
|
var pkr = this.publicKeyRing;
|
||||||
|
|
||||||
if (! pkr.isComplete() ) {
|
if (! pkr.isComplete() ) {
|
||||||
|
@ -57,18 +76,21 @@ TxProposals.prototype.create = function(toAddress, amountSat, utxos, privs) {
|
||||||
.setOutputs([{address: toAddress, amountSat: amountSat}])
|
.setOutputs([{address: toAddress, amountSat: amountSat}])
|
||||||
;
|
;
|
||||||
|
|
||||||
if (privs) {
|
if (priv) {
|
||||||
b.sign(privs);
|
//console.log('*** SIGNING IDX:', pkr.addressIndex, pkr.changeAddressIndex);
|
||||||
|
b.sign( priv.getAll(pkr.addressIndex, pkr.changeAddressIndex) );
|
||||||
}
|
}
|
||||||
|
|
||||||
var tx = b.build();
|
var tx = b.build();
|
||||||
|
var me = {};
|
||||||
|
if (priv)
|
||||||
|
me[priv.id] = Date.now();
|
||||||
|
|
||||||
this.txs.push(
|
this.txs.push(
|
||||||
new TxProposal({
|
new TxProposal({
|
||||||
signedBy: {
|
signedBy: me,
|
||||||
},
|
seenBy: me,
|
||||||
seenBy: {
|
tx: tx,
|
||||||
},
|
|
||||||
tx: tx
|
|
||||||
})
|
})
|
||||||
);
|
);
|
||||||
return tx;
|
return tx;
|
||||||
|
|
|
@ -42,30 +42,53 @@ angular.module('copay.network')
|
||||||
|
|
||||||
// TODO -> probably not in network.js
|
// TODO -> probably not in network.js
|
||||||
var createWallet = function(walletId) {
|
var createWallet = function(walletId) {
|
||||||
|
|
||||||
console.log('### CREATING WALLET. ID:' + walletId);
|
console.log('### CREATING WALLET. ID:' + walletId);
|
||||||
|
|
||||||
|
var priv = new copay.PrivateKey({networkName: config.networkName});
|
||||||
|
console.log('\t### PrivateKey Initialized');
|
||||||
|
|
||||||
//TODO create a wallet and WalletId, not only pkr
|
//TODO create a wallet and WalletId, not only pkr
|
||||||
var pkr = new copay.PublicKeyRing({
|
var pkr = new copay.PublicKeyRing({
|
||||||
network: config.networkName,
|
networkName: config.networkName,
|
||||||
id: walletId,
|
id: walletId,
|
||||||
});
|
});
|
||||||
pkr.addCopayer();
|
|
||||||
console.log('\t### PublicKeyRing Initialized:');
|
// Add self to the ring.
|
||||||
|
pkr.addCopayer(priv.getBIP32().extendedPublicKeyString());
|
||||||
|
console.log('\t### PublicKeyRing Initialized');
|
||||||
|
|
||||||
|
var txp = new copay.TxProposals({
|
||||||
|
networkName: config.networkName,
|
||||||
|
publicKeyRing: pkr,
|
||||||
|
});
|
||||||
|
console.log('\t### TxProposals Initialized');
|
||||||
|
|
||||||
Storage.addWalletId(pkr.id);
|
Storage.addWalletId(pkr.id);
|
||||||
Storage.set(pkr.id, 'publicKeyRing', pkr.toObj());
|
Storage.set(pkr.id, 'publicKeyRing', pkr.toObj());
|
||||||
|
Storage.set(pkr.id, 'privateKey', priv.toObj());
|
||||||
|
Storage.set(pkr.id, 'txProposals', txp.toObj());
|
||||||
|
console.log('\t### Wallet Stored');
|
||||||
|
|
||||||
|
// Store it on rootScope
|
||||||
|
$rootScope.priv = priv; // TODO secure this.
|
||||||
$rootScope.walletId = pkr.id;
|
$rootScope.walletId = pkr.id;
|
||||||
$rootScope.publicKeyRing = pkr;
|
$rootScope.publicKeyRing = pkr;
|
||||||
|
$rootScope.txProposals = txp;
|
||||||
};
|
};
|
||||||
|
|
||||||
var openWallet = function (walletId) {
|
var openWallet = function (walletId) {
|
||||||
var ret = false;
|
var ret = false;
|
||||||
var pkr = Storage.get(walletId, 'publicKeyRing');
|
var pkr = Storage.get(walletId, 'publicKeyRing');
|
||||||
|
var priv = Storage.get(walletId, 'privateKey');
|
||||||
|
var txp = Storage.get(walletId, 'txProposals');
|
||||||
|
|
||||||
if (pkr) {
|
if (pkr) {
|
||||||
console.log('### WALLET OPENED:', walletId, pkr);
|
console.log('### WALLET OPENED:', walletId, pkr);
|
||||||
$rootScope.walletId = walletId;
|
$rootScope.walletId = walletId;
|
||||||
$rootScope.publicKeyRing = new copay.PublicKeyRing.fromObj(pkr);
|
$rootScope.publicKeyRing = new copay.PublicKeyRing.fromObj(pkr);
|
||||||
|
$rootScope.txProposals = new copay.TxProposals.fromObj(txp);
|
||||||
|
$rootScope.priv = new copay.PrivateKey.fromObj(priv); //TODO secure
|
||||||
ret = true;
|
ret = true;
|
||||||
}
|
}
|
||||||
return ret;
|
return ret;
|
||||||
|
@ -133,7 +156,6 @@ angular.module('copay.network')
|
||||||
|
|
||||||
// public methods
|
// public methods
|
||||||
var init = function(cb) {
|
var init = function(cb) {
|
||||||
|
|
||||||
var cp = $rootScope.cp = new copay.CopayPeer({
|
var cp = $rootScope.cp = new copay.CopayPeer({
|
||||||
apiKey: config.p2pApiKey,
|
apiKey: config.p2pApiKey,
|
||||||
debug: config.p2pDebug,
|
debug: config.p2pDebug,
|
||||||
|
@ -141,7 +163,6 @@ angular.module('copay.network')
|
||||||
});
|
});
|
||||||
_setupHandlers();
|
_setupHandlers();
|
||||||
|
|
||||||
// inicia session
|
|
||||||
cp.start(function(peerId) {
|
cp.start(function(peerId) {
|
||||||
return cb();
|
return cb();
|
||||||
});
|
});
|
||||||
|
@ -156,15 +177,15 @@ angular.module('copay.network')
|
||||||
_refreshUx();
|
_refreshUx();
|
||||||
};
|
};
|
||||||
|
|
||||||
var connect = function(peerId, openCallback, failCallBack) {
|
var connect = function(peerId, openCallback, failCallback) {
|
||||||
if ($rootScope.cp) {
|
if ($rootScope.cp) {
|
||||||
$rootScope.cp.connectTo(peerId, openCallback, function () {
|
$rootScope.cp.connectTo(peerId, openCallback, function () {
|
||||||
disconnect();
|
disconnect();
|
||||||
failCallBack();
|
failCallback();
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
return failCallBack();
|
return failCallback();
|
||||||
};
|
};
|
||||||
|
|
||||||
return {
|
return {
|
||||||
|
|
|
@ -67,4 +67,25 @@ describe('PrivateKey model', function() {
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it('should calculate .id', function () {
|
||||||
|
var w1 = new PrivateKey(config);
|
||||||
|
should.exist(w1.id);
|
||||||
|
w1.id.length.should.equal(40);
|
||||||
|
});
|
||||||
|
it('fromObj toObj roundtrip', function () {
|
||||||
|
var w1 = new PrivateKey(config);
|
||||||
|
var w2 = PrivateKey.fromObj(w1.toObj());
|
||||||
|
|
||||||
|
w2.getBIP32().extendedPrivateKeyString().should.equal(w1.getBIP32().extendedPrivateKeyString());
|
||||||
|
w2.getBIP32().extendedPublicKeyString().should.equal(w1.getBIP32().extendedPublicKeyString());
|
||||||
|
w2.id.should.equal(w1.id);
|
||||||
|
|
||||||
|
|
||||||
|
w2.getBIP32(1,1).extendedPrivateKeyString().should
|
||||||
|
.equal(w1.getBIP32(1,1).extendedPrivateKeyString());
|
||||||
|
w2.getBIP32(1,0).extendedPrivateKeyString().should
|
||||||
|
.equal(w1.getBIP32(1,0).extendedPrivateKeyString());
|
||||||
|
});
|
||||||
|
|
||||||
|
|
||||||
});
|
});
|
||||||
|
|
|
@ -44,11 +44,13 @@ var createW = function (bip32s) {
|
||||||
else
|
else
|
||||||
w.addCopayer();
|
w.addCopayer();
|
||||||
}
|
}
|
||||||
w.generateAddress(true);
|
w.generateAddress(true);
|
||||||
w.generateAddress(true);
|
w.generateAddress(true);
|
||||||
w.generateAddress(true);
|
w.generateAddress(true);
|
||||||
w.generateAddress(false);
|
w.generateAddress(false);
|
||||||
w.generateAddress(false);
|
w.generateAddress(false);
|
||||||
|
w.generateAddress(false);
|
||||||
|
//3x3 indexes
|
||||||
|
|
||||||
return w;
|
return w;
|
||||||
};
|
};
|
||||||
|
@ -91,57 +93,64 @@ describe('TxProposals model', function() {
|
||||||
networkName: config.networkName,
|
networkName: config.networkName,
|
||||||
publicKeyRing: createW([priv.getBIP32()]),
|
publicKeyRing: createW([priv.getBIP32()]),
|
||||||
});
|
});
|
||||||
should.exist(w);
|
|
||||||
w.network.name.should.equal('livenet');
|
|
||||||
|
|
||||||
|
|
||||||
|
var ts = Date.now();
|
||||||
for (var isChange=0; isChange<2; isChange++) {
|
for (var isChange=0; isChange<2; isChange++) {
|
||||||
for (var index=0; index<3; index++) {
|
for (var index=0; index<3; index++) {
|
||||||
unspentTest[0].address = w.publicKeyRing.getAddress(index, isChange);
|
unspentTest[0].address = w.publicKeyRing.getAddress(index, isChange);
|
||||||
unspentTest[0].scriptPubKey = w.publicKeyRing.getRedeemScript(index, isChange).getBuffer();
|
unspentTest[0].scriptPubKey = w.publicKeyRing.getRedeemScript(index, isChange).getBuffer();
|
||||||
|
|
||||||
var tx = w.create(
|
var tx = w.create(
|
||||||
'15q6HKjWHAksHcH91JW23BJEuzZgFwydBt',
|
'15q6HKjWHAksHcH91JW23BJEuzZgFwydBt',
|
||||||
bignum('123456789'),
|
bignum('123456789'),
|
||||||
unspentTest,
|
unspentTest,
|
||||||
[priv.get(index,isChange)]
|
priv
|
||||||
);
|
);
|
||||||
should.exist(tx);
|
should.exist(tx);
|
||||||
tx.isComplete().should.equal(false);
|
tx.isComplete().should.equal(false);
|
||||||
tx.countInputMissingSignatures(0).should.equal(2);
|
tx.countInputMissingSignatures(0).should.equal(2);
|
||||||
|
(w.txs[0].signedBy[priv.id] - ts > 0).should.equal(true);
|
||||||
|
(w.txs[0].seenBy[priv.id] - ts > 0).should.equal(true);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
});
|
});
|
||||||
it('#create. Signing with derivate keys block', function () {
|
it('#toObj #fromObj roundtrip', function () {
|
||||||
|
|
||||||
var priv = new PrivateKey(config);
|
var priv = new PrivateKey(config);
|
||||||
|
|
||||||
var privs = priv.getAll(3,3);
|
|
||||||
|
|
||||||
var w = new TxProposals({
|
var w = new TxProposals({
|
||||||
networkName: config.networkName,
|
networkName: config.networkName,
|
||||||
publicKeyRing: createW([priv.getBIP32()]),
|
publicKeyRing: createW([priv.getBIP32()]),
|
||||||
});
|
});
|
||||||
should.exist(w);
|
var ts = Date.now();
|
||||||
w.network.name.should.equal('livenet');
|
var isChange=0;
|
||||||
|
var index=0;
|
||||||
|
|
||||||
for (var isChange=0; isChange<2; isChange++) {
|
unspentTest[0].address = w.publicKeyRing.getAddress(index, isChange);
|
||||||
for (var index=0; index<3; index++) {
|
unspentTest[0].scriptPubKey = w.publicKeyRing.getRedeemScript(index, isChange).getBuffer();
|
||||||
unspentTest[0].address = w.publicKeyRing.getAddress(index, isChange);
|
var tx = w.create(
|
||||||
unspentTest[0].scriptPubKey = w.publicKeyRing.getRedeemScript(index, isChange).getBuffer();
|
'15q6HKjWHAksHcH91JW23BJEuzZgFwydBt',
|
||||||
var tx = w.create(
|
bignum('123456789'),
|
||||||
'15q6HKjWHAksHcH91JW23BJEuzZgFwydBt',
|
unspentTest,
|
||||||
bignum('123456789'),
|
priv
|
||||||
unspentTest,
|
);
|
||||||
privs
|
tx.isComplete().should.equal(false);
|
||||||
);
|
tx.countInputMissingSignatures(0).should.equal(2);
|
||||||
should.exist(tx);
|
(w.txs[0].signedBy[priv.id] - ts > 0).should.equal(true);
|
||||||
tx.isComplete().should.equal(false);
|
(w.txs[0].seenBy[priv.id] - ts > 0).should.equal(true);
|
||||||
tx.countInputMissingSignatures(0).should.equal(2);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
var o = w.toObj();
|
||||||
|
should.exist(o);
|
||||||
|
o.txs.length.should.equal(1);
|
||||||
|
should.exist(o.txs[0].txHex);
|
||||||
|
should.exist(o.txs[0].signedBy);
|
||||||
|
should.exist(o.txs[0].seenBy);
|
||||||
|
should.exist(o.txs[0].signedBy[priv.id]);
|
||||||
|
|
||||||
|
var w2 = TxProposals.fromObj(o);
|
||||||
|
var tx2 = w2.txs[0].tx;
|
||||||
|
tx2.isComplete().should.equal(false);
|
||||||
|
tx2.countInputMissingSignatures(0).should.equal(2);
|
||||||
|
(w2.txs[0].signedBy[priv.id] - ts > 0).should.equal(true);
|
||||||
|
(w2.txs[0].seenBy[priv.id] - ts > 0).should.equal(true);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue