copay/js/models/core/TxProposals.js

166 lines
3.7 KiB
JavaScript

'use strict';
var imports = require('soop').imports();
var bitcore = require('bitcore');
var util = bitcore.util;
var Transaction = bitcore.Transaction;
var Builder = bitcore.TransactionBuilder;
var Script = bitcore.Script;
var buffertools = bitcore.buffertools;
var Storage = imports.Storage || require('../storage/Base');
var storage = Storage.default();
function TxProposal(opts) {
this.seenBy = opts.seenBy || {};
this.signedBy = opts.signedBy || {};
this.builder = opts.builder;
};
module.exports = require('soop')(TxProposal);
function TxProposals(opts) {
opts = opts || {};
this.walletId = opts.walletId;
this.network = opts.networkName === 'livenet' ?
bitcore.networks.livenet : bitcore.networks.testnet;
this.txps = [];
}
TxProposals.fromObj = function(o) {
var ret = new TxProposals({
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),
});
});
return ret;
};
TxProposals.prototype.toObj = function() {
var ret = [];
this.txps.forEach(function(t) {
ret.push({
seenBy: t.seenBy,
signedBy: t.signedBy,
builderObj: t.builder.toObj(),
});
});
return {
txps: ret,
walletId: this.walletId,
networkName: this.network.name,
};
};
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=[];
Object.keys(theirTxps).forEach(function(hash) {
if (!myTxps[hash]) {
ready.push(theirTxps[hash]); // only in theirs;
fromTheirs++;
}
else {
toMerge[hash]=theirTxps[hash]; // need Merging
merged++;
}
});
Object.keys(myTxps).forEach(function(hash) {
if(!toMerge[hash]) {
ready.push(myTxps[hash]); // only in myTxps;
fromUs++;
}
});
return {
stats: {
fromUs: fromUs,
fromTheirs: fromTheirs,
merged: merged,
},
ready: ready,
toMerge: toMerge,
};
};
TxProposals.prototype._mergeMetadata = function(myTxps, theirTxps, mergeInfo) {
var toMerge = mergeInfo.toMerge;
Object.keys(toMerge).forEach(function(hash) {
var v0 = myTxps[hash];
var v1 = toMerge[hash];
Object.keys(v1.seenBy).forEach(function(k) {
v0.seenBy[k] = v1.seenBy[k];
});
Object.keys(v1.signedBy).forEach(function(k) {
v0.signedBy[k] = v1.signedBy[k];
});
});
};
TxProposals.prototype._mergeBuilder = function(myTxps, theirTxps, mergeInfo) {
var self = this;
var toMerge = mergeInfo.toMerge;
Object.keys(toMerge).forEach(function(hash) {
var v0 = myTxps[hash].builder;
var v1 = toMerge[hash].builder;
v0.merge(v1);
});
};
TxProposals.prototype.add = function(data) {
this.txps.push( new TxProposal(data) );
};
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 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]);
});
this.txps=mergeInfo.ready;
return mergeInfo.stats;
};
module.exports = require('soop')(TxProposals);