Fix Conflicts:

views/addresses.html
	views/send.html
	views/transactions.html
This commit is contained in:
Gustavo Maximiliano Cortez 2014-09-05 17:06:25 -03:00
commit 6a855b7ac1
18 changed files with 393 additions and 89 deletions

View file

@ -13,7 +13,7 @@ if (localConfig) {
if (key === 'networkName' && config['forceNetwork']) {
return;
}
config[name] = value;
config[key] = value;
});
}
}

View file

@ -34,7 +34,7 @@ angular.module('copayApp.controllers').controller('SendController',
set: function (newValue) {
this._alternative = newValue;
if (typeof(newValue) === 'number' && $scope.isRateAvailable) {
this._amount = Number.parseFloat(
this._amount = parseFloat(
(rateService.fromFiat(newValue, config.alternativeIsoCode) * satToUnit
).toFixed(config.unitDecimals), 10);
} else {
@ -52,7 +52,7 @@ angular.module('copayApp.controllers').controller('SendController',
set: function (newValue) {
this._amount = newValue;
if (typeof(newValue) === 'number' && $scope.isRateAvailable) {
this._alternative = Number.parseFloat(
this._alternative = parseFloat(
(rateService.toFiat(newValue * config.unitToSatoshi, config.alternativeIsoCode)
).toFixed(2), 10);
} else {

View file

@ -1,23 +1,45 @@
'use strict';
// 62.9% typed (by google's closure-compiler account)
var bitcore = require('bitcore');
var HK = bitcore.HierarchicalKey;
var WalletKey = bitcore.WalletKey;
var networks = bitcore.networks;
var util = bitcore.util;
var _ = require('underscore');
var preconditions = require('preconditions').instance();
var HDPath = require('./HDPath');
/**
* @desc
* Wrapper for bitcore.HierarchicalKey to be used inside of Copay.
*
* @param {Object} opts
* @param {string} opts.networkName if set to 'testnet', use the test3 bitcoin
* network constants (livenet otherwise)
* @param {string} opts.extendedPrivateKeyString if set, use this private key
* string, othewise create a new
* private key
*/
function PrivateKey(opts) {
opts = opts || {};
this.network = opts.networkName === 'testnet' ?
networks.testnet : networks.livenet;
this.network = opts.networkName === 'testnet' ? networks.testnet : networks.livenet;
var init = opts.extendedPrivateKeyString || this.network.name;
this.bip = new HK(init);
this.privateKeyCache = {};
this.publicHex = this.deriveBIP45Branch().eckey.public.toString('hex');
};
/**
* @desc Retrieve this derivated private key's public key in hexa format
*
* The value returned is calculated using the path from PrivateKey's
* <tt>HDParams.IdFullBranch</tt>. This key is used to identify the copayer
* (signing messages mostly).
*
* @returns {string} the public key in a hexadecimal string
*/
PrivateKey.prototype.getId = function() {
if (!this.id) {
this.cacheId();
@ -25,6 +47,15 @@ PrivateKey.prototype.getId = function() {
return this.id;
};
/**
* @desc Retrieve this private key's private key in hex format
*
* The value returned is calculated using the path from PrivateKey's
* <tt>HDParams.IdFullBranch</tt>. This key is used to identify the copayer
* (signing messages mostly).
*
* @returns {string} the private key in a hexadecimal string
*/
PrivateKey.prototype.getIdPriv = function() {
if (!this.idpriv) {
this.cacheId();
@ -32,6 +63,15 @@ PrivateKey.prototype.getIdPriv = function() {
return this.idpriv;
};
/**
* @desc Retrieve this private key's private key
*
* The value returned is calculated using the path from PrivateKey's
* <tt>HDParams.IdFullBranch</tt>. This key is used to identify the copayer
* (signing messages mostly).
*
* @returns {bitcore.PrivateKey} the private key
*/
PrivateKey.prototype.getIdKey = function() {
if (!this.idkey) {
this.cacheId();
@ -39,6 +79,11 @@ PrivateKey.prototype.getIdKey = function() {
return this.idkey;
};
/**
* @desc Caches the result of deriving IdFullBranch
*
* @private
*/
PrivateKey.prototype.cacheId = function() {
var path = HDPath.IdFullBranch;
var idhk = this.bip.derive(path);
@ -47,54 +92,116 @@ PrivateKey.prototype.cacheId = function() {
this.idpriv = idhk.eckey.private.toString('hex');
};
/**
* @desc Derive the master branch for Copay.
*/
PrivateKey.prototype.deriveBIP45Branch = function() {
if (!this.bip45Branch) {
this.bip45Branch = this.bip.derive(HDPath.BIP45_PUBLIC_PREFIX);
}
return this.bip45Branch;
}
PrivateKey.trim = function(data) {
var opts = {};
['networkName', 'extendedPrivateKeyString'].forEach(function(k){
opts[k] = data[k];
});
return opts;
};
/**
* @desc Returns an object with information needed to rebuild a PrivateKey
* (as most of its properties are derived from the extended private key).
*
* @TODO: Figure out if this is the correct pattern
* This is a static method and is probably used for serialization.
*
* @static
* @param {Object} data
* @param {*} data.networkName - a name for a bitcoin network
* @param {*} data.extendedPrivateKeyString - a bip32 extended private key
* @returns {Object} an object with two properties: networkName and
* extendedPrivateKeyString, taken from the <tt>data</tt>
* parameter.
*/
PrivateKey.trim = function(data) {
var opts = {};
['networkName', 'extendedPrivateKeyString'].forEach(function(k){
opts[k] = data[k];
});
return opts
};
/**
* @desc Generate a private Key from a serialized object
*
* @TODO: This method uses PrivateKey.trim but it's actually not needed...
*
* @param {Object} data
* @param {*} data.networkName - a name for a bitcoin network
* @param {*} data.extendedPrivateKeyString - a bip32 extended private key
* @returns {PrivateKey}
*/
PrivateKey.fromObj = function(obj) {
return new PrivateKey(PrivateKey.trim(obj));
};
/**
* @desc Serialize a private key, keeping only the data necessary to rebuild it
*
* @returns {Object}
*/
PrivateKey.prototype.toObj = function() {
return {
extendedPrivateKeyString: this.getExtendedPrivateKeyString(),
networkName: this.network.name,
networkName: this.network.name
};
};
/**
* @desc Retrieve a BIP32 extended public key as generated by bitcore
*
* @returns {string}
*/
PrivateKey.prototype.getExtendedPublicKeyString = function() {
return this.bip.extendedPublicKeyString();
};
/**
* @desc Retrieve a BIP32 extended private key as generated by bitcore
*
* @returns {string}
*/
PrivateKey.prototype.getExtendedPrivateKeyString = function() {
return this.bip.extendedPrivateKeyString();
};
/**
* @desc
* Retrieve a HierarchicalKey derived from the given path as generated by
* bitcore
* @param {string} path - a string for derivation (something like "m/234'/1/2")
* @returns {bitcore.HierarchicalKey}
*/
PrivateKey.prototype._getHK = function(path) {
if (typeof path === 'undefined') {
if (_.isUndefined(path)) {
return this.bip;
}
var ret = this.bip.derive(path);
return ret;
};
/**
* @desc
* Retrieve an array of WalletKey derived from given paths. {@see PrivateKey#getForPath}
*
* @param {string[]} paths - the paths to derive
* @returns {bitcore.WalletKey[]} - the derived keys
*/
PrivateKey.prototype.getForPaths = function(paths) {
return paths.map(this.getForPath.bind(this));
};
/**
* @desc
* Retrieve a WalletKey derived from a path.
*
* @param {string} paths - the path to derive
* @returns {bitcore.WalletKey} - the derived key
*/
PrivateKey.prototype.getForPath = function(path) {
var pk = this.privateKeyCache[path];
if (!pk) {
@ -110,14 +217,38 @@ PrivateKey.prototype.getForPath = function(path) {
return wk;
};
/**
* @desc
* Retrieve a Branch for Copay using the given path
*
* @TODO: Investigate when is this called and if this is really needed
*
* @param {number} index - the index of the key to generate
* @param {boolean} isChange - whether this is a change adderess or a receive
* @param {number} cosigner - the cosigner index
* @return {bitcore.HierarchicalKey}
*/
PrivateKey.prototype.get = function(index, isChange, cosigner) {
// TODO: Add parameter validation?
var path = HDPath.FullBranch(index, isChange, cosigner);
return this.getForPath(path);
};
/**
* @desc
* Retrieve multiple branches for Copay up to the received indexes
*
* @TODO: Investigate when is this called and if this is really needed
*
* @param {number} receiveIndex - the number of receive addresses to generate
* @param {number} changeIndex - the number of change addresses to generate
* @param {number} cosigner - the cosigner index
* @return {bitcore.HierarchicalKey}
*/
PrivateKey.prototype.getAll = function(receiveIndex, changeIndex, cosigner) {
if (typeof receiveIndex === 'undefined' || typeof changeIndex === 'undefined')
throw new Error('Invalid parameters');
preconditions.checkArgument(!_.isUndefined(receiveIndex) && !_.isUndefined(changeIndex));
var ret = [];
for (var i = 0; i < receiveIndex; i++) {
@ -129,6 +260,4 @@ PrivateKey.prototype.getAll = function(receiveIndex, changeIndex, cosigner) {
return ret;
};
module.exports = PrivateKey;

View file

@ -44,6 +44,11 @@ TxProposals.prototype.getNtxids = function() {
return Object.keys(this.txps);
};
TxProposals.prototype.deleteOne = function(ntxid) {
preconditions.checkState(this.txps[ntxid], 'Unknown TXP: ' + ntxid);
delete this.txps[ntxid];
};
TxProposals.prototype.deleteAll = function() {
this.txps = {};
};

View file

@ -1534,6 +1534,57 @@ Wallet.prototype.getUnspent = function(cb) {
});
};
Wallet.prototype.removeTxWithSpentInputs = function(cb) {
var self = this;
cb = cb || function () {};
var txps = [];
var maxRejectCount = this.maxRejectCount();
for (var ntxid in this.txProposals.txps) {
var txp = this.txProposals.txps[ntxid];
txp.ntxid = ntxid;
if (txp.isPending(maxRejectCount)) {
txps.push(txp);
}
}
var inputs = [];
txps.forEach(function (txp) {
txp.builder.utxos.forEach(function (utxo) {
inputs.push({ ntxid: txp.ntxid, txid: utxo.txid, vout: utxo.vout });
});
});
if (inputs.length === 0)
return;
var proposalsChanged = false;
this.blockchain.getUnspent(this.getAddressesStr(), function(err, unspentList) {
if (err) return cb(err);
unspentList.forEach(function (unspent) {
inputs.forEach(function (input) {
input.unspent = input.unspent || (input.txid === unspent.txid && input.vout === unspent.vout);
});
});
inputs.forEach(function (input) {
if (!input.unspent) {
proposalsChanged = true;
self.txProposals.deleteOne(input.ntxid);
}
});
if (proposalsChanged) {
self.emit('txProposalsUpdated');
self.store();
}
cb(null);
});
};
Wallet.prototype.createTx = function(toAddress, amountSatStr, comment, opts, cb) {
var self = this;

View file

@ -340,6 +340,7 @@ Network.prototype.getCopayerIds = function() {
Network.prototype.send = function(dest, payload, cb) {
preconditions.checkState(this.socket);
preconditions.checkArgument(payload);
var self = this;
@ -357,7 +358,8 @@ Network.prototype.send = function(dest, payload, cb) {
var to = dest[ii];
if (to == this.copayerId)
continue;
log.debug('SEND to: ' + to, this.copayerId, payload);
log.debug('SEND to: ' + to, this.copayerId, JSON.stringify(payload));
var message = this.encode(to, payload);
this.socket.emit('message', message);

View file

@ -165,6 +165,8 @@ angular.module('copayApp.services')
if (!w) return root.onErrorDigest();
if (!w.isReady()) return;
w.removeTxWithSpentInputs();
$rootScope.balanceByAddr = {};
$rootScope.updatingBalance = true;