tx: refactor network handling in json serialization.

This commit is contained in:
Christopher Jeffrey 2016-11-17 04:05:32 -08:00
parent 97703e4c7d
commit 39aee21030
No known key found for this signature in database
GPG Key ID: 8962AB9DE6666BBD
11 changed files with 119 additions and 86 deletions

View File

@ -211,10 +211,8 @@ Chain.prototype._open = co(function* open() {
this.logger.info('Chain Height: %d', tip.height); this.logger.info('Chain Height: %d', tip.height);
if (tip.height > this.bestHeight) { if (tip.height > this.bestHeight)
this.bestHeight = tip.height; this.bestHeight = tip.height;
this.network.updateHeight(tip.height);
}
this.logger.memory(); this.logger.memory();
@ -853,7 +851,6 @@ Chain.prototype.disconnect = co(function* disconnect(entry) {
this.height = prev.height; this.height = prev.height;
this.bestHeight = prev.height; this.bestHeight = prev.height;
this.network.updateHeight(prev.height);
this.emit('tip', prev); this.emit('tip', prev);
this.emit('disconnect', entry, block); this.emit('disconnect', entry, block);
@ -900,7 +897,6 @@ Chain.prototype.reconnect = co(function* reconnect(entry) {
this.state = result.state; this.state = result.state;
this.bestHeight = entry.height; this.bestHeight = entry.height;
this.network.updateHeight(entry.height);
this.emit('tip', entry); this.emit('tip', entry);
this.emit('reconnect', entry, block); this.emit('reconnect', entry, block);
@ -1250,10 +1246,8 @@ Chain.prototype._add = co(function* add(block) {
if (prev) if (prev)
height = prev.height + 1; height = prev.height + 1;
if (height > this.bestHeight) { if (height > this.bestHeight)
this.bestHeight = height; this.bestHeight = height;
this.network.updateHeight(height);
}
// If previous block wasn't ever seen, // If previous block wasn't ever seen,
// add it current to orphans and break. // add it current to orphans and break.
@ -1267,10 +1261,8 @@ Chain.prototype._add = co(function* add(block) {
// We do this even for orphans (peers will send // We do this even for orphans (peers will send
// us their highest block during the initial // us their highest block during the initial
// getblocks sync, making it an orphan). // getblocks sync, making it an orphan).
if (block.getCoinbaseHeight() > this.bestHeight) { if (block.getCoinbaseHeight() > this.bestHeight)
this.bestHeight = block.getCoinbaseHeight(); this.bestHeight = block.getCoinbaseHeight();
this.network.updateHeight(this.bestHeight);
}
this.emit('orphan', block, block.getCoinbaseHeight()); this.emit('orphan', block, block.getCoinbaseHeight());

View File

@ -180,7 +180,7 @@ HTTPClient.prototype.onDisconnect = function onDisconnect() {
*/ */
HTTPClient.prototype._request = co(function* _request(method, endpoint, json) { HTTPClient.prototype._request = co(function* _request(method, endpoint, json) {
var query, network, height, res; var query, network, res;
if (this.token) { if (this.token) {
if (!json) if (!json)
@ -210,11 +210,6 @@ HTTPClient.prototype._request = co(function* _request(method, endpoint, json) {
if (network && network !== this.network.type) if (network && network !== this.network.type)
throw new Error('Wrong network.'); throw new Error('Wrong network.');
height = +res.headers['x-bcoin-height'];
if (utils.isNumber(height))
this.network.updateHeight(height);
if (res.statusCode === 404) if (res.statusCode === 404)
return; return;

View File

@ -605,8 +605,8 @@ HTTPServer.prototype._init = function _init() {
coins = yield this.node.getCoinsByAddress(req.options.address); coins = yield this.node.getCoinsByAddress(req.options.address);
send(200, coins.map(function(coin) { send(200, coins.map(function(coin) {
return coin.toJSON(); return coin.toJSON(this.network);
})); }, this));
})); }));
// UTXO by id // UTXO by id
@ -621,7 +621,7 @@ HTTPServer.prototype._init = function _init() {
if (!coin) if (!coin)
return send(404); return send(404);
send(200, coin.toJSON()); send(200, coin.toJSON(this.network));
})); }));
// Bulk read UTXOs // Bulk read UTXOs
@ -633,8 +633,8 @@ HTTPServer.prototype._init = function _init() {
coins = yield this.node.getCoinsByAddress(req.options.address); coins = yield this.node.getCoinsByAddress(req.options.address);
send(200, coins.map(function(coin) { send(200, coins.map(function(coin) {
return coin.toJSON(); return coin.toJSON(this.network);
})); }, this));
})); }));
// TX by hash // TX by hash
@ -650,7 +650,7 @@ HTTPServer.prototype._init = function _init() {
yield this.node.fillHistory(tx); yield this.node.fillHistory(tx);
send(200, tx.toJSON()); send(200, tx.toJSON(this.network));
})); }));
// TX by address // TX by address
@ -667,8 +667,8 @@ HTTPServer.prototype._init = function _init() {
} }
send(200, txs.map(function(tx) { send(200, txs.map(function(tx) {
return tx.toJSON(); return tx.toJSON(this.network);
})); }, this));
})); }));
// Bulk read TXs // Bulk read TXs
@ -685,8 +685,8 @@ HTTPServer.prototype._init = function _init() {
} }
send(200, txs.map(function(tx) { send(200, txs.map(function(tx) {
return tx.toJSON(); return tx.toJSON(this.network);
})); }, this));
})); }));
// Block by hash/height // Block by hash/height
@ -701,7 +701,7 @@ HTTPServer.prototype._init = function _init() {
if (!block) if (!block)
return send(404); return send(404);
send(200, block.toJSON()); send(200, block.toJSON(this.network));
})); }));
// Mempool snapshot // Mempool snapshot
@ -719,8 +719,8 @@ HTTPServer.prototype._init = function _init() {
} }
send(200, txs.map(function(tx) { send(200, txs.map(function(tx) {
return tx.toJSON(); return tx.toJSON(this.network);
})); }, this));
})); }));
// Broadcast TX // Broadcast TX
@ -910,7 +910,7 @@ HTTPServer.prototype._init = function _init() {
var passphrase = options.passphrase; var passphrase = options.passphrase;
var tx = yield req.wallet.createTX(options); var tx = yield req.wallet.createTX(options);
yield req.wallet.sign(tx, passphrase); yield req.wallet.sign(tx, passphrase);
send(200, tx.toJSON()); send(200, tx.toJSON(this.network));
})); }));
// Sign TX // Sign TX
@ -920,7 +920,7 @@ HTTPServer.prototype._init = function _init() {
var tx = req.options.tx; var tx = req.options.tx;
enforce(tx, 'TX is required.'); enforce(tx, 'TX is required.');
yield req.wallet.sign(tx, passphrase); yield req.wallet.sign(tx, passphrase);
send(200, tx.toJSON()); send(200, tx.toJSON(this.network));
})); }));
// Fill TX // Fill TX
@ -928,7 +928,7 @@ HTTPServer.prototype._init = function _init() {
var tx = req.options.tx; var tx = req.options.tx;
enforce(tx, 'TX is required.'); enforce(tx, 'TX is required.');
yield req.wallet.fillHistory(tx); yield req.wallet.fillHistory(tx);
send(200, tx.toJSON()); send(200, tx.toJSON(this.network));
})); }));
// Zap Wallet TXs // Zap Wallet TXs
@ -1068,8 +1068,8 @@ HTTPServer.prototype._init = function _init() {
sortCoins(coins); sortCoins(coins);
send(200, coins.map(function(coin) { send(200, coins.map(function(coin) {
return coin.toJSON(); return coin.toJSON(this.network);
})); }, this));
})); }));
// Locked coins // Locked coins
@ -1120,7 +1120,7 @@ HTTPServer.prototype._init = function _init() {
if (!coin) if (!coin)
return send(404); return send(404);
send(200, coin.toJSON()); send(200, coin.toJSON(this.network));
})); }));
// Wallet TXs // Wallet TXs
@ -1547,6 +1547,7 @@ function ClientSocket(server, socket) {
this.filter = null; this.filter = null;
this.api = false; this.api = false;
this.network = this.server.network;
this.node = this.server.node; this.node = this.server.node;
this.chain = this.server.chain; this.chain = this.server.chain;
this.mempool = this.server.mempool; this.mempool = this.server.mempool;
@ -1658,7 +1659,7 @@ ClientSocket.prototype.watchChain = function watchChain() {
this.bind(pool, 'tx', function(tx) { this.bind(pool, 'tx', function(tx) {
if (self.testFilter(tx)) if (self.testFilter(tx))
self.emit('mempool tx', tx.toJSON()); self.emit('mempool tx', tx.toJSON(self.network));
}); });
}; };
@ -1679,7 +1680,7 @@ ClientSocket.prototype.testBlock = function testBlock(block) {
for (i = 0; i < block.txs.length; i++) { for (i = 0; i < block.txs.length; i++) {
tx = block.txs[i]; tx = block.txs[i];
if (this.testFilter(tx)) if (this.testFilter(tx))
txs.push(tx.toJSON()); txs.push(tx.toJSON(this.network));
} }
if (txs.length === 0) if (txs.length === 0)
@ -1757,7 +1758,7 @@ ClientSocket.prototype.scanner = function scanner(entry, txs) {
var i; var i;
for (i = 0; i < txs.length; i++) for (i = 0; i < txs.length; i++)
json[i] = txs[i].toJSON(); json[i] = txs[i].toJSON(this.network);
this.emit('block tx', entry.toJSON(), json); this.emit('block tx', entry.toJSON(), json);

View File

@ -592,7 +592,6 @@ Block.prototype.getPrevout = function getPrevout() {
Block.prototype.inspect = function inspect() { Block.prototype.inspect = function inspect() {
return { return {
type: 'block',
hash: this.rhash, hash: this.rhash,
height: this.height, height: this.height,
size: this.getSize(), size: this.getSize(),
@ -619,9 +618,9 @@ Block.prototype.inspect = function inspect() {
* @returns {Object} * @returns {Object}
*/ */
Block.prototype.toJSON = function toJSON() { Block.prototype.toJSON = function toJSON(network) {
network = Network.get(network);
return { return {
type: 'block',
hash: this.rhash, hash: this.rhash,
height: this.height, height: this.height,
version: this.version, version: this.version,
@ -632,7 +631,7 @@ Block.prototype.toJSON = function toJSON() {
nonce: this.nonce, nonce: this.nonce,
totalTX: this.totalTX, totalTX: this.totalTX,
txs: this.txs.map(function(tx) { txs: this.txs.map(function(tx) {
return tx.toJSON(); return tx.toJSON(network);
}) })
}; };
}; };

View File

@ -103,8 +103,7 @@ Coin.fromOptions = function fromOptions(options) {
*/ */
Coin.prototype.getConfirmations = function getConfirmations(height) { Coin.prototype.getConfirmations = function getConfirmations(height) {
if (height == null) assert(typeof height === 'number', 'Must pass a height.');
height = Network.primary.height;
if (this.height === -1) if (this.height === -1)
return 0; return 0;
@ -151,7 +150,7 @@ Coin.prototype.inspect = function inspect() {
coinbase: this.coinbase, coinbase: this.coinbase,
hash: this.hash ? utils.revHex(this.hash) : null, hash: this.hash ? utils.revHex(this.hash) : null,
index: this.index, index: this.index,
age: this.getAge(), // age: this.getAge(),
address: this.getAddress() address: this.getAddress()
}; };
}; };
@ -164,11 +163,13 @@ Coin.prototype.inspect = function inspect() {
* @returns {Object} * @returns {Object}
*/ */
Coin.prototype.toJSON = function toJSON() { Coin.prototype.toJSON = function toJSON(network) {
var address = this.getAddress(); var address = this.getAddress();
network = Network.get(network);
if (address) if (address)
address = address.toBase58(); address = address.toBase58(network);
return { return {
version: this.version, version: this.version,

View File

@ -266,15 +266,17 @@ Input.prototype.inspect = function inspect() {
* @returns {Object} * @returns {Object}
*/ */
Input.prototype.toJSON = function toJSON() { Input.prototype.toJSON = function toJSON(network) {
var address = this.getAddress(); var address = this.getAddress();
network = Network.get(network);
if (address) if (address)
address = address.toBase58(); address = address.toBase58(network);
return { return {
prevout: this.prevout.toJSON(), prevout: this.prevout.toJSON(),
coin: this.coin ? this.coin.toJSON() : null, coin: this.coin ? this.coin.toJSON(network) : null,
script: this.script.toJSON(), script: this.script.toJSON(),
witness: this.witness.toJSON(), witness: this.witness.toJSON(),
sequence: this.sequence, sequence: this.sequence,

View File

@ -1312,11 +1312,7 @@ MTX.prototype.sortMembers = function sortMembers() {
*/ */
MTX.prototype.avoidFeeSniping = function avoidFeeSniping(height) { MTX.prototype.avoidFeeSniping = function avoidFeeSniping(height) {
if (height == null) assert(typeof height === 'number', 'Must pass in height.');
height = Network.primary.height;
if (height === -1)
height = 0;
if ((Math.random() * 10 | 0) === 0) if ((Math.random() * 10 | 0) === 0)
height = Math.max(0, height - (Math.random() * 100 | 0)); height = Math.max(0, height - (Math.random() * 100 | 0));

View File

@ -131,11 +131,13 @@ Output.prototype.inspect = function inspect() {
* @returns {Object} * @returns {Object}
*/ */
Output.prototype.toJSON = function toJSON() { Output.prototype.toJSON = function toJSON(network) {
var address = this.getAddress(); var address = this.getAddress();
network = Network.get(network);
if (address) if (address)
address = address.toBase58(); address = address.toBase58(network);
return { return {
value: utils.btc(this.value), value: utils.btc(this.value),

View File

@ -1767,15 +1767,11 @@ TX.prototype.getPriority = function getPriority(height, size) {
var sum = 0; var sum = 0;
var i, input, age; var i, input, age;
assert(typeof height === 'number', 'Must pass in height.');
if (this.isCoinbase()) if (this.isCoinbase())
return sum; return sum;
if (height == null) {
height = this.height;
if (height === -1)
height = Network.primary.height;
}
if (size == null) if (size == null)
size = this.maxSize(); size = this.maxSize();
@ -1901,8 +1897,7 @@ TX.prototype.getRate = function getRate(size) {
*/ */
TX.prototype.getConfirmations = function getConfirmations(height) { TX.prototype.getConfirmations = function getConfirmations(height) {
if (height == null) assert(typeof height === 'number', 'Must pass in height.');
height = Network.primary.height;
if (this.height === -1) if (this.height === -1)
return 0; return 0;
@ -2093,8 +2088,13 @@ TX.getRate = function getRate(size, fee) {
*/ */
TX.prototype.inspect = function inspect() { TX.prototype.inspect = function inspect() {
var rate = this.getRate();
// Rate can exceed 53 bits in testing.
if (!utils.isSafeInteger(rate))
rate = 0;
return { return {
type: 'tx',
hash: this.rhash, hash: this.rhash,
witnessHash: this.rwhash, witnessHash: this.rwhash,
size: this.getSize(), size: this.getSize(),
@ -2103,9 +2103,7 @@ TX.prototype.inspect = function inspect() {
value: utils.btc(this.getOutputValue()), value: utils.btc(this.getOutputValue()),
fee: utils.btc(this.getFee()), fee: utils.btc(this.getFee()),
minFee: utils.btc(this.getMinFee()), minFee: utils.btc(this.getMinFee()),
rate: this.getRate(), // Rate can sometimes exceed 53 bits in testing rate: utils.btc(rate),
confirmations: this.getConfirmations(),
priority: this.getPriority(),
date: utils.date(this.ts || this.ps), date: utils.date(this.ts || this.ps),
block: this.block ? utils.revHex(this.block) : null, block: this.block ? utils.revHex(this.block) : null,
ts: this.ts, ts: this.ts,
@ -2127,25 +2125,33 @@ TX.prototype.inspect = function inspect() {
* @returns {Object} * @returns {Object}
*/ */
TX.prototype.toJSON = function toJSON() { TX.prototype.toJSON = function toJSON(network) {
var rate = this.getRate();
// Rate can exceed 53 bits in testing.
if (!utils.isSafeInteger(rate))
rate = 0;
network = Network.get(network);
return { return {
type: 'tx',
hash: utils.revHex(this.hash('hex')), hash: utils.revHex(this.hash('hex')),
witnessHash: utils.revHex(this.witnessHash('hex')), witnessHash: utils.revHex(this.witnessHash('hex')),
height: this.height, height: this.height,
block: this.block ? utils.revHex(this.block) : null, block: this.block ? utils.revHex(this.block) : null,
ts: this.ts, ts: this.ts,
ps: this.ps, ps: this.ps,
date: utils.date(this.ts || this.ps),
index: this.index, index: this.index,
fee: utils.btc(this.getFee()), fee: utils.btc(this.getFee()),
confirmations: this.getConfirmations(), rate: utils.btc(rate),
version: this.version, version: this.version,
flag: this.flag, flag: this.flag,
inputs: this.inputs.map(function(input) { inputs: this.inputs.map(function(input) {
return input.toJSON(); return input.toJSON(network);
}), }),
outputs: this.outputs.map(function(output) { outputs: this.outputs.map(function(output) {
return output.toJSON(); return output.toJSON(network);
}), }),
locktime: this.locktime locktime: this.locktime
}; };

View File

@ -24,7 +24,6 @@ function Network(options) {
assert(!Network[options.type], 'Cannot create two networks.'); assert(!Network[options.type], 'Cannot create two networks.');
this.type = options.type; this.type = options.type;
this.height = -1;
this.seeds = options.seeds; this.seeds = options.seeds;
this.magic = options.magic; this.magic = options.magic;
this.port = options.port; this.port = options.port;
@ -77,15 +76,6 @@ Network.segnet3 = null;
Network.segnet4 = null; Network.segnet4 = null;
Network.simnet = null; Network.simnet = null;
/**
* Update the height of the network.
* @param {Number} height
*/
Network.prototype.updateHeight = function updateHeight(height) {
this.height = height;
};
/** /**
* Determine how many blocks to request * Determine how many blocks to request
* based on current height of the chain. * based on current height of the chain.
@ -169,6 +159,31 @@ Network.get = function get(type) {
assert(false, 'Unknown network.'); assert(false, 'Unknown network.');
}; };
/**
* Get a network with a string or a Network object.
* @param {NetworkType|Network} type - Network type.
* @returns {Network}
*/
Network.ensure = function ensure(type) {
if (!type) {
assert(Network.primary, 'No default network.');
return Network.primary;
}
if (type instanceof Network)
return type;
if (typeof type === 'string') {
if (networks[type])
return Network.create(type);
}
assert(Network.primary, 'No default network.');
return Network.primary;
};
/** /**
* Get a network by its magic number. * Get a network by its magic number.
* @returns {Network} * @returns {Network}

View File

@ -3180,6 +3180,8 @@ function Details(txdb, tx) {
this.chainHeight = txdb.walletdb.state.height; this.chainHeight = txdb.walletdb.state.height;
this.hash = tx.hash('hex'); this.hash = tx.hash('hex');
this.size = tx.getSize();
this.vsize = tx.getVirtualSize();
this.tx = tx; this.tx = tx;
this.block = tx.block; this.block = tx.block;
@ -3303,6 +3305,17 @@ Details.prototype.getFee = function getFee() {
return inputValue - outputValue; return inputValue - outputValue;
}; };
/**
* Calculate fee rate. Only works if wallet
* owns all inputs. Returns 0 otherwise.
* @param {Amount} fee
* @returns {Rate}
*/
Details.prototype.getRate = function getRate(fee) {
return TX.getRate(this.vsize, fee);
};
/** /**
* Convert details to a more json-friendly object. * Convert details to a more json-friendly object.
* @returns {Object} * @returns {Object}
@ -3310,6 +3323,13 @@ Details.prototype.getFee = function getFee() {
Details.prototype.toJSON = function toJSON() { Details.prototype.toJSON = function toJSON() {
var self = this; var self = this;
var fee = this.getFee();
var rate = this.getRate(fee);
// Rate can exceed 53 bits in testing.
if (!utils.isSafeInteger(rate))
rate = 0;
return { return {
wid: this.wid, wid: this.wid,
id: this.id, id: this.id,
@ -3318,8 +3338,12 @@ Details.prototype.toJSON = function toJSON() {
block: this.block ? utils.revHex(this.block) : null, block: this.block ? utils.revHex(this.block) : null,
ts: this.ts, ts: this.ts,
ps: this.ps, ps: this.ps,
date: utils.date(this.ts || this.ps),
index: this.index, index: this.index,
fee: utils.btc(this.getFee()), size: this.size,
virtualSize: this.vsize,
fee: utils.btc(fee),
rate: utils.btc(rate),
confirmations: this.getConfirmations(), confirmations: this.getConfirmations(),
inputs: this.inputs.map(function(input) { inputs: this.inputs.map(function(input) {
return input.toJSON(self.network); return input.toJSON(self.network);