From 7e165ca6addd7e9ff923999180e6523451b9cc07 Mon Sep 17 00:00:00 2001 From: Bechi Date: Wed, 16 Apr 2014 17:25:33 -0300 Subject: [PATCH 01/17] copayers-page --- css/main.css | 11 ++++++++++- index.html | 22 ++++++++++++++++------ 2 files changed, 26 insertions(+), 7 deletions(-) diff --git a/css/main.css b/css/main.css index 9db1e305c..c42153d1b 100644 --- a/css/main.css +++ b/css/main.css @@ -135,7 +135,6 @@ h3 { span.panel-res { float: right; - width: 3%; padding: 0.4rem 0.55rem; margin: 0 1rem; border-radius: 1rem; @@ -160,6 +159,11 @@ span.panel-res { margin: 0.5rem 0 1rem; } +.share-wallet.panel { + background-color: #111; + color: #FBE500; +} + button.primary { background-color: #111; } button.secondary { background-color: #FAE448 !important; } @@ -180,3 +184,8 @@ button.secondary:hover { background-color: #FFDF00 !important;} .size-60 { font-size: 60px; } .size-72 { font-size: 72px; } .m10t {margin-top: 10px;} +.p0r {padding-right: 0;} +.p70r {padding-right: 70px;} +.p70l {padding-left: 70px;} +.p5h {padding: 0 5px;} +.br100 {border-radius: 100%;} \ No newline at end of file diff --git a/index.html b/index.html index 8c725b41c..d5850c738 100644 --- a/index.html +++ b/index.html @@ -98,10 +98,17 @@ - + diff --git a/js/controllers/header.js b/js/controllers/header.js index 9653731f9..db906ca53 100644 --- a/js/controllers/header.js +++ b/js/controllers/header.js @@ -1,7 +1,7 @@ 'use strict'; angular.module('copay.header').controller('HeaderController', - function($scope, $rootScope, $location, Network) { + function($scope, $rootScope, $location, walletFactory) { $scope.menu = [{ 'title': 'Home', 'icon': 'fi-home', @@ -35,15 +35,14 @@ angular.module('copay.header').controller('HeaderController', return false; }; - $scope.init = function() { - $rootScope.isLogged = false; - }; - $scope.signout = function() { - Network.disconnect(function() { + var w = $rootScope.wallet; + if (w) { + w.disconnect(); + delete $rootScope['wallet']; $location.path('signin'); $rootScope.$digest(); - }); + } }; $scope.clearFlashMessage = function() { diff --git a/js/controllers/peer.js b/js/controllers/peer.js index b99729a5a..f6f482315 100644 --- a/js/controllers/peer.js +++ b/js/controllers/peer.js @@ -1,7 +1,7 @@ 'use strict'; angular.module('copay.peer').controller('PeerController', - function($scope, $rootScope, $location, $routeParams, Network) { + function($scope, $rootScope, $location, $routeParams) { $scope.init = function() { //Network.connect($rootScope.masterId); diff --git a/js/controllers/send.js b/js/controllers/send.js index 71687fdeb..682d89dc9 100644 --- a/js/controllers/send.js +++ b/js/controllers/send.js @@ -1,7 +1,7 @@ 'use strict'; angular.module('copay.send').controller('SendController', - function($scope, $rootScope, $location, Network) { + function($scope, $rootScope, $location) { $scope.title = 'Send'; if (!$rootScope.wallet.id) { @@ -11,8 +11,6 @@ angular.module('copay.send').controller('SendController', $scope.sendTest = function() { var w = $rootScope.wallet; - var pkr = w.publicKeyRing; - var txp = w.txProposals; w.createTx( '15q6HKjWHAksHcH91JW23BJEuzZgFwydBt', '12345',function() { $rootScope.$digest(); }); diff --git a/js/controllers/signin.js b/js/controllers/signin.js index cc84f6823..e112e366c 100644 --- a/js/controllers/signin.js +++ b/js/controllers/signin.js @@ -46,20 +46,22 @@ console.log('[signin.js.42:create:]'); //TODO $scope.join = function(cid) { console.log('[signin.js.42:join:]'); //TODO $scope.loading = true; - - if (cid) { - Network.init(null, function() { - Network.connect(cid, - function() { - $location.path('peer'); - $rootScope.$digest(); - }, function() { - $rootScope.flashMessage = { message: 'Connection refussed', type: 'error'}; - $location.path('home'); - $rootScope.$digest(); - }); - }); - } +// +// if (cid) { +// var w = walletFactory.(walletId); + //TODO + // Network.init(null, function() { + // Network.connect(cid, + // function() { + // $location.path('peer'); + // $rootScope.$digest(); + // }, function() { + // $rootScope.flashMessage = { message: 'Connection refussed', type: 'error'}; + // $location.path('home'); + // $rootScope.$digest(); + // }); + // }); +// } }; // if (peerData && peerData.peerId && peerData.connectedPeers.length > 0) { diff --git a/js/services/network.js b/js/services/network.js deleted file mode 100644 index 55a6e9c90..000000000 --- a/js/services/network.js +++ /dev/null @@ -1,70 +0,0 @@ -'use strict'; - -angular.module('copay.network') - .factory('Network', function($rootScope) { - var peer; - - var _refreshUx = function() { - var net = $rootScope.wallet.network; - log('*** UPDATING UX'); //TODO - $rootScope.peedId = net.peerId; - $rootScope.connectedPeers = net.connectedPeers; - $rootScope.$digest(); - }; - - var closeWallet = function() { - var w = $rootScope.wallet; - if (w && w.id) w.store(); - - log('### CLOSING WALLET'); - delete $rootScope['wallet']; - }; - - // public methods - var init = function(walletId, cb) { - if (!$rootScope.wallet) { - // create an empty Wallet - $rootScope.wallet = new copay.Wallet(config); - } - var w = $rootScope.wallet; -console.log('[network.js.30:walletId:]',walletId); //TODO - if (!walletId) w.openWalletId(); - w.on('created', _refreshUx); - w.on('txProposals', _refreshUx); - w.on('publicKeyRing', _refreshUx); - w.on('abort', function() { - disconnect(); - _refreshUx(); - }); - w.netStart(cb); - }; - - var disconnect = function() { - var w = $rootScope.wallet; - var net = w.network; - - if (net) { - net.disconnect(); - } - closeWallet(); - }; - - var connect = function(peerId, openCallback, failCallback) { - $rootScope.wallet.connectTo(peerId); - $rootScope.wallet.on('open', openCallback); - $rootScope.wallet.on('close', failCallback); - }; - - var sendTxProposals = function(recipients) { - var w = $rootScope.wallet; - w.sendTxProposals(recipients); - }; - - return { - init: init, - connect: connect, - disconnect: disconnect, - sendTxProposals: sendTxProposals, - } - }); - diff --git a/util/build.js b/util/build.js index e7e22e046..eca71fa0a 100755 --- a/util/build.js +++ b/util/build.js @@ -42,7 +42,8 @@ var createBundle = function(opts) { b.require('./copay', { expose: 'copay' }); - b.require('./js/models/core/Wallet'); + b.require('./js/models/core/WalletFactory.js'); + if (!opts.dontminify) { b.transform({ From e676f4e69d68b87248d974308abe4de8c4c0c6a5 Mon Sep 17 00:00:00 2001 From: Matias Alejo Garcia Date: Wed, 16 Apr 2014 19:18:19 -0300 Subject: [PATCH 04/17] fix create --- js/controllers/signin.js | 2 +- js/models/core/Wallet.js | 5 ++--- 2 files changed, 3 insertions(+), 4 deletions(-) diff --git a/js/controllers/signin.js b/js/controllers/signin.js index e112e366c..13f0dcbf9 100644 --- a/js/controllers/signin.js +++ b/js/controllers/signin.js @@ -14,7 +14,7 @@ angular.module('copay.signin').controller('SigninController', }; var _setupUxHandlers = function(w) { - w.on('open', function(){ + w.on('created', function(){ $location.path('peer'); $rootScope.wallet = w; $rootScope.$digest(); diff --git a/js/models/core/Wallet.js b/js/models/core/Wallet.js index 43f419d85..0a6493192 100644 --- a/js/models/core/Wallet.js +++ b/js/models/core/Wallet.js @@ -115,16 +115,15 @@ Wallet.prototype._handleNetworkChange = function(newPeer) { this.sendTxProposals(newPeer); }; -Wallet.prototype.netStart = function(cb) { +Wallet.prototype.netStart = function() { var self = this; var net = this.network; - net.on('networkChange', function() { self._handleNetworkChange() } ); + net.on('networkChange', function() { self._handleNetworkChange(); } ); net.on('data', function() { self._handleData();}); net.on('open', function() {}); // TODO net.on('close', function() {}); // TODO net.start(function(peerId) { self.emit('created'); - return cb(); }); }; From 8856683a170c32f98149436acea442361fece945 Mon Sep 17 00:00:00 2001 From: Matias Alejo Garcia Date: Wed, 16 Apr 2014 20:58:57 -0300 Subject: [PATCH 05/17] fix join wallet WIP --- js/controllers/header.js | 1 - js/controllers/signin.js | 9 +++++- js/models/core/Wallet.js | 33 ++++++++++++++++--- js/models/core/WalletFactory.js | 56 +++++++++++++++++++++++++++++++-- js/models/network/WebRTC.js | 8 +++-- test/test.walletfactory.js | 2 +- 6 files changed, 96 insertions(+), 13 deletions(-) diff --git a/js/controllers/header.js b/js/controllers/header.js index db906ca53..91f00d863 100644 --- a/js/controllers/header.js +++ b/js/controllers/header.js @@ -41,7 +41,6 @@ angular.module('copay.header').controller('HeaderController', w.disconnect(); delete $rootScope['wallet']; $location.path('signin'); - $rootScope.$digest(); } }; diff --git a/js/controllers/signin.js b/js/controllers/signin.js index 13f0dcbf9..122cdc02a 100644 --- a/js/controllers/signin.js +++ b/js/controllers/signin.js @@ -46,6 +46,14 @@ console.log('[signin.js.42:create:]'); //TODO $scope.join = function(cid) { console.log('[signin.js.42:join:]'); //TODO $scope.loading = true; + walletFactory.connectTo(cid, function(w) { +console.log('[signin.js.50]'); //TODO + _setupUxHandlers(w); + w.netStart(); + }); + }; + + // // if (cid) { // var w = walletFactory.(walletId); @@ -62,7 +70,6 @@ console.log('[signin.js.42:join:]'); //TODO // }); // }); // } - }; // if (peerData && peerData.peerId && peerData.connectedPeers.length > 0) { // $rootScope.peerId = peerData.peerId; diff --git a/js/models/core/Wallet.js b/js/models/core/Wallet.js index 0a6493192..1d2141117 100644 --- a/js/models/core/Wallet.js +++ b/js/models/core/Wallet.js @@ -39,7 +39,6 @@ Wallet.getRandomId = function() { }; Wallet.prototype._handlePublicKeyRing = function(senderId, data, isInbound) { - this.openWalletId(data.walletId); this.log('RECV PUBLICKEYRING:',data); var shouldSend = false; @@ -66,7 +65,6 @@ Wallet.prototype._handlePublicKeyRing = function(senderId, data, isInbound) { Wallet.prototype._handleTxProposals = function(senderId, data, isInbound) { - this.openWalletId(data.walletId); this.log('RECV TXPROPOSAL:',data); //TODO var shouldSend = false; @@ -94,6 +92,11 @@ Wallet.prototype._handleTxProposals = function(senderId, data, isInbound) { }; Wallet.prototype._handleData = function(senderId, data, isInbound) { + + if (this.id !== data.walletId) + throw new Error('wrong message received: Bad wallet ID'); + + switch(data.type) { case 'publicKeyRing': this._handlePublicKeyRing(senderId, data, isInbound); @@ -108,9 +111,13 @@ Wallet.prototype._handleData = function(senderId, data, isInbound) { }; Wallet.prototype._handleNetworkChange = function(newPeer) { + +console.log('[Wallet.js.112:newPeer:]',newPeer); //TODO if (!newPeer) return; +console.log('[Wallet.js.112:newPeer:]',newPeer); //TODO this.log('#### Setting new PEER:', newPeer); + this.sendWalletId(newPeer); this.sendPublicKeyRing(newPeer); this.sendTxProposals(newPeer); }; @@ -118,8 +125,8 @@ Wallet.prototype._handleNetworkChange = function(newPeer) { Wallet.prototype.netStart = function() { var self = this; var net = this.network; - net.on('networkChange', function() { self._handleNetworkChange(); } ); - net.on('data', function() { self._handleData();}); + net.on('networkChange', self._handleNetworkChange.bind(self) ); + net.on('data', self._handleData.bind(self) ); net.on('open', function() {}); // TODO net.on('close', function() {}); // TODO net.start(function(peerId) { @@ -151,6 +158,17 @@ Wallet.prototype.sendTxProposals = function(recipients) { this.emit('txProposalsUpdated', this.txProposals); }; + +Wallet.prototype.sendWalletId = function(recipients) { + this.log('### SENDING walletId TO:', recipients||'All', this.walletId); + + this.network.send(recipients, { + type: 'walletId', + walletId: this.id, + }); +}; + + Wallet.prototype.sendPublicKeyRing = function(recipients) { this.log('### SENDING publicKeyRing TO:', recipients||'All', this.publicKeyRing.toObj()); @@ -308,8 +326,13 @@ Wallet.prototype.createTxSync = function(toAddress, amountSatStr, utxos, opts) { }; Wallet.prototype.connectTo = function(peerId) { - this.network.connectTo(peerId); + throw new Error('Wallet.connectTo.. not yet implemented!'); }; + +Wallet.prototype.disconnect = function() { + this.network.disconnect(); +}; + // // HERE? not sure // Wallet.prototype.cleanPeers = function() { // this.storage.remove('peerData'); diff --git a/js/models/core/WalletFactory.js b/js/models/core/WalletFactory.js index 05865d93c..baef0b27c 100644 --- a/js/models/core/WalletFactory.js +++ b/js/models/core/WalletFactory.js @@ -60,6 +60,7 @@ WalletFactory.prototype.read = function(walletId) { opts.storage = this.storage; opts.network = this.network; opts.blockchain = this.blockchain; + opts.verbose = this.verbose; var w = new Wallet(opts); @@ -102,6 +103,8 @@ WalletFactory.prototype.create = function(opts) { opts.storage = this.storage; opts.network = this.network; opts.blockchain = this.blockchain; + opts.verbose = this.verbose; + opts.spendUnconfirmed = opts.spendUnconfirmed || this.walletDefaults.spendUnconfirmed; opts.requiredCopayers = requiredCopayers; opts.totalCopayers = totalCopayers; @@ -112,9 +115,44 @@ WalletFactory.prototype.create = function(opts) { }; WalletFactory.prototype.open = function(walletId) { - if(!WalletFactory.read(walletId)) { - WalletFactory.create({id: walletId}); - } + var w = this.read(walletId) || this.create({id: walletId}); + return w; +}; + +WalletFactory.prototype.openRemote = function(peedId) { + var s = WalletFactory.storage; + opts = opts || {}; + this.log('### CREATING NEW WALLET.' + (opts.id ? ' USING ID: ' + opts.id : ' NEW ID')); + + opts.privateKey = opts.privateKey || new PrivateKey({ networkName: this.networkName }); + this.log('\t### PrivateKey Initialized'); + + var requiredCopayers = opts.requiredCopayers || this.walletDefaults.requiredCopayers; + var totalCopayers = opts.totalCopayers || this.walletDefaults.totalCopayers; + + opts.publicKeyRing = opts.publicKeyRing || new PublicKeyRing({ + networkName: this.networkName, + requiredCopayers: requiredCopayers, + totalCopayers: totalCopayers, + }); + opts.publicKeyRing.addCopayer(opts.privateKey.getBIP32().extendedPublicKeyString()); + this.log('\t### PublicKeyRing Initialized'); + + opts.txProposals = opts.txProposals || new TxProposals({ + networkName: this.networkName, + }); + this.log('\t### TxProposals Initialized'); + + opts.storage = this.storage; + opts.network = this.network; + opts.blockchain = this.blockchain; + opts.spendUnconfirmed = opts.spendUnconfirmed || this.walletDefaults.spendUnconfirmed; + opts.requiredCopayers = requiredCopayers; + opts.totalCopayers = totalCopayers; + var w = new Wallet(opts); + w.store(); + this.addWalletId(w.id); + return w; }; WalletFactory.prototype.getWalletIds = function() { @@ -142,4 +180,16 @@ WalletFactory.prototype.addWalletId = function(walletId) { this.storage.setGlobal('walletIds', ids); }; + +WalletFactory.prototype.connectTo = function(peerId, cb) { + var self=this; + self.network.start(function() { + self.network.connectTo(peerId) + self.network.on('walletId', function(walletId) { +console.log('[WalletFactory.js.187]'); //TODO + return cb(self.open(walletId)); + }); + }); +}; + module.exports = require('soop')(WalletFactory); diff --git a/js/models/network/WebRTC.js b/js/models/network/WebRTC.js index bb125fce1..9160cc857 100644 --- a/js/models/network/WebRTC.js +++ b/js/models/network/WebRTC.js @@ -103,6 +103,9 @@ Network.prototype._onData = function(data, isInbound) { case 'disconnect': this._onClose(obj.sender); break; + case 'walletId': + this.emit('walletId', obj.data.walletId); + break; default: this.emit('data', obj.sender, obj.data, isInbound); } @@ -158,7 +161,6 @@ Network.prototype._setupConnectionHandlers = function(dataConn, isInbound) { dataConn.on('close', function() { if (self.closing) return; console.log('### CLOSE RECV FROM:', dataConn.peer); - self._onClose(dataConn.peer); this.emit('close'); }); @@ -166,6 +168,8 @@ Network.prototype._setupConnectionHandlers = function(dataConn, isInbound) { Network.prototype._notify = function(newPeer) { this._showConnectedPeers(); + +console.log('[WebRTC.js.172]', newPeer); //TODO this.emit('networkChange', newPeer); }; @@ -269,7 +273,7 @@ Network.prototype.connectTo = function(peerId) { }; -Network.prototype.disconnect = function(peerId, cb) { +Network.prototype.disconnect = function(cb) { var self = this; self.closing = 1; diff --git a/test/test.walletfactory.js b/test/test.walletfactory.js index d3b7c7044..38fe165f8 100644 --- a/test/test.walletfactory.js +++ b/test/test.walletfactory.js @@ -5,7 +5,7 @@ var should = chai.should(); var WebRTC = require('../js/models/network/WebRTC'); var Insight = require('../js/models/blockchain/Insight'); -var FakeStorage = require('./FakeStorage'); +var FakeStorage = require('./mocks/FakeStorage'); var WalletFactory = typeof copay === 'undefined' ? require('soop').load('../js/models/core/WalletFactory',{ Network: WebRTC, From 4a6448268776e62b3b9a395ec031e6b78214d084 Mon Sep 17 00:00:00 2001 From: Matias Alejo Garcia Date: Wed, 16 Apr 2014 21:10:04 -0300 Subject: [PATCH 06/17] fix tests --- test/test.Wallet.js | 130 +++++++++++++++++--------------------------- 1 file changed, 49 insertions(+), 81 deletions(-) diff --git a/test/test.Wallet.js b/test/test.Wallet.js index e4f36e522..87423c7ee 100644 --- a/test/test.Wallet.js +++ b/test/test.Wallet.js @@ -3,12 +3,10 @@ var chai = chai || require('chai'); var should = chai.should(); var copay = copay || require('../copay'); -var Wallet = require('soop').load('../js/models/core/Wallet', { - Storage: require('./mocks/FakeStorage'), - Network: copay.WebRTC, - Blockchain: copay.Insight -}); - +var Wallet = require('../js/models/core/Wallet'); +var Storage= require('./mocks/FakeStorage'); +var Network= copay.WebRTC; +var Blockchain= copay.Insight; var addCopayers = function (w) { for(var i=0; i<4; i++) { @@ -17,73 +15,65 @@ var addCopayers = function (w) { }; describe('Wallet model', function() { + var config = { - wallet: { - requiredCopayers: 3, - totalCopayers: 5, - }, + requiredCopayers: 3, + totalCopayers: 5, + spendUnconfirmed: 1, blockchain: { host: 'test.insight.is', port: 80 }, + networkName: 'testnet', }; - var opts = {}; + it('should fail to create an instance', function () { + (function(){new Wallet(config)}).should.throw(); + }); + + var createW = function () { + var c = JSON.parse(JSON.stringify(config)); + + c.privateKey = new copay.PrivateKey({ networkName: c.networkName }); + + c.publicKeyRing = new copay.PublicKeyRing({ + networkName: c.networkName, + requiredCopayers: c.requiredCopayers, + totalCopayers: c.totalCopayers, + }); + c.publicKeyRing.addCopayer(c.privateKey.getBIP32().extendedPublicKeyString()); + + c.txProposals = new copay.TxProposals({ + networkName: c.networkName, + }); + c.storage = new Storage(config.storage); + c.network = new Network(config.network); + c.blockchain = new Blockchain(config.blockchain); + + c.networkName = config.networkName; + c.verbose = config.verbose; + + return new Wallet(c); + } it('should create an instance', function () { - var opts = {}; - var w = new Wallet(config); + var w = createW(); should.exist(w); - }); - - - it('should fail to load', function () { - var opts = {}; - var w = new Wallet(config); - w.load(123); - should.not.exist(w.id); - }); - - - it('should create', function () { - var opts = {}; - var w = new Wallet(config); - w.create(); + w.publicKeyRing.walletId.should.equal(w.id); + w.txProposals.walletId.should.equal(w.id); + w.requiredCopayers.should.equal(3); should.exist(w.id); should.exist(w.publicKeyRing); should.exist(w.privateKey); should.exist(w.txProposals); }); - it('should list unspent', function (done) { + it('should provide some basic features', function () { var opts = {}; - var w = new Wallet(config); - w.create(); + var w = createW(); addCopayers(w); w.publicKeyRing.generateAddress(false); - - should.exist(w.id); w.publicKeyRing.isComplete().should.equal(true); - - w.listUnspent(function(utxos) { - utxos.length.should.equal(0); - done(); - }); - }); - - describe('factory', function() { - it('should create the factory', function() { - should.exist(Wallet.factory); - }); - it('should be able to create wallets', function() { - var w = Wallet.factory.create(config, opts); - should.exist(w); - }); - it.skip('should be able to get wallets', function() { - var w = Wallet.factory.create(config, opts); - var v = Wallet.factory.get(config, w.id); - should.exist(w); - }); }); var unspentTest = [ @@ -97,9 +87,8 @@ describe('Wallet model', function() { } ]; - var createWallet = function (bip32s) { - var w = new Wallet(config); - w.create(); + var createW2 = function (bip32s) { + var w = createW(); should.exist(w); var pkr = w.publicKeyRing; @@ -125,12 +114,12 @@ describe('Wallet model', function() { it('#create, 1 sign', function () { - var w = createWallet(); + var w = createW2(); unspentTest[0].address = w.publicKeyRing.getAddress(1, true).toString(); unspentTest[0].scriptPubKey = w.publicKeyRing.getScriptPubKeyHex(1, true); - w.createTx( + w.createTxSync( '15q6HKjWHAksHcH91JW23BJEuzZgFwydBt', '123456789', unspentTest @@ -148,14 +137,14 @@ describe('Wallet model', function() { it('#create. Signing with derivate keys', function () { - var w = createWallet(); + var w = createW2(); var ts = Date.now(); for (var isChange=0; isChange<2; isChange++) { for (var index=0; index<3; index++) { unspentTest[0].address = w.publicKeyRing.getAddress(index, isChange).toString(); unspentTest[0].scriptPubKey = w.publicKeyRing.getScriptPubKeyHex(index, isChange); - w.createTx( + w.createTxSync( '15q6HKjWHAksHcH91JW23BJEuzZgFwydBt', '123456789', unspentTest @@ -172,25 +161,4 @@ describe('Wallet model', function() { } }); - // TODO: when sign is implemented - it.skip('#create, signing with wrong key', function () { - var w1 = createWallet(); - - unspentTest[0].address = w.publicKeyRing.getAddress(1, true).toString(); - unspentTest[0].scriptPubKey = w.publicKeyRing.getScriptPubKeyHex(1, true); - - var priv = new PrivateKey(config); - w.create( - '15q6HKjWHAksHcH91JW23BJEuzZgFwydBt', - '123456789', - unspentTest - ); - var tx = w.txps[0].builder.build(); - should.exist(tx); - tx.isComplete().should.equal(false); - Object.keys(w.txps[0].signedBy).length.should.equal(0); - Object.keys(w.txps[0].seenBy).length.should.equal(1); - }); - - }); From 8166fa5c8e9c460b552c40c4ea6e009cd3c67cb3 Mon Sep 17 00:00:00 2001 From: "Ryan X. Charles" Date: Tue, 15 Apr 2014 18:06:42 -0300 Subject: [PATCH 07/17] change default network to "Base" ...since it won't be used for the command-line (yet). --- API.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/API.js b/API.js index dd6d2fe19..cf6e68bfe 100644 --- a/API.js +++ b/API.js @@ -12,7 +12,7 @@ API.prototype._init = function(opts) { var Wallet = require('soop').load('./js/models/core/Wallet', { Storage: opts.Storage || require('./test/mocks/FakeStorage'), - Network: opts.Network || require('./js/models/network/WebRTC'), + Network: opts.Network || require('./js/models/network/Base'), Blockchain: opts.Blockchain || require('./js/models/blockchain/Insight') }); From 08f918a9a7a5a3ab97fd12cabfa974a333f3fa88 Mon Sep 17 00:00:00 2001 From: "Ryan X. Charles" Date: Wed, 16 Apr 2014 15:26:04 -0300 Subject: [PATCH 08/17] add File storage class and tests --- bin/copay | 5 +- js/models/storage/File.js | 87 ++++++++++++++++++++++ package.json | 3 +- test/test.storage.File.js | 147 ++++++++++++++++++++++++++++++++++++++ 4 files changed, 238 insertions(+), 4 deletions(-) create mode 100644 js/models/storage/File.js create mode 100644 test/test.storage.File.js diff --git a/bin/copay b/bin/copay index 2721da0e2..9890f66cd 100755 --- a/bin/copay +++ b/bin/copay @@ -18,11 +18,10 @@ var main = function() { var api = new API(commander); var args = commander.args; + var command = args[0]; + var commandArgs = args.slice(1); try { - var command = args[0]; - var commandArgs = args.slice(1); - if (command[0] == '_' || typeof api[command] != 'function') throw new Error('invalid command'); diff --git a/js/models/storage/File.js b/js/models/storage/File.js new file mode 100644 index 000000000..1f659f8fc --- /dev/null +++ b/js/models/storage/File.js @@ -0,0 +1,87 @@ +'use strict'; +var imports = require('soop').imports(); +var fs = imports.fs || require('fs'); + +function Storage(opts) { + opts = opts || {}; + + this.data = {}; + this.filename = opts.filename; +} + +Storage.prototype.load = function(callback) { + if (!this.filename) + throw new Error('No filename'); + + fs.readFile(this.filename, function(err, data) { + if (err) return callback(err); + + try { + this.data = JSON.parse(data); + } catch (err) { + return callback(err); + } + + return callback(null); + }); +}; + +Storage.prototype.save = function(callback) { + var data = JSON.stringify(this.data); + + //TODO: update to use a queue to ensure that saves are made sequentially + fs.writeFile(this.filename, data, function(err) { + return callback(err); + }); +}; + +Storage.prototype._read = function(k) { + return this.data[k]; +}; + +Storage.prototype._write = function(k, v, callback) { + this.data[k] = v; + this.save(callback); +}; + +// get value by key +Storage.prototype.getGlobal = function(k) { + return this.data[k]; +}; + +// set value for key +Storage.prototype.setGlobal = function(k, v, callback) { + this._write(k, v, callback); +}; + +// remove value for key +Storage.prototype.removeGlobal = function(k, callback) { + delete this.data[k]; + this.save(callback); +}; + +Storage.prototype._key = function(walletId, k) { + return walletId + '::' + k; +}; +// get value by key +Storage.prototype.get = function(walletId, k) { + return this.getGlobal(this._key(walletId, k)); +}; + +// set value for key +Storage.prototype.set = function(walletId, k, v, callback) { + this.setGlobal(this._key(walletId,k), v, callback); +}; + +// remove value for key +Storage.prototype.remove = function(walletId, k, callback) { + this.removeGlobal(this._key(walletId, k), callback); +}; + +// remove all values +Storage.prototype.clearAll = function(callback) { + this.data = {}; + this.save(callback); +}; + +module.exports = require('soop')(Storage); diff --git a/package.json b/package.json index c16e0a9a7..7e0cbdd62 100644 --- a/package.json +++ b/package.json @@ -35,6 +35,7 @@ "uglifyify": "~1.2.3", "soop": "~0.1.5", "bitcore": "git://github.com/maraoz/bitcore.git#5e636f6b9c7f8e629b1a502025556e886c3b75e1", - "chai": "~1.9.1" + "chai": "~1.9.1", + "sinon": "~1.9.1" } } diff --git a/test/test.storage.File.js b/test/test.storage.File.js new file mode 100644 index 000000000..d3d47ca96 --- /dev/null +++ b/test/test.storage.File.js @@ -0,0 +1,147 @@ +'use strict'; + +var chai = chai || require('chai'); +var should = chai.should(); +var Storage = Storage || require('../js/models/storage/File.js'); +var sinon = sinon || require('sinon'); + +describe('Storage/File', function() { + it('should exist', function() { + should.exist(Storage); + }); + + describe('#load', function(done) { + it('should call fs.readFile', function(done) { + var fs = {} + fs.readFile = function(filename, callback) { + filename.should.equal('myfilename'); + callback(); + }; + var Storage = require('soop').load('../js/models/storage/File.js', {fs: fs}); + var storage = new Storage({filename: 'myfilename', password: 'password'}); + storage.load(function(err) { + done(); + }); + }); + }); + + describe('#save', function(done) { + it('should call fs.writeFile', function(done) { + var fs = {} + fs.writeFile = function(filename, data, callback) { + filename.should.equal('myfilename'); + callback(); + }; + var Storage = require('soop').load('../js/models/storage/File.js', {fs: fs}); + var storage = new Storage({filename: 'myfilename', password: 'password'}); + storage.save(function(err) { + done(); + }); + }); + }); + + describe('#_read', function() { + it('should return the value of a key', function() { + var storage = new Storage(); + storage.data = {'test':'data'}; + storage._read('test').should.equal('data'); + }); + }); + + describe('#_write', function() { + it('should save the value of a key and then run save', function(done) { + var storage = new Storage(); + storage.save = function(callback) { + storage.data['key'].should.equal('value'); + callback(); + }; + storage._write('key', 'value', function() { + done(); + }); + }); + }); + + describe('#getGlobal', function() { + it('should store a global key', function(done) { + var storage = new Storage(); + storage.save = function(callback) { + storage.data['key'].should.equal('value'); + callback(); + }; + storage.setGlobal('key', 'value', function() { + done(); + }); + }); + }); + + describe('#setGlobal', function() { + it('should store a global key', function(done) { + var storage = new Storage(); + storage.save = function(callback) { + storage.data['key'].should.equal('value'); + callback(); + }; + storage.setGlobal('key', 'value', function() { + done(); + }); + }); + }); + + describe('#removeGlobal', function() { + it('should remove a global key', function(done) { + var storage = new Storage(); + storage.data.key = 'value'; + storage.save = function(callback) { + should.not.exist(storage.data['key']); + callback(); + }; + storage.removeGlobal('key', function() { + done(); + }); + }); + }); + + describe('#_key', function() { + it('should merge the wallet id and item key', function() { + var storage = new Storage(); + storage._key('wallet', 'key').should.equal('wallet::key'); + }); + }); + + describe('#get', function() { + it('should call getGlobal with the correct key', function() { + var storage = new Storage(); + storage.getGlobal = sinon.spy(); + storage.get('wallet', 'key'); + storage.getGlobal.calledOnce.should.equal(true); + storage.getGlobal.calledWith('wallet::key').should.equal(true); + }); + }); + + describe('#set', function() { + it('should call setGlobal with the correct key', function() { + var storage = new Storage(); + storage.setGlobal = sinon.spy(); + storage.set('wallet', 'key'); + storage.setGlobal.calledOnce.should.equal(true); + storage.setGlobal.calledWith('wallet::key').should.equal(true); + }); + }); + + describe('#remove', function() { + it('should call removeGlobal with the correct key', function() { + var storage = new Storage(); + storage.removeGlobal = sinon.spy(); + storage.remove('wallet', 'key'); + storage.removeGlobal.calledOnce.should.equal(true); + storage.removeGlobal.calledWith('wallet::key').should.equal(true); + }); + }); + + describe('#clearAll', function() { + it('should set data to {}', function() { + + }); + }); + +}); From b442e110e4c51b39e804c35f547c5fd3cc3d0b54 Mon Sep 17 00:00:00 2001 From: "Ryan X. Charles" Date: Wed, 16 Apr 2014 16:52:42 -0300 Subject: [PATCH 09/17] make tests work by faking storage --- API.js | 3 +++ test/test.API.js | 20 +++++++++++--------- 2 files changed, 14 insertions(+), 9 deletions(-) diff --git a/API.js b/API.js index cf6e68bfe..5cf8d0841 100644 --- a/API.js +++ b/API.js @@ -20,6 +20,9 @@ API.prototype._init = function(opts) { wallet: { requiredCopayers: opts.requiredCopayers || 3, totalCopayers: opts.totalCopayers || 5, + }, + storage: { + filename: 'copaywallet.json' } }; diff --git a/test/test.API.js b/test/test.API.js index 75161997e..a3046d20e 100644 --- a/test/test.API.js +++ b/test/test.API.js @@ -4,11 +4,13 @@ var chai = chai || require('chai'); var should = chai.should(); var copay = copay || require('../copay'); var API = API || copay.API; +var Storage = Storage || require('../test/mocks/FakeStorage'); describe('API', function() { it('should have a command called "echo"', function() { - var api = new API(); + + var api = new API({Storage: Storage}); should.exist(api.echo); }); @@ -22,7 +24,7 @@ describe('API', function() { }) it('should throw an error for all commands when called with wrong number of arguments', function() { - var api = new API(); + var api = new API({Storage: Storage}); for (var i in API.prototype) { var f = API.prototype[i]; if (i[0] != '_' && typeof f == 'function') { @@ -49,7 +51,7 @@ describe('API', function() { describe('#echo', function() { it('should echo a string', function(done) { - var api = new API(); + var api = new API({Storage: Storage}); var str = 'mystr'; api.echo(str, function(err, result) { result.should.equal(str); @@ -60,7 +62,7 @@ describe('API', function() { describe('#echoNumber', function() { it('should echo a number', function(done) { - var api = new API(); + var api = new API({Storage: Storage}); var num = 500; api.echoNumber(num, function(err, result) { result.should.equal(num); @@ -72,7 +74,7 @@ describe('API', function() { describe('#echoObject', function() { it('should echo an object', function(done) { - var api = new API(); + var api = new API({Storage: Storage}); var obj = {test:'test'}; api.echoObject(obj, function(err, result) { result.test.should.equal(obj.test); @@ -84,7 +86,7 @@ describe('API', function() { describe('#getArgTypes', function() { it('should get the argTypes of echo', function(done) { - var api = new API(); + var api = new API({Storage: Storage}); api.getArgTypes('echo', function(err, result) { result[0][1].should.equal('string'); done(); @@ -94,7 +96,7 @@ describe('API', function() { describe('#getCommands', function() { it('should get all the commands', function(done) { - var api = new API(); + var api = new API({Storage: Storage}); var n = 0; for (var i in api) @@ -110,7 +112,7 @@ describe('API', function() { describe('#getPublicKeyRingId', function() { it('should get a public key ring ID', function(done) { - var api = new API(); + var api = new API({Storage: Storage}); api.getPublicKeyRingId(function(err, result) { result.length.should.be.greaterThan(5); done(); @@ -120,7 +122,7 @@ describe('API', function() { describe('#help', function() { it('should call _cmd_getCommands', function(done) { - var api = new API(); + var api = new API({Storage: Storage}); api._cmd_getCommands = function(callback) { (typeof arguments[0]).should.equal('function'); callback(null, ['item']); From 5f8deb7d0ba343f849c836b37764a696af17625d Mon Sep 17 00:00:00 2001 From: "Ryan X. Charles" Date: Wed, 16 Apr 2014 17:37:32 -0300 Subject: [PATCH 10/17] update File to write wallets to different files the walletId is the filename --- js/models/storage/File.js | 49 ++++++++++++++++++++++++--------------- test/test.storage.File.js | 45 +++++++++++++++++------------------ 2 files changed, 51 insertions(+), 43 deletions(-) diff --git a/js/models/storage/File.js b/js/models/storage/File.js index 1f659f8fc..9b3fa5f34 100644 --- a/js/models/storage/File.js +++ b/js/models/storage/File.js @@ -6,47 +6,54 @@ function Storage(opts) { opts = opts || {}; this.data = {}; - this.filename = opts.filename; } -Storage.prototype.load = function(callback) { - if (!this.filename) - throw new Error('No filename'); - - fs.readFile(this.filename, function(err, data) { +Storage.prototype.load = function(walletId, callback) { + fs.readFile(walletId, function(err, data) { if (err) return callback(err); try { - this.data = JSON.parse(data); + this.data[walletId] = JSON.parse(data); } catch (err) { - return callback(err); + if (callback) + return callback(err); } - return callback(null); + if (callback) + return callback(null); }); }; -Storage.prototype.save = function(callback) { - var data = JSON.stringify(this.data); +Storage.prototype.save = function(walletId, callback) { + var data = JSON.stringify(this.data[walletId]); //TODO: update to use a queue to ensure that saves are made sequentially - fs.writeFile(this.filename, data, function(err) { - return callback(err); + fs.writeFile(walletId, data, function(err) { + if (callback) + return callback(err); }); }; Storage.prototype._read = function(k) { - return this.data[k]; + var split = k.split('::'); + var walletId = split[0]; + var key = split[1]; + return this.data[walletId][key]; }; Storage.prototype._write = function(k, v, callback) { - this.data[k] = v; - this.save(callback); + var split = k.split('::'); + var walletId = split[0]; + var key = split[1]; + if (!this.data[walletId]) + this.data[walletId] = {}; + this.data[walletId][key] = v; + this.save(walletId, callback); }; // get value by key Storage.prototype.getGlobal = function(k) { - return this.data[k]; + return this._read(k); }; // set value for key @@ -56,13 +63,17 @@ Storage.prototype.setGlobal = function(k, v, callback) { // remove value for key Storage.prototype.removeGlobal = function(k, callback) { - delete this.data[k]; - this.save(callback); + var split = k.split('::'); + var walletId = split[0]; + var key = split[1]; + delete this.data[walletId][key]; + this.save(walletId, callback); }; Storage.prototype._key = function(walletId, k) { return walletId + '::' + k; }; + // get value by key Storage.prototype.get = function(walletId, k) { return this.getGlobal(this._key(walletId, k)); diff --git a/test/test.storage.File.js b/test/test.storage.File.js index d3d47ca96..b54a34215 100644 --- a/test/test.storage.File.js +++ b/test/test.storage.File.js @@ -18,8 +18,8 @@ describe('Storage/File', function() { callback(); }; var Storage = require('soop').load('../js/models/storage/File.js', {fs: fs}); - var storage = new Storage({filename: 'myfilename', password: 'password'}); - storage.load(function(err) { + var storage = new Storage({password: 'password'}); + storage.load('myfilename', function(err) { done(); }); }); @@ -33,8 +33,8 @@ describe('Storage/File', function() { callback(); }; var Storage = require('soop').load('../js/models/storage/File.js', {fs: fs}); - var storage = new Storage({filename: 'myfilename', password: 'password'}); - storage.save(function(err) { + var storage = new Storage({password: 'password'}); + storage.save('myfilename', function(err) { done(); }); }); @@ -43,45 +43,42 @@ describe('Storage/File', function() { describe('#_read', function() { it('should return the value of a key', function() { var storage = new Storage(); - storage.data = {'test':'data'}; - storage._read('test').should.equal('data'); + storage.data = {'walletId':{'test':'data'}}; + storage._read('walletId::test').should.equal('data'); }); }); describe('#_write', function() { it('should save the value of a key and then run save', function(done) { var storage = new Storage(); - storage.save = function(callback) { - storage.data['key'].should.equal('value'); + storage.save = function(walletId, callback) { + storage.data[walletId]['key'].should.equal('value'); callback(); }; - storage._write('key', 'value', function() { + storage._write('walletId::key', 'value', function() { done(); }); }); }); describe('#getGlobal', function() { - it('should store a global key', function(done) { + it('should call storage._read', function() { var storage = new Storage(); - storage.save = function(callback) { - storage.data['key'].should.equal('value'); - callback(); - }; - storage.setGlobal('key', 'value', function() { - done(); - }); + storage.data = {'walletId':{'test':'test'}}; + storage._read = sinon.spy(); + storage.getGlobal('walletId::test'); + storage._read.calledOnce.should.equal(true); }); }); describe('#setGlobal', function() { it('should store a global key', function(done) { var storage = new Storage(); - storage.save = function(callback) { - storage.data['key'].should.equal('value'); + storage.save = function(walletId, callback) { + storage.data[walletId]['key'].should.equal('value'); callback(); }; - storage.setGlobal('key', 'value', function() { + storage.setGlobal('walletId::key', 'value', function() { done(); }); }); @@ -90,12 +87,12 @@ describe('Storage/File', function() { describe('#removeGlobal', function() { it('should remove a global key', function(done) { var storage = new Storage(); - storage.data.key = 'value'; - storage.save = function(callback) { - should.not.exist(storage.data['key']); + storage.data = {'walletId':{'key':'value'}}; + storage.save = function(walletId, callback) { + should.not.exist(storage.data[walletId]['key']); callback(); }; - storage.removeGlobal('key', function() { + storage.removeGlobal('walletId::key', function() { done(); }); }); From 96a6203bb0ada1a9895449756c4987b0ff7c8872 Mon Sep 17 00:00:00 2001 From: "Ryan X. Charles" Date: Wed, 16 Apr 2014 21:02:53 -0300 Subject: [PATCH 11/17] make my code work with the latest interface changes ...to Wallet and WalletFactory --- API.js | 23 +++++------------------ js/models/core/WalletFactory.js | 22 ++-------------------- js/models/storage/Base.js | 3 +++ js/models/storage/File.js | 4 ++++ js/models/storage/LocalPlain.js | 15 +++++++++++++++ test/mocks/FakeStorage.js | 4 ++++ test/test.API.js | 8 ++++---- 7 files changed, 37 insertions(+), 42 deletions(-) diff --git a/API.js b/API.js index 5cf8d0841..76f30a29e 100644 --- a/API.js +++ b/API.js @@ -10,26 +10,13 @@ API.prototype._init = function(opts) { opts = opts || {}; self.opts = opts; - var Wallet = require('soop').load('./js/models/core/Wallet', { + var WalletFactory = require('soop').load('./js/models/core/WalletFactory', { Storage: opts.Storage || require('./test/mocks/FakeStorage'), Network: opts.Network || require('./js/models/network/Base'), Blockchain: opts.Blockchain || require('./js/models/blockchain/Insight') }); - - var config = { - wallet: { - requiredCopayers: opts.requiredCopayers || 3, - totalCopayers: opts.totalCopayers || 5, - }, - storage: { - filename: 'copaywallet.json' - } - }; - var walletConfig = opts.walletConfig || config; - var walletOpts = opts.walletOpts || {}; - - self.wallet = self.opts.wallet || Wallet.factory.create(walletConfig, walletOpts); + this.walletFactory = new WalletFactory(opts); }; API._coerceArgTypes = function(args, argTypes) { @@ -182,13 +169,13 @@ API.prototype.getCommands = decorate('getCommands', [ ['callback', 'function'] ]); -API.prototype._cmd_getPublicKeyRingId = function(callback) { +API.prototype._cmd_getWalletIds = function(callback) { var self = this; - return callback(null, self.wallet.publicKeyRing.walletId); + return callback(null, self.walletFactory.getWalletIds()); }; -API.prototype.getPublicKeyRingId = decorate('getPublicKeyRingId', [ +API.prototype.getWalletIds = decorate('getWalletIds', [ ['callback', 'function'] ]); diff --git a/js/models/core/WalletFactory.js b/js/models/core/WalletFactory.js index baef0b27c..3bcd14070 100644 --- a/js/models/core/WalletFactory.js +++ b/js/models/core/WalletFactory.js @@ -110,7 +110,6 @@ WalletFactory.prototype.create = function(opts) { opts.totalCopayers = totalCopayers; var w = new Wallet(opts); w.store(); - this.addWalletId(w.id); return w; }; @@ -156,28 +155,11 @@ WalletFactory.prototype.openRemote = function(peedId) { }; WalletFactory.prototype.getWalletIds = function() { - var ids = this.storage.getGlobal('walletIds'); - return ids || []; + return this.storage.getWalletIds(); } -WalletFactory.prototype._delWalletId = function(walletId) { - var ids = this.getWalletIds(); - var index = ids.indexOf(walletId); - if (index === -1) return; - ids.splice(index, 1); // removes walletId - this.storage.setGlobal('walletIds', ids); -}; - WalletFactory.prototype.remove = function(walletId) { - WalletFactory._delWalletId(walletId); - // TODO remove wallet contents, not only the id (Wallet.remove?) -}; - -WalletFactory.prototype.addWalletId = function(walletId) { - var ids = this.getWalletIds(); - if (ids.indexOf(walletId) !== -1) return; - ids.push(walletId); - this.storage.setGlobal('walletIds', ids); + // TODO remove wallet contents }; diff --git a/js/models/storage/Base.js b/js/models/storage/Base.js index 8f61f4dfe..29ca2564c 100644 --- a/js/models/storage/Base.js +++ b/js/models/storage/Base.js @@ -17,6 +17,9 @@ Storage.prototype.set = function(walletId,v) { Storage.prototype.remove = function(walletId, k) { }; +Storage.prototype.getWalletIds = function() { +}; + // remove all values Storage.prototype.clearAll = function() { }; diff --git a/js/models/storage/File.js b/js/models/storage/File.js index 9b3fa5f34..2c07b7010 100644 --- a/js/models/storage/File.js +++ b/js/models/storage/File.js @@ -89,6 +89,10 @@ Storage.prototype.remove = function(walletId, k, callback) { this.removeGlobal(this._key(walletId, k), callback); }; +Storage.prototype.getWalletIds = function() { + return []; +}; + // remove all values Storage.prototype.clearAll = function(callback) { this.data = {}; diff --git a/js/models/storage/LocalPlain.js b/js/models/storage/LocalPlain.js index 1bda410f2..d32234899 100644 --- a/js/models/storage/LocalPlain.js +++ b/js/models/storage/LocalPlain.js @@ -52,6 +52,21 @@ Storage.prototype.remove = function(walletId, k) { this.removeGlobal(this._key(walletId,k)); }; +Storage.prototype.getWalletIds = function() { + var walletIds = []; + + for (var i = 0; i < localStorage.length; i++) { + var key = localStorage.key(i); + var split = key.split('::'); + if (split.length == 2) { + var walletId = split[0]; + walletIds.push(walletId); + } + } + + return walletIds; +}; + // remove all values Storage.prototype.clearAll = function() { localStorage.clear(); diff --git a/test/mocks/FakeStorage.js b/test/mocks/FakeStorage.js index ef50df677..5819905e5 100644 --- a/test/mocks/FakeStorage.js +++ b/test/mocks/FakeStorage.js @@ -23,4 +23,8 @@ FakeStorage.prototype.clear = function() { delete this['storage']; } +FakeStorage.prototype.getWalletIds = function() { + return []; +}; + module.exports = require('soop')(FakeStorage); diff --git a/test/test.API.js b/test/test.API.js index a3046d20e..96795f75a 100644 --- a/test/test.API.js +++ b/test/test.API.js @@ -110,11 +110,11 @@ describe('API', function() { }); }); - describe('#getPublicKeyRingId', function() { - it('should get a public key ring ID', function(done) { + describe('#getWalletIds', function() { + it('should get the wallet ids', function(done) { var api = new API({Storage: Storage}); - api.getPublicKeyRingId(function(err, result) { - result.length.should.be.greaterThan(5); + api.getWalletIds(function(err, result) { + result.length.should.be.greaterThan(-1); done(); }); }); From 90cf7e7f7759d7b5b8baf3e5ce2bee33b6bf5d84 Mon Sep 17 00:00:00 2001 From: Manuel Araoz Date: Wed, 16 Apr 2014 21:39:42 -0300 Subject: [PATCH 12/17] fix browser tests --- copay.js | 2 +- util/build.js | 9 ++++++++- 2 files changed, 9 insertions(+), 2 deletions(-) diff --git a/copay.js b/copay.js index 0966485a4..d68d1cfb1 100644 --- a/copay.js +++ b/copay.js @@ -10,7 +10,7 @@ var Insight = module.exports.Insight = require('./js/models/blockchain/Insight') var StorageLocalPlain = module.exports.StorageLocalPlain = require('./js/models/storage/LocalPlain'); var StorageLocalEncrypted = module.exports.StorageLocalEncrypted = require('./js/models/storage/LocalEncrypted'); -var WalletFactory = require('soop').load('./js/models/core/WalletFactory.js',{ +var WalletFactory = require('soop').load('./js/models/core/WalletFactory',{ Network: WebRTC, Blockchain: Insight, Storage: StorageLocalPlain, diff --git a/util/build.js b/util/build.js index eca71fa0a..509c43466 100755 --- a/util/build.js +++ b/util/build.js @@ -42,7 +42,14 @@ var createBundle = function(opts) { b.require('./copay', { expose: 'copay' }); - b.require('./js/models/core/WalletFactory.js'); + b.require('./js/models/core/WalletFactory'); + b.require('./js/models/core/Wallet'); + b.require('./js/models/core/Wallet', { + expose: '../js/models/core/Wallet' + }); + b.require('./test/mocks/FakeStorage', { + expose: './mocks/FakeStorage' + }); if (!opts.dontminify) { From 8478402237b8eae95b537484d23f20437f101fec Mon Sep 17 00:00:00 2001 From: Manuel Araoz Date: Wed, 16 Apr 2014 17:07:14 -0300 Subject: [PATCH 13/17] add wallet setup view (not integrated) --- index.html | 32 ++++++++++++++++++++++++++++++++ js/app.js | 2 ++ js/config.js | 4 ++++ js/controllers/setup.js | 34 ++++++++++++++++++++++++++++++++++ js/routes.js | 3 +++ 5 files changed, 75 insertions(+) create mode 100644 js/controllers/setup.js diff --git a/index.html b/index.html index 0300f7588..3a670a9ae 100644 --- a/index.html +++ b/index.html @@ -96,6 +96,37 @@ + + + diff --git a/js/app.js b/js/app.js index 21859c3ff..f1fff46a0 100644 --- a/js/app.js +++ b/js/app.js @@ -11,6 +11,7 @@ angular.module('copay',[ 'copay.backup', 'copay.walletFactory', 'copay.signin', + 'copay.setup', 'copay.peer' ]); @@ -21,5 +22,6 @@ angular.module('copay.send', []); angular.module('copay.backup', []); angular.module('copay.walletFactory', []); angular.module('copay.signin', []); +angular.module('copay.setup', []); angular.module('copay.peer', []); diff --git a/js/config.js b/js/config.js index cbc46bab8..d73f23cdb 100644 --- a/js/config.js +++ b/js/config.js @@ -7,6 +7,10 @@ var config = { maxPeers: 3, debug: 3, }, + limits: { + totalCopayers: 10, + mPlusN: 15 + }, wallet: { requiredCopayers: 2, totalCopayers: 3, diff --git a/js/controllers/setup.js b/js/controllers/setup.js new file mode 100644 index 000000000..30828843e --- /dev/null +++ b/js/controllers/setup.js @@ -0,0 +1,34 @@ +'use strict'; + +angular.module('copay.setup').controller('SetupController', + function($scope, $rootScope, $location, Network) { + + $scope.loading = false; + + $scope.selectedWalletId = false; + $scope.totalCopayers = config.wallet.totalCopayers; + $scope.TCValues = []; + for (var n = 1; n <= config.limits.totalCopayers; n++) + $scope.TCValues.push(n); + + var updateRCSelect = function(n) { + $scope.requiredCopayers = parseInt(Math.min(n / 2 + 1, config.limits.mPlusN-n)); + $scope.RCValues = []; + for (var m = 1; m <= n; m++) { + if (n + m <= config.limits.mPlusN) { + $scope.RCValues.push(m); + } + } + }; + updateRCSelect($scope.totalCopayers); + + $scope.$watch('totalCopayers', function(tc) { + updateRCSelect(tc); + }) + + $scope.create = function(totalCopayers, requiredCopayers) { + alert(totalCopayers); + alert(requiredCopayers); + }; + + }); diff --git a/js/routes.js b/js/routes.js index 3793d88bd..5c655b208 100644 --- a/js/routes.js +++ b/js/routes.js @@ -12,6 +12,9 @@ angular .when('/signin', { templateUrl: 'signin.html' }) + .when('/setup', { + templateUrl: 'setup.html' + }) .when('/home', { templateUrl: 'home.html' }) From b50407400913e893af98c0fab2eec9456672b5bf Mon Sep 17 00:00:00 2001 From: Manuel Araoz Date: Wed, 16 Apr 2014 19:05:04 -0300 Subject: [PATCH 14/17] actually create wallet and redirect --- js/controllers/setup.js | 17 +++++++++++++---- ...t.walletfactory.js => test.Walletfactory.js} | 0 2 files changed, 13 insertions(+), 4 deletions(-) rename test/{test.walletfactory.js => test.Walletfactory.js} (100%) diff --git a/js/controllers/setup.js b/js/controllers/setup.js index 30828843e..e084218a3 100644 --- a/js/controllers/setup.js +++ b/js/controllers/setup.js @@ -1,11 +1,10 @@ 'use strict'; angular.module('copay.setup').controller('SetupController', - function($scope, $rootScope, $location, Network) { + function($scope, $rootScope, $location, walletFactory) { $scope.loading = false; - $scope.selectedWalletId = false; $scope.totalCopayers = config.wallet.totalCopayers; $scope.TCValues = []; for (var n = 1; n <= config.limits.totalCopayers; n++) @@ -27,8 +26,18 @@ angular.module('copay.setup').controller('SetupController', }) $scope.create = function(totalCopayers, requiredCopayers) { - alert(totalCopayers); - alert(requiredCopayers); + $scope.loading = true; + var opts = { + requiredCopayers: requiredCopayers, + totalCopayers: totalCopayers + }; + var w = walletFactory.create(); + w.on('open', function(){ + $location.path('peer'); + $rootScope.wallet = w; + $rootScope.$digest(); + }); + w.netStart(); }; }); diff --git a/test/test.walletfactory.js b/test/test.Walletfactory.js similarity index 100% rename from test/test.walletfactory.js rename to test/test.Walletfactory.js From 9df76b90fddb64e5afc38cbb8a1b1924b3964d35 Mon Sep 17 00:00:00 2001 From: Manuel Araoz Date: Wed, 16 Apr 2014 19:45:22 -0300 Subject: [PATCH 15/17] m-of-n integration complete --- index.html | 5 ++++- js/controllers/setup.js | 9 +++++++-- js/controllers/signin.js | 7 +------ js/models/core/Wallet.js | 2 ++ 4 files changed, 14 insertions(+), 9 deletions(-) diff --git a/index.html b/index.html index 3a670a9ae..25796ab8e 100644 --- a/index.html +++ b/index.html @@ -102,6 +102,7 @@ Connecting to wallet...
+

Create new multisig wallet

Select total number of copayers

@@ -120,7 +121,9 @@
+ ng-click="create(totalCopayers, requiredCopayers)"> + Create {{requiredCopayers}}-of-{{totalCopayers}} wallet +
diff --git a/js/controllers/setup.js b/js/controllers/setup.js index e084218a3..a8f25cb3e 100644 --- a/js/controllers/setup.js +++ b/js/controllers/setup.js @@ -31,12 +31,17 @@ angular.module('copay.setup').controller('SetupController', requiredCopayers: requiredCopayers, totalCopayers: totalCopayers }; - var w = walletFactory.create(); - w.on('open', function(){ + var w = walletFactory.create(opts); + w.on('created', function(){ $location.path('peer'); $rootScope.wallet = w; $rootScope.$digest(); }); + w.on('openError', function(){ + $scope.loading = false; + $rootScope.flashMessage = {type:'error', message: 'Wallet not found'}; + $location.path('signin'); + }); w.netStart(); }; diff --git a/js/controllers/signin.js b/js/controllers/signin.js index 122cdc02a..4b25c800f 100644 --- a/js/controllers/signin.js +++ b/js/controllers/signin.js @@ -27,12 +27,7 @@ angular.module('copay.signin').controller('SigninController', }; $scope.create = function() { -console.log('[signin.js.42:create:]'); //TODO - $scope.loading = true; - - var w = walletFactory.create(); - _setupUxHandlers(w); - w.netStart(); + $location.path('setup'); }; $scope.open = function(walletId) { diff --git a/js/models/core/Wallet.js b/js/models/core/Wallet.js index 1d2141117..98bc6faba 100644 --- a/js/models/core/Wallet.js +++ b/js/models/core/Wallet.js @@ -22,6 +22,8 @@ function Wallet(opts) { self[k] = opts[k]; }); + console.log('creating '+opts.requiredCopayers+' of '+opts.totalCopayers+' wallet'); + this.id = opts.id || Wallet.getRandomId(); this.publicKeyRing.walletId = this.id; this.txProposals.walletId = this.id; From 9a2c5a66fc703c9392be87aa4501bcc7e544c95d Mon Sep 17 00:00:00 2001 From: "Ryan X. Charles" Date: Wed, 16 Apr 2014 21:49:30 -0300 Subject: [PATCH 16/17] add latest bitcore master to the repo --- lib/bitcore.js | 375 +++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 375 insertions(+) create mode 100644 lib/bitcore.js diff --git a/lib/bitcore.js b/lib/bitcore.js new file mode 100644 index 000000000..3ef2263bb --- /dev/null +++ b/lib/bitcore.js @@ -0,0 +1,375 @@ +require= +// modules are defined as an array +// [ module function, map of requireuires ] +// +// map of requireuires is short require name -> numeric require +// +// anything defined in a previous bundle is accessed via the +// orig method which is the requireuire for previous bundles +(function outer (modules, cache, entry) { + // Save the require from previous bundle to this closure if any + var previousRequire = typeof require == "function" && require; + + function newRequire(name, jumped, inSkipCache){ + + var m, skipCache = inSkipCache; + if (typeof name === 'string') { + if (name.charAt(0) === '!' ) { + name = name.substr(1); + skipCache=true; + } + } + if(skipCache || !cache[name]) { + if(!modules[name]) { + // if we cannot find the the module within our internal map or + // cache jump to the current global require ie. the last bundle + // that was added to the page. + var currentRequire = typeof require == "function" && require; + if (!jumped && currentRequire) return currentRequire(name, true); + + // If there are other bundles on this page the require from the + // previous one is saved to 'previousRequire'. Repeat this as + // many times as there are bundles until the module is found or + // we exhaust the require chain. + if (previousRequire) return previousRequire(name, true); + throw new Error('Cannot find module \'' + name + '\''); + } + + m = {exports:{}}; + var nextSkipCache = inSkipCache ? false : skipCache; + if (!skipCache) cache[name] = m; + skipCache = false; + modules[name][0].call(m.exports, function(x){ + var id = modules[name][1][x]; + return newRequire(id ? id : x, false, nextSkipCache); + },m,m.exports,outer,modules,cache,entry); + } + return m ? m.exports:cache[name].exports; + } + for(var i=0;in;n++)t*=256,t+=e[n];return t}function t(e){return i(e,1)}function n(e){return i(e,4)}var r=require("soop").imports(),s=r.base58||require("base58-native").base58,h=r.coinUtil||require("./util/util"),d=r.Key||require("./Key"),c=r.Point||require("./Point"),a=r.bignum||require("bignum"),o=(require("crypto"),require("./networks")),y=new a("FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEBAAEDCE6AF48A03BBFD25E8CD0364141",16),l=(new a("79BE667EF9DCBBAC55A06295CE870B07029BFCDB2DCE28D959F2815B16F81798",16),function(i){if("mainnet"==i||"livenet"==i?this.version=o.livenet.bip32privateVersion:"testnet"==i&&(this.version=o.testnet.bip32privateVersion),"mainnet"==i||"livenet"==i||"testnet"==i)return this.depth=0,this.parentFingerprint=new e([0,0,0,0]),this.childIndex=new e([0,0,0,0]),this.chainCode=d.generateSync().private,this.eckey=d.generateSync(),this.hasPrivateKey=!0,this.pubKeyHash=h.sha256ripe160(this.eckey.public),this.buildExtendedPublicKey(),void this.buildExtendedPrivateKey();if("string"==typeof i){var t=s.decode(i);if(82!=t.length)throw new Error("Not enough data");var n=t.slice(78,82);i=t.slice(0,78);var r=h.sha256(h.sha256(i));if(r[0]!=n[0]||r[1]!=n[1]||r[2]!=n[2]||r[3]!=n[3])throw new Error("Invalid checksum")}void 0!==i&&this.initFromBytes(i)});l.seed=function(i,t){if(t||(t="livenet"),e.isBuffer(i)||(i=new e(i,"hex")),i.length<16)return!1;var n=h.sha512hmac(i,new e("Bitcoin seed")),r=new l;return r.depth=0,r.parentFingerprint=new e([0,0,0,0]),r.childIndex=new e([0,0,0,0]),r.chainCode=n.slice(32,64),r.version=o[t].bip32privateVersion,r.eckey=new d,r.eckey.private=n.slice(0,32),r.eckey.regenerateSync(),r.hasPrivateKey=!0,r.pubKeyHash=h.sha256ripe160(r.eckey.public),r.buildExtendedPublicKey(),r.buildExtendedPrivateKey(),r},l.prototype.initFromBytes=function(e){if(78!=e.length)throw new Error("not enough data");this.version=n(e.slice(0,4)),this.depth=t(e.slice(4,5)),this.parentFingerprint=e.slice(5,9),this.childIndex=n(e.slice(9,13)),this.chainCode=e.slice(13,45);var i=e.slice(45,78),r=this.version==o.livenet.bip32privateVersion||this.version==o.testnet.bip32privateVersion,s=this.version==o.livenet.bip32publicVersion||this.version==o.testnet.bip32publicVersion;if(r&&0==i[0])this.eckey=new d,this.eckey.private=i.slice(1,33),this.eckey.compressed=!0,this.eckey.regenerateSync(),this.pubKeyHash=h.sha256ripe160(this.eckey.public),this.hasPrivateKey=!0;else{if(!s||2!=i[0]&&3!=i[0])throw new Error("Invalid key");this.eckey=new d,this.eckey.public=i,this.pubKeyHash=h.sha256ripe160(this.eckey.public),this.hasPrivateKey=!1}this.buildExtendedPublicKey(),this.buildExtendedPrivateKey()},l.prototype.buildExtendedPublicKey=function(){this.extendedPublicKey=new e([]);var i=null;switch(this.version){case o.livenet.bip32publicVersion:case o.livenet.bip32privateVersion:i=o.livenet.bip32publicVersion;break;case o.testnet.bip32publicVersion:case o.testnet.bip32privateVersion:i=o.testnet.bip32publicVersion;break;default:throw new Error("Unknown version")}this.extendedPublicKey=e.concat([this.extendedPublicKey,new e([i>>24])]),this.extendedPublicKey=e.concat([this.extendedPublicKey,new e([i>>16&255])]),this.extendedPublicKey=e.concat([this.extendedPublicKey,new e([i>>8&255])]),this.extendedPublicKey=e.concat([this.extendedPublicKey,new e([255&i])]),this.extendedPublicKey=e.concat([this.extendedPublicKey,new e([this.depth])]),this.extendedPublicKey=e.concat([this.extendedPublicKey,this.parentFingerprint]),this.extendedPublicKey=e.concat([this.extendedPublicKey,new e([this.childIndex>>>24])]),this.extendedPublicKey=e.concat([this.extendedPublicKey,new e([this.childIndex>>>16&255])]),this.extendedPublicKey=e.concat([this.extendedPublicKey,new e([this.childIndex>>>8&255])]),this.extendedPublicKey=e.concat([this.extendedPublicKey,new e([255&this.childIndex])]),this.extendedPublicKey=e.concat([this.extendedPublicKey,this.chainCode]),this.extendedPublicKey=e.concat([this.extendedPublicKey,this.eckey.public])},l.prototype.extendedPublicKeyString=function(i){if(void 0===i||"base58"===i){var t=h.sha256(h.sha256(this.extendedPublicKey)),n=t.slice(0,4),r=e.concat([this.extendedPublicKey,n]);return s.encode(r)}if("hex"===i)return this.extendedPublicKey.toString("hex");throw new Error("bad format")},l.prototype.buildExtendedPrivateKey=function(){if(this.hasPrivateKey){this.extendedPrivateKey=new e([]);var i=this.version;this.extendedPrivateKey=e.concat([this.extendedPrivateKey,new e([i>>24])]),this.extendedPrivateKey=e.concat([this.extendedPrivateKey,new e([i>>16&255])]),this.extendedPrivateKey=e.concat([this.extendedPrivateKey,new e([i>>8&255])]),this.extendedPrivateKey=e.concat([this.extendedPrivateKey,new e([255&i])]),this.extendedPrivateKey=e.concat([this.extendedPrivateKey,new e([this.depth])]),this.extendedPrivateKey=e.concat([this.extendedPrivateKey,this.parentFingerprint]),this.extendedPrivateKey=e.concat([this.extendedPrivateKey,new e([this.childIndex>>>24])]),this.extendedPrivateKey=e.concat([this.extendedPrivateKey,new e([this.childIndex>>>16&255])]),this.extendedPrivateKey=e.concat([this.extendedPrivateKey,new e([this.childIndex>>>8&255])]),this.extendedPrivateKey=e.concat([this.extendedPrivateKey,new e([255&this.childIndex])]),this.extendedPrivateKey=e.concat([this.extendedPrivateKey,this.chainCode]),this.extendedPrivateKey=e.concat([this.extendedPrivateKey,new e([0])]),this.extendedPrivateKey=e.concat([this.extendedPrivateKey,this.eckey.private])}},l.prototype.extendedPrivateKeyString=function(i){if(void 0===i||"base58"===i){var t=h.sha256(h.sha256(this.extendedPrivateKey)),n=t.slice(0,4),r=e.concat([this.extendedPrivateKey,n]);return s.encode(r)}if("hex"===i)return this.extendedPrivateKey.toString("hex");throw new Error("bad format")},l.prototype.derive=function(e){var i=e.split("/");if("m"==e||"M"==e||"m'"==e||"M'"==e)return this;var t=this;for(var n in i){var r=i[n];if(0!=n){var s=r.length>1&&"'"==r[r.length-1],h=2147483647&parseInt(s?r.slice(0,r.length-1):r);s&&(h+=2147483648),t=t.deriveChild(h)}else if("m"!=r)throw new Error("invalid path")}return t},l.prototype.deriveChild=function(i){var t=[];t.push(i>>24&255),t.push(i>>16&255),t.push(i>>8&255),t.push(255&i),t=new e(t);var n=0!=(2147483648&i),r=this.version==o.livenet.bip32privateVersion||this.version==o.testnet.bip32privateVersion;if(n&&(!this.hasPrivateKey||!r))throw new Error("Cannot do private key derivation without private key");var s=null;if(this.hasPrivateKey){var u=null;u=e.concat(n?[new e([0]),this.eckey.private,t]:[this.eckey.public,t]);var v=h.sha512hmac(u,this.chainCode),p=a.fromBuffer(v.slice(0,32),{size:32}),b=v.slice(32,64),K=a.fromBuffer(this.eckey.private,{size:32}),x=p.add(K).mod(y);s=new l,s.chainCode=b,s.eckey=new d,s.eckey.private=x.toBuffer({size:32}),s.eckey.regenerateSync(),s.hasPrivateKey=!0}else{var u=e.concat([this.eckey.public,t]),v=h.sha512hmac(u,this.chainCode),p=a.fromBuffer(v.slice(0,32),{size:32}),b=v.slice(32,64),P=new d;P.private=p.toBuffer({size:32}),P.regenerateSync();var w=c.fromKey(P),f=new d;f.public=this.eckey.public;var F=c.fromKey(f),k=c.add(w,F).toKey().public;s=new l,s.chainCode=new e(b);var g=new d;g.public=k,s.eckey=g,s.hasPrivateKey=!1}return s.childIndex=i,s.parentFingerprint=this.pubKeyHash.slice(0,4),s.version=this.version,s.depth=this.depth+1,s.eckey.compressed=!0,s.pubKeyHash=h.sha256ripe160(s.eckey.public),s.buildExtendedPublicKey(),s.buildExtendedPrivateKey(),s},module.exports=require("soop")(l)}).call(this,require("buffer").Buffer); +},{"./Key":"Af1Gom","./Point":"8PQ/SZ","./networks":"ULNIu2","./util/util":"ACyo5H","base58-native":"xtP2pj","bignum":"J4nwo8","buffer":75,"crypto":79,"soop":146}],"KqTx5b":[function(require,module,exports){ +(function(t){function e(t){"object"!=typeof t&&(t={}),this.hash=t.hash||null,this.prev_hash=t.prev_hash||i.NULL_HASH,this.merkle_root=t.merkle_root||i.NULL_HASH,this.timestamp=t.timestamp||0,this.bits=t.bits||0,this.nonce=t.nonce||0,this.version=t.version||0,this.height=t.height||0,this.size=t.size||0,this.active=t.active||!1,this.chainWork=t.chainWork||i.EMPTY_BUFFER,this.txs=t.txs||[]}var r=require("soop").imports(),i=r.util||require("./util/util"),o=(r.Debug1||function(){},r.Script||require("./Script")),s=r.Bignum||require("bignum"),h=(r.Binary||require("binary"),r.Step||require("step"),r.buffertools||require("buffertools")),n=r.Transaction||require("./Transaction"),a=n.In,c=n.Out,u=n.COINBASE_OP,l=r.VerificationError||require("./util/error").VerificationError,f={maxTimeOffset:7200,largestHash:s(2).pow(256)};e.prototype.getHeader=function(){var e=new t(80),r=0;return e.writeUInt32LE(this.version,r),r+=4,this.prev_hash.copy(e,r),r+=32,this.merkle_root.copy(e,r),r+=32,e.writeUInt32LE(this.timestamp,r),r+=4,e.writeUInt32LE(this.bits,r),r+=4,e.writeUInt32LE(this.nonce,r),r+=4,e},e.prototype.parse=function(t,e){if(this.version=t.word32le(),this.prev_hash=t.buffer(32),this.merkle_root=t.buffer(32),this.timestamp=t.word32le(),this.bits=t.word32le(),this.nonce=t.word32le(),this.txs=[],this.size=0,!e)for(var r=t.varInt(),i=0;r>i;i++){var o=new n;o.parse(t),this.txs.push(o)}},e.prototype.calcHash=function(){var t=this.getHeader();return i.twoSha256(t)},e.prototype.checkHash=function(){return this.hash&&this.hash.length?0==h.compare(this.calcHash(),this.hash):!1},e.prototype.getHash=function(){return this.hash&&this.hash.length||(this.hash=this.calcHash()),this.hash},e.prototype.checkProofOfWork=function(){var t=i.decodeDiffBits(this.bits),e=h.reverse(this.hash);if(h.compare(e,t)>0)throw new l("Difficulty target not met");return!0},e.prototype.getWork=function(){var t=i.decodeDiffBits(this.bits,!0);return f.largestHash.div(t.add(1))},e.prototype.checkTimestamp=function(){var t=(new Date).getTime()/1e3;if(this.timestamp>t+f.maxTimeOffset)throw new l("Timestamp too far into the future");return!0},e.prototype.checkTransactions=function(t){if(!Array.isArray(t)||t.length<=0)throw new l("No transactions");if(!t[0].isCoinBase())throw new l("First tx must be coinbase");for(var e=1;e1;s=Math.floor((s+1)/2)){for(var h=0;s>h;h+=2){var a=Math.min(h+1,s-1),c=r[o+h],u=r[o+a];r.push(i.twoSha256(t.concat([c,u])))}o+=s}return r},e.prototype.calcMerkleRoot=function(t){var e=this.getMerkleTree(t);return e[e.length-1]},e.prototype.checkMerkleRoot=function(e){if(!this.merkle_root||!this.merkle_root.length)throw new l("No merkle root");if(0!==h.compare(this.calcMerkleRoot(e),new t(this.merkle_root)))throw new l("Merkle root incorrect");return!0},e.prototype.checkBlock=function(t){if(!this.checkHash())throw new l("Block hash invalid");if(this.checkProofOfWork(),this.checkTimestamp(),t&&(this.checkTransactions(t),!this.checkMerkleRoot(t)))throw new l("Merkle hash invalid");return!0},e.getBlockValue=function(t){var e=s(50).mul(i.COIN);return e=e.div(s(2).pow(Math.floor(t/21e4)))},e.prototype.getBlockValue=function(){return e.getBlockValue(this.height)},e.prototype.toString=function(){return""},e.prototype.createCoinbaseTx=function(t){var e=new n;return e.ins.push(new a({s:i.EMPTY_BUFFER,q:4294967295,o:u})),e.outs.push(new c({v:i.bigIntToValue(this.getBlockValue()),s:o.createPubKeyOut(t).getBuffer()})),e},e.prototype.solve=function(t,e){var r=this.getHeader(),o=i.decodeDiffBits(this.bits);t.solve(r,o,e)},e.prototype.getStandardizedObject=function(t){var e={hash:i.formatHashFull(this.getHash()),version:this.version,prev_block:i.formatHashFull(this.prev_hash),mrkl_root:i.formatHashFull(this.merkle_root),time:this.timestamp,bits:this.bits,nonce:this.nonce,height:this.height};if(t){var r=this.getMerkleTree(t).map(function(t){return i.formatHashFull(t)});e.mrkl_root=r[r.length-1],e.n_tx=t.length;var o=80;o+=i.getVarIntSize(t.length),t=t.map(function(t){return t=t.getStandardizedObject(),o+=t.size,t}),e.size=o,e.tx=t,e.mrkl_tree=r}else e.size=this.size;return e},module.exports=require("soop")(e)}).call(this,require("buffer").Buffer); +},{"./Script":"clx6XL","./Transaction":"RNv6Te","./util/error":155,"./util/util":"ACyo5H","bignum":"J4nwo8","binary":62,"buffer":75,"buffertools":"fugeBw","soop":146,"step":147}],"./Block":[function(require,module,exports){ +module.exports=require('KqTx5b'); +},{}],"ZnXdbH":[function(require,module,exports){ +function Bloom(){this.data="",this.hashFuncs=0}function ROTL32(t,n){return t<>32-n}function getBlockU32(t,n){var o=4*t,s=n[o+0]<<0|n[o+1]<<8|n[o+2]<<16|n[o+3]<<24;return s}function toInt(t){return~~t}function min(t,n){return n>t?t:n}var MAX_BLOOM_FILTER_SIZE=36e3,MAX_HASH_FUNCS=50,LN2SQUARED=.48045301391820144,LN2=.6931471805599453,bit_mask=[1,2,4,8,16,32,64,128];Bloom.prototype.hash=function(t,n){for(var o=t*(4294967295/(this.hashFuncs-1)),s=3432918353,a=461845907,h=n.length/4,i=-h;i;i++){var r=getBlockU32(i);r*=s,r=ROTLF32(r,15),r*=a,o^=r,o=ROTFL(o,13),o=5*o+3864292196}var e=n.slice(4*h),r=0;switch(3&n.length){case 3:r^=e[2]<<16;case 2:r^=e[1]<<8;case 1:r^=e[0],r*=s,r=ROTL32(r,15),r*=a,o^=r}return o^=n.length,o^=o>>16,o*=2246822507,o^=o>>13,o*=3266489909,o^=o>>16,o%(8*this.data.length)},Bloom.prototype.insert=function(t){for(var n=0;n>3]|=bit_mask[7&o]}},Bloom.prototype.contains=function(t){for(var n=0;n>3]&bit_mask[7&o]))return!1}return!0},Bloom.prototype.sizeOk=function(){return this.data.length<=MAX_BLOOM_FILTER_SIZE&&this.hashFuncs<=MAX_HASH_FUNCS},Bloom.prototype.init=function(t,n){var o=min(toInt(-1/LN2SQUARED*t*Math.log(n)),8*MAX_BLOOM_FILTER_SIZE)/8;this.data[o]=0,this.hashFuncs=min(toInt(8*this.data.length/t*LN2),MAX_HASH_FUNCS)},module.exports=require("soop")(Bloom); +},{"soop":146}],"./Bloom":[function(require,module,exports){ +module.exports=require('ZnXdbH'); +},{}],"./Buffers.monkey":[function(require,module,exports){ +module.exports=require('jmkPxi'); +},{}],"jmkPxi":[function(require,module,exports){ +(function(f){exports.patch=function(t){t.prototype.skip=function(t){if(0!=t){if(t==this.length)return this.buffers=[],void(this.length=0);var s=this.pos(t);this.buffers=this.buffers.slice(s.buf),this.buffers[0]=new f(this.buffers[0].slice(s.offset)),this.length-=t}}}}).call(this,require("buffer").Buffer); +},{"buffer":75}],"./Connection":[function(require,module,exports){ +module.exports=require('h81grl'); +},{}],"h81grl":[function(require,module,exports){ +(function(e){function t(e,r){t.super(this,arguments),this.socket=e,this.peer=r,this.active=!1,this.recvVer=0,this.sendVer=0,this.bestHeight=0,this.inbound=!!e.server,this.getaddr=!1,this.buffers=new c,(new Date).getTime()>1329696e6&&(this.recvVer=209,this.sendVer=209),this.setupHandlers()}var r=require("soop").imports(),s=r.config||require("./config"),n=r.log||require("./util/log"),i=r.network||require("./networks")[s.network],o=1e7,a=7e4,h=(r.Binary||require("binary"),r.Put||require("bufferput")),c=r.Buffers||require("buffers");require("./Buffers.monkey").patch(c);var d=require("./Block"),f=require("./Transaction"),u=r.util||require("./util/util"),p=r.Parser||require("./util/BinaryParser"),g=r.buffertools||require("buffertools"),l=r.doubleSha256||u.twoSha256,v=u.generateNonce(),b=6e4;t.parent=r.parent||require("events").EventEmitter,t.prototype.setupHandlers=function(){this.socket.addListener("connect",this.handleConnect.bind(this)),this.socket.addListener("error",this.handleError.bind(this)),this.socket.addListener("end",this.handleDisconnect.bind(this)),this.socket.addListener("data",function(e){var t=35;n.debug("["+this.peer+"] Recieved "+e.length+" bytes of data:"),n.debug("... "+g.toHex(e.slice(0,t>e.length?e.length:t))+(e.length>t?"...":""))}.bind(this)),this.socket.addListener("data",this.handleData.bind(this))},t.prototype.handleConnect=function(){this.inbound||this.sendVersion(),this.emit("connect",{conn:this,socket:this.socket,peer:this.peer})},t.prototype.handleError=function(e){110==e.errno||"ETIMEDOUT"==e.errno?n.info("connection timed out for "+this.peer):111==e.errno||"ECONNREFUSED"==e.errno?n.info("connection refused for "+this.peer):n.warn("connection with "+this.peer+" "+e.toString()),this.emit("error",{conn:this,socket:this.socket,peer:this.peer,err:e})},t.prototype.handleDisconnect=function(){this.emit("disconnect",{conn:this,socket:this.socket,peer:this.peer})},t.prototype.handleMessage=function(t){if(t){try{switch(t.command){case"version":if(0===g.compare(v,t.nonce))return void this.socket.end();this.inbound&&this.sendVersion(),t.version>=209&&this.sendMessage("verack",new e([])),this.sendVer=Math.min(t.version,a),t.version<209?this.recvVer=Math.min(t.version,a):this.once("verack",function(){this.recvVer=t.version}.bind(this)),this.bestHeight=t.start_height;break;case"verack":this.recvVer=Math.min(t.version,a),this.active=!0;break;case"ping":"object"==typeof t.nonce&&this.sendPong(t.nonce)}}catch(r){return void n.err('Error while handling "'+t.command+'" message from '+this.peer+":\n"+(r.stack?r.stack:r.toString()))}this.emit(t.command,{conn:this,socket:this.socket,peer:this.peer,message:t})}},t.prototype.sendPong=function(e){this.sendMessage("pong",e)},t.prototype.sendVersion=function(){var t="/BitcoinX:0.1/",r=new h;r.word32le(a),r.word64le(1),r.word64le(Math.round((new Date).getTime()/1e3)),r.pad(26),r.pad(26),r.put(v),r.varint(t.length),r.put(new e(t,"ascii")),r.word32le(0),this.sendMessage("version",r.buffer())},t.prototype.sendGetBlocks=function(t,r,s){r=r||u.NULL_HASH;var n=new h;n.word32le(this.sendVer),n.varint(t.length);for(var i=0;i12)throw"Command name too long";var a;a=this.sendVer>=209?l(r).slice(0,4):new e([]);var c=new h;c.put(s),c.put(o),c.pad(12-o.length),c.word32le(r.length),c.put(a),c.put(r);var d=c.buffer();n.debug("["+this.peer+"] Sending message "+t+" ("+r.length+" bytes)"),this.socket.write(d)}catch(f){n.err("Error while sending message to peer "+this.peer+": "+(f.stack?f.stack:f.toString()))}},t.prototype.handleData=function(e){return this.buffers.push(e),this.buffers.length>o?(n.err("Peer "+this.peer+" exceeded maxreceivebuffer, disconnecting."+(err.stack?err.stack:err.toString())),void this.socket.destroy()):void this.processData()},t.prototype.processData=function(){if(!(this.buffers.length<20)){for(var e=i.magic,t=0;;){if(this.buffers.get(t)===e[0]&&this.buffers.get(t+1)===e[1]&&this.buffers.get(t+2)===e[2]&&this.buffers.get(t+3)===e[3]){0!==t&&(n.debug("["+this.peer+"] Received "+t+" bytes of inter-message garbage: "),n.debug("... "+this.buffers.slice(0,t)),this.buffers.skip(t));break}if(t>this.buffers.length-4)return void this.buffers.skip(t);t++}var r=this.buffers.get(16)+(this.buffers.get(17)<<8)+(this.buffers.get(18)<<16)+(this.buffers.get(19)<<24),s=this.recvVer>=209?24:20,o=s+r;if(!(this.buffers.length=209?this.buffers.slice(20,24):null;if(n.debug("["+this.peer+"] Received message "+a+" ("+r+" bytes)"),null!==c){var d=l(h).slice(0,4);if(0!==g.compare(d,c))return void n.err("["+this.peer+"] Checksum failed",{cmd:a,expected:d.toString("hex"),actual:c.toString("hex")})}var f;try{f=this.parseMessage(a,h)}catch(u){n.err("Error while parsing message "+a+" from "+this.peer+":\n"+(u.stack?u.stack:u.toString()))}f&&this.handleMessage(f),this.buffers.skip(o),this.processData()}}},t.prototype.parseMessage=function(e,t){var r,s=new p(t),i={command:e};switch(e){case"version":i.version=s.word32le(),i.services=s.word64le(),i.timestamp=s.word64le(),i.addr_me=s.buffer(26),i.addr_you=s.buffer(26),i.nonce=s.buffer(8),i.subversion=s.varStr(),i.start_height=s.word32le();break;case"inv":case"getdata":for(i.count=s.varInt(),i.invs=[],r=0;rr;r++)i.starts.push(s.buffer(32));i.stop=s.buffer(32);break;case"addr":var u=s.varInt();for(u>1e3&&(u=1e3),i.addrs=[],r=0;u>r;r++)i.addrs.push({time:s.word32le(),services:s.word64le(),ip:s.buffer(16),port:s.word16be()});break;case"alert":i.payload=s.varStr(),i.signature=s.varStr();break;case"ping":this.recvVer>b&&(i.nonce=s.buffer(8));break;case"getaddr":case"verack":case"reject":break;default:return n.err("Connection.parseMessage(): Command not implemented",{cmd:e}),null}return i},module.exports=require("soop")(t)}).call(this,require("buffer").Buffer); +},{"./Block":"KqTx5b","./Buffers.monkey":"jmkPxi","./Transaction":"RNv6Te","./config":"4itQ50","./networks":"ULNIu2","./util/BinaryParser":"b3ZSD7","./util/log":"AdF7pF","./util/util":"ACyo5H","binary":62,"buffer":75,"bufferput":"aXRuS6","buffers":"OBo3aV","buffertools":"fugeBw","events":84,"soop":146}],"ypnq12":[function(require,module,exports){ +exports.intFromCompact=function(r){var t=(r>>>24&255)>>>0,n=(16777215&r)<<8*(t-3)>>>0;return n}; +},{}],"./Deserialize":[function(require,module,exports){ +module.exports=require('ypnq12'); +},{}],"./Gruntfile":[function(require,module,exports){ +module.exports=require('NbSoFu'); +},{}],"NbSoFu":[function(require,module,exports){ +"use strict";module.exports=function(s){s.loadNpmTasks("grunt-contrib-watch"),s.loadNpmTasks("grunt-mocha-test"),s.loadNpmTasks("grunt-markdown"),s.loadNpmTasks("grunt-shell"),s.initConfig({shell:{browserify:{options:{stdout:!0,stderr:!0},command:"dev"===s.option("target")?"node ./browser/build.js -a -d ":"node ./browser/build.js -a"}},watch:{readme:{files:["README.md"],tasks:["markdown"]},scripts:{files:["**/*.js","**/*.html","!**/node_modules/**","!browser/bundle.js","!browser/testdata.js","!browser/vendor-bundle.js"],tasks:["shell"]}},mochaTest:{options:{reporter:"spec"},src:["test/*.js"]},markdown:{all:{files:[{expand:!0,src:"README.md",dest:".",ext:".html"}]}}}),s.registerTask("default",["shell","watch"])}; +},{}],"./Key":[function(require,module,exports){ +module.exports=require('Af1Gom'); +},{}],"Af1Gom":[function(require,module,exports){ +(function(e,r){if(e.versions){var t=require("bindings")("KeyModule"),s=t.Key;module.exports=s}else{var o=require("./browser/vendor-bundle.js").ECKey,n=require("buffertools"),i=function(){this._pub=null,this.compressed=!0},u=i.bufferToArray=function(e){for(var r=[],t=e.length,s=0;t>s;s++)r.push(e.readUInt8(s));return r};Object.defineProperty(i.prototype,"public",{set:function(e){if(!r.isBuffer(e))throw new Error("Arg should be a buffer");var t=e[0];this.compressed=4!==t,this._pub=e},get:function(){return this._pub}}),i.generateSync=function(){var e=new o;e.setCompressed(!0);var t=e.getPub(),s=new i;return s.private=new r(e.priv.toByteArrayUnsigned()),s.public=new r(t),s},i.prototype.regenerateSync=function(){if(!this.private)throw new Error("Key does not have a private key set");var e=new o(n.toHex(this.private));return e.setCompressed(this.compressed),this.public=new r(e.getPub()),this},i.prototype.signSync=function(e){if(!this.private)throw new Error("Key does not have a private key set");if(!r.isBuffer(e)||32!==e.length)throw new Error("Arg should be a 32 bytes hash buffer");var t=new o(n.toHex(this.private));t.setCompressed(this.compressed);var s=t.sign(u(e));return new r(s)},i.prototype.verifySignature=function(e,r,t){try{var s=this.verifySignatureSync(e,r);t(null,s)}catch(o){t(o)}},i.prototype.verifySignatureSync=function(e,t){var s=this;if(!r.isBuffer(e)||32!==e.length)throw new Error("Arg 1 should be a 32 bytes hash buffer");if(!r.isBuffer(t))throw new Error("Arg 2 should be a buffer");if(!s.public)throw new Error("Key does not have a public key set");var n=new o;n.setPub(u(s.public)),n.setCompressed(s.compressed);var i=u(t),f=n.verify(u(e),i);return f},module.exports=i}}).call(this,require("/Users/ryanxcharles/dev/bitcore/node_modules/browserify/node_modules/insert-module-globals/node_modules/process/browser.js"),require("buffer").Buffer); +},{"./browser/vendor-bundle.js":53,"/Users/ryanxcharles/dev/bitcore/node_modules/browserify/node_modules/insert-module-globals/node_modules/process/browser.js":91,"bindings":66,"buffer":75,"buffertools":"fugeBw"}],"ahN55r":[function(require,module,exports){ +exports.patch=function(t){t.prototype.round=function(t){if(!t)return Math.round(this);var r=Math.pow(10,t);return Math.round(this*r)/r}}; +},{}],"./Number.monkey":[function(require,module,exports){ +module.exports=require('ahN55r'); +},{}],"./Opcode":[function(require,module,exports){ +module.exports=require('zHwnes'); +},{}],"zHwnes":[function(require,module,exports){ +function Opcode(O){this.code=O}var imports=require("soop").imports();Opcode.prototype.toString=function(){return Opcode.reverseMap[this.code]},Opcode.map={OP_FALSE:0,OP_0:0,OP_PUSHDATA1:76,OP_PUSHDATA2:77,OP_PUSHDATA4:78,OP_1NEGATE:79,OP_RESERVED:80,OP_TRUE:81,OP_1:81,OP_2:82,OP_3:83,OP_4:84,OP_5:85,OP_6:86,OP_7:87,OP_8:88,OP_9:89,OP_10:90,OP_11:91,OP_12:92,OP_13:93,OP_14:94,OP_15:95,OP_16:96,OP_NOP:97,OP_VER:98,OP_IF:99,OP_NOTIF:100,OP_VERIF:101,OP_VERNOTIF:102,OP_ELSE:103,OP_ENDIF:104,OP_VERIFY:105,OP_RETURN:106,OP_TOALTSTACK:107,OP_FROMALTSTACK:108,OP_2DROP:109,OP_2DUP:110,OP_3DUP:111,OP_2OVER:112,OP_2ROT:113,OP_2SWAP:114,OP_IFDUP:115,OP_DEPTH:116,OP_DROP:117,OP_DUP:118,OP_NIP:119,OP_OVER:120,OP_PICK:121,OP_ROLL:122,OP_ROT:123,OP_SWAP:124,OP_TUCK:125,OP_CAT:126,OP_SUBSTR:127,OP_LEFT:128,OP_RIGHT:129,OP_SIZE:130,OP_INVERT:131,OP_AND:132,OP_OR:133,OP_XOR:134,OP_EQUAL:135,OP_EQUALVERIFY:136,OP_RESERVED1:137,OP_RESERVED2:138,OP_1ADD:139,OP_1SUB:140,OP_2MUL:141,OP_2DIV:142,OP_NEGATE:143,OP_ABS:144,OP_NOT:145,OP_0NOTEQUAL:146,OP_ADD:147,OP_SUB:148,OP_MUL:149,OP_DIV:150,OP_MOD:151,OP_LSHIFT:152,OP_RSHIFT:153,OP_BOOLAND:154,OP_BOOLOR:155,OP_NUMEQUAL:156,OP_NUMEQUALVERIFY:157,OP_NUMNOTEQUAL:158,OP_LESSTHAN:159,OP_GREATERTHAN:160,OP_LESSTHANOREQUAL:161,OP_GREATERTHANOREQUAL:162,OP_MIN:163,OP_MAX:164,OP_WITHIN:165,OP_RIPEMD160:166,OP_SHA1:167,OP_SHA256:168,OP_HASH160:169,OP_HASH256:170,OP_CODESEPARATOR:171,OP_CHECKSIG:172,OP_CHECKSIGVERIFY:173,OP_CHECKMULTISIG:174,OP_CHECKMULTISIGVERIFY:175,OP_NOP1:176,OP_NOP2:177,OP_NOP3:178,OP_NOP4:179,OP_NOP5:180,OP_NOP6:181,OP_NOP7:182,OP_NOP8:183,OP_NOP9:184,OP_NOP10:185,OP_PUBKEYHASH:253,OP_PUBKEY:254,OP_INVALIDOPCODE:255},Opcode.reverseMap=[];for(var k in Opcode.map)Opcode.map.hasOwnProperty(k)&&(Opcode.reverseMap[Opcode.map[k]]=k.substr(3));Opcode.asList=function(){var O=[];for(var P in Opcode.map)Opcode.map.hasOwnProperty(P)&&O.push(P);return O},module.exports=require("soop")(Opcode); +},{"soop":146}],"6VMrjH":[function(require,module,exports){ +(function(t){function e(r,o,i){if("string"==typeof r){if(r.indexOf(":")&&!o){var n=r.split(":");r=n[0],o=n[1]}this.host=r,this.port=+o||8333}else if(r instanceof e)this.host=r.host,this.port=r.port;else{if(!t.isBuffer(r))throw new Error("Could not instantiate peer, invalid parameter type: "+typeof r);if(0!=s.compare(e.IPV6_IPV4_PADDING,r.slice(0,12)))throw new Error("IPV6 not supported yet! Cannot instantiate host.");this.host=Array.prototype.slice.apply(r.slice(12)).join("."),this.port=+o||8333}this.services=i?i:null,this.lastSeen=0}var r=require("soop").imports(),o=r.Net||require("net"),i=r.Binary||require("binary"),s=r.buffertools||require("buffertools");e.IPV6_IPV4_PADDING=new t([0,0,0,0,0,0,0,0,0,0,255,255]),e.prototype.createConnection=function(){var t=o.createConnection(this.port,this.host);return t},e.prototype.getHostAsBuffer=function(){return new t(this.host.split("."))},e.prototype.toString=function(){return this.host+":"+this.port},e.prototype.toBuffer=function(){var t=i.put();return t.word32le(this.lastSeen),t.word64le(this.services),t.put(this.getHostAsBuffer()),t.word16be(this.port),t.buffer()},module.exports=require("soop")(e)}).call(this,require("buffer").Buffer); +},{"binary":62,"buffer":75,"buffertools":"fugeBw","net":71,"soop":146}],"./Peer":[function(require,module,exports){ +module.exports=require('6VMrjH'); +},{}],"./PeerManager":[function(require,module,exports){ +module.exports=require('z6R5yC'); +},{}],"z6R5yC":[function(require,module,exports){ +function PeerManager(){this.active=!1,this.timer=null,this.peers=[],this.connections=[],this.isConnected=!1,this.peerDiscovery=!1,this.interval=5e3,this.minConnections=8,this.minKnownPeers=10}var imports=require("soop").imports(),config=imports.config||require("./config"),log=imports.log||require("./util/log"),network=imports.network||require("./networks")[config.network],Connection=imports.Connection||require("soop").load("./Connection",{config:config,network:network})||require("./Connection"),Peer=imports.Peer||require("./Peer");GetAdjustedTime=imports.GetAdjustedTime||function(){return Math.floor((new Date).getTime()/1e3)},PeerManager.parent=imports.parent||require("events").EventEmitter,PeerManager.Connection=Connection,PeerManager.prototype.start=function(){this.active=!0,this.timer||(this.timer=setInterval(this.checkStatus.bind(this),this.interval))},PeerManager.prototype.stop=function(){this.active=!1,this.timer&&(clearInterval(this.timer),this.timer=null);for(var e=0;e=31402||this.peers.length<1e3)&&(e.conn.sendGetAddr(),e.conn.getaddr=!0)},PeerManager.prototype.handleReady=function(e){log.info("connected to "+e.conn.peer.host+":"+e.conn.peer.port),this.emit("connect",{pm:this,conn:e.conn,socket:e.socket,peer:e.peer}),0==this.isConnected&&(this.emit("netConnected",e),this.isConnected=!0)},PeerManager.prototype.handleAddr=function(e){if(this.peerDiscovery){var n=GetAdjustedTime();e.message.addrs.forEach(function(e){try{(e.time<=1e8||e.time>n+600)&&(e.time=n-432e3);var t=new Peer(e.ip,e.port,e.services);t.lastSeen=e.time,this.peers.push(t)}catch(r){log.warn("Invalid addr received: "+r.message)}}.bind(this)),e.message.addrs.length<1e3&&(e.conn.getaddr=!1)}},PeerManager.prototype.handleGetAddr=function(){},PeerManager.prototype.handleError=function(e){log.err("unkown error with peer "+e.peer+" (disconnecting): "+e.err),this.handleDisconnect.apply(this,[].slice.call(arguments))},PeerManager.prototype.handleDisconnect=function(e){log.info("disconnected from peer "+e.peer);var n=this.connections.indexOf(e.conn);-1!=n&&this.connections.splice(n,1),this.connections.length||(this.emit("netDisconnected"),this.isConnected=!1)},PeerManager.prototype.getActiveConnection=function(){var e=this.connections.filter(function(e){return e.active});if(e.length){var n=Math.floor(Math.random()*e.length),t=e[n];return t.socket.writable?t:(e.splice(n,1),this.getActiveConnection())}return null},PeerManager.prototype.getActiveConnections=function(){return this.connections.slice(0)},module.exports=require("soop")(PeerManager); +},{"./Connection":"h81grl","./Peer":"6VMrjH","./config":"4itQ50","./networks":"ULNIu2","./util/log":"AdF7pF","events":84,"soop":146}],"./Point":[function(require,module,exports){ +module.exports=require('8PQ/SZ'); +},{}],"8PQ/SZ":[function(require,module,exports){ +(function(e,r){"use strict";var s=require("soop").imports(),o=s.Key||require("./Key"),n=s.bignum||require("bignum"),t=require("assert");if(!e.versions){var i=require("./browser/vendor-bundle.js").ECKey,u=require("./browser/vendor-bundle.js").ECPointFp,f=require("./browser/vendor-bundle.js").ECFieldElementFp,d=require("./browser/vendor-bundle.js").getSECCurveByName,c=require("./browser/vendor-bundle.js").BigInteger;require("chai").should()}var l=function(e,r){this.x=e,this.y=r};l.add=function(s,i){if(e.versions){var g=s.toKey();g.compressed=!1;var p=i.toKey();p.compressed=!1;var w=o.addUncompressed(g.public,p.public),b=new o;return b.compressed=!1,b.public=w,b.compressed=!0,l.fromKey(b)}var m=d("secp256k1"),v=s.x.toBuffer({size:32}).toString("hex"),a=new c(v,16),y=s.y.toBuffer({size:32}).toString("hex"),B=new c(y,16),h=new f(m.getCurve().getQ(),a),C=new f(m.getCurve().getQ(),B),x=new u(m.getCurve(),h,C),z=i.x.toBuffer({size:32}).toString("hex"),q=new c(z,16),K=i.y.toBuffer({size:32}).toString("hex"),j=new c(K,16),P=new f(m.getCurve().getQ(),q),E=new f(m.getCurve().getQ(),j),S=new u(m.getCurve(),P,E),A=x.add(S),Q=new l,U=new r(A.getX().toBigInteger().toByteArrayUnsigned());Q.x=n.fromBuffer(U,{size:U.length}),t(U.length<=32);var F=new r(A.getY().toBigInteger().toByteArrayUnsigned());return t(F.length<=32),Q.y=n.fromBuffer(F,{size:F.length}),Q},l.fromKey=function(s){if(e.versions){var t=new l,u=new r(s.public),f=new o;return f.compressed=s.compressed,f.public=u,f.compressed=!1,t.x=n.fromBuffer(f.public.slice(1,33),{size:32}),t.y=n.fromBuffer(f.public.slice(33,65),{size:32}),t}var t=new l,u=new r(s.public),f=new i;return f.setCompressed(s.compressed),f.setPub(o.bufferToArray(u)),f.setCompressed(!1),t.x=n.fromBuffer(new r(f.getPub()).slice(1,33),{size:32}),t.y=n.fromBuffer(new r(f.getPub()).slice(33,65),{size:32}),t},l.prototype.toKey=function(){if(e.versions){var s=this.x.toBuffer({size:32}),n=this.y.toBuffer({size:32}),t=new o;t.compressed=!1;var u=new r([4]);return t.public=r.concat([u,s,n]),t.compressed=!0,t}var s=this.x.toBuffer({size:32}),n=this.y.toBuffer({size:32}),t=new i;t.setCompressed(!1);var u=new r([4]),f=r.concat([u,s,n]);t.setPub(o.bufferToArray(f)),t.setCompressed(!0);var d=new o;return d.public=new r(t.getPub()),d},module.exports=require("soop")(l)}).call(this,require("/Users/ryanxcharles/dev/bitcore/node_modules/browserify/node_modules/insert-module-globals/node_modules/process/browser.js"),require("buffer").Buffer); +},{"./Key":"Af1Gom","./browser/vendor-bundle.js":53,"/Users/ryanxcharles/dev/bitcore/node_modules/browserify/node_modules/insert-module-globals/node_modules/process/browser.js":91,"assert":72,"bignum":"J4nwo8","buffer":75,"chai":112,"soop":146}],"./PrivateKey":[function(require,module,exports){ +module.exports=require('+A60Qr'); +},{}],"+A60Qr":[function(require,module,exports){ +(function(t){function e(t,i,r){e.super(this,arguments),void 0!==r&&this.compressed(r)}var i=require("soop").imports(),r=i.parent||require("./util/VersionedData"),n=i.networks||require("./networks");e.parent=r,r.applyEncodingsTo(e),e.prototype.validate=function(){if(this.doAsBinary(function(){if(e.super(this,"validate",arguments),this.data.length<32||this.data.length>33&&!this.compressed()||34==this.data.length&&1!=this.data[33]||this.data.length>34)throw new Error("invalid data length")}),"undefined"==typeof this.network())throw new Error("invalid network")},e.prototype.payload=function(t){if(t)return this.doAsBinary(function(){t.copy(this.data,1)}),t;var e=this.as("binary");return 34==e.length?e.slice(1,33):33==e.length?e.slice(1):void 0},e.prototype.compressed=function(e){if(void 0===e){var i=34,r=this.as("binary");if(r.length==i&&1==r[i-1])return!0;if(r.length==i-1)return!1;throw new Error("invalid private key")}this.doAsBinary(function(){var i=34;if(e){var r=new t(i);this.data.copy(r),this.data=r,this.data[i-1]=1}else this.data=this.data.slice(0,i-1)})},e.prototype.network=function(){var t,e=this.version(),i=n.livenet,r=n.testnet;return e===i.privKeyVersion?t=i:e===r.privKeyVersion&&(t=r),t},module.exports=require("soop")(e)}).call(this,require("buffer").Buffer); +},{"./networks":"ULNIu2","./util/VersionedData":"QLzNQg","buffer":75,"soop":146}],"Svwrvc":[function(require,module,exports){ +(function(t){function e(t){t=t||{},this.host=t.host||"127.0.0.1",this.port=t.port||8332,this.user=t.user||"user",this.pass=t.pass||"pass",this.protocol="http"==t.protocol?n:i,this.batchedCalls=null,this.disableAgent=t.disableAgent||!1}function r(t,e,r){function s(t,e){return function(){var s=arguments.length-1;if(this.batchedCalls)var s=arguments.length;for(var o=0;s>o;o++)e[o]&&(arguments[o]=e[o](arguments[o]));this.batchedCalls?this.batchedCalls.push({jsonrpc:"2.0",method:t,params:c(arguments)}):r.call(this,{method:t,params:c(arguments,0,arguments.length-1)},arguments[arguments.length-1])}}var o={str:function(t){return t.toString()},"int":function(t){return parseFloat(t)},"float":function(t){return parseFloat(t)},bool:function(t){return t===!0||"1"==t||"true"==t||"true"==t.toString().toLowerCase()}};for(var n in e)if(e.hasOwnProperty(n)){for(var i=e[n].split(" "),a=0;a=OP_1&&OP_16>=t}function prefixSize(t){return OP_PUSHDATA1>t?1:255>=t?2:65535>=t?3:5}function encodeLen(t){var r=void 0;return OP_PUSHDATA1>t?(r=new Buffer(1),r.writeUInt8(t,0)):255>=t?(r=new Buffer(2),r.writeUInt8(OP_PUSHDATA1,0),r.writeUInt8(t,1)):65535>=t?(r=new Buffer(3),r.writeUInt8(OP_PUSHDATA2,0),r.writeUInt16LE(t,1)):(r=new Buffer(5),r.writeUInt8(OP_PUSHDATA4,0),r.writeUInt32LE(t,1)),r}var imports=require("soop").imports(),config=imports.config||require("./config"),log=imports.log||require("./util/log"),Opcode=imports.Opcode||require("./Opcode"),buffertools=imports.buffertools||require("buffertools");for(var i in Opcode.map)eval(i+" = "+Opcode.map[i]+";");var util=imports.util||require("./util/util"),Parser=imports.Parser||require("./util/BinaryParser"),Put=imports.Put||require("bufferput"),TX_UNKNOWN=0,TX_PUBKEY=1,TX_PUBKEYHASH=2,TX_MULTISIG=3,TX_SCRIPTHASH=4,TX_TYPES=["unknown","pubkey","pubkeyhash","multisig","scripthash"];Script.TX_UNKNOWN=TX_UNKNOWN,Script.TX_PUBKEY=TX_PUBKEY,Script.TX_PUBKEYHASH=TX_PUBKEYHASH,Script.TX_MULTISIG=TX_MULTISIG,Script.TX_SCRIPTHASH=TX_SCRIPTHASH,Script.prototype.parse=function(){this.chunks=[];for(var t=new Parser(this.buffer);!t.eof();){var r,e,i=t.word8();i>0&&OP_PUSHDATA1>i?this.chunks.push(t.buffer(i)):i===OP_PUSHDATA1?(r=t.word8(),e=t.buffer(r),this.chunks.push(e)):i===OP_PUSHDATA2?(r=t.word16le(),e=t.buffer(r),this.chunks.push(e)):i===OP_PUSHDATA4?(r=t.word32le(),e=t.buffer(r),this.chunks.push(e)):this.chunks.push(i)}},Script.prototype.isPushOnly=function(){for(var t=0;tOP_16)return!1}return!0},Script.prototype.isP2SH=function(){return 3==this.chunks.length&&this.chunks[0]==OP_HASH160&&Buffer.isBuffer(this.chunks[1])&&20==this.chunks[1].length&&this.chunks[2]==OP_EQUAL},Script.prototype.isPubkey=function(){return 2==this.chunks.length&&Buffer.isBuffer(this.chunks[0])&&this.chunks[1]==OP_CHECKSIG},Script.prototype.isPubkeyHash=function(){return 5==this.chunks.length&&this.chunks[0]==OP_DUP&&this.chunks[1]==OP_HASH160&&Buffer.isBuffer(this.chunks[2])&&20==this.chunks[2].length&&this.chunks[3]==OP_EQUALVERIFY&&this.chunks[4]==OP_CHECKSIG},Script.prototype.isMultiSig=function(){return this.chunks.length>3&&isSmallIntOp(this.chunks[0])&&isSmallIntOp(this.chunks[this.chunks.length-2])&&this.chunks[this.chunks.length-1]==OP_CHECKMULTISIG},Script.prototype.finishedMultiSig=function(){for(var t=0,r=0;ri;i++){var u=this.chunks[i];if(i>0&&(e+=" "),e+=Buffer.isBuffer(u)?"0x"+util.formatBuffer(u,t?null:0):Opcode.reverseMap[u],r&&i>r){e+=" ...";break}}return e},Script.prototype.toString=function(t,r){var e="