This commit is contained in:
Matias Alejo Garcia 2014-04-18 19:28:28 -03:00
commit 04d7d5abf0
11 changed files with 265 additions and 574 deletions

View file

@ -215,7 +215,7 @@
<h3>Address</h3> <h3>Address</h3>
<div class="row"> <div class="row">
<div class="large-6 columns"> <div class="large-6 columns">
<a class="panel db" ng-repeat="addr in addrs" ng-click="selectAddr(addr)">{{addr}} <span class="right">{{balanceByAddr[addr] || 0}} BTC &gt;</span></a> <a class="panel db" ng-repeat="addr in addrs" ng-click="selectAddr(addr)">{{addr}} <span class="right">{{balanceByAddr[addr] || 0}} BTC</span></a>
</div> </div>
<div class="large-3 columns line-dashed-v text-center"> <div class="large-3 columns line-dashed-v text-center">
<qrcode size="160" data="{{selectedAddr}}"></qrcode> <qrcode size="160" data="{{selectedAddr}}"></qrcode>
@ -238,20 +238,27 @@
<div class="row" ng-show='$root.wallet.publicKeyRing.isComplete()'> <div class="row" ng-show='$root.wallet.publicKeyRing.isComplete()'>
<div class="large-12 columns"> <div class="large-12 columns">
<h3>Pending Transactions <small>({{txs.length}})</small></h3> <h3>Pending Transactions <small>({{txs.length}})</small></h3>
<div class="panel pending" ng-repeat="txp in txs"> <div class="panel pending" ng-repeat="tx in txs">
<div class="row" ng-repeat="o in txs.outs"> NTXID: {{tx.ntxid}}
<p class="large-5 columns"> {{o.address}}</p> CREATOR: {{tx.creator}}
<i class="large-2 columns fi-arrow-right size-16 text-center"></i> CREATED_TS: {{tx.createdTs}}
<div class="row" ng-repeat="o in tx.outs">
<p class="large-5 columns"> {{o.value}} BTC </p> <p class="large-5 columns"> {{o.value}} BTC </p>
<i class="large-2 columns fi-arrow-right size-16 text-center"></i>
<p class="large-5 columns"> {{o.address}}</p>
</div> </div>
<div class="large-12 columns m0 panel panel-sign" ng-show="txp.signedByUs"> <div class="large-12 columns m0 panel panel-sign" ng-show="tx.signedByUs">
<i class="fi-check size-40"></i> YOU SIGNED! <i class="fi-check size-40"></i> Signed by you already
</div> </div>
<div class="large-12 columns m0" ng-show="!txp.signedByUs"> <div class="large-12 columns m0" ng-show="!tx.signedByUs">
<div class="line"></div> <div class="line"></div>
<button class="primary round large-4 columns"><i class="large-2 columns fi-x size-16 text-center"></i> Ignore</button> <button class="primary round large-4 columns"><i class="large-2 columns fi-x size-16 text-center"></i> Ignore</button>
<small class="large-4 columns text-center">Faltan 3 cosigners</small> <small class="large-4 columns text-center">
<button class="secondary round large-4 columns" ng-click="sign(txp.ntxid)"><i class="large-2 columns fi-check size-16 text-center"></i> Sign</button> <span ng-show="tx.missingSignatures==1"> One signature </span>
<span ng-show="tx.missingSignatures>1"> {{tx.missingSignatures}} signatures </span>
missing
</small>
<button class="secondary round large-4 columns" ng-click="sign(tx.ntxid)"><i class="large-2 columns fi-check size-16 text-center"></i> Sign</button>
</div> </div>
</div> <!-- end of row --> </div> <!-- end of row -->
</div> <!-- end of pending --> </div> <!-- end of pending -->

View file

@ -3,13 +3,13 @@
var config = { var config = {
networkName: 'testnet', networkName: 'testnet',
network: { network: {
// key: 'lwjd5qra8257b9', // key: 'lwjd5qra8257b9',
// This is for running local peerJs with params: ./peerjs -p 10009 -k 'sdfjhwefh' // This is for running local peerJs with params: ./peerjs -p 10009 -k 'sdfjhwefh'
key: 'sdfjhwefh', key: 'sdfjhwefh',
host: '192.168.1.100', host: 'localhost',
port: 10009, port: 10009,
path: '/', path: '/',
maxPeers: 10, maxPeers: 3,
debug: 3, debug: 3,
}, },
limits: { limits: {
@ -23,12 +23,12 @@ var config = {
verbose: 1, verbose: 1,
}, },
blockchain: { blockchain: {
host: 'test.insight.is', host: 'localhost',
port: 80 port: 3001
}, },
socket: { socket: {
host: 'test.insight.is', host: 'localhost',
port: 80 port: 3001
}, },
verbose: 1, verbose: 1,
}; };

View file

@ -10,10 +10,12 @@ angular.module('copay.home').controller('HomeController',
var _updateBalance = function () { var _updateBalance = function () {
w.getBalance(function (balance, balanceByAddr) { w.getBalance(function (balance, balanceByAddr) {
$scope.balanceByAddr = balanceByAddr; if (balanceByAddr && Object.keys(balanceByAddr).length) {
$scope.addrs = Object.keys(balanceByAddr); $scope.balanceByAddr = balanceByAddr;
$scope.selectedAddr = $scope.addrs[0]; $scope.addrs = Object.keys(balanceByAddr);
$scope.$digest(); $scope.selectedAddr = $scope.addrs[0];
$scope.$digest();
}
}); });
var socket = Socket($scope); var socket = Socket($scope);
controllerUtils.handleTransactionByAddress($scope, _updateBalance); controllerUtils.handleTransactionByAddress($scope, _updateBalance);
@ -33,4 +35,5 @@ angular.module('copay.home').controller('HomeController',
$location.path('signin'); $location.path('signin');
} }
_updateBalance(); _updateBalance();
w.on('refresh',_updateBalance);
}); });

