send tx
This commit is contained in:
parent
270891b5fd
commit
04d7d5abf0
11 changed files with 265 additions and 574 deletions
|
|
@ -102,7 +102,7 @@ Insight.prototype._request = function(options, callback) {
|
|||
return callback({message: 'Wrong response from insight'});
|
||||
}
|
||||
} else {
|
||||
return callback({message: 'Error ' + response.statusCode});
|
||||
return callback({message: 'Error ' + request.status});
|
||||
}
|
||||
}
|
||||
};
|
||||
|
|
|
|||
|
|
@ -14,10 +14,27 @@ var Storage = imports.Storage || require('../storage/Base');
|
|||
var storage = Storage.default();
|
||||
|
||||
function TxProposal(opts) {
|
||||
this.creator = opts.creator;
|
||||
this.createdTs = opts.createdTs;
|
||||
this.seenBy = opts.seenBy || {};
|
||||
this.signedBy = opts.signedBy || {};
|
||||
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);
|
||||
|
||||
|
||||
|
|
@ -26,7 +43,7 @@ function TxProposals(opts) {
|
|||
this.walletId = opts.walletId;
|
||||
this.network = opts.networkName === 'livenet' ?
|
||||
bitcore.networks.livenet : bitcore.networks.testnet;
|
||||
this.txps = [];
|
||||
this.txps = {};
|
||||
}
|
||||
|
||||
TxProposals.fromObj = function(o) {
|
||||
|
|
@ -34,12 +51,10 @@ TxProposals.fromObj = function(o) {
|
|||
networkName: o.networkName,
|
||||
walletId: o.walletId,
|
||||
});
|
||||
o.txps.forEach(function(t) {
|
||||
ret.txps.push({
|
||||
seenBy: t.seenBy,
|
||||
signedBy: t.signedBy,
|
||||
builder: new Builder.fromObj(t.builderObj),
|
||||
});
|
||||
o.txps.forEach(function(o2) {
|
||||
var t = TxProposal.fromObj(o2);
|
||||
var id = t.builder.build().getNormalizedHash().toString('hex');
|
||||
ret.txps[id] = t;
|
||||
});
|
||||
return ret;
|
||||
};
|
||||
|
|
@ -47,13 +62,10 @@ TxProposals.fromObj = function(o) {
|
|||
|
||||
TxProposals.prototype.toObj = function() {
|
||||
var ret = [];
|
||||
this.txps.forEach(function(t) {
|
||||
ret.push({
|
||||
seenBy: t.seenBy,
|
||||
signedBy: t.signedBy,
|
||||
builderObj: t.builder.toObj(),
|
||||
});
|
||||
});
|
||||
for(var id in this.txps){
|
||||
var t = this.txps[id];
|
||||
ret.push(t.toObj());
|
||||
}
|
||||
return {
|
||||
txps: ret,
|
||||
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) {
|
||||
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]) {
|
||||
ready.push(theirTxps[hash]); // only in theirs;
|
||||
ready[hash]=theirTxps[hash]; // only in theirs;
|
||||
fromTheirs++;
|
||||
}
|
||||
else {
|
||||
toMerge[hash]=theirTxps[hash]; // need Merging
|
||||
merged++;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
Object.keys(myTxps).forEach(function(hash) {
|
||||
for(var hash in myTxps){
|
||||
if(!toMerge[hash]) {
|
||||
ready.push(myTxps[hash]); // only in myTxps;
|
||||
ready[hash]=myTxps[hash]; // only in myTxps;
|
||||
fromUs++;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
return {
|
||||
stats: {
|
||||
|
|
@ -124,42 +127,48 @@ TxProposals.prototype._mergeMetadata = function(myTxps, theirTxps, mergeInfo) {
|
|||
|
||||
|
||||
TxProposals.prototype._mergeBuilder = function(myTxps, theirTxps, mergeInfo) {
|
||||
var self = this;
|
||||
var toMerge = mergeInfo.toMerge;
|
||||
|
||||
Object.keys(toMerge).forEach(function(hash) {
|
||||
for(var hash in toMerge){
|
||||
var v0 = myTxps[hash].builder;
|
||||
var v1 = toMerge[hash].builder;
|
||||
|
||||
v0.merge(v1);
|
||||
});
|
||||
};
|
||||
};
|
||||
|
||||
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) {
|
||||
if (this.network.name !== t.network.name)
|
||||
throw new Error('network mismatch in:', t);
|
||||
|
||||
var res = [];
|
||||
|
||||
var myTxps = this._getNormHash(this.txps);
|
||||
var theirTxps = this._getNormHash(t.txps);
|
||||
var myTxps = this.txps;
|
||||
var theirTxps = t.txps;
|
||||
|
||||
var mergeInfo = this._startMerge(myTxps, theirTxps);
|
||||
this._mergeMetadata(myTxps, theirTxps, mergeInfo);
|
||||
this._mergeBuilder(myTxps, theirTxps, mergeInfo);
|
||||
|
||||
Object.keys(mergeInfo.toMerge).forEach(function(hash) {
|
||||
mergeInfo.ready.push(myTxps[hash]);
|
||||
mergeInfo.ready[hash] = myTxps[hash];
|
||||
});
|
||||
|
||||
this.txps=mergeInfo.ready;
|
||||
return mergeInfo.stats;
|
||||
};
|
||||
|
||||
|
||||
|
||||
module.exports = require('soop')(TxProposals);
|
||||
|
|
|
|||
|
|
@ -256,75 +256,82 @@ Wallet.prototype.generateAddress = function() {
|
|||
return addr;
|
||||
};
|
||||
|
||||
// TODO : sort by time... / signed.
|
||||
Wallet.prototype.getTxProposals = function() {
|
||||
var ret = [];
|
||||
var self= this;
|
||||
self.txProposals.txps.forEach(function(txp) {
|
||||
for(var k in this.txProposals.txps) {
|
||||
var txp = this.txProposals.txps[k];
|
||||
var i = {txp:txp};
|
||||
i.ntxid = txp.builder.build().getNormalizedHash();
|
||||
i.signedByUs = txp.signedBy[self.privateKey.getId()]?true:false;
|
||||
i.ntxid = k;
|
||||
i.signedByUs = txp.signedBy[this.privateKey.getId()]?true:false;
|
||||
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;
|
||||
};
|
||||
|
||||
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) {
|
||||
var txp = this._findTxByNtxid(ntxid);
|
||||
var self = this;
|
||||
var txp = self.txProposals.txps[ntxid];
|
||||
if (!txp) return;
|
||||
|
||||
var pkr = this.publicKeyRing;
|
||||
var keys = this.privateKey.getAll(pkr.addressIndex, pkr.changeAddressIndex);
|
||||
var ret = txp.builder.sign(keys);
|
||||
var pkr = self.publicKeyRing;
|
||||
var keys = self.privateKey.getAll(pkr.addressIndex, pkr.changeAddressIndex);
|
||||
|
||||
if (ret.signaturesAdded) {
|
||||
txp.signedBy[this.privateKey.getId()] = Date.now();
|
||||
this.log('[Wallet.js.230:ret:]',ret); //TODO
|
||||
if (ret.isFullySigned) {
|
||||
this.log('[Wallet.js.231] BROADCASTING TX!!!'); //TODO
|
||||
var tx = txp.builder.build();
|
||||
var txHex = tx.serialize().toString('hex');
|
||||
this.blockchain.sendRawTransaction(txHex, function(txid) {
|
||||
this.log('[Wallet.js.235:txid:]',txid); //TODO
|
||||
if (txid) {
|
||||
this.store(true);
|
||||
}
|
||||
});
|
||||
}
|
||||
else {
|
||||
this.sendTxProposals();
|
||||
this.store(true);
|
||||
}
|
||||
var b = txp.builder;
|
||||
var before = b.signaturesAdded;
|
||||
b.sign(keys);
|
||||
|
||||
var ret = false;
|
||||
if (b.signaturesAdded > before) {
|
||||
txp.signedBy[self.privateKey.getId()] = Date.now();
|
||||
this.sendTxProposals();
|
||||
this.store(true);
|
||||
ret = true;
|
||||
}
|
||||
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() {
|
||||
var ret=false;
|
||||
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()]) {
|
||||
txp.seenBy[self.privateKey.getId()] = Date.now();
|
||||
ret = true;
|
||||
}
|
||||
});
|
||||
}
|
||||
return ret;
|
||||
};
|
||||
|
||||
|
|
@ -359,9 +366,12 @@ Wallet.prototype.getBalance = function(cb) {
|
|||
var balance = 0;
|
||||
var balanceByAddr = {};
|
||||
var COIN = bitcore.util.COIN;
|
||||
var addresses = this.getAddressesStr(true);
|
||||
|
||||
if (!addresses.length) return cb(0,[]);
|
||||
|
||||
// Prefill balanceByAddr with main address
|
||||
this.getAddressesStr(true).forEach(function(a){
|
||||
addresses.forEach(function(a){
|
||||
balanceByAddr[a]=0;
|
||||
});
|
||||
this.getUnspent(function(utxos) {
|
||||
|
|
@ -371,9 +381,9 @@ Wallet.prototype.getBalance = function(cb) {
|
|||
balance = balance + 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;
|
||||
});
|
||||
};
|
||||
return cb(balance / COIN, balanceByAddr);
|
||||
});
|
||||
};
|
||||
|
|
@ -395,14 +405,10 @@ Wallet.prototype.createTx = function(toAddress, amountSatStr, opts, cb) {
|
|||
if (typeof opts.spendUnconfirmed === 'undefined') {
|
||||
opts.spendUnconfirmed = this.spendUnconfirmed;
|
||||
}
|
||||
|
||||
if (!opts.remainderOut) {
|
||||
opts.remainderOut={ address: this.publicKeyRing.generateAddress(true).toString()};
|
||||
}
|
||||
|
||||
self.getUnspent(function(unspentList) {
|
||||
// TODO check enough funds, etc.
|
||||
self.createTxSync(toAddress, amountSatStr, unspentList, opts);
|
||||
self.sendPublicKeyRing(); // Change Address
|
||||
self.sendTxProposals();
|
||||
self.store();
|
||||
return cb();
|
||||
|
|
@ -440,6 +446,8 @@ Wallet.prototype.createTxSync = function(toAddress, amountSatStr, utxos, opts) {
|
|||
this.txProposals.add({
|
||||
signedBy: priv && b.signaturesAdded ? me : {},
|
||||
seenBy: priv ? me : {},
|
||||
creator: priv.id,
|
||||
createdTs: Date.now(),
|
||||
builder: b,
|
||||
});
|
||||
};
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue