fcoin/lib/wallet/pathinfo.js
2016-10-04 01:36:01 -07:00

310 lines
5.8 KiB
JavaScript

/*!
* pathinfo.js - pathinfo object for bcoin
* Copyright (c) 2014-2016, Christopher Jeffrey (MIT License).
* https://github.com/bcoin-org/bcoin
*/
'use strict';
var utils = require('../utils/utils');
/**
* Path Info
* @constructor
* @param {WalletDB} db
* @param {WalletID} wid
* @param {TX} tx
* @param {Object} table
*/
function PathInfo(wallet, tx, paths) {
if (!(this instanceof PathInfo))
return new PathInfo(wallet, tx, paths);
// All relevant Accounts for
// inputs and outputs (for database indexing).
this.accounts = [];
// All output paths (for deriving during sync).
this.paths = [];
// Wallet
this.wallet = wallet;
// Wallet ID
this.wid = wallet.wid;
// Wallet Label
this.id = wallet.id;
// Map of address hashes->paths.
this.pathMap = {};
// Current transaction.
this.tx = null;
// Wallet-specific details cache.
this._details = null;
this._json = null;
if (tx)
this.fromTX(tx, paths);
}
/**
* Instantiate path info from a transaction.
* @private
* @param {TX} tx
* @param {Object} table
* @returns {PathInfo}
*/
PathInfo.prototype.fromTX = function fromTX(tx, paths) {
var uniq = {};
var i, hashes, hash, path;
this.tx = tx;
for (i = 0; i < paths.length; i++) {
path = paths[i];
this.pathMap[path.hash] = path;
if (!uniq[path.account]) {
uniq[path.account] = true;
this.accounts.push(path.account);
}
}
hashes = tx.getOutputHashes('hex');
for (i = 0; i < hashes.length; i++) {
hash = hashes[i];
path = this.pathMap[hash];
if (path)
this.paths.push(path);
}
return this;
};
/**
* Instantiate path info from a transaction.
* @param {WalletDB} db
* @param {WalletID} wid
* @param {TX} tx
* @param {Object} table
* @returns {PathInfo}
*/
PathInfo.fromTX = function fromTX(wallet, tx, paths) {
return new PathInfo(wallet).fromTX(tx, paths);
};
/**
* Test whether the map has paths
* for a given address hash.
* @param {Hash} hash
* @returns {Boolean}
*/
PathInfo.prototype.hasPath = function hasPath(hash) {
if (!hash)
return false;
return this.pathMap[hash] != null;
};
/**
* Get path for a given address hash.
* @param {Hash} hash
* @returns {Path}
*/
PathInfo.prototype.getPath = function getPath(hash) {
if (!hash)
return;
return this.pathMap[hash];
};
/**
* Convert path info to transaction details.
* @returns {Details}
*/
PathInfo.prototype.toDetails = function toDetails() {
var details = this._details;
if (!details) {
details = new Details(this);
this._details = details;
}
return details;
};
/**
* Convert path info to JSON details (caches json).
* @returns {Object}
*/
PathInfo.prototype.toJSON = function toJSON() {
var json = this._json;
if (!json) {
json = this.toDetails().toJSON();
this._json = json;
}
return json;
};
/**
* Transaction Details
* @constructor
* @param {PathInfo} info
*/
function Details(info) {
if (!(this instanceof Details))
return new Details(info);
this.db = info.wallet.db;
this.network = this.db.network;
this.wid = info.wid;
this.id = info.id;
this.hash = info.tx.hash('hex');
this.height = info.tx.height;
this.block = info.tx.block;
this.index = info.tx.index;
this.confirmations = info.tx.getConfirmations(this.db.height);
this.fee = info.tx.getFee();
this.ts = info.tx.ts;
this.ps = info.tx.ps;
this.tx = info.tx;
this.inputs = [];
this.outputs = [];
this.init(info.pathMap);
}
/**
* Initialize transactions details
* by pushing on mapped members.
* @private
* @param {Object} table
*/
Details.prototype.init = function init(map) {
this._insert(this.tx.inputs, true, this.inputs, map);
this._insert(this.tx.outputs, false, this.outputs, map);
};
/**
* Insert members in the input or output vector.
* @private
* @param {Input[]|Output[]} vector
* @param {Array} target
* @param {Object} table
*/
Details.prototype._insert = function _insert(vector, input, target, map) {
var i, io, address, hash, path, member;
for (i = 0; i < vector.length; i++) {
io = vector[i];
member = new DetailsMember();
if (input) {
if (io.coin)
member.value = io.coin.value;
} else {
member.value = io.value;
}
address = io.getAddress();
if (address) {
member.address = address;
hash = address.getHash('hex');
path = map[hash];
if (path)
member.path = path;
}
target.push(member);
}
};
/**
* Convert details to a more json-friendly object.
* @returns {Object}
*/
Details.prototype.toJSON = function toJSON() {
var self = this;
return {
wid: this.wid,
id: this.id,
hash: utils.revHex(this.hash),
height: this.height,
block: this.block ? utils.revHex(this.block) : null,
ts: this.ts,
ps: this.ps,
index: this.index,
fee: utils.btc(this.fee),
confirmations: this.confirmations,
inputs: this.inputs.map(function(input) {
return input.toJSON(self.network);
}),
outputs: this.outputs.map(function(output) {
return output.toJSON(self.network);
}),
tx: this.tx.toRaw().toString('hex')
};
};
/**
* Transaction Details Member
* @constructor
* @property {Number} value
* @property {Address} address
* @property {Path} path
*/
function DetailsMember() {
if (!(this instanceof DetailsMember))
return new DetailsMember();
this.value = 0;
this.address = null;
this.path = null;
}
/**
* Convert the member to a more json-friendly object.
* @param {Network} network
* @returns {Object}
*/
DetailsMember.prototype.toJSON = function toJSON(network) {
return {
value: utils.btc(this.value),
address: this.address
? this.address.toBase58(network)
: null,
path: this.path
? this.path.toJSON()
: null
};
};
/*
* Expose
*/
module.exports = PathInfo;