View file

@ -1,4 +1,5 @@
'use strict'; 'use strict';
var bitcore = require('bitcore');
angular.module('copay.transactions').controller('TransactionsController', angular.module('copay.transactions').controller('TransactionsController',
function($scope, $rootScope, $location, Socket, controllerUtils) { function($scope, $rootScope, $location, Socket, controllerUtils) {
@ -9,7 +10,7 @@ angular.module('copay.transactions').controller('TransactionsController',
var _updateTxs = function() { var _updateTxs = function() {
var w =$rootScope.wallet; var w =$rootScope.wallet;
var inT = w.getTxProposals(); var inT = w.getTxProposals();
var ts = []; var txs = [];
inT.forEach(function(i){ inT.forEach(function(i){
var b = i.txp.builder; var b = i.txp.builder;
@ -18,20 +19,27 @@ angular.module('copay.transactions').controller('TransactionsController',
feeSat: b.feeSat, feeSat: b.feeSat,
}; };
var outs = []; var outs = [];
var bitcore = require('bitcore');
tx.outs.forEach(function(o) { tx.outs.forEach(function(o) {
var s = o.getScript(); var addr = bitcore.Address.fromScriptPubKey(o.getScript(), config.networkName)[0].toString();
var aStr = bitcore.Address.fromScript(s, config.networkName).toString(); if (!w.addressIsOwn(addr)) {
if (!w.addressIsOwn(aStr))
outs.push({ outs.push({
address: aStr, address: addr,
value: bitcore.util.valueToBigInt(o.getValue())/bitcore.util.COIN, value: bitcore.util.valueToBigInt(o.getValue())/bitcore.util.COIN,
}); });
}
}); });
one.outs = outs; one.outs = outs;
ts.push(one);
// TOD: check missingSignatures === in al inputs?
one.missingSignatures = tx.countInputMissingSignatures(0);
one.signedByUs = i.signedByUs;
one.ntxid = i.ntxid;
one.creator = i.txp.creator,
one.createdTs = i.txp.createdTs;
txs.push(one);
}); });
$scope.txs = ts; $scope.txs = txs;
}; };
@ -40,6 +48,8 @@ angular.module('copay.transactions').controller('TransactionsController',
} }
else { else {
_updateTxs(); _updateTxs();
var w = $rootScope.wallet;
w.on('refresh',_updateTxs);
var socket = Socket($scope); var socket = Socket($scope);
socket.on('connect', controllerUtils.handleTransactionByAddress($scope)); socket.on('connect', controllerUtils.handleTransactionByAddress($scope));
} }
@ -47,7 +57,23 @@ angular.module('copay.transactions').controller('TransactionsController',
$scope.sign = function (ntxid) { $scope.sign = function (ntxid) {
var w = $rootScope.wallet; var w = $rootScope.wallet;
var ret = w.sign(ntxid); var ret = w.sign(ntxid);
$rootScope.flashMessage = {type:'success', message: 'Transactions SEND! : ' + ret}; _updateTxs();
var p = w.getTxProposal(ntxid);
if (p.txp.builder.isFullySigned()) {
w.sendTx(ntxid, function(txid) {
$rootScope.flashMessage = txid
? {type:'success', message: 'Transactions SENT! txid:' + txid}
: {type:'error', message: 'There was an error sending the Transaction'}
;
});
}
else {
$rootScope.flashMessage = ret
? {type:'success', message: 'Transactions signed'}
: {type:'error', message: 'There was an error signing the Transaction'}
;
}
_updateTxs(); _updateTxs();
}; };
}); });

View file

@ -102,7 +102,7 @@ Insight.prototype._request = function(options, callback) {
return callback({message: 'Wrong response from insight'}); return callback({message: 'Wrong response from insight'});
} }
} else { } else {
return callback({message: 'Error ' + response.statusCode}); return callback({message: 'Error ' + request.status});
} }
} }
}; };

View file

