coins: refactor and comments.
This commit is contained in:
parent
b437b33760
commit
b77aa9240e
@ -237,8 +237,8 @@ Chain.prototype._close = function close() {
|
||||
* Perform all necessary contextual verification on a block.
|
||||
* @private
|
||||
* @param {Block|MerkleBlock} block
|
||||
* @param {ChainEntry} entry
|
||||
* @returns {Promise}
|
||||
* @param {ChainEntry} prev
|
||||
* @returns {Promise} - Returns {@link ContextResult}.
|
||||
*/
|
||||
|
||||
Chain.prototype.verifyContext = co(function* verifyContext(block, prev) {
|
||||
@ -608,7 +608,7 @@ Chain.prototype.verifyDuplicates = co(function* verifyDuplicates(block, prev, st
|
||||
* @param {Block} block
|
||||
* @param {ChainEntry} prev
|
||||
* @param {DeploymentState} state
|
||||
* @returns {Promise}
|
||||
* @returns {Promise} - Returns {@link CoinView}.
|
||||
*/
|
||||
|
||||
Chain.prototype.verifyInputs = co(function* verifyInputs(block, prev, state) {
|
||||
@ -2244,9 +2244,10 @@ Chain.prototype.verifyFinal = co(function* verifyFinal(prev, tx, flags) {
|
||||
|
||||
/**
|
||||
* Get the necessary minimum time and height sequence locks for a transaction.
|
||||
* @param {TX} tx
|
||||
* @param {LockFlags} flags
|
||||
* @param {ChainEntry} prev
|
||||
* @param {TX} tx
|
||||
* @param {CoinView} view
|
||||
* @param {LockFlags} flags
|
||||
* @returns {Promise}
|
||||
* [Error, Number(minTime), Number(minHeight)].
|
||||
*/
|
||||
@ -2295,9 +2296,10 @@ Chain.prototype.getLocks = co(function* getLocks(prev, tx, view, flags) {
|
||||
|
||||
/**
|
||||
* Verify sequence locks.
|
||||
* @param {TX} tx
|
||||
* @param {LockFlags} flags
|
||||
* @param {ChainEntry} prev
|
||||
* @param {TX} tx
|
||||
* @param {CoinView} view
|
||||
* @param {LockFlags} flags
|
||||
* @returns {Promise} - Returns Boolean.
|
||||
*/
|
||||
|
||||
|
||||
@ -937,9 +937,9 @@ ChainDB.prototype.getRawBlock = co(function* getRawBlock(block) {
|
||||
});
|
||||
|
||||
/**
|
||||
* Get a block and fill it with coins (historical).
|
||||
* @param {Hash} hash
|
||||
* @returns {Promise} - Returns {@link Block}.
|
||||
* Get a historical block coin viewpoint.
|
||||
* @param {Block} hash
|
||||
* @returns {Promise} - Returns {@link CoinView}.
|
||||
*/
|
||||
|
||||
ChainDB.prototype.getBlockView = co(function* getBlockView(block) {
|
||||
@ -1789,6 +1789,7 @@ ChainDB.prototype.saveOptions = function saveOptions() {
|
||||
* Index a transaction by txid and address.
|
||||
* @private
|
||||
* @param {TX} tx
|
||||
* @param {CoinView} view
|
||||
*/
|
||||
|
||||
ChainDB.prototype.indexTX = function indexTX(tx, view) {
|
||||
@ -1838,6 +1839,7 @@ ChainDB.prototype.indexTX = function indexTX(tx, view) {
|
||||
* Remove transaction from index.
|
||||
* @private
|
||||
* @param {TX} tx
|
||||
* @param {CoinView} view
|
||||
*/
|
||||
|
||||
ChainDB.prototype.unindexTX = function unindexTX(tx, view) {
|
||||
|
||||
@ -19,15 +19,14 @@ var decompress = compressor.decompress;
|
||||
|
||||
/**
|
||||
* Represents the outputs for a single transaction.
|
||||
* @exports Coins
|
||||
* @constructor
|
||||
* @param {TX|Object} tx/options - TX or options object.
|
||||
* @param {Object?} options - Options object.
|
||||
* @property {Hash} hash - Transaction hash.
|
||||
* @property {Number} version - Transaction version.
|
||||
* @property {Number} height - Transaction height (-1 if unconfirmed).
|
||||
* @property {Boolean} coinbase - Whether the containing
|
||||
* transaction is a coinbase.
|
||||
* @property {Coin[]} outputs - Coins.
|
||||
* @property {CoinEntry[]} outputs - Coins.
|
||||
*/
|
||||
|
||||
function Coins(options) {
|
||||
@ -52,7 +51,7 @@ function Coins(options) {
|
||||
|
||||
Coins.prototype.fromOptions = function fromOptions(options) {
|
||||
if (options.version != null) {
|
||||
assert(util.isNumber(options.version));
|
||||
assert(util.isUInt32(options.version));
|
||||
this.version = options.version;
|
||||
}
|
||||
|
||||
@ -74,6 +73,7 @@ Coins.prototype.fromOptions = function fromOptions(options) {
|
||||
if (options.outputs) {
|
||||
assert(Array.isArray(options.outputs));
|
||||
this.outputs = options.outputs;
|
||||
this.cleanup();
|
||||
}
|
||||
|
||||
return this;
|
||||
@ -96,6 +96,8 @@ Coins.fromOptions = function fromOptions(options) {
|
||||
*/
|
||||
|
||||
Coins.prototype.add = function add(index, entry) {
|
||||
assert(index >= 0);
|
||||
|
||||
while (this.outputs.length <= index)
|
||||
this.outputs.push(null);
|
||||
|
||||
@ -139,7 +141,8 @@ Coins.prototype.has = function has(index) {
|
||||
};
|
||||
|
||||
/**
|
||||
* Test whether the collection has a coin.
|
||||
* Test whether the collection
|
||||
* has an unspent coin.
|
||||
* @param {Number} index
|
||||
* @returns {Boolean}
|
||||
*/
|
||||
@ -202,7 +205,7 @@ Coins.prototype.getCoin = function getCoin(index) {
|
||||
};
|
||||
|
||||
/**
|
||||
* Remove a coin entry and return it.
|
||||
* Spend a coin entry and return it.
|
||||
* @param {Number} index
|
||||
* @returns {CoinEntry}
|
||||
*/
|
||||
@ -219,7 +222,28 @@ Coins.prototype.spend = function spend(index) {
|
||||
};
|
||||
|
||||
/**
|
||||
* Cleanup spent outputs.
|
||||
* Remove a coin entry and return it.
|
||||
* @param {Number} index
|
||||
* @returns {CoinEntry}
|
||||
*/
|
||||
|
||||
Coins.prototype.remove = function remove(index) {
|
||||
var entry;
|
||||
|
||||
if (index >= this.outputs.length)
|
||||
return false;
|
||||
|
||||
entry = this.outputs[index];
|
||||
|
||||
this.outputs[index] = null;
|
||||
this.cleanup();
|
||||
|
||||
return entry;
|
||||
};
|
||||
|
||||
/**
|
||||
* Calculate unspent length of coins.
|
||||
* @returns {Number}
|
||||
*/
|
||||
|
||||
Coins.prototype.length = function length() {
|
||||
@ -232,7 +256,7 @@ Coins.prototype.length = function length() {
|
||||
};
|
||||
|
||||
/**
|
||||
* Cleanup spent outputs.
|
||||
* Cleanup spent outputs (remove pruned).
|
||||
*/
|
||||
|
||||
Coins.prototype.cleanup = function cleanup() {
|
||||
@ -284,12 +308,12 @@ Coins.prototype.isEmpty = function isEmpty() {
|
||||
*/
|
||||
|
||||
/**
|
||||
* Serialize the coins object.
|
||||
* @returns {Buffer}
|
||||
* Write the coins object to writer.
|
||||
* @param {BufferWriter} bw
|
||||
* @returns {BufferWriter}
|
||||
*/
|
||||
|
||||
Coins.prototype.toRaw = function toRaw() {
|
||||
var bw = new BufferWriter();
|
||||
Coins.prototype.toWriter = function toWriter(bw) {
|
||||
var len = this.length();
|
||||
var size = Math.floor((len + 5) / 8);
|
||||
var first = this.isUnspent(0);
|
||||
@ -344,19 +368,27 @@ Coins.prototype.toRaw = function toRaw() {
|
||||
output.toWriter(bw);
|
||||
}
|
||||
|
||||
return bw.render();
|
||||
return bw;
|
||||
};
|
||||
|
||||
/**
|
||||
* Inject data from serialized coins.
|
||||
* Serialize the coins object.
|
||||
* @returns {Buffer}
|
||||
*/
|
||||
|
||||
Coins.prototype.toRaw = function toRaw() {
|
||||
return this.toWriter(new BufferWriter()).render();
|
||||
};
|
||||
|
||||
/**
|
||||
* Inject data from buffer reader.
|
||||
* @private
|
||||
* @param {Buffer} data
|
||||
* @param {BufferReader} br
|
||||
* @param {Hash} hash
|
||||
* @returns {Coins}
|
||||
*/
|
||||
|
||||
Coins.prototype.fromRaw = function fromRaw(data, hash) {
|
||||
var br = new BufferReader(data);
|
||||
Coins.prototype.fromReader = function fromReader(br, hash) {
|
||||
var first = null;
|
||||
var second = null;
|
||||
var i, j, code, size, offset, ch;
|
||||
@ -407,6 +439,18 @@ Coins.prototype.fromRaw = function fromRaw(data, hash) {
|
||||
return this;
|
||||
};
|
||||
|
||||
/**
|
||||
* Inject data from serialized coins.
|
||||
* @private
|
||||
* @param {Buffer} data
|
||||
* @param {Hash} hash
|
||||
* @returns {Coins}
|
||||
*/
|
||||
|
||||
Coins.prototype.fromRaw = function fromRaw(data, hash) {
|
||||
return this.fromReader(new BufferReader(data), hash);
|
||||
};
|
||||
|
||||
/**
|
||||
* Parse a single serialized coin.
|
||||
* @param {Buffer} data
|
||||
@ -478,7 +522,18 @@ Coins.parseCoin = function parseCoin(data, hash, index) {
|
||||
};
|
||||
|
||||
/**
|
||||
* Instantiate coins from a serialized Buffer.
|
||||
* Instantiate coins from a buffer reader.
|
||||
* @param {Buffer} data
|
||||
* @param {Hash} hash - Transaction hash.
|
||||
* @returns {Coins}
|
||||
*/
|
||||
|
||||
Coins.fromReader = function fromReader(br, hash) {
|
||||
return new Coins().fromReader(br, hash);
|
||||
};
|
||||
|
||||
/**
|
||||
* Instantiate coins from a buffer.
|
||||
* @param {Buffer} data
|
||||
* @param {Hash} hash - Transaction hash.
|
||||
* @returns {Coins}
|
||||
@ -533,22 +588,24 @@ Coins.fromTX = function fromTX(tx, height) {
|
||||
};
|
||||
|
||||
/**
|
||||
* A compressed coin is an object which defers
|
||||
* A coin entry is an object which defers
|
||||
* parsing of a coin. Say there is a transaction
|
||||
* with 100 outputs. When a block comes in,
|
||||
* there may only be _one_ input in that entire
|
||||
* block which redeems an output from that
|
||||
* transaction. When parsing the Coins, there
|
||||
* is no sense to get _all_ of them into their
|
||||
* abstract form. A compressed coin is just a
|
||||
* abstract form. A coin entry is just a
|
||||
* pointer to that coin in the Coins buffer, as
|
||||
* well as a size. Parsing is done only if that
|
||||
* coin is being redeemed.
|
||||
* well as a size. Parsing and decompression
|
||||
* is done only if that coin is being redeemed.
|
||||
* @constructor
|
||||
* @private
|
||||
* @param {Number} offset
|
||||
* @param {Number} size
|
||||
* @param {Buffer} raw
|
||||
* @property {Number} offset
|
||||
* @property {Number} size
|
||||
* @property {Buffer} raw
|
||||
* @property {Output|null} output
|
||||
* @property {Boolean} spent
|
||||
*/
|
||||
|
||||
function CoinEntry() {
|
||||
@ -577,7 +634,7 @@ CoinEntry.prototype.reader = function reader() {
|
||||
};
|
||||
|
||||
/**
|
||||
* Parse the deferred data and return a Coin.
|
||||
* Parse the deferred data and return a coin.
|
||||
* @param {Coins} coins
|
||||
* @param {Number} index
|
||||
* @returns {Coin}
|
||||
@ -601,7 +658,7 @@ CoinEntry.prototype.toCoin = function toCoin(coins, index) {
|
||||
};
|
||||
|
||||
/**
|
||||
* Parse the deferred data and return an Output.
|
||||
* Parse the deferred data and return an output.
|
||||
* @returns {Output}
|
||||
*/
|
||||
|
||||
@ -639,7 +696,7 @@ CoinEntry.prototype.toWriter = function toWriter(bw) {
|
||||
};
|
||||
|
||||
/**
|
||||
* Instantiate compressed coin from reader.
|
||||
* Instantiate coin entry from reader.
|
||||
* @param {BufferReader} br
|
||||
* @returns {CoinEntry}
|
||||
*/
|
||||
@ -653,7 +710,7 @@ CoinEntry.fromReader = function fromReader(br) {
|
||||
};
|
||||
|
||||
/**
|
||||
* Instantiate compressed coin from output.
|
||||
* Instantiate coin entry from output.
|
||||
* @param {Output} output
|
||||
* @returns {CoinEntry}
|
||||
*/
|
||||
@ -665,7 +722,7 @@ CoinEntry.fromOutput = function fromOutput(output) {
|
||||
};
|
||||
|
||||
/**
|
||||
* Instantiate compressed coin from coin.
|
||||
* Instantiate coin entry from coin.
|
||||
* @param {Coin} coin
|
||||
* @returns {CoinEntry}
|
||||
*/
|
||||
|
||||
@ -1,5 +1,5 @@
|
||||
/*!
|
||||
* coinview.js - coinview object for bcoin
|
||||
* coinview.js - coin viewpoint object for bcoin
|
||||
* Copyright (c) 2014-2016, Christopher Jeffrey (MIT License).
|
||||
* https://github.com/bcoin-org/bcoin
|
||||
*/
|
||||
@ -12,20 +12,22 @@ var Coins = require('./coins');
|
||||
var UndoCoins = require('./undocoins');
|
||||
var BufferReader = require('../utils/reader');
|
||||
var BufferWriter = require('../utils/writer');
|
||||
var CoinEntry = Coins.CoinEntry;
|
||||
|
||||
/**
|
||||
* A collections of {@link Coins} objects.
|
||||
* @exports CoinView
|
||||
* A collection of {@link Coins} objects.
|
||||
* @constructor
|
||||
* @param {Object} coins - A hash-to-coins map.
|
||||
* @property {Object} coins
|
||||
* @param {Object} map - A hash-to-coins map.
|
||||
* @param {UndoCoins} undo - Spent coins.
|
||||
* @property {Object} map
|
||||
* @property {UndoCoins} undo
|
||||
*/
|
||||
|
||||
function CoinView() {
|
||||
if (!(this instanceof CoinView))
|
||||
return new CoinView();
|
||||
|
||||
this.unspent = {};
|
||||
this.map = {};
|
||||
this.undo = new UndoCoins();
|
||||
}
|
||||
|
||||
@ -36,7 +38,7 @@ function CoinView() {
|
||||
*/
|
||||
|
||||
CoinView.prototype.get = function get(hash) {
|
||||
return this.unspent[hash];
|
||||
return this.map[hash];
|
||||
};
|
||||
|
||||
/**
|
||||
@ -46,7 +48,7 @@ CoinView.prototype.get = function get(hash) {
|
||||
*/
|
||||
|
||||
CoinView.prototype.has = function has(hash) {
|
||||
return this.unspent[hash] != null;
|
||||
return this.map[hash] != null;
|
||||
};
|
||||
|
||||
/**
|
||||
@ -55,10 +57,25 @@ CoinView.prototype.has = function has(hash) {
|
||||
*/
|
||||
|
||||
CoinView.prototype.add = function add(coins) {
|
||||
this.unspent[coins.hash] = coins;
|
||||
this.map[coins.hash] = coins;
|
||||
return coins;
|
||||
};
|
||||
|
||||
/**
|
||||
* Remove coins from the collection.
|
||||
* @param {Coins} coins
|
||||
* @returns {Boolean}
|
||||
*/
|
||||
|
||||
CoinView.prototype.remove = function remove(hash) {
|
||||
if (!this.map[hash])
|
||||
return false;
|
||||
|
||||
delete this.map[hash];
|
||||
|
||||
return true;
|
||||
};
|
||||
|
||||
/**
|
||||
* Add a tx to the collection.
|
||||
* @param {TX} tx
|
||||
@ -83,9 +100,8 @@ CoinView.prototype.removeTX = function removeTX(tx, height) {
|
||||
};
|
||||
|
||||
/**
|
||||
* Add a tx to the collection.
|
||||
* @param {TX} tx
|
||||
* @param {Number} height
|
||||
* Add a coin to the collection.
|
||||
* @param {Coin} coin
|
||||
*/
|
||||
|
||||
CoinView.prototype.addCoin = function addCoin(coin) {
|
||||
@ -104,9 +120,10 @@ CoinView.prototype.addCoin = function addCoin(coin) {
|
||||
};
|
||||
|
||||
/**
|
||||
* Add a tx to the collection.
|
||||
* @param {TX} tx
|
||||
* @param {Number} height
|
||||
* Add an output to the collection.
|
||||
* @param {Hash} hash
|
||||
* @param {Number} index
|
||||
* @param {Output} output
|
||||
*/
|
||||
|
||||
CoinView.prototype.addOutput = function addOutput(hash, index, output) {
|
||||
@ -125,10 +142,42 @@ CoinView.prototype.addOutput = function addOutput(hash, index, output) {
|
||||
};
|
||||
|
||||
/**
|
||||
* Remove a coin and return it.
|
||||
* Spend an output.
|
||||
* @param {Hash} hash
|
||||
* @param {Number} index
|
||||
* @returns {Boolean}
|
||||
*/
|
||||
|
||||
CoinView.prototype.spendOutput = function spendOutput(hash, index) {
|
||||
var coins = this.get(hash);
|
||||
|
||||
if (!coins)
|
||||
return false;
|
||||
|
||||
return this.spendFrom(coins, index);
|
||||
};
|
||||
|
||||
/**
|
||||
* Remove an output.
|
||||
* @param {Hash} hash
|
||||
* @param {Number} index
|
||||
* @returns {Boolean}
|
||||
*/
|
||||
|
||||
CoinView.prototype.removeOutput = function removeOutput(hash, index) {
|
||||
var coins = this.get(hash);
|
||||
|
||||
if (!coins)
|
||||
return false;
|
||||
|
||||
return coins.remove(index);
|
||||
};
|
||||
|
||||
/**
|
||||
* Spend a coin from coins object.
|
||||
* @param {Coins} coins
|
||||
* @param {Number} index
|
||||
* @returns {Coin}
|
||||
* @returns {Boolean}
|
||||
*/
|
||||
|
||||
CoinView.prototype.spendFrom = function spendFrom(coins, index) {
|
||||
@ -152,9 +201,8 @@ CoinView.prototype.spendFrom = function spendFrom(coins, index) {
|
||||
};
|
||||
|
||||
/**
|
||||
* Get a single coin.
|
||||
* @param {Hash} hash
|
||||
* @param {Number} index
|
||||
* Get a single coin by input.
|
||||
* @param {Input} input
|
||||
* @returns {Coin}
|
||||
*/
|
||||
|
||||
@ -168,26 +216,9 @@ CoinView.prototype.getCoin = function getCoin(input) {
|
||||
};
|
||||
|
||||
/**
|
||||
* Get a single coin.
|
||||
* @param {Hash} hash
|
||||
* @param {Number} index
|
||||
* @returns {Coin}
|
||||
*/
|
||||
|
||||
CoinView.prototype.getHeight = function getHeight(input) {
|
||||
var coins = this.get(input.prevout.hash);
|
||||
|
||||
if (!coins)
|
||||
return -1;
|
||||
|
||||
return coins.height;
|
||||
};
|
||||
|
||||
/**
|
||||
* Get a single coin.
|
||||
* @param {Hash} hash
|
||||
* @param {Number} index
|
||||
* @returns {Coin}
|
||||
* Get a single output by input.
|
||||
* @param {Input} input
|
||||
* @returns {Output}
|
||||
*/
|
||||
|
||||
CoinView.prototype.getOutput = function getOutput(input) {
|
||||
@ -200,13 +231,74 @@ CoinView.prototype.getOutput = function getOutput(input) {
|
||||
};
|
||||
|
||||
/**
|
||||
* Retrieve coins from database.
|
||||
* @param {TX} tx
|
||||
* @returns {Promise}
|
||||
* Get a single entry by input.
|
||||
* @param {Input} input
|
||||
* @returns {CoinEntry}
|
||||
*/
|
||||
|
||||
CoinView.prototype.getCoins = co(function* getCoins(db, hash) {
|
||||
var coins = this.unspent[hash];
|
||||
CoinView.prototype.getEntry = function getEntry(input) {
|
||||
var coins = this.get(input.prevout.hash);
|
||||
|
||||
if (!coins)
|
||||
return;
|
||||
|
||||
return coins.get(input.prevout.index);
|
||||
};
|
||||
|
||||
/**
|
||||
* Test whether the view has an entry by input.
|
||||
* @param {Input} input
|
||||
* @returns {Boolean}
|
||||
*/
|
||||
|
||||
CoinView.prototype.hasEntry = function hasEntry(input) {
|
||||
var coins = this.get(input.prevout.hash);
|
||||
|
||||
if (!coins)
|
||||
return false;
|
||||
|
||||
return coins.has(input.prevout.index);
|
||||
};
|
||||
|
||||
/**
|
||||
* Get coins height by input.
|
||||
* @param {Input} input
|
||||
* @returns {Number}
|
||||
*/
|
||||
|
||||
CoinView.prototype.getHeight = function getHeight(input) {
|
||||
var coins = this.get(input.prevout.hash);
|
||||
|
||||
if (!coins)
|
||||
return -1;
|
||||
|
||||
return coins.height;
|
||||
};
|
||||
|
||||
/**
|
||||
* Get coins coinbase flag by input.
|
||||
* @param {Input} input
|
||||
* @returns {Boolean}
|
||||
*/
|
||||
|
||||
CoinView.prototype.isCoinbase = function isCoinbase(input) {
|
||||
var coins = this.get(input.prevout.hash);
|
||||
|
||||
if (!coins)
|
||||
return false;
|
||||
|
||||
return coins.coinbase;
|
||||
};
|
||||
|
||||
/**
|
||||
* Retrieve coins from database.
|
||||
* @param {ChainDB} db
|
||||
* @param {TX} tx
|
||||
* @returns {Promise} - Returns {@link Coins}.
|
||||
*/
|
||||
|
||||
CoinView.prototype.readCoins = co(function* readCoins(db, hash) {
|
||||
var coins = this.map[hash];
|
||||
|
||||
if (!coins) {
|
||||
coins = yield db.getCoins(hash);
|
||||
@ -214,7 +306,7 @@ CoinView.prototype.getCoins = co(function* getCoins(db, hash) {
|
||||
if (!coins)
|
||||
return;
|
||||
|
||||
this.unspent[hash] = coins;
|
||||
this.map[hash] = coins;
|
||||
}
|
||||
|
||||
return coins;
|
||||
@ -224,21 +316,27 @@ CoinView.prototype.getCoins = co(function* getCoins(db, hash) {
|
||||
* Read all input coins into unspent map.
|
||||
* @param {ChainDB} db
|
||||
* @param {TX} tx
|
||||
* @returns {Promise} - Returns {Boolean}.
|
||||
*/
|
||||
|
||||
CoinView.prototype.ensureInputs = co(function* ensureInputs(db, tx) {
|
||||
var found = true;
|
||||
var i, input;
|
||||
|
||||
for (i = 0; i < tx.inputs.length; i++) {
|
||||
input = tx.inputs[i];
|
||||
yield this.getCoins(db, input.prevout.hash);
|
||||
if (!(yield this.readCoins(db, input.prevout.hash)))
|
||||
found = false;
|
||||
}
|
||||
|
||||
return found;
|
||||
});
|
||||
|
||||
/**
|
||||
* Spend coins for transaction.
|
||||
* @param {ChainDB} db
|
||||
* @param {TX} tx
|
||||
* @returns {Boolean}
|
||||
* @returns {Promise} - Returns {Boolean}.
|
||||
*/
|
||||
|
||||
CoinView.prototype.spendInputs = co(function* spendInputs(db, tx) {
|
||||
@ -247,7 +345,7 @@ CoinView.prototype.spendInputs = co(function* spendInputs(db, tx) {
|
||||
for (i = 0; i < tx.inputs.length; i++) {
|
||||
input = tx.inputs[i];
|
||||
prevout = input.prevout;
|
||||
coins = yield this.getCoins(db, prevout.hash);
|
||||
coins = yield this.readCoins(db, prevout.hash);
|
||||
|
||||
if (!coins)
|
||||
return false;
|
||||
@ -265,24 +363,26 @@ CoinView.prototype.spendInputs = co(function* spendInputs(db, tx) {
|
||||
*/
|
||||
|
||||
CoinView.prototype.toArray = function toArray() {
|
||||
var keys = Object.keys(this.unspent);
|
||||
var keys = Object.keys(this.map);
|
||||
var out = [];
|
||||
var i, hash;
|
||||
|
||||
for (i = 0; i < keys.length; i++) {
|
||||
hash = keys[i];
|
||||
out.push(this.unspent[hash]);
|
||||
out.push(this.map[hash]);
|
||||
}
|
||||
|
||||
return out;
|
||||
};
|
||||
|
||||
/**
|
||||
* Convert collection to an array.
|
||||
* @returns {Coins[]}
|
||||
* Write coin data to buffer writer
|
||||
* as it pertains to a transaction.
|
||||
* @param {BufferWriter} bw
|
||||
* @param {TX} tx
|
||||
*/
|
||||
|
||||
CoinView.prototype.toPrevWriter = function toPrevWriter(bw, tx) {
|
||||
CoinView.prototype.toFast = function toFast(bw, tx) {
|
||||
var i, input, coins, entry;
|
||||
|
||||
for (i = 0; i < tx.inputs.length; i++) {
|
||||
@ -309,58 +409,157 @@ CoinView.prototype.toPrevWriter = function toPrevWriter(bw, tx) {
|
||||
};
|
||||
|
||||
/**
|
||||
* Convert collection to an array.
|
||||
* @returns {Coins[]}
|
||||
* Read serialized view data from a buffer
|
||||
* reader as it pertains to a transaction.
|
||||
* @private
|
||||
* @param {BufferReader} br
|
||||
* @param {TX} tx
|
||||
*/
|
||||
|
||||
CoinView.prototype.toPrev = function toPrev(tx) {
|
||||
return this.toPrevWriter(new BufferWriter()).render();
|
||||
};
|
||||
|
||||
/**
|
||||
* Convert collection to an array.
|
||||
* @returns {Coins[]}
|
||||
*/
|
||||
|
||||
CoinView.prototype.fromPrevReader = function fromPrevReader(br, tx) {
|
||||
var i, input, coins, entry;
|
||||
CoinView.prototype.fromFast = function fromFast(br, tx) {
|
||||
var i, input, prevout, coins, entry;
|
||||
|
||||
for (i = 0; i < tx.inputs.length; i++) {
|
||||
input = tx.inputs[i];
|
||||
coins = this.get(input.prevout.hash);
|
||||
prevout = input.prevout.hash;
|
||||
|
||||
if (br.readU8() === 0)
|
||||
continue;
|
||||
|
||||
coins = this.get(prevout.hash);
|
||||
|
||||
if (!coins) {
|
||||
coins = new Coins();
|
||||
coins.hash = input.prevout.hash;
|
||||
coins.hash = prevout.hash;
|
||||
coins.coinbase = false;
|
||||
this.add(coins);
|
||||
}
|
||||
|
||||
if (br.readU8() === 1) {
|
||||
entry = Coins.CoinEntry.fromReader(br);
|
||||
coins.add(input.prevout.index, entry);
|
||||
}
|
||||
entry = CoinEntry.fromReader(br);
|
||||
coins.add(prevout.index, entry);
|
||||
}
|
||||
|
||||
return this;
|
||||
};
|
||||
|
||||
/**
|
||||
* Convert collection to an array.
|
||||
* @returns {Coins[]}
|
||||
* Write coin data to buffer writer
|
||||
* as it pertains to a transaction.
|
||||
* @param {BufferWriter} bw
|
||||
* @param {TX} tx
|
||||
*/
|
||||
|
||||
CoinView.fromPrevReader = function fromPrevReader(br, tx) {
|
||||
return new CoinView().fromPrevReader(br, tx);
|
||||
CoinView.prototype.toWriter = function toWriter(bw, tx) {
|
||||
var map = {};
|
||||
var i, input, prevout, coins, entry, height;
|
||||
|
||||
for (i = 0; i < tx.inputs.length; i++) {
|
||||
input = tx.inputs[i];
|
||||
prevout = input.prevout;
|
||||
coins = this.get(prevout.hash);
|
||||
|
||||
if (!coins) {
|
||||
bw.writeU8(0);
|
||||
continue;
|
||||
}
|
||||
|
||||
entry = coins.get(prevout.index);
|
||||
|
||||
if (!entry) {
|
||||
bw.writeU8(0);
|
||||
continue;
|
||||
}
|
||||
|
||||
bw.writeU8(1);
|
||||
|
||||
if (!map[prevout.hash]) {
|
||||
height = coins.height;
|
||||
if (height === -1)
|
||||
height = 0;
|
||||
bw.writeVarint(height * 2 + (coins.coinbase ? 1 : 0));
|
||||
bw.writeVarint(coins.version);
|
||||
map[prevout.hash] = true;
|
||||
}
|
||||
|
||||
entry.toWriter(bw);
|
||||
}
|
||||
|
||||
return bw;
|
||||
};
|
||||
|
||||
/**
|
||||
* Convert collection to an array.
|
||||
* @returns {Coins[]}
|
||||
* Serialize coin data to as it
|
||||
* pertains to a transaction.
|
||||
* @param {TX} tx
|
||||
* @returns {Buffer}
|
||||
*/
|
||||
|
||||
CoinView.fromPrev = function fromPrev(data, tx) {
|
||||
return new CoinView().fromPrevReader(new BufferReader(data), tx);
|
||||
CoinView.prototype.toRaw = function toRaw(tx) {
|
||||
return this.toWriter(new BufferWriter()).render();
|
||||
};
|
||||
|
||||
/**
|
||||
* Read serialized view data from a buffer
|
||||
* reader as it pertains to a transaction.
|
||||
* @private
|
||||
* @param {BufferReader} br
|
||||
* @param {TX} tx
|
||||
*/
|
||||
|
||||
CoinView.prototype.fromReader = function fromReader(br, tx) {
|
||||
var i, input, prevout, coins, entry, height;
|
||||
|
||||
for (i = 0; i < tx.inputs.length; i++) {
|
||||
input = tx.inputs[i];
|
||||
prevout = input.prevout.hash;
|
||||
|
||||
if (br.readU8() === 0)
|
||||
continue;
|
||||
|
||||
coins = this.get(prevout.hash);
|
||||
|
||||
if (!coins) {
|
||||
coins = new Coins();
|
||||
coins.hash = prevout.hash;
|
||||
height = br.readVarint();
|
||||
coins.coinbase = (height & 1) !== 0;
|
||||
height = height / 2 | 0;
|
||||
if (height === 0)
|
||||
height = -1;
|
||||
coins.height = height;
|
||||
coins.version = br.readVarint();
|
||||
this.add(coins);
|
||||
}
|
||||
|
||||
entry = CoinEntry.fromReader(br);
|
||||
coins.add(prevout.index, entry);
|
||||
}
|
||||
|
||||
return this;
|
||||
};
|
||||
|
||||
/**
|
||||
* Read serialized view data from a buffer
|
||||
* reader as it pertains to a transaction.
|
||||
* @param {BufferReader} br
|
||||
* @param {TX} tx
|
||||
* @returns {CoinView}
|
||||
*/
|
||||
|
||||
CoinView.fromReader = function fromReader(br, tx) {
|
||||
return new CoinView().fromReader(br, tx);
|
||||
};
|
||||
|
||||
/**
|
||||
* Read serialized view data from a buffer
|
||||
* as it pertains to a transaction.
|
||||
* @param {Buffer} data
|
||||
* @param {TX} tx
|
||||
* @returns {CoinView}
|
||||
*/
|
||||
|
||||
CoinView.fromRaw = function fromRaw(data, tx) {
|
||||
return new CoinView().fromReader(new BufferReader(data), tx);
|
||||
};
|
||||
|
||||
/*
|
||||
|
||||
@ -123,7 +123,6 @@ UndoCoins.prototype.top = function top() {
|
||||
* Re-apply undo coins to a view, effectively unspending them.
|
||||
* @param {CoinView} view
|
||||
* @param {Outpoint} outpoint
|
||||
* @returns {Coin}
|
||||
*/
|
||||
|
||||
UndoCoins.prototype.apply = function apply(view, outpoint) {
|
||||
@ -137,15 +136,15 @@ UndoCoins.prototype.apply = function apply(view, outpoint) {
|
||||
if (undo.height !== -1) {
|
||||
coins = new Coins();
|
||||
|
||||
assert(!view.unspent[hash]);
|
||||
view.unspent[hash] = coins;
|
||||
assert(!view.map[hash]);
|
||||
view.map[hash] = coins;
|
||||
|
||||
coins.hash = hash;
|
||||
coins.coinbase = undo.coinbase;
|
||||
coins.height = undo.height;
|
||||
coins.version = undo.version;
|
||||
} else {
|
||||
coins = view.unspent[hash];
|
||||
coins = view.map[hash];
|
||||
assert(coins);
|
||||
}
|
||||
|
||||
|
||||
@ -617,7 +617,7 @@ HTTPServer.prototype._init = function _init() {
|
||||
coins = yield this.node.getCoinsByAddress(req.options.address);
|
||||
|
||||
send(200, coins.map(function(coin) {
|
||||
return coin.toJSON(this.network);
|
||||
return coin.getJSON(this.network);
|
||||
}, this));
|
||||
}));
|
||||
|
||||
@ -633,7 +633,7 @@ HTTPServer.prototype._init = function _init() {
|
||||
if (!coin)
|
||||
return send(404);
|
||||
|
||||
send(200, coin.toJSON(this.network));
|
||||
send(200, coin.getJSON(this.network));
|
||||
}));
|
||||
|
||||
// Bulk read UTXOs
|
||||
@ -645,7 +645,7 @@ HTTPServer.prototype._init = function _init() {
|
||||
coins = yield this.node.getCoinsByAddress(req.options.address);
|
||||
|
||||
send(200, coins.map(function(coin) {
|
||||
return coin.toJSON(this.network);
|
||||
return coin.getJSON(this.network);
|
||||
}, this));
|
||||
}));
|
||||
|
||||
@ -660,7 +660,7 @@ HTTPServer.prototype._init = function _init() {
|
||||
if (!tx)
|
||||
return send(404);
|
||||
|
||||
send(200, tx.toJSON(this.network));
|
||||
send(200, tx.getJSON(this.network));
|
||||
}));
|
||||
|
||||
// TX by address
|
||||
@ -672,7 +672,7 @@ HTTPServer.prototype._init = function _init() {
|
||||
txs = yield this.node.getTXByAddress(req.options.address);
|
||||
|
||||
send(200, txs.map(function(tx) {
|
||||
return tx.toJSON(this.network);
|
||||
return tx.getJSON(this.network);
|
||||
}, this));
|
||||
}));
|
||||
|
||||
@ -685,7 +685,7 @@ HTTPServer.prototype._init = function _init() {
|
||||
txs = yield this.node.getTXByAddress(req.options.address);
|
||||
|
||||
send(200, txs.map(function(tx) {
|
||||
return tx.toJSON(this.network);
|
||||
return tx.getJSON(this.network);
|
||||
}, this));
|
||||
}));
|
||||
|
||||
@ -706,7 +706,7 @@ HTTPServer.prototype._init = function _init() {
|
||||
if (!view)
|
||||
return send(404);
|
||||
|
||||
send(200, block.toJSON(this.network, view));
|
||||
send(200, block.getJSON(this.network, view));
|
||||
}));
|
||||
|
||||
// Mempool snapshot
|
||||
@ -719,7 +719,7 @@ HTTPServer.prototype._init = function _init() {
|
||||
txs = this.mempool.getHistory();
|
||||
|
||||
send(200, txs.map(function(tx) {
|
||||
return tx.toJSON(this.network);
|
||||
return tx.getJSON(this.network);
|
||||
}, this));
|
||||
}));
|
||||
|
||||
@ -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(this.network));
|
||||
send(200, tx.getJSON(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(this.network));
|
||||
send(200, tx.getJSON(this.network));
|
||||
}));
|
||||
|
||||
// Zap Wallet TXs
|
||||
@ -1060,7 +1060,7 @@ HTTPServer.prototype._init = function _init() {
|
||||
sortCoins(coins);
|
||||
|
||||
send(200, coins.map(function(coin) {
|
||||
return coin.toJSON(this.network);
|
||||
return coin.getJSON(this.network);
|
||||
}, this));
|
||||
}));
|
||||
|
||||
@ -1112,7 +1112,7 @@ HTTPServer.prototype._init = function _init() {
|
||||
if (!coin)
|
||||
return send(404);
|
||||
|
||||
send(200, coin.toJSON(this.network));
|
||||
send(200, coin.getJSON(this.network));
|
||||
}));
|
||||
|
||||
// Wallet TXs
|
||||
@ -1898,7 +1898,7 @@ ClientSocket.prototype.frameEntry = function frameEntry(entry) {
|
||||
ClientSocket.prototype.frameTX = function frameTX(tx) {
|
||||
if (this.raw)
|
||||
return tx.toRaw();
|
||||
return tx.toJSON(this.network);
|
||||
return tx.getJSON(this.network);
|
||||
};
|
||||
|
||||
ClientSocket.prototype.join = function join(id) {
|
||||
|
||||
@ -420,7 +420,8 @@ Mempool.prototype.getCoin = function getCoin(hash, index) {
|
||||
*/
|
||||
|
||||
Mempool.prototype.isSpent = function isSpent(hash, index) {
|
||||
return this.spents[hash + index] != null;
|
||||
var key = Outpoint.toKey(hash, index);
|
||||
return this.spents[key] != null;
|
||||
};
|
||||
|
||||
/**
|
||||
@ -431,7 +432,8 @@ Mempool.prototype.isSpent = function isSpent(hash, index) {
|
||||
*/
|
||||
|
||||
Mempool.prototype.getSpent = function getSpent(hash, index) {
|
||||
return this.spents[hash + index];
|
||||
var key = Outpoint.toKey(hash, index);
|
||||
return this.spents[key];
|
||||
};
|
||||
|
||||
/**
|
||||
@ -442,7 +444,8 @@ Mempool.prototype.getSpent = function getSpent(hash, index) {
|
||||
*/
|
||||
|
||||
Mempool.prototype.getSpentTX = function getSpentTX(hash, index) {
|
||||
var entry = this.spents[hash + index];
|
||||
var key = Outpoint.toKey(hash, index);
|
||||
var entry = this.spents[key];
|
||||
|
||||
if (!entry)
|
||||
return;
|
||||
@ -732,6 +735,7 @@ Mempool.prototype._addTX = co(function* _addTX(tx) {
|
||||
* This function will also resolve orphans if possible (the
|
||||
* resolved orphans _will_ be validated).
|
||||
* @param {MempoolEntry} entry
|
||||
* @param {CoinView} view
|
||||
* @returns {Promise}
|
||||
*/
|
||||
|
||||
@ -809,6 +813,7 @@ Mempool.prototype.removeEntry = function removeEntry(entry, limit) {
|
||||
/**
|
||||
* Verify a transaction with mempool standards.
|
||||
* @param {TX} tx
|
||||
* @param {CoinView} view
|
||||
* @returns {Promise}
|
||||
*/
|
||||
|
||||
@ -947,6 +952,7 @@ Mempool.prototype.verify = co(function* verify(entry, view) {
|
||||
* Verify inputs, return a boolean
|
||||
* instead of an error based on success.
|
||||
* @param {TX} tx
|
||||
* @param {CoinView} view
|
||||
* @param {VerifyFlags} flags
|
||||
* @returns {Promise}
|
||||
*/
|
||||
@ -966,6 +972,7 @@ Mempool.prototype.verifyResult = co(function* verifyResult(tx, view, flags) {
|
||||
* Verify inputs for standard
|
||||
* _and_ mandatory flags on failure.
|
||||
* @param {TX} tx
|
||||
* @param {CoinView} view
|
||||
* @param {VerifyFlags} flags
|
||||
* @returns {Promise}
|
||||
*/
|
||||
@ -1418,21 +1425,13 @@ Mempool.prototype.removeOrphan = function removeOrphan(hash) {
|
||||
*/
|
||||
|
||||
Mempool.prototype.isDoubleSpend = function isDoubleSpend(tx) {
|
||||
var spent = {};
|
||||
var i, input, prevout, key;
|
||||
var i, input, prevout;
|
||||
|
||||
for (i = 0; i < tx.inputs.length; i++) {
|
||||
input = tx.inputs[i];
|
||||
prevout = input.prevout;
|
||||
key = prevout.hash + prevout.index;
|
||||
|
||||
if (this.isSpent(prevout.hash, prevout.index))
|
||||
return true;
|
||||
|
||||
if (spent[key])
|
||||
return true;
|
||||
|
||||
spent[key] = true;
|
||||
}
|
||||
|
||||
return false;
|
||||
@ -1441,6 +1440,7 @@ Mempool.prototype.isDoubleSpend = function isDoubleSpend(tx) {
|
||||
/**
|
||||
* Get coin viewpoint.
|
||||
* @param {TX} tx
|
||||
* @param {CoinView} view
|
||||
* @returns {Promise} - Returns {@link CoinView}.
|
||||
*/
|
||||
|
||||
@ -1476,6 +1476,7 @@ Mempool.prototype.getCoinView = co(function* getCoinView(tx) {
|
||||
/**
|
||||
* Spend coins for transaction.
|
||||
* @param {TX} tx
|
||||
* @param {CoinView} view
|
||||
* @returns {Boolean}
|
||||
*/
|
||||
|
||||
@ -1511,6 +1512,7 @@ Mempool.prototype.getSnapshot = function getSnapshot() {
|
||||
/**
|
||||
* Check sequence locks on a transaction against the current tip.
|
||||
* @param {TX} tx
|
||||
* @param {CoinView} view
|
||||
* @param {LockFlags} flags
|
||||
* @returns {Promise} - Returns Boolean.
|
||||
*/
|
||||
@ -1534,6 +1536,7 @@ Mempool.prototype.verifyFinal = function verifyFinal(tx, flags) {
|
||||
* Map a transaction to the mempool.
|
||||
* @private
|
||||
* @param {MempoolEntry} entry
|
||||
* @param {CoinView} view
|
||||
*/
|
||||
|
||||
Mempool.prototype.trackEntry = function trackEntry(entry, view) {
|
||||
@ -1550,7 +1553,7 @@ Mempool.prototype.trackEntry = function trackEntry(entry, view) {
|
||||
|
||||
for (i = 0; i < tx.inputs.length; i++) {
|
||||
input = tx.inputs[i];
|
||||
key = input.prevout.hash + input.prevout.index;
|
||||
key = input.prevout.toKey();
|
||||
|
||||
if (this.options.indexAddress)
|
||||
this.coinIndex.removeCoin(input.prevout);
|
||||
@ -1595,7 +1598,7 @@ Mempool.prototype.untrackEntry = function untrackEntry(entry) {
|
||||
|
||||
for (i = 0; i < tx.inputs.length; i++) {
|
||||
input = tx.inputs[i];
|
||||
key = input.prevout.hash + input.prevout.index;
|
||||
key = input.prevout.toKey();
|
||||
|
||||
if (this.options.indexAddress)
|
||||
this.coinIndex.removeCoin(input.prevout);
|
||||
@ -1821,7 +1824,7 @@ AddressIndex.prototype.getCoins = function getCoins(address) {
|
||||
};
|
||||
|
||||
AddressIndex.prototype.addCoin = function addCoin(coin) {
|
||||
var key = coin.hash + coin.index;
|
||||
var key = coin.toKey();
|
||||
var hash = coin.getHash('hex');
|
||||
var outpoint, items;
|
||||
|
||||
@ -1842,7 +1845,7 @@ AddressIndex.prototype.addCoin = function addCoin(coin) {
|
||||
};
|
||||
|
||||
AddressIndex.prototype.removeCoin = function removeCoin(coin) {
|
||||
var key = coin.hash + coin.index;
|
||||
var key = coin.toKey();
|
||||
var hash = this.map[key];
|
||||
var outpoint, items;
|
||||
|
||||
|
||||
@ -617,6 +617,7 @@ Block.prototype.inspect = function inspect() {
|
||||
/**
|
||||
* Inspect the block and return a more
|
||||
* user-friendly representation of the data.
|
||||
* @param {CoinView?} view
|
||||
* @returns {Object}
|
||||
*/
|
||||
|
||||
@ -645,13 +646,25 @@ Block.prototype.format = function format(view) {
|
||||
|
||||
/**
|
||||
* Convert the block to an object suitable
|
||||
* for JSON serialization. Note that the hashes
|
||||
* will be reversed to abide by bitcoind's legacy
|
||||
* of little-endian uint256s.
|
||||
* for JSON serialization.
|
||||
* @returns {Object}
|
||||
*/
|
||||
|
||||
Block.prototype.toJSON = function toJSON(network, view) {
|
||||
Block.prototype.toJSON = function toJSON() {
|
||||
return this.getJSON();
|
||||
};
|
||||
|
||||
/**
|
||||
* Convert the block to an object suitable
|
||||
* for JSON serialization. Note that the hashes
|
||||
* will be reversed to abide by bitcoind's legacy
|
||||
* of little-endian uint256s.
|
||||
* @param {Network} network
|
||||
* @param {CoinView} view
|
||||
* @returns {Object}
|
||||
*/
|
||||
|
||||
Block.prototype.getJSON = function getJSON(network, view) {
|
||||
network = Network.get(network);
|
||||
return {
|
||||
hash: this.rhash(),
|
||||
@ -664,7 +677,7 @@ Block.prototype.toJSON = function toJSON(network, view) {
|
||||
nonce: this.nonce,
|
||||
totalTX: this.totalTX,
|
||||
txs: this.txs.map(function(tx) {
|
||||
return tx.toJSON(network, view);
|
||||
return tx.getJSON(network, view);
|
||||
})
|
||||
};
|
||||
};
|
||||
|
||||
@ -110,6 +110,40 @@ Coin.prototype.getConfirmations = function getConfirmations(height) {
|
||||
return height - this.height + 1;
|
||||
};
|
||||
|
||||
/**
|
||||
* Serialize coin to a key
|
||||
* suitable for a hash table.
|
||||
* @returns {String}
|
||||
*/
|
||||
|
||||
Coin.prototype.toKey = function toKey() {
|
||||
return this.hash + this.index;
|
||||
};
|
||||
|
||||
/**
|
||||
* Inject properties from hash table key.
|
||||
* @private
|
||||
* @param {String} key
|
||||
* @returns {Coin}
|
||||
*/
|
||||
|
||||
Coin.prototype.fromKey = function fromKey(key) {
|
||||
assert(key.length > 64);
|
||||
this.hash = key.slice(0, 64);
|
||||
this.index = +key.slice(64);
|
||||
return this;
|
||||
};
|
||||
|
||||
/**
|
||||
* Instantiate coin from hash table key.
|
||||
* @param {String} key
|
||||
* @returns {Coin}
|
||||
*/
|
||||
|
||||
Coin.fromKey = function fromKey(key) {
|
||||
return new Coin().fromKey(key);
|
||||
};
|
||||
|
||||
/**
|
||||
* Convert the coin to a more user-friendly object.
|
||||
* @returns {Object}
|
||||
@ -131,13 +165,25 @@ Coin.prototype.inspect = function inspect() {
|
||||
|
||||
/**
|
||||
* Convert the coin to an object suitable
|
||||
* for JSON serialization. Note that the hash
|
||||
* will be reversed to abide by bitcoind's legacy
|
||||
* of little-endian uint256s.
|
||||
* for JSON serialization.
|
||||
* @returns {Object}
|
||||
*/
|
||||
|
||||
Coin.prototype.toJSON = function toJSON(network, minimal) {
|
||||
Coin.prototype.toJSON = function toJSON() {
|
||||
return this.getJSON();
|
||||
};
|
||||
|
||||
/**
|
||||
* Convert the coin to an object suitable
|
||||
* for JSON serialization. Note that the hash
|
||||
* will be reversed to abide by bitcoind's legacy
|
||||
* of little-endian uint256s.
|
||||
* @param {Network} network
|
||||
* @param {Boolean} minimal
|
||||
* @returns {Object}
|
||||
*/
|
||||
|
||||
Coin.prototype.getJSON = function getJSON(network, minimal) {
|
||||
var address = this.getAddress();
|
||||
|
||||
network = Network.get(network);
|
||||
|
||||
@ -81,6 +81,7 @@ Input.fromOptions = function fromOptions(options) {
|
||||
* Get the previous output script type as a string.
|
||||
* Will "guess" based on the input script and/or
|
||||
* witness if coin is not available.
|
||||
* @param {Coin?} coin
|
||||
* @returns {ScriptType} type
|
||||
*/
|
||||
|
||||
@ -104,6 +105,7 @@ Input.prototype.getType = function getType(coin) {
|
||||
/**
|
||||
* Get the redeem script. Will attempt to resolve nested
|
||||
* redeem scripts if witnessscripthash is behind a scripthash.
|
||||
* @param {Coin?} coin
|
||||
* @returns {Script?} Redeem script.
|
||||
*/
|
||||
|
||||
@ -140,6 +142,7 @@ Input.prototype.getRedeem = function getRedeem(coin) {
|
||||
|
||||
/**
|
||||
* Get the redeem script type.
|
||||
* @param {Coin?} coin
|
||||
* @returns {String} subtype
|
||||
*/
|
||||
|
||||
@ -163,6 +166,7 @@ Input.prototype.getSubtype = function getSubtype(coin) {
|
||||
* Get the previous output script's address. Will "guess"
|
||||
* based on the input script and/or witness if coin
|
||||
* is not available.
|
||||
* @param {Coin?} coin
|
||||
* @returns {Address?} address
|
||||
*/
|
||||
|
||||
@ -230,6 +234,7 @@ Input.prototype.inspect = function inspect() {
|
||||
|
||||
/**
|
||||
* Convert the input to a more user-friendly object.
|
||||
* @param {Coin?} coin
|
||||
* @returns {Object}
|
||||
*/
|
||||
|
||||
@ -249,13 +254,25 @@ Input.prototype.format = function format(coin) {
|
||||
|
||||
/**
|
||||
* Convert the input to an object suitable
|
||||
* for JSON serialization. Note that the hashes
|
||||
* will be reversed to abide by bitcoind's legacy
|
||||
* of little-endian uint256s.
|
||||
* for JSON serialization.
|
||||
* @returns {Object}
|
||||
*/
|
||||
|
||||
Input.prototype.toJSON = function toJSON(network, coin) {
|
||||
return this.getJSON();
|
||||
};
|
||||
|
||||
/**
|
||||
* Convert the input to an object suitable
|
||||
* for JSON serialization. Note that the hashes
|
||||
* will be reversed to abide by bitcoind's legacy
|
||||
* of little-endian uint256s.
|
||||
* @param {Network} network
|
||||
* @param {Coin} coin
|
||||
* @returns {Object}
|
||||
*/
|
||||
|
||||
Input.prototype.getJSON = function getJSON(network, coin) {
|
||||
var address;
|
||||
|
||||
network = Network.get(network);
|
||||
@ -272,7 +289,7 @@ Input.prototype.toJSON = function toJSON(network, coin) {
|
||||
witness: this.witness.toJSON(),
|
||||
sequence: this.sequence,
|
||||
address: address,
|
||||
coin: coin ? coin.toJSON(network, true) : null
|
||||
coin: coin ? coin.getJSON(network, true) : null
|
||||
};
|
||||
};
|
||||
|
||||
|
||||
@ -20,7 +20,7 @@ var Input = require('./input');
|
||||
var Output = require('./output');
|
||||
var Coin = require('./coin');
|
||||
var Outpoint = require('./outpoint');
|
||||
var CoinMap = require('../blockchain/coinview');
|
||||
var CoinView = require('../blockchain/coinview');
|
||||
var KeyRing = require('./keyring');
|
||||
var Address = require('./address');
|
||||
var workerPool = require('../workers/workerpool').pool;
|
||||
@ -55,13 +55,7 @@ var encoding = require('../utils/encoding');
|
||||
* @property {Number} changeIndex - Index of the change output (-1 if unknown).
|
||||
* @property {Number} height - Height of the block the
|
||||
* transaction was included in (-1 if unconfirmed).
|
||||
* @property {ReversedHash|null} rblock - Reversed block hash (uint256le).
|
||||
* @property {ReversedHash} rhash - Reversed transaction hash (uint256le).
|
||||
* @property {ReversedHash} rwhash - Reversed witness
|
||||
* transaction hash (uint256le).
|
||||
* @property {String} txid - Transaction ID.
|
||||
* @property {String} wtxid - Witness transaction ID (Same as txid if no
|
||||
* witness is present. All zeroes if coinbase).
|
||||
* @property {CoinView} view
|
||||
*/
|
||||
|
||||
function MTX(options) {
|
||||
@ -72,7 +66,7 @@ function MTX(options) {
|
||||
|
||||
this.mutable = true;
|
||||
this.changeIndex = -1;
|
||||
this.view = new CoinMap();
|
||||
this.view = new CoinView();
|
||||
|
||||
if (options)
|
||||
this.fromOptions(options);
|
||||
@ -1341,14 +1335,23 @@ MTX.prototype.format = function format() {
|
||||
return TX.prototype.inspect.call(this, this.view);
|
||||
};
|
||||
|
||||
/**
|
||||
* Convert transaction to JSON.
|
||||
* @returns {Object}
|
||||
*/
|
||||
|
||||
MTX.prototype.toJSON = function toJSON() {
|
||||
return TX.prototype.toJSON.call(this, null, this.view);
|
||||
};
|
||||
|
||||
/**
|
||||
* Convert transaction to JSON.
|
||||
* @param {Network} network
|
||||
* @returns {Object}
|
||||
*/
|
||||
|
||||
MTX.prototype.toJSON = function toJSON(network) {
|
||||
return TX.prototype.toJSON.call(this, network, this.view);
|
||||
MTX.prototype.getJSON = function getJSON(network) {
|
||||
return TX.prototype.getJSON.call(this, network, this.view);
|
||||
};
|
||||
|
||||
/**
|
||||
|
||||
@ -64,6 +64,40 @@ Outpoint.prototype.isNull = function isNull() {
|
||||
return this.index === 0xffffffff && this.hash === constants.NULL_HASH;
|
||||
};
|
||||
|
||||
/**
|
||||
* Serialize outpoint to a key
|
||||
* suitable for a hash table.
|
||||
* @returns {String}
|
||||
*/
|
||||
|
||||
Outpoint.prototype.toKey = function toKey() {
|
||||
return Outpoint.toKey(this.hash, this.index);
|
||||
};
|
||||
|
||||
/**
|
||||
* Inject properties from hash table key.
|
||||
* @private
|
||||
* @param {String} key
|
||||
* @returns {Outpoint}
|
||||
*/
|
||||
|
||||
Outpoint.prototype.fromKey = function fromKey(key) {
|
||||
assert(key.length > 64);
|
||||
this.hash = key.slice(0, 64);
|
||||
this.index = +key.slice(64);
|
||||
return this;
|
||||
};
|
||||
|
||||
/**
|
||||
* Instantiate outpoint from hash table key.
|
||||
* @param {String} key
|
||||
* @returns {Outpoint}
|
||||
*/
|
||||
|
||||
Outpoint.fromKey = function fromKey(key) {
|
||||
return new Outpoint().fromKey(key);
|
||||
};
|
||||
|
||||
/**
|
||||
* Write outpoint to a buffer writer.
|
||||
* @param {BufferWriter} bw
|
||||
@ -190,6 +224,21 @@ Outpoint.fromTX = function fromTX(tx, index) {
|
||||
return new Outpoint().fromTX(tx, index);
|
||||
};
|
||||
|
||||
/**
|
||||
* Serialize outpoint to a key
|
||||
* suitable for a hash table.
|
||||
* @param {Hash} hash
|
||||
* @param {Number} index
|
||||
* @returns {String}
|
||||
*/
|
||||
|
||||
Outpoint.toKey = function toKey(hash, index) {
|
||||
assert(typeof hash === 'string');
|
||||
assert(hash.length === 64);
|
||||
assert(index >= 0);
|
||||
return hash + index;
|
||||
};
|
||||
|
||||
/**
|
||||
* Convert the outpoint to a user-friendly string.
|
||||
* @returns {String}
|
||||
|
||||
@ -131,7 +131,18 @@ Output.prototype.inspect = function inspect() {
|
||||
* @returns {Object}
|
||||
*/
|
||||
|
||||
Output.prototype.toJSON = function toJSON(network) {
|
||||
Output.prototype.toJSON = function toJSON() {
|
||||
return this.getJSON();
|
||||
};
|
||||
|
||||
/**
|
||||
* Convert the output to an object suitable
|
||||
* for JSON serialization.
|
||||
* @param {Network} network
|
||||
* @returns {Object}
|
||||
*/
|
||||
|
||||
Output.prototype.getJSON = function getJSON(network) {
|
||||
var address = this.getAddress();
|
||||
|
||||
network = Network.get(network);
|
||||
|
||||
@ -58,13 +58,6 @@ var BAD_NONSTD_P2WSH = 3;
|
||||
* was first seen. Only non-zero on unconfirmed transactions.
|
||||
* @property {Number} height - Height of the block the
|
||||
* transaction was included in (-1 if unconfirmed).
|
||||
* @property {ReversedHash|null} rblock - Reversed block hash (uint256le).
|
||||
* @property {ReversedHash} rhash - Reversed transaction hash (uint256le).
|
||||
* @property {ReversedHash} rwhash - Reversed witness
|
||||
* transaction hash (uint256le).
|
||||
* @property {String} txid - Transaction ID.
|
||||
* @property {String} wtxid - Witness transaction ID (Same as txid if no
|
||||
* witness is present. All zeroes if coinbase).
|
||||
*/
|
||||
|
||||
function TX(options) {
|
||||
@ -689,7 +682,8 @@ TX.prototype.signatureHashV1 = function signatureHashV1(index, prev, value, type
|
||||
|
||||
/**
|
||||
* Verify all transaction inputs.
|
||||
* @param {VerifyFlags} [flags=STANDARD_VERIFY_FLAGS]
|
||||
* @param {CoinView} view
|
||||
* @param {VerifyFlags?} [flags=STANDARD_VERIFY_FLAGS]
|
||||
* @returns {Boolean} Whether the inputs are valid.
|
||||
*/
|
||||
|
||||
@ -753,6 +747,7 @@ TX.prototype.verifyInput = function verifyInput(index, coin, flags) {
|
||||
/**
|
||||
* Verify the transaction inputs on the worker pool
|
||||
* (if workers are enabled).
|
||||
* @param {CoinView} view
|
||||
* @param {VerifyFlags?} [flags=STANDARD_VERIFY_FLAGS]
|
||||
* @returns {Promise}
|
||||
* @returns {Boolean} Whether the inputs are valid.
|
||||
@ -817,6 +812,7 @@ TX.prototype.isRBF = function isRBF() {
|
||||
|
||||
/**
|
||||
* Calculate the fee for the transaction.
|
||||
* @param {CoinView} view
|
||||
* @returns {Amount} fee (zero if not all coins are available).
|
||||
*/
|
||||
|
||||
@ -829,6 +825,7 @@ TX.prototype.getFee = function getFee(view) {
|
||||
|
||||
/**
|
||||
* Calculate the total input value.
|
||||
* @param {CoinView} view
|
||||
* @returns {Amount} value
|
||||
*/
|
||||
|
||||
@ -881,6 +878,7 @@ TX.prototype.getOutputValue = function getOutputValue() {
|
||||
/**
|
||||
* Get all input addresses.
|
||||
* @private
|
||||
* @param {CoinView} view
|
||||
* @returns {Array}
|
||||
*/
|
||||
|
||||
@ -943,6 +941,7 @@ TX.prototype._getOutputAddresses = function getOutputAddresses() {
|
||||
/**
|
||||
* Get all addresses.
|
||||
* @private
|
||||
* @param {CoinView} view
|
||||
* @returns {Array}
|
||||
*/
|
||||
|
||||
@ -968,6 +967,7 @@ TX.prototype._getAddresses = function getAddresses(view) {
|
||||
/**
|
||||
* Get all input addresses.
|
||||
* @private
|
||||
* @param {CoinView} view
|
||||
* @returns {Address[]} addresses
|
||||
*/
|
||||
|
||||
@ -986,6 +986,7 @@ TX.prototype.getOutputAddresses = function getOutputAddresses() {
|
||||
|
||||
/**
|
||||
* Get all addresses.
|
||||
* @param {CoinView} view
|
||||
* @returns {Address[]} addresses
|
||||
*/
|
||||
|
||||
@ -995,6 +996,7 @@ TX.prototype.getAddresses = function getAddresses(view) {
|
||||
|
||||
/**
|
||||
* Get all input address hashes.
|
||||
* @param {CoinView} view
|
||||
* @returns {Hash[]} hashes
|
||||
*/
|
||||
|
||||
@ -1037,6 +1039,7 @@ TX.prototype.getOutputHashes = function getOutputHashes(enc) {
|
||||
|
||||
/**
|
||||
* Get all address hashes.
|
||||
* @param {CoinView} view
|
||||
* @returns {Hash[]} hashes
|
||||
*/
|
||||
|
||||
@ -1059,6 +1062,7 @@ TX.prototype.getHashes = function getHashes(view, enc) {
|
||||
/**
|
||||
* Test whether the transaction has
|
||||
* all coins available/filled.
|
||||
* @param {CoinView} view
|
||||
* @returns {Boolean}
|
||||
*/
|
||||
|
||||
@ -1135,6 +1139,7 @@ TX.prototype.getLegacySigops = function getLegacySigops() {
|
||||
|
||||
/**
|
||||
* Calculate accurate sigop count, taking into account redeem scripts.
|
||||
* @param {CoinView} view
|
||||
* @returns {Number} sigop count
|
||||
*/
|
||||
|
||||
@ -1161,6 +1166,7 @@ TX.prototype.getScripthashSigops = function getScripthashSigops(view) {
|
||||
|
||||
/**
|
||||
* Calculate sigops weight, taking into account witness programs.
|
||||
* @param {CoinView} view
|
||||
* @param {VerifyFlags?} flags
|
||||
* @returns {Number} sigop weight
|
||||
*/
|
||||
@ -1197,6 +1203,7 @@ TX.prototype.getSigopsWeight = function getSigopsWeight(view, flags) {
|
||||
|
||||
/**
|
||||
* Calculate virtual sigop count.
|
||||
* @param {CoinView} view
|
||||
* @param {VerifyFlags?} flags
|
||||
* @returns {Number} sigop count
|
||||
*/
|
||||
@ -1271,7 +1278,7 @@ TX.prototype.isSane = function isSane(ret) {
|
||||
|
||||
for (i = 0; i < this.inputs.length; i++) {
|
||||
input = this.inputs[i];
|
||||
key = input.prevout.hash + input.prevout.index;
|
||||
key = input.prevout.toKey();
|
||||
if (prevout[key]) {
|
||||
ret.reason = 'bad-txns-inputs-duplicate';
|
||||
ret.score = 100;
|
||||
@ -1388,6 +1395,7 @@ TX.prototype.isStandard = function isStandard(ret) {
|
||||
* Perform contextual checks to verify coin and input
|
||||
* script standardness (including the redeem script).
|
||||
* @see AreInputsStandard()
|
||||
* @param {CoinView} view
|
||||
* @param {VerifyFlags?} flags
|
||||
* @returns {Boolean}
|
||||
*/
|
||||
@ -1431,6 +1439,7 @@ TX.prototype.hasStandardInputs = function hasStandardInputs(view) {
|
||||
/**
|
||||
* Perform contextual checks to verify coin and witness standardness.
|
||||
* @see IsBadWitness()
|
||||
* @param {CoinView} view
|
||||
* @returns {Boolean}
|
||||
*/
|
||||
|
||||
@ -1464,6 +1473,7 @@ TX.prototype.hasStandardWitness = function hasStandardWitness(view, ret) {
|
||||
* Perform contextual checks to verify coin and witness standardness.
|
||||
* @private
|
||||
* @see IsBadWitness()
|
||||
* @param {CoinView} view
|
||||
* @returns {Boolean}
|
||||
*/
|
||||
|
||||
@ -1595,6 +1605,7 @@ TX.prototype.getWitnessStandard = function getWitnessStandard(view) {
|
||||
* (coinbases can only be spent 100 blocks or more
|
||||
* after they're created). Note that this function is
|
||||
* consensus critical.
|
||||
* @param {CoinView} view
|
||||
* @param {Number} spendHeight - Height at which the
|
||||
* transaction is being spent. In the mempool this is
|
||||
* the chain height plus one at the time it entered the pool.
|
||||
@ -1698,6 +1709,7 @@ TX.prototype.getModifiedSize = function getModifiedSize(size) {
|
||||
|
||||
/**
|
||||
* Calculate the transaction priority.
|
||||
* @param {CoinView} view
|
||||
* @param {Number?} height - If not present, tx height
|
||||
* or network height will be used.
|
||||
* @param {Number?} size - Size to calculate priority
|
||||
@ -1740,6 +1752,7 @@ TX.prototype.getPriority = function getPriority(view, height, size) {
|
||||
|
||||
/**
|
||||
* Calculate the transaction's on-chain value.
|
||||
* @param {CoinView} view
|
||||
* @param {Number?} height
|
||||
* @returns {Number}
|
||||
*/
|
||||
@ -1778,6 +1791,7 @@ TX.prototype.getChainValue = function getChainValue(view, height) {
|
||||
* free threshold in priority. A transaction which
|
||||
* passed this test is most likely relayable
|
||||
* without a fee.
|
||||
* @param {CoinView} view
|
||||
* @param {Number?} height - If not present, tx
|
||||
* height or network height will be used.
|
||||
* @param {Number?} size - If not present, modified
|
||||
@ -1826,6 +1840,7 @@ TX.prototype.getRoundFee = function getRoundFee(size, rate) {
|
||||
/**
|
||||
* Calculate the transaction's rate based on size
|
||||
* and fees. Size will be calculated if not present.
|
||||
* @param {CoinView} view
|
||||
* @param {Number?} size
|
||||
* @returns {Rate}
|
||||
*/
|
||||
@ -2009,6 +2024,7 @@ TX.prototype.inspect = function inspect() {
|
||||
/**
|
||||
* Inspect the transaction and return a more
|
||||
* user-friendly representation of the data.
|
||||
* @param {CoinView} view
|
||||
* @returns {Object}
|
||||
*/
|
||||
|
||||
@ -2026,8 +2042,8 @@ TX.prototype.format = function format(view) {
|
||||
}
|
||||
|
||||
return {
|
||||
hash: this.rhash(),
|
||||
witnessHash: this.rwhash(),
|
||||
hash: this.txid(),
|
||||
witnessHash: this.wtxid(),
|
||||
size: this.getSize(),
|
||||
virtualSize: this.getVirtualSize(),
|
||||
height: this.height,
|
||||
@ -2053,13 +2069,25 @@ TX.prototype.format = function format(view) {
|
||||
|
||||
/**
|
||||
* Convert the transaction to an object suitable
|
||||
* for JSON serialization. Note that the hashes
|
||||
* will be reversed to abide by bitcoind's legacy
|
||||
* of little-endian uint256s.
|
||||
* for JSON serialization.
|
||||
* @returns {Object}
|
||||
*/
|
||||
|
||||
TX.prototype.toJSON = function toJSON(network, view) {
|
||||
TX.prototype.toJSON = function toJSON() {
|
||||
return this.getJSON();
|
||||
};
|
||||
|
||||
/**
|
||||
* Convert the transaction to an object suitable
|
||||
* for JSON serialization. Note that the hashes
|
||||
* will be reversed to abide by bitcoind's legacy
|
||||
* of little-endian uint256s.
|
||||
* @param {Network} network
|
||||
* @param {CoinView} view
|
||||
* @returns {Object}
|
||||
*/
|
||||
|
||||
TX.prototype.getJSON = function getJSON(network, view) {
|
||||
var rate = 0;
|
||||
var fee = 0;
|
||||
|
||||
@ -2075,10 +2103,10 @@ TX.prototype.toJSON = function toJSON(network, view) {
|
||||
network = Network.get(network);
|
||||
|
||||
return {
|
||||
hash: util.revHex(this.hash('hex')),
|
||||
witnessHash: util.revHex(this.witnessHash('hex')),
|
||||
hash: this.txid(),
|
||||
witnessHash: this.wtxid(),
|
||||
height: this.height,
|
||||
block: this.block ? util.revHex(this.block) : null,
|
||||
block: this.rblock(),
|
||||
ts: this.ts,
|
||||
ps: this.ps,
|
||||
date: util.date(this.ts || this.ps),
|
||||
@ -2089,10 +2117,10 @@ TX.prototype.toJSON = function toJSON(network, view) {
|
||||
flag: this.flag,
|
||||
inputs: this.inputs.map(function(input) {
|
||||
var coin = view ? view.getCoin(input) : null;
|
||||
return input.toJSON(network, coin);
|
||||
return input.getJSON(network, coin);
|
||||
}),
|
||||
outputs: this.outputs.map(function(output) {
|
||||
return output.toJSON(network);
|
||||
return output.getJSON(network);
|
||||
}),
|
||||
locktime: this.locktime
|
||||
};
|
||||
@ -2398,8 +2426,10 @@ TX.prototype.frameWitnessWriter = function frameWitnessWriter(bw) {
|
||||
|
||||
start = bw.written;
|
||||
|
||||
for (i = 0; i < this.inputs.length; i++)
|
||||
this.inputs[i].witness.toWriter(bw);
|
||||
for (i = 0; i < this.inputs.length; i++) {
|
||||
input = this.inputs[i];
|
||||
input.witness.toWriter(bw);
|
||||
}
|
||||
|
||||
witnessSize += bw.written - start;
|
||||
|
||||
|
||||
@ -390,7 +390,7 @@ TXDB.prototype.verifyInputs = co(function* verifyInputs(tx, block) {
|
||||
if (!orphans[i])
|
||||
continue;
|
||||
|
||||
key = prevout.hash + prevout.index;
|
||||
key = prevout.toKey();
|
||||
|
||||
// In theory, someone could try to DoS
|
||||
// us by creating tons of fake transactions
|
||||
@ -452,7 +452,7 @@ TXDB.prototype.resolveOutputs = co(function* resolveOutputs(tx, block, resolved)
|
||||
|
||||
for (i = 0; i < tx.outputs.length; i++) {
|
||||
output = tx.outputs[i];
|
||||
key = hash + i;
|
||||
key = Outpoint.toKey(hash, i);
|
||||
orphans = this.orphans[key];
|
||||
|
||||
if (!orphans)
|
||||
@ -505,7 +505,7 @@ TXDB.prototype.resolveOutputs = co(function* resolveOutputs(tx, block, resolved)
|
||||
|
||||
TXDB.prototype.saveCredit = co(function* saveCredit(credit, path) {
|
||||
var coin = credit.coin;
|
||||
var key = coin.hash + coin.index;
|
||||
var key = coin.toKey();
|
||||
var raw = credit.toRaw();
|
||||
|
||||
yield this.addOutpointMap(coin.hash, coin.index);
|
||||
@ -524,7 +524,7 @@ TXDB.prototype.saveCredit = co(function* saveCredit(credit, path) {
|
||||
|
||||
TXDB.prototype.removeCredit = co(function* removeCredit(credit, path) {
|
||||
var coin = credit.coin;
|
||||
var key = coin.hash + coin.index;
|
||||
var key = coin.toKey();
|
||||
|
||||
yield this.removeOutpointMap(coin.hash, coin.index);
|
||||
|
||||
@ -1789,7 +1789,7 @@ TXDB.prototype.unlockTX = function unlockTX(tx) {
|
||||
*/
|
||||
|
||||
TXDB.prototype.lockCoin = function lockCoin(coin) {
|
||||
var key = coin.hash + coin.index;
|
||||
var key = coin.toKey();
|
||||
this.locked[key] = true;
|
||||
};
|
||||
|
||||
@ -1799,7 +1799,7 @@ TXDB.prototype.lockCoin = function lockCoin(coin) {
|
||||
*/
|
||||
|
||||
TXDB.prototype.unlockCoin = function unlockCoin(coin) {
|
||||
var key = coin.hash + coin.index;
|
||||
var key = coin.toKey();
|
||||
delete this.locked[key];
|
||||
};
|
||||
|
||||
@ -1809,7 +1809,7 @@ TXDB.prototype.unlockCoin = function unlockCoin(coin) {
|
||||
*/
|
||||
|
||||
TXDB.prototype.isLocked = function isLocked(coin) {
|
||||
var key = coin.hash + coin.index;
|
||||
var key = coin.toKey();
|
||||
return this.locked[key] === true;
|
||||
};
|
||||
|
||||
@ -2237,7 +2237,7 @@ TXDB.prototype.getCredits = function getCredits(account) {
|
||||
var hash = parts[0];
|
||||
var index = parts[1];
|
||||
var credit = Credit.fromRaw(value);
|
||||
var ckey = hash + index;
|
||||
var ckey = Outpoint.toKey(hash, index);
|
||||
credit.coin.hash = hash;
|
||||
credit.coin.index = index;
|
||||
self.coinCache.set(ckey, value);
|
||||
@ -2514,7 +2514,7 @@ TXDB.prototype.getCoin = co(function* getCoin(hash, index) {
|
||||
|
||||
TXDB.prototype.getCredit = co(function* getCredit(hash, index) {
|
||||
var state = this.state;
|
||||
var key = hash + index;
|
||||
var key = Outpoint.toKey(hash, index);
|
||||
var data = this.coinCache.get(key);
|
||||
var credit;
|
||||
|
||||
@ -2603,7 +2603,7 @@ TXDB.prototype.updateSpentCoin = co(function* updateSpentCoin(tx, index) {
|
||||
*/
|
||||
|
||||
TXDB.prototype.hasCoin = function hasCoin(hash, index) {
|
||||
var key = hash + index;
|
||||
var key = Outpoint.toKey(hash, index);
|
||||
|
||||
if (this.coinCache.has(key))
|
||||
return Promise.resolve(true);
|
||||
|
||||
@ -1583,7 +1583,7 @@ Wallet.prototype.createTX = co(function* createTX(options, force) {
|
||||
if (!tx.isSane())
|
||||
throw new Error('CheckTransaction failed.');
|
||||
|
||||
if (!tx.checkInputs(this.db.state.height))
|
||||
if (!tx.checkInputs(this.db.state.height + 1))
|
||||
throw new Error('CheckInputs failed.');
|
||||
|
||||
total = yield this.template(tx);
|
||||
|
||||
@ -70,6 +70,7 @@ jobs._execute = function execute(p) {
|
||||
* Execute tx.verify() on worker.
|
||||
* @see TX#verify
|
||||
* @param {TX} tx
|
||||
* @param {CoinView} view
|
||||
* @param {VerifyFlags} flags
|
||||
* @returns {Boolean}
|
||||
*/
|
||||
|
||||
@ -183,7 +183,7 @@ VerifyPacket.prototype.cmd = packetTypes.VERIFY;
|
||||
|
||||
VerifyPacket.prototype.toWriter = function(bw) {
|
||||
this.tx.toWriter(bw);
|
||||
this.view.toPrevWriter(bw, this.tx);
|
||||
this.view.toWriter(bw, this.tx);
|
||||
bw.write32(this.flags != null ? this.flags : -1);
|
||||
};
|
||||
|
||||
@ -192,7 +192,7 @@ VerifyPacket.fromRaw = function fromRaw(TX, CoinView, data) {
|
||||
var packet = new VerifyPacket();
|
||||
|
||||
packet.tx = TX.fromReader(br);
|
||||
packet.view = CoinView.fromPrevReader(br, packet.tx);
|
||||
packet.view = CoinView.fromReader(br, packet.tx);
|
||||
|
||||
packet.flags = br.read32();
|
||||
|
||||
@ -247,7 +247,7 @@ SignPacket.prototype.toWriter = function toWriter(bw) {
|
||||
var i, ring;
|
||||
|
||||
this.tx.toWriter(bw);
|
||||
this.tx.view.toPrevWriter(bw, this.tx);
|
||||
this.tx.view.toWriter(bw, this.tx);
|
||||
|
||||
bw.writeVarint(this.rings.length);
|
||||
|
||||
@ -265,7 +265,7 @@ SignPacket.fromRaw = function fromRaw(MTX, KeyRing, data) {
|
||||
var i, count, ring;
|
||||
|
||||
packet.tx = MTX.fromReader(br);
|
||||
packet.tx.view.fromPrevReader(br, packet.tx);
|
||||
packet.tx.view.fromReader(br, packet.tx);
|
||||
|
||||
count = br.readVarint();
|
||||
|
||||
|
||||
@ -260,6 +260,7 @@ WorkerPool.prototype.execute = function execute(packet, timeout) {
|
||||
/**
|
||||
* Execute the tx verification job (default timeout).
|
||||
* @param {TX} tx
|
||||
* @param {CoinView} view
|
||||
* @param {VerifyFlags} flags
|
||||
* @returns {Promise} - Returns Boolean.
|
||||
*/
|
||||
|
||||
@ -1,32 +1,36 @@
|
||||
'use strict';
|
||||
|
||||
var fs = require('fs');
|
||||
var heapdump = require('heapdump');
|
||||
|
||||
var MempoolEntry = require('../lib/mempool/mempoolentry');
|
||||
var Coins = require('../lib/blockchain/coins');
|
||||
var TX = require('../lib/primitives/tx');
|
||||
var CoinView = require('../lib/blockchain/coinview');
|
||||
|
||||
var SNAPSHOT = __dirname + '/../dump.heapsnapshot';
|
||||
var tx = parseTX('../test/data/tx4.hex');
|
||||
var raw, coins, entry;
|
||||
|
||||
function parseTX(file) {
|
||||
var filename = __dirname + '/' + file;
|
||||
var data = fs.readFileSync(filename, 'utf8');
|
||||
var data = fs.readFileSync(__dirname + '/' + file, 'utf8');
|
||||
var parts = data.trim().split(/\n+/);
|
||||
var hex = parts[0].trim();
|
||||
var tx = TX.fromRaw(hex, 'hex');
|
||||
var i, tx, coin;
|
||||
var raw = parts[0];
|
||||
var tx = TX.fromRaw(raw.trim(), 'hex');
|
||||
var view = new CoinView();
|
||||
var i, prev;
|
||||
|
||||
for (i = 1; i < parts.length; i++) {
|
||||
hex = parts[i].trim();
|
||||
coin = TX.fromRaw(hex, 'hex');
|
||||
tx.fillCoins(coin);
|
||||
raw = parts[i];
|
||||
prev = TX.fromRaw(raw.trim(), 'hex');
|
||||
view.addTX(prev, -1);
|
||||
}
|
||||
|
||||
return tx;
|
||||
return { tx: tx, view: view };
|
||||
}
|
||||
|
||||
var coins = Coins.fromRaw(Coins.fromTX(tx).toRaw(), tx.hash('hex'));
|
||||
var entry = MempoolEntry.fromTX(tx, 1000000);
|
||||
raw = Coins.fromTX(tx.tx, 0).toRaw();
|
||||
coins = Coins.fromRaw(raw, tx.hash('hex'));
|
||||
entry = MempoolEntry.fromTX(tx, tx.view, 1000000);
|
||||
|
||||
setInterval(function() {
|
||||
console.log(tx.hash('hex'));
|
||||
|
||||
@ -1,10 +1,14 @@
|
||||
'use strict';
|
||||
|
||||
var BN = require('bn.js');
|
||||
var bcoin = require('bcoin');
|
||||
var constants = bcoin.constants;
|
||||
var util = require('../lib/utils/util');
|
||||
var constants = require('../lib/protocol/constants');
|
||||
var TX = require('../lib/primitives/tx');
|
||||
var Block = require('../lib/primitives/block');
|
||||
var Script = require('../lib/script/script');
|
||||
var Opcode = require('../lib/script/opcode');
|
||||
var opcodes = constants.opcodes;
|
||||
var util = bcoin.util;
|
||||
var main, testnet, regtest, segnet3, segnet4, btcd;
|
||||
|
||||
function createGenesisBlock(options) {
|
||||
var flags = options.flags;
|
||||
@ -19,7 +23,7 @@ function createGenesisBlock(options) {
|
||||
}
|
||||
|
||||
if (!script) {
|
||||
script = bcoin.script.fromArray([
|
||||
script = Script.fromArray([
|
||||
new Buffer('04678afdb0fe5548271967f1a67130b7105cd6a828e039'
|
||||
+ '09a67962e0ea1f61deb649f6bc3f4cef38c4f35504e51ec112de5c3'
|
||||
+ '84df7ba0b8d578a4c702b6bf11d5f', 'hex'),
|
||||
@ -30,7 +34,7 @@ function createGenesisBlock(options) {
|
||||
if (!reward)
|
||||
reward = 50 * constants.COIN;
|
||||
|
||||
tx = new bcoin.tx({
|
||||
tx = new TX({
|
||||
version: 1,
|
||||
flag: 1,
|
||||
inputs: [{
|
||||
@ -39,9 +43,9 @@ function createGenesisBlock(options) {
|
||||
index: 0xffffffff
|
||||
},
|
||||
script: [
|
||||
bcoin.opcode.fromNumber(new BN(486604799)),
|
||||
bcoin.opcode.fromPush(new Buffer([4])),
|
||||
bcoin.opcode.fromData(flags)
|
||||
Opcode.fromNumber(new BN(486604799)),
|
||||
Opcode.fromPush(new Buffer([4])),
|
||||
Opcode.fromData(flags)
|
||||
],
|
||||
sequence: 0xffffffff
|
||||
}],
|
||||
@ -52,7 +56,7 @@ function createGenesisBlock(options) {
|
||||
locktime: 0
|
||||
});
|
||||
|
||||
block = new bcoin.block({
|
||||
block = new Block({
|
||||
version: options.version,
|
||||
prevBlock: constants.NULL_HASH,
|
||||
merkleRoot: tx.hash('hex'),
|
||||
@ -67,42 +71,42 @@ function createGenesisBlock(options) {
|
||||
return block;
|
||||
}
|
||||
|
||||
var main = createGenesisBlock({
|
||||
main = createGenesisBlock({
|
||||
version: 1,
|
||||
ts: 1231006505,
|
||||
bits: 486604799,
|
||||
nonce: 2083236893
|
||||
});
|
||||
|
||||
var testnet = createGenesisBlock({
|
||||
testnet = createGenesisBlock({
|
||||
version: 1,
|
||||
ts: 1296688602,
|
||||
bits: 486604799,
|
||||
nonce: 414098458
|
||||
});
|
||||
|
||||
var regtest = createGenesisBlock({
|
||||
regtest = createGenesisBlock({
|
||||
version: 1,
|
||||
ts: 1296688602,
|
||||
bits: 545259519,
|
||||
nonce: 2
|
||||
});
|
||||
|
||||
var segnet3 = createGenesisBlock({
|
||||
segnet3 = createGenesisBlock({
|
||||
version: 1,
|
||||
ts: 1452831101,
|
||||
bits: 486604799,
|
||||
nonce: 0
|
||||
});
|
||||
|
||||
var segnet4 = createGenesisBlock({
|
||||
segnet4 = createGenesisBlock({
|
||||
version: 1,
|
||||
ts: 1452831101,
|
||||
bits: 503447551,
|
||||
nonce: 0
|
||||
});
|
||||
|
||||
var btcd = createGenesisBlock({
|
||||
btcd = createGenesisBlock({
|
||||
version: 1,
|
||||
ts: 1401292357,
|
||||
bits: 545259519,
|
||||
@ -120,20 +124,20 @@ util.log('');
|
||||
util.log(segnet4);
|
||||
util.log('');
|
||||
util.log('');
|
||||
util.log('main hash: %s', main.rhash);
|
||||
util.log('main hash: %s', main.rhash());
|
||||
util.log('main raw: %s', main.toRaw().toString('hex'));
|
||||
util.log('');
|
||||
util.log('testnet hash: %s', testnet.rhash);
|
||||
util.log('testnet hash: %s', testnet.rhash());
|
||||
util.log('testnet raw: %s', testnet.toRaw().toString('hex'));
|
||||
util.log('');
|
||||
util.log('regtest hash: %s', regtest.rhash);
|
||||
util.log('regtest hash: %s', regtest.rhash());
|
||||
util.log('regtest raw: %s', regtest.toRaw().toString('hex'));
|
||||
util.log('');
|
||||
util.log('segnet3 hash: %s', segnet3.rhash);
|
||||
util.log('segnet3 hash: %s', segnet3.rhash());
|
||||
util.log('segnet3 raw: %s', segnet3.toRaw().toString('hex'));
|
||||
util.log('');
|
||||
util.log('segnet4 hash: %s', segnet4.rhash);
|
||||
util.log('segnet4 hash: %s', segnet4.rhash());
|
||||
util.log('segnet4 raw: %s', segnet4.toRaw().toString('hex'));
|
||||
util.log('');
|
||||
util.log('btcd simnet hash: %s', btcd.rhash);
|
||||
util.log('btcd simnet hash: %s', btcd.rhash());
|
||||
util.log('btcd simnet raw: %s', btcd.toRaw().toString('hex'));
|
||||
|
||||
Loading…
Reference in New Issue
Block a user