diff --git a/lib/chain/chain.js b/lib/chain/chain.js index 27007cfa..267f4f4e 100644 --- a/lib/chain/chain.js +++ b/lib/chain/chain.js @@ -211,10 +211,8 @@ Chain.prototype._open = co(function* open() { this.logger.info('Chain Height: %d', tip.height); - if (tip.height > this.bestHeight) { + if (tip.height > this.bestHeight) this.bestHeight = tip.height; - this.network.updateHeight(tip.height); - } this.logger.memory(); @@ -853,7 +851,6 @@ Chain.prototype.disconnect = co(function* disconnect(entry) { this.height = prev.height; this.bestHeight = prev.height; - this.network.updateHeight(prev.height); this.emit('tip', prev); this.emit('disconnect', entry, block); @@ -900,7 +897,6 @@ Chain.prototype.reconnect = co(function* reconnect(entry) { this.state = result.state; this.bestHeight = entry.height; - this.network.updateHeight(entry.height); this.emit('tip', entry); this.emit('reconnect', entry, block); @@ -1250,10 +1246,8 @@ Chain.prototype._add = co(function* add(block) { if (prev) height = prev.height + 1; - if (height > this.bestHeight) { + if (height > this.bestHeight) this.bestHeight = height; - this.network.updateHeight(height); - } // If previous block wasn't ever seen, // 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 // us their highest block during the initial // getblocks sync, making it an orphan). - if (block.getCoinbaseHeight() > this.bestHeight) { + if (block.getCoinbaseHeight() > this.bestHeight) this.bestHeight = block.getCoinbaseHeight(); - this.network.updateHeight(this.bestHeight); - } this.emit('orphan', block, block.getCoinbaseHeight()); diff --git a/lib/http/client.js b/lib/http/client.js index 0935c985..fdc1a97b 100644 --- a/lib/http/client.js +++ b/lib/http/client.js @@ -180,7 +180,7 @@ HTTPClient.prototype.onDisconnect = function onDisconnect() { */ HTTPClient.prototype._request = co(function* _request(method, endpoint, json) { - var query, network, height, res; + var query, network, res; if (this.token) { if (!json) @@ -210,11 +210,6 @@ HTTPClient.prototype._request = co(function* _request(method, endpoint, json) { if (network && network !== this.network.type) throw new Error('Wrong network.'); - height = +res.headers['x-bcoin-height']; - - if (utils.isNumber(height)) - this.network.updateHeight(height); - if (res.statusCode === 404) return; diff --git a/lib/http/server.js b/lib/http/server.js index 71b5cb35..398d8b21 100644 --- a/lib/http/server.js +++ b/lib/http/server.js @@ -605,8 +605,8 @@ HTTPServer.prototype._init = function _init() { coins = yield this.node.getCoinsByAddress(req.options.address); send(200, coins.map(function(coin) { - return coin.toJSON(); - })); + return coin.toJSON(this.network); + }, this)); })); // UTXO by id @@ -621,7 +621,7 @@ HTTPServer.prototype._init = function _init() { if (!coin) return send(404); - send(200, coin.toJSON()); + send(200, coin.toJSON(this.network)); })); // Bulk read UTXOs @@ -633,8 +633,8 @@ HTTPServer.prototype._init = function _init() { coins = yield this.node.getCoinsByAddress(req.options.address); send(200, coins.map(function(coin) { - return coin.toJSON(); - })); + return coin.toJSON(this.network); + }, this)); })); // TX by hash @@ -650,7 +650,7 @@ HTTPServer.prototype._init = function _init() { yield this.node.fillHistory(tx); - send(200, tx.toJSON()); + send(200, tx.toJSON(this.network)); })); // TX by address @@ -667,8 +667,8 @@ HTTPServer.prototype._init = function _init() { } send(200, txs.map(function(tx) { - return tx.toJSON(); - })); + return tx.toJSON(this.network); + }, this)); })); // Bulk read TXs @@ -685,8 +685,8 @@ HTTPServer.prototype._init = function _init() { } send(200, txs.map(function(tx) { - return tx.toJSON(); - })); + return tx.toJSON(this.network); + }, this)); })); // Block by hash/height @@ -701,7 +701,7 @@ HTTPServer.prototype._init = function _init() { if (!block) return send(404); - send(200, block.toJSON()); + send(200, block.toJSON(this.network)); })); // Mempool snapshot @@ -719,8 +719,8 @@ HTTPServer.prototype._init = function _init() { } send(200, txs.map(function(tx) { - return tx.toJSON(); - })); + return tx.toJSON(this.network); + }, this)); })); // Broadcast TX @@ -910,7 +910,7 @@ HTTPServer.prototype._init = function _init() { var passphrase = options.passphrase; var tx = yield req.wallet.createTX(options); yield req.wallet.sign(tx, passphrase); - send(200, tx.toJSON()); + send(200, tx.toJSON(this.network)); })); // Sign TX @@ -920,7 +920,7 @@ HTTPServer.prototype._init = function _init() { var tx = req.options.tx; enforce(tx, 'TX is required.'); yield req.wallet.sign(tx, passphrase); - send(200, tx.toJSON()); + send(200, tx.toJSON(this.network)); })); // Fill TX @@ -928,7 +928,7 @@ HTTPServer.prototype._init = function _init() { var tx = req.options.tx; enforce(tx, 'TX is required.'); yield req.wallet.fillHistory(tx); - send(200, tx.toJSON()); + send(200, tx.toJSON(this.network)); })); // Zap Wallet TXs @@ -1068,8 +1068,8 @@ HTTPServer.prototype._init = function _init() { sortCoins(coins); send(200, coins.map(function(coin) { - return coin.toJSON(); - })); + return coin.toJSON(this.network); + }, this)); })); // Locked coins @@ -1120,7 +1120,7 @@ HTTPServer.prototype._init = function _init() { if (!coin) return send(404); - send(200, coin.toJSON()); + send(200, coin.toJSON(this.network)); })); // Wallet TXs @@ -1547,6 +1547,7 @@ function ClientSocket(server, socket) { this.filter = null; this.api = false; + this.network = this.server.network; this.node = this.server.node; this.chain = this.server.chain; this.mempool = this.server.mempool; @@ -1658,7 +1659,7 @@ ClientSocket.prototype.watchChain = function watchChain() { this.bind(pool, 'tx', function(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++) { tx = block.txs[i]; if (this.testFilter(tx)) - txs.push(tx.toJSON()); + txs.push(tx.toJSON(this.network)); } if (txs.length === 0) @@ -1757,7 +1758,7 @@ ClientSocket.prototype.scanner = function scanner(entry, txs) { var 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); diff --git a/lib/primitives/block.js b/lib/primitives/block.js index 26d60f9b..a2ecf145 100644 --- a/lib/primitives/block.js +++ b/lib/primitives/block.js @@ -592,7 +592,6 @@ Block.prototype.getPrevout = function getPrevout() { Block.prototype.inspect = function inspect() { return { - type: 'block', hash: this.rhash, height: this.height, size: this.getSize(), @@ -619,9 +618,9 @@ Block.prototype.inspect = function inspect() { * @returns {Object} */ -Block.prototype.toJSON = function toJSON() { +Block.prototype.toJSON = function toJSON(network) { + network = Network.get(network); return { - type: 'block', hash: this.rhash, height: this.height, version: this.version, @@ -632,7 +631,7 @@ Block.prototype.toJSON = function toJSON() { nonce: this.nonce, totalTX: this.totalTX, txs: this.txs.map(function(tx) { - return tx.toJSON(); + return tx.toJSON(network); }) }; }; diff --git a/lib/primitives/coin.js b/lib/primitives/coin.js index 6627443a..09139a81 100644 --- a/lib/primitives/coin.js +++ b/lib/primitives/coin.js @@ -103,8 +103,7 @@ Coin.fromOptions = function fromOptions(options) { */ Coin.prototype.getConfirmations = function getConfirmations(height) { - if (height == null) - height = Network.primary.height; + assert(typeof height === 'number', 'Must pass a height.'); if (this.height === -1) return 0; @@ -151,7 +150,7 @@ Coin.prototype.inspect = function inspect() { coinbase: this.coinbase, hash: this.hash ? utils.revHex(this.hash) : null, index: this.index, - age: this.getAge(), + // age: this.getAge(), address: this.getAddress() }; }; @@ -164,11 +163,13 @@ Coin.prototype.inspect = function inspect() { * @returns {Object} */ -Coin.prototype.toJSON = function toJSON() { +Coin.prototype.toJSON = function toJSON(network) { var address = this.getAddress(); + network = Network.get(network); + if (address) - address = address.toBase58(); + address = address.toBase58(network); return { version: this.version, diff --git a/lib/primitives/input.js b/lib/primitives/input.js index 68b8cd1d..e36f9792 100644 --- a/lib/primitives/input.js +++ b/lib/primitives/input.js @@ -266,15 +266,17 @@ Input.prototype.inspect = function inspect() { * @returns {Object} */ -Input.prototype.toJSON = function toJSON() { +Input.prototype.toJSON = function toJSON(network) { var address = this.getAddress(); + network = Network.get(network); + if (address) - address = address.toBase58(); + address = address.toBase58(network); return { prevout: this.prevout.toJSON(), - coin: this.coin ? this.coin.toJSON() : null, + coin: this.coin ? this.coin.toJSON(network) : null, script: this.script.toJSON(), witness: this.witness.toJSON(), sequence: this.sequence, diff --git a/lib/primitives/mtx.js b/lib/primitives/mtx.js index 1ab9d970..136f796a 100644 --- a/lib/primitives/mtx.js +++ b/lib/primitives/mtx.js @@ -1312,11 +1312,7 @@ MTX.prototype.sortMembers = function sortMembers() { */ MTX.prototype.avoidFeeSniping = function avoidFeeSniping(height) { - if (height == null) - height = Network.primary.height; - - if (height === -1) - height = 0; + assert(typeof height === 'number', 'Must pass in height.'); if ((Math.random() * 10 | 0) === 0) height = Math.max(0, height - (Math.random() * 100 | 0)); diff --git a/lib/primitives/output.js b/lib/primitives/output.js index cbcf53de..92118752 100644 --- a/lib/primitives/output.js +++ b/lib/primitives/output.js @@ -131,11 +131,13 @@ Output.prototype.inspect = function inspect() { * @returns {Object} */ -Output.prototype.toJSON = function toJSON() { +Output.prototype.toJSON = function toJSON(network) { var address = this.getAddress(); + network = Network.get(network); + if (address) - address = address.toBase58(); + address = address.toBase58(network); return { value: utils.btc(this.value), diff --git a/lib/primitives/tx.js b/lib/primitives/tx.js index 1bd05047..c4510645 100644 --- a/lib/primitives/tx.js +++ b/lib/primitives/tx.js @@ -1767,15 +1767,11 @@ TX.prototype.getPriority = function getPriority(height, size) { var sum = 0; var i, input, age; + assert(typeof height === 'number', 'Must pass in height.'); + if (this.isCoinbase()) return sum; - if (height == null) { - height = this.height; - if (height === -1) - height = Network.primary.height; - } - if (size == null) size = this.maxSize(); @@ -1901,8 +1897,7 @@ TX.prototype.getRate = function getRate(size) { */ TX.prototype.getConfirmations = function getConfirmations(height) { - if (height == null) - height = Network.primary.height; + assert(typeof height === 'number', 'Must pass in height.'); if (this.height === -1) return 0; @@ -2093,8 +2088,13 @@ TX.getRate = function getRate(size, fee) { */ TX.prototype.inspect = function inspect() { + var rate = this.getRate(); + + // Rate can exceed 53 bits in testing. + if (!utils.isSafeInteger(rate)) + rate = 0; + return { - type: 'tx', hash: this.rhash, witnessHash: this.rwhash, size: this.getSize(), @@ -2103,9 +2103,7 @@ TX.prototype.inspect = function inspect() { value: utils.btc(this.getOutputValue()), fee: utils.btc(this.getFee()), minFee: utils.btc(this.getMinFee()), - rate: this.getRate(), // Rate can sometimes exceed 53 bits in testing - confirmations: this.getConfirmations(), - priority: this.getPriority(), + rate: utils.btc(rate), date: utils.date(this.ts || this.ps), block: this.block ? utils.revHex(this.block) : null, ts: this.ts, @@ -2127,25 +2125,33 @@ TX.prototype.inspect = function inspect() { * @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 { - type: 'tx', hash: utils.revHex(this.hash('hex')), witnessHash: utils.revHex(this.witnessHash('hex')), height: this.height, block: this.block ? utils.revHex(this.block) : null, ts: this.ts, ps: this.ps, + date: utils.date(this.ts || this.ps), index: this.index, fee: utils.btc(this.getFee()), - confirmations: this.getConfirmations(), + rate: utils.btc(rate), version: this.version, flag: this.flag, inputs: this.inputs.map(function(input) { - return input.toJSON(); + return input.toJSON(network); }), outputs: this.outputs.map(function(output) { - return output.toJSON(); + return output.toJSON(network); }), locktime: this.locktime }; diff --git a/lib/protocol/network.js b/lib/protocol/network.js index 4144937d..ab55d6c6 100644 --- a/lib/protocol/network.js +++ b/lib/protocol/network.js @@ -24,7 +24,6 @@ function Network(options) { assert(!Network[options.type], 'Cannot create two networks.'); this.type = options.type; - this.height = -1; this.seeds = options.seeds; this.magic = options.magic; this.port = options.port; @@ -77,15 +76,6 @@ Network.segnet3 = null; Network.segnet4 = 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 * based on current height of the chain. @@ -169,6 +159,31 @@ Network.get = function get(type) { 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. * @returns {Network} diff --git a/lib/wallet/txdb.js b/lib/wallet/txdb.js index f1a3bbe4..342230a1 100644 --- a/lib/wallet/txdb.js +++ b/lib/wallet/txdb.js @@ -3180,6 +3180,8 @@ function Details(txdb, tx) { this.chainHeight = txdb.walletdb.state.height; this.hash = tx.hash('hex'); + this.size = tx.getSize(); + this.vsize = tx.getVirtualSize(); this.tx = tx; this.block = tx.block; @@ -3303,6 +3305,17 @@ Details.prototype.getFee = function getFee() { 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. * @returns {Object} @@ -3310,6 +3323,13 @@ Details.prototype.getFee = function getFee() { Details.prototype.toJSON = function toJSON() { 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 { wid: this.wid, id: this.id, @@ -3318,8 +3338,12 @@ Details.prototype.toJSON = function toJSON() { block: this.block ? utils.revHex(this.block) : null, ts: this.ts, ps: this.ps, + date: utils.date(this.ts || this.ps), 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(), inputs: this.inputs.map(function(input) { return input.toJSON(self.network);