@ -14,10 +14,27 @@ var Storage = imports.Storage || require('../storage/Base');
var storage = Storage.default(); var storage = Storage.default();
function TxProposal(opts) { function TxProposal(opts) {
this.creator = opts.creator;
this.createdTs = opts.createdTs;
this.seenBy = opts.seenBy || {}; this.seenBy = opts.seenBy || {};
this.signedBy = opts.signedBy || {}; this.signedBy = opts.signedBy || {};
this.builder = opts.builder; this.builder = opts.builder;
}
TxProposal.prototype.toObj = function() {
var o = JSON.parse(JSON.stringify(this));
delete o['builder'];
o.builderObj = this.builder.toObj();
return o;
}; };
TxProposal.fromObj = function(o) {
var t = new TxProposal(o);
var b = new Builder.fromObj(o.builderObj);
t.builder = b;
return t;
};
module.exports = require('soop')(TxProposal); module.exports = require('soop')(TxProposal);
@ -26,7 +43,7 @@ function TxProposals(opts) {
this.walletId = opts.walletId; this.walletId = opts.walletId;
this.network = opts.networkName === 'livenet' ? this.network = opts.networkName === 'livenet' ?
bitcore.networks.livenet : bitcore.networks.testnet; bitcore.networks.livenet : bitcore.networks.testnet;
this.txps = []; this.txps = {};
} }
TxProposals.fromObj = function(o) { TxProposals.fromObj = function(o) {
@ -34,12 +51,10 @@ TxProposals.fromObj = function(o) {
networkName: o.networkName, networkName: o.networkName,
walletId: o.walletId, walletId: o.walletId,
}); });
o.txps.forEach(function(t) { o.txps.forEach(function(o2) {
ret.txps.push({ var t = TxProposal.fromObj(o2);
seenBy: t.seenBy, var id = t.builder.build().getNormalizedHash().toString('hex');
signedBy: t.signedBy, ret.txps[id] = t;
builder: new Builder.fromObj(t.builderObj),
});
}); });
return ret; return ret;
}; };
@ -47,13 +62,10 @@ TxProposals.fromObj = function(o) {
TxProposals.prototype.toObj = function() { TxProposals.prototype.toObj = function() {
var ret = []; var ret = [];
this.txps.forEach(function(t) { for(var id in this.txps){
ret.push({ var t = this.txps[id];
seenBy: t.seenBy, ret.push(t.toObj());
signedBy: t.signedBy, }
builderObj: t.builder.toObj(),
});
});
return { return {
txps: ret, txps: ret,
walletId: this.walletId, walletId: this.walletId,
@ -62,36 +74,27 @@ TxProposals.prototype.toObj = function() {
}; };
TxProposals.prototype._getNormHash = function(txps) {
var ret = {};
txps.forEach(function(txp) {
var hash = txp.builder.build().getNormalizedHash().toString('hex');
ret[hash]=txp;
});
return ret;
};
TxProposals.prototype._startMerge = function(myTxps, theirTxps) { TxProposals.prototype._startMerge = function(myTxps, theirTxps) {
var fromUs=0, fromTheirs=0, merged =0; var fromUs=0, fromTheirs=0, merged =0;
var toMerge = {}, ready=[]; var toMerge = {}, ready={};
Object.keys(theirTxps).forEach(function(hash) { for(var hash in theirTxps){
if (!myTxps[hash]) { if (!myTxps[hash]) {
ready.push(theirTxps[hash]); // only in theirs; ready[hash]=theirTxps[hash]; // only in theirs;
fromTheirs++; fromTheirs++;
} }
else { else {
toMerge[hash]=theirTxps[hash]; // need Merging toMerge[hash]=theirTxps[hash]; // need Merging
merged++; merged++;
} }
}); }
Object.keys(myTxps).forEach(function(hash) { for(var hash in myTxps){
if(!toMerge[hash]) { if(!toMerge[hash]) {
ready.push(myTxps[hash]); // only in myTxps; ready[hash]=myTxps[hash]; // only in myTxps;
fromUs++; fromUs++;
} }
}); }
return { return {
stats: { stats: {
@ -124,42 +127,48 @@ TxProposals.prototype._mergeMetadata = function(myTxps, theirTxps, mergeInfo) {
TxProposals.prototype._mergeBuilder = function(myTxps, theirTxps, mergeInfo) { TxProposals.prototype._mergeBuilder = function(myTxps, theirTxps, mergeInfo) {
var self = this;
var toMerge = mergeInfo.toMerge; var toMerge = mergeInfo.toMerge;
Object.keys(toMerge).forEach(function(hash) { for(var hash in toMerge){
var v0 = myTxps[hash].builder; var v0 = myTxps[hash].builder;
var v1 = toMerge[hash].builder; var v1 = toMerge[hash].builder;
v0.merge(v1); v0.merge(v1);
}); };
}; };
TxProposals.prototype.add = function(data) { TxProposals.prototype.add = function(data) {
this.txps.push( new TxProposal(data) ); var id = data.builder.build().getNormalizedHash().toString('hex');
this.txps[id] = new TxProposal(data);
}; };
TxProposals.prototype.remove = function(ntxid) {
console.log('[TxProposals.js.147] DELETING:', ntxid); //TODO
delete this.txps[ntxid];
};
TxProposals.prototype.merge = function(t) { TxProposals.prototype.merge = function(t) {
if (this.network.name !== t.network.name) if (this.network.name !== t.network.name)
throw new Error('network mismatch in:', t); throw new Error('network mismatch in:', t);
var res = []; var res = [];
var myTxps = this._getNormHash(this.txps); var myTxps = this.txps;
var theirTxps = this._getNormHash(t.txps); var theirTxps = t.txps;
var mergeInfo = this._startMerge(myTxps, theirTxps); var mergeInfo = this._startMerge(myTxps, theirTxps);
this._mergeMetadata(myTxps, theirTxps, mergeInfo); this._mergeMetadata(myTxps, theirTxps, mergeInfo);
this._mergeBuilder(myTxps, theirTxps, mergeInfo); this._mergeBuilder(myTxps, theirTxps, mergeInfo);
Object.keys(mergeInfo.toMerge).forEach(function(hash) { Object.keys(mergeInfo.toMerge).forEach(function(hash) {
mergeInfo.ready.push(myTxps[hash]); mergeInfo.ready[hash] = myTxps[hash];
}); });
this.txps=mergeInfo.ready; this.txps=mergeInfo.ready;
return mergeInfo.stats; return mergeInfo.stats;
}; };
module.exports = require('soop')(TxProposals); module.exports = require('soop')(TxProposals);

View file

@ -256,75 +256,82 @@ Wallet.prototype.generateAddress = function() {
return addr; return addr;
}; };
// TODO : sort by time... / signed.
Wallet.prototype.getTxProposals = function() { Wallet.prototype.getTxProposals = function() {
var ret = []; var ret = [];
var self= this; for(var k in this.txProposals.txps) {
self.txProposals.txps.forEach(function(txp) { var txp = this.txProposals.txps[k];
var i = {txp:txp}; var i = {txp:txp};
i.ntxid = txp.builder.build().getNormalizedHash(); i.ntxid = k;
i.signedByUs = txp.signedBy[self.privateKey.getId()]?true:false; i.signedByUs = txp.signedBy[this.privateKey.getId()]?true:false;
ret.push(i); ret.push(i);
});
return ret;
};
// TODO: this can be precalculated.
Wallet.prototype._findTxByNtxid = function(ntxid) {
var ret;
var l = this.txProposals.txps.length;
var id = ntxid.toString('hex');
for(var i=0; i<l; i++) {
var txp = this.txProposals.txps[i];
var id2 = txp.builder.build().getNormalizedHash().toString('hex');
if (id === id2 ) {
ret = txp;
}
} }
return ret; return ret;
}; };
Wallet.prototype.getTxProposal = function(ntxid) {
var txp = this.txProposals.txps[ntxid];
var i = {txp:txp};
i.ntxid = ntxid;
i.signedByUs = txp.signedBy[this.privateKey.getId()]?true:false;
return i;
};
Wallet.prototype.sign = function(ntxid) { Wallet.prototype.sign = function(ntxid) {
var txp = this._findTxByNtxid(ntxid); var self = this;
var txp = self.txProposals.txps[ntxid];
if (!txp) return; if (!txp) return;
var pkr = this.publicKeyRing; var pkr = self.publicKeyRing;
var keys = this.privateKey.getAll(pkr.addressIndex, pkr.changeAddressIndex); var keys = self.privateKey.getAll(pkr.addressIndex, pkr.changeAddressIndex);
var ret = txp.builder.sign(keys);
if (ret.signaturesAdded) { var b = txp.builder;
txp.signedBy[this.privateKey.getId()] = Date.now(); var before = b.signaturesAdded;
this.log('[Wallet.js.230:ret:]',ret); //TODO b.sign(keys);
if (ret.isFullySigned) {
this.log('[Wallet.js.231] BROADCASTING TX!!!'); //TODO var ret = false;
var tx = txp.builder.build(); if (b.signaturesAdded > before) {
var txHex = tx.serialize().toString('hex'); txp.signedBy[self.privateKey.getId()] = Date.now();
this.blockchain.sendRawTransaction(txHex, function(txid) { this.sendTxProposals();
this.log('[Wallet.js.235:txid:]',txid); //TODO this.store(true);
if (txid) { ret = true;
this.store(true);
}
});
}
else {
this.sendTxProposals();
this.store(true);
}
} }
return ret; return ret;
}; };
Wallet.prototype.sendTx = function(ntxid) {
var txp = this.txProposals.txps[ntxid];
if (!txp) return;
var tx = txp.builder.build();
if (!tx.isComplete()) return;
this.log('[Wallet.js.231] BROADCASTING TX!!!'); //TODO
var txHex = tx.serialize().toString('hex');
this.log('[Wallet.js.261:txHex:]',txHex); //TODO
var self = this;
this.blockchain.sendRawTransaction(txHex, function(txid) {
self.log('BITCOND txid:',txid); //TODO
if (txid) {
self.txProposals.remove(ntxid);
self.store(true);
}
return (txid);
});
};
Wallet.prototype.addSeenToTxProposals = function() { Wallet.prototype.addSeenToTxProposals = function() {
var ret=false; var ret=false;
var self=this; var self=this;
this.txProposals.txps.forEach(function(txp) { for(var k in this.txProposals.txps) {
var txp = this.txProposals.txps[k];
if (!txp.seenBy[self.privateKey.getId()]) { if (!txp.seenBy[self.privateKey.getId()]) {
txp.seenBy[self.privateKey.getId()] = Date.now(); txp.seenBy[self.privateKey.getId()] = Date.now();
ret = true; ret = true;
} }
}); }
return ret; return ret;
}; };
@ -359,9 +366,12 @@ Wallet.prototype.getBalance = function(cb) {
var balance = 0; var balance = 0;
var balanceByAddr = {}; var balanceByAddr = {};
var COIN = bitcore.util.COIN; var COIN = bitcore.util.COIN;
var addresses = this.getAddressesStr(true);
if (!addresses.length) return cb(0,[]);
// Prefill balanceByAddr with main address // Prefill balanceByAddr with main address
this.getAddressesStr(true).forEach(function(a){ addresses.forEach(function(a){
balanceByAddr[a]=0; balanceByAddr[a]=0;
}); });
this.getUnspent(function(utxos) { this.getUnspent(function(utxos) {
@ -371,9 +381,9 @@ Wallet.prototype.getBalance = function(cb) {
balance = balance + amt; balance = balance + amt;
balanceByAddr[u.address] = (balanceByAddr[u.address]||0) + amt; balanceByAddr[u.address] = (balanceByAddr[u.address]||0) + amt;
} }
Object.keys(balanceByAddr).forEach(function(a) { for(var a in balanceByAddr){
balanceByAddr[a] = balanceByAddr[a]/COIN; balanceByAddr[a] = balanceByAddr[a]/COIN;
}); };
return cb(balance / COIN, balanceByAddr); return cb(balance / COIN, balanceByAddr);
}); });
}; };
@ -395,14 +405,10 @@ Wallet.prototype.createTx = function(toAddress, amountSatStr, opts, cb) {
if (typeof opts.spendUnconfirmed === 'undefined') { if (typeof opts.spendUnconfirmed === 'undefined') {
opts.spendUnconfirmed = this.spendUnconfirmed; opts.spendUnconfirmed = this.spendUnconfirmed;
} }
if (!opts.remainderOut) {
opts.remainderOut={ address: this.publicKeyRing.generateAddress(true).toString()};
}
self.getUnspent(function(unspentList) { self.getUnspent(function(unspentList) {
// TODO check enough funds, etc. // TODO check enough funds, etc.
self.createTxSync(toAddress, amountSatStr, unspentList, opts); self.createTxSync(toAddress, amountSatStr, unspentList, opts);
self.sendPublicKeyRing(); // Change Address
self.sendTxProposals(); self.sendTxProposals();
self.store(); self.store();
return cb(); return cb();
@ -440,6 +446,8 @@ Wallet.prototype.createTxSync = function(toAddress, amountSatStr, utxos, opts) {
this.txProposals.add({ this.txProposals.add({
signedBy: priv && b.signaturesAdded ? me : {}, signedBy: priv && b.signaturesAdded ? me : {},
seenBy: priv ? me : {}, seenBy: priv ? me : {},
creator: priv.id,
createdTs: Date.now(),
builder: b, builder: b,
}); });
}; };

View file

@ -23,7 +23,6 @@ angular.module('copay.controllerUtils').factory('controllerUtils', function ($ro
root.setupUxHandlers = function(w) { root.setupUxHandlers = function(w) {
w.on('badMessage', function(peerId) { w.on('badMessage', function(peerId) {
$rootScope.flashMessage = {type:'error', message: 'Received wrong message from peer id:' + peerId}; $rootScope.flashMessage = {type:'error', message: 'Received wrong message from peer id:' + peerId};
}); });

File diff suppressed because one or more lines are too long

1
lib/bitcore.js Symbolic link
View file

@ -0,0 +1 @@
../../bitcore/browser/bundle.js

View file

@ -125,21 +125,22 @@ describe('TxProposals model', function() {
priv, priv,
pkr pkr
)); ));
var tx = w.txps[0].builder.build(); var k = Object.keys(w.txps)[0];
var tx = w.txps[k].builder.build();
tx.isComplete().should.equal(false); tx.isComplete().should.equal(false);
tx.countInputMissingSignatures(0).should.equal(2); tx.countInputMissingSignatures(0).should.equal(2);
(w.txps[0].signedBy[priv.id] - ts > 0).should.equal(true); (w.txps[k].signedBy[priv.id] - ts > 0).should.equal(true);
(w.txps[0].seenBy[priv.id] - ts > 0).should.equal(true); (w.txps[k].seenBy[priv.id] - ts > 0).should.equal(true);
w.merge(w); w.merge(w);
w.txps.length.should.equal(1); Object.keys(w.txps).length.should.equal(1);
tx.isComplete().should.equal(false); tx.isComplete().should.equal(false);
tx.countInputMissingSignatures(0).should.equal(2); tx.countInputMissingSignatures(0).should.equal(2);
(w.txps[0].signedBy[priv.id] - ts > 0).should.equal(true); (w.txps[k].signedBy[priv.id] - ts > 0).should.equal(true);
(w.txps[0].seenBy[priv.id] - ts > 0).should.equal(true); (w.txps[k].seenBy[priv.id] - ts > 0).should.equal(true);
}); });
@ -168,12 +169,13 @@ describe('TxProposals model', function() {
pkr pkr
)); ));
var tx = w.txps[0].builder.build(); var k = Object.keys(w.txps)[0];
var tx = w.txps[k].builder.build();
tx.isComplete().should.equal(false); tx.isComplete().should.equal(false);
tx.countInputMissingSignatures(0).should.equal(1); tx.countInputMissingSignatures(0).should.equal(1);
Object.keys(w.txps[0].signedBy).length.should.equal(0); Object.keys(w.txps[k].signedBy).length.should.equal(0);
Object.keys(w.txps[0].seenBy).length.should.equal(1); Object.keys(w.txps[k].seenBy).length.should.equal(1);
var w2 = new TxProposals({ var w2 = new TxProposals({
@ -191,21 +193,22 @@ describe('TxProposals model', function() {
pkr pkr
)); ));
var tx = w2.txps[0].builder.build(); var k = Object.keys(w.txps)[0];
var tx = w2.txps[k].builder.build();
tx.isComplete().should.equal(false); tx.isComplete().should.equal(false);
tx.countInputMissingSignatures(0).should.equal(2); tx.countInputMissingSignatures(0).should.equal(2);
(w2.txps[0].signedBy[priv.id] - ts > 0).should.equal(true); (w2.txps[k].signedBy[priv.id] - ts > 0).should.equal(true);
(w2.txps[0].seenBy[priv.id] - ts > 0).should.equal(true); (w2.txps[k].seenBy[priv.id] - ts > 0).should.equal(true);
w.merge(w2); w.merge(w2);
w.txps.length.should.equal(1); Object.keys(w.txps).length.should.equal(1);
var tx = w.txps[0].builder.build(); var tx = w.txps[k].builder.build();
tx.isComplete().should.equal(false); tx.isComplete().should.equal(false);
tx.countInputMissingSignatures(0).should.equal(2); tx.countInputMissingSignatures(0).should.equal(2);
(w.txps[0].signedBy[priv.id] - ts > 0).should.equal(true); (w.txps[k].signedBy[priv.id] - ts > 0).should.equal(true);
(w.txps[0].seenBy[priv.id] - ts > 0).should.equal(true); (w.txps[k].seenBy[priv.id] - ts > 0).should.equal(true);
}); });
@ -243,12 +246,13 @@ var _dumpChunks = function (scriptSig, label) {
pkr pkr
)); ));
var tx = w.txps[0].builder.build(); var k = Object.keys(w.txps)[0];
var tx = w.txps[k].builder.build();
tx.isComplete().should.equal(false); tx.isComplete().should.equal(false);
tx.countInputMissingSignatures(0).should.equal(1); tx.countInputMissingSignatures(0).should.equal(1);
Object.keys(w.txps[0].signedBy).length.should.equal(0); Object.keys(w.txps[k].signedBy).length.should.equal(0);
Object.keys(w.txps[0].seenBy).length.should.equal(1); Object.keys(w.txps[k].seenBy).length.should.equal(1);
var w2 = new TxProposals({ var w2 = new TxProposals({
@ -265,21 +269,22 @@ var _dumpChunks = function (scriptSig, label) {
priv, priv,
pkr pkr
)); ));
tx = w2.txps[0].builder.build(); var k = Object.keys(w2.txps)[0];
tx = w2.txps[k].builder.build();
tx.isComplete().should.equal(false); tx.isComplete().should.equal(false);
tx.countInputMissingSignatures(0).should.equal(2); tx.countInputMissingSignatures(0).should.equal(2);
(w2.txps[0].signedBy[priv.id] - ts > 0).should.equal(true); (w2.txps[k].signedBy[priv.id] - ts > 0).should.equal(true);
(w2.txps[0].seenBy[priv.id] - ts > 0).should.equal(true); (w2.txps[k].seenBy[priv.id] - ts > 0).should.equal(true);
w.merge(w2); w.merge(w2);
w.txps.length.should.equal(1); Object.keys(w.txps).length.should.equal(1);
tx = w.txps[0].builder.build(); tx = w.txps[k].builder.build();
tx.isComplete().should.equal(false); tx.isComplete().should.equal(false);
tx.countInputMissingSignatures(0).should.equal(2); tx.countInputMissingSignatures(0).should.equal(2);
(w.txps[0].signedBy[priv.id] - ts > 0).should.equal(true); (w.txps[k].signedBy[priv.id] - ts > 0).should.equal(true);
(w.txps[0].seenBy[priv.id] - ts > 0).should.equal(true); (w.txps[k].seenBy[priv.id] - ts > 0).should.equal(true);
var w3 = new TxProposals({ var w3 = new TxProposals({
@ -296,22 +301,22 @@ var _dumpChunks = function (scriptSig, label) {
priv2, priv2,
pkr pkr
)); ));
tx = w3.txps[0].builder.build(); tx = w3.txps[k].builder.build();
tx.isComplete().should.equal(false); tx.isComplete().should.equal(false);
tx.countInputMissingSignatures(0).should.equal(2); tx.countInputMissingSignatures(0).should.equal(2);
(w3.txps[0].signedBy[priv2.id] - ts > 0).should.equal(true); (w3.txps[k].signedBy[priv2.id] - ts > 0).should.equal(true);
(w3.txps[0].seenBy[priv2.id] - ts > 0).should.equal(true); (w3.txps[k].seenBy[priv2.id] - ts > 0).should.equal(true);
w.merge(w3); w.merge(w3);
w.txps.length.should.equal(1); Object.keys(w.txps).length.should.equal(1);
(w.txps[0].signedBy[priv.id] - ts > 0).should.equal(true); (w.txps[k].signedBy[priv.id] - ts > 0).should.equal(true);
(w.txps[0].seenBy[priv.id] - ts > 0).should.equal(true); (w.txps[k].seenBy[priv.id] - ts > 0).should.equal(true);
(w.txps[0].signedBy[priv2.id] - ts > 0).should.equal(true); (w.txps[k].signedBy[priv2.id] - ts > 0).should.equal(true);
(w.txps[0].seenBy[priv2.id] - ts > 0).should.equal(true); (w.txps[k].seenBy[priv2.id] - ts > 0).should.equal(true);
tx = w.txps[0].builder.build(); tx = w.txps[k].builder.build();
tx.isComplete().should.equal(false); tx.isComplete().should.equal(false);
tx.countInputMissingSignatures(0).should.equal(1); tx.countInputMissingSignatures(0).should.equal(1);
}); });
@ -341,11 +346,12 @@ var _dumpChunks = function (scriptSig, label) {
priv, priv,
pkr pkr
)); ));
var tx = w.txps[0].builder.build(); var k = Object.keys(w.txps)[0];
var tx = w.txps[k].builder.build();
tx.isComplete().should.equal(false); tx.isComplete().should.equal(false);
tx.countInputMissingSignatures(0).should.equal(2); tx.countInputMissingSignatures(0).should.equal(2);
(w.txps[0].signedBy[priv.id] - ts > 0).should.equal(true); (w.txps[k].signedBy[priv.id] - ts > 0).should.equal(true);
(w.txps[0].seenBy[priv.id] - ts > 0).should.equal(true); (w.txps[k].seenBy[priv.id] - ts > 0).should.equal(true);
var w2 = new TxProposals({ var w2 = new TxProposals({
@ -361,11 +367,11 @@ var _dumpChunks = function (scriptSig, label) {
priv2, priv2,
pkr pkr
)); ));
var tx = w2.txps[0].builder.build(); var tx = w2.txps[k].builder.build();
tx.isComplete().should.equal(false); tx.isComplete().should.equal(false);
tx.countInputMissingSignatures(0).should.equal(2); tx.countInputMissingSignatures(0).should.equal(2);
(w2.txps[0].signedBy[priv2.id] - ts > 0).should.equal(true); (w2.txps[k].signedBy[priv2.id] - ts > 0).should.equal(true);
(w2.txps[0].seenBy[priv2.id] - ts > 0).should.equal(true); (w2.txps[k].seenBy[priv2.id] - ts > 0).should.equal(true);
var w3 = new TxProposals({ var w3 = new TxProposals({
@ -381,34 +387,34 @@ var _dumpChunks = function (scriptSig, label) {
priv3, priv3,
pkr pkr
)); ));
var tx = w3.txps[0].builder.build(); var tx = w3.txps[k].builder.build();
tx.isComplete().should.equal(false); tx.isComplete().should.equal(false);
tx.countInputMissingSignatures(0).should.equal(2); tx.countInputMissingSignatures(0).should.equal(2);
(w3.txps[0].signedBy[priv3.id] - ts > 0).should.equal(true); (w3.txps[k].signedBy[priv3.id] - ts > 0).should.equal(true);
(w3.txps[0].seenBy[priv3.id] - ts > 0).should.equal(true); (w3.txps[k].seenBy[priv3.id] - ts > 0).should.equal(true);
w.merge(w2); w.merge(w2);
w.txps.length.should.equal(1); Object.keys(w.txps).length.should.equal(1);
var tx = w.txps[0].builder.build(); var tx = w.txps[k].builder.build();
tx.isComplete().should.equal(false); tx.isComplete().should.equal(false);
tx.countInputMissingSignatures(0).should.equal(1); tx.countInputMissingSignatures(0).should.equal(1);
(w.txps[0].seenBy[priv.id] - ts > 0).should.equal(true); (w.txps[k].seenBy[priv.id] - ts > 0).should.equal(true);
(w.txps[0].seenBy[priv2.id] - ts > 0).should.equal(true); (w.txps[k].seenBy[priv2.id] - ts > 0).should.equal(true);
(w.txps[0].signedBy[priv.id] - ts > 0).should.equal(true); (w.txps[k].signedBy[priv.id] - ts > 0).should.equal(true);
(w.txps[0].signedBy[priv2.id] - ts > 0).should.equal(true); (w.txps[k].signedBy[priv2.id] - ts > 0).should.equal(true);
w.merge(w3); w.merge(w3);
var tx = w.txps[0].builder.build(); var tx = w.txps[k].builder.build();
tx.isComplete().should.equal(true); tx.isComplete().should.equal(true);
tx.countInputMissingSignatures(0).should.equal(0); tx.countInputMissingSignatures(0).should.equal(0);
w.txps.length.should.equal(1); Object.keys(w.txps).length.should.equal(1);
(w.txps[0].seenBy[priv.id] - ts > 0).should.equal(true); (w.txps[k].seenBy[priv.id] - ts > 0).should.equal(true);
(w.txps[0].seenBy[priv2.id] - ts > 0).should.equal(true); (w.txps[k].seenBy[priv2.id] - ts > 0).should.equal(true);
(w.txps[0].seenBy[priv3.id] - ts > 0).should.equal(true); (w.txps[k].seenBy[priv3.id] - ts > 0).should.equal(true);
(w.txps[0].signedBy[priv.id] - ts > 0).should.equal(true); (w.txps[k].signedBy[priv.id] - ts > 0).should.equal(true);
(w.txps[0].signedBy[priv2.id] - ts > 0).should.equal(true); (w.txps[k].signedBy[priv2.id] - ts > 0).should.equal(true);
(w.txps[0].signedBy[priv3.id] - ts > 0).should.equal(true); (w.txps[k].signedBy[priv3.id] - ts > 0).should.equal(true);
}); });
@ -435,11 +441,12 @@ var _dumpChunks = function (scriptSig, label) {
priv, priv,
pkr pkr
)); ));
var tx = w.txps[0].builder.build(); var k = Object.keys(w.txps)[0];
var tx = w.txps[k].builder.build();
tx.isComplete().should.equal(false); tx.isComplete().should.equal(false);
tx.countInputMissingSignatures(0).should.equal(2); tx.countInputMissingSignatures(0).should.equal(2);
(w.txps[0].signedBy[priv.id] - ts > 0).should.equal(true); (w.txps[k].signedBy[priv.id] - ts > 0).should.equal(true);
(w.txps[0].seenBy[priv.id] - ts > 0).should.equal(true); (w.txps[k].seenBy[priv.id] - ts > 0).should.equal(true);
var o = w.toObj(); var o = w.toObj();
should.exist(o); should.exist(o);
@ -451,18 +458,22 @@ var _dumpChunks = function (scriptSig, label) {
should.exist(o.txps[0].builderObj.valueInSat); should.exist(o.txps[0].builderObj.valueInSat);
should.exist(o.txps[0].signedBy[priv.id]); should.exist(o.txps[0].signedBy[priv.id]);
var w2 = TxProposals.fromObj(o); var o2 = JSON.parse(JSON.stringify(o));
var w2 = TxProposals.fromObj(o2);
w2.walletId.should.equal(w.walletId); w2.walletId.should.equal(w.walletId);
var tx2 = w2.txps[0].builder.build(); var tx2 = w2.txps[k].builder.build();
tx2.isComplete().should.equal(false); tx2.isComplete().should.equal(false);
tx2.countInputMissingSignatures(0).should.equal(2); tx2.countInputMissingSignatures(0).should.equal(2);
(w2.txps[0].signedBy[priv.id] - ts > 0).should.equal(true); (w2.txps[k].signedBy[priv.id] - ts > 0).should.equal(true);
(w2.txps[0].seenBy[priv.id] - ts > 0).should.equal(true); (w2.txps[k].seenBy[priv.id] - ts > 0).should.equal(true);
should.exist(w2.txps[0].builder); should.exist(w2.txps[k].builder);
should.exist(w2.txps[0].builder.valueInSat); should.exist(w2.txps[k].builder.valueInSat);
w2.merge(w); w2.merge(w);
Object.keys(w2.txps).length.should.equal(1);
}); });
}); });

View file

@ -126,11 +126,12 @@ describe('Wallet model', function() {
); );
var t = w.txProposals; var t = w.txProposals;
var tx = t.txps[0].builder.build(); var k = Object.keys(t.txps)[0];
var tx = t.txps[k].builder.build();
should.exist(tx); should.exist(tx);
tx.isComplete().should.equal(false); tx.isComplete().should.equal(false);
Object.keys(t.txps[0].signedBy).length.should.equal(1); Object.keys(t.txps[k].signedBy).length.should.equal(1);
Object.keys(t.txps[0].seenBy).length.should.equal(1); Object.keys(t.txps[k].seenBy).length.should.equal(1);
}); });
it('#addressIsOwn', function () { it('#addressIsOwn', function () {
@ -157,13 +158,14 @@ describe('Wallet model', function() {
unspentTest unspentTest
); );
var t = w.txProposals; var t = w.txProposals;
var tx = t.txps[0].builder.build(); var k = Object.keys(t.txps)[0];
var tx = t.txps[k].builder.build();
should.exist(tx); should.exist(tx);
tx.isComplete().should.equal(false); tx.isComplete().should.equal(false);
tx.countInputMissingSignatures(0).should.equal(2); tx.countInputMissingSignatures(0).should.equal(2);
( t.txps[0].signedBy[w.privateKey.id] - ts > 0).should.equal(true); ( t.txps[k].signedBy[w.privateKey.id] - ts > 0).should.equal(true);
( t.txps[0].seenBy[w.privateKey.id] - ts > 0).should.equal(true); ( t.txps[k].seenBy[w.privateKey.id] - ts > 0).should.equal(true);
} }
} }
}); });