net/miner/hd: classify.

This commit is contained in:
Christopher Jeffrey 2017-11-15 21:23:47 -08:00
parent daa55a05bc
commit 280d5d38e5
No known key found for this signature in database
GPG Key ID: 8962AB9DE6666BBD
6 changed files with 5434 additions and 5333 deletions

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@ -14,15 +14,9 @@ const StaticWriter = require('bufio/lib/staticwriter');
const TX = require('../primitives/tx');
/**
* Mempool Entry
* Represents a mempool entry.
* @alias module:mempool.MempoolEntry
* @constructor
* @param {Object} options
* @param {TX} options.tx - Transaction in mempool.
* @param {Number} options.height - Entry height.
* @param {Number} options.priority - Entry priority.
* @param {Number} options.time - Entry time.
* @param {Amount} options.value - Value of on-chain coins.
* @property {TX} tx
* @property {Number} height
* @property {Number} priority
@ -30,338 +24,351 @@ const TX = require('../primitives/tx');
* @property {Amount} value
*/
function MempoolEntry(options) {
if (!(this instanceof MempoolEntry))
return new MempoolEntry(options);
class MempoolEntry {
/**
* Create a mempool entry.
* @constructor
* @param {Object} options
* @param {TX} options.tx - Transaction in mempool.
* @param {Number} options.height - Entry height.
* @param {Number} options.priority - Entry priority.
* @param {Number} options.time - Entry time.
* @param {Amount} options.value - Value of on-chain coins.
*/
this.tx = null;
this.height = -1;
this.size = 0;
this.sigops = 0;
this.priority = 0;
this.fee = 0;
this.deltaFee = 0;
this.time = 0;
this.value = 0;
this.coinbase = false;
this.dependencies = false;
this.descFee = 0;
this.descSize = 0;
constructor(options) {
this.tx = null;
this.height = -1;
this.size = 0;
this.sigops = 0;
this.priority = 0;
this.fee = 0;
this.deltaFee = 0;
this.time = 0;
this.value = 0;
this.coinbase = false;
this.dependencies = false;
this.descFee = 0;
this.descSize = 0;
if (options)
this.fromOptions(options);
if (options)
this.fromOptions(options);
}
/**
* Inject properties from options object.
* @private
* @param {Object} options
*/
fromOptions(options) {
this.tx = options.tx;
this.height = options.height;
this.size = options.size;
this.sigops = options.sigops;
this.priority = options.priority;
this.fee = options.fee;
this.deltaFee = options.deltaFee;
this.time = options.time;
this.value = options.value;
this.coinbase = options.coinbase;
this.dependencies = options.dependencies;
this.descFee = options.descFee;
this.descSize = options.descSize;
return this;
}
/**
* Instantiate mempool entry from options.
* @param {Object} options
* @returns {MempoolEntry}
*/
static fromOptions(options) {
return new this().fromOptions(options);
}
/**
* Inject properties from transaction.
* @private
* @param {TX} tx
* @param {Number} height
*/
fromTX(tx, view, height) {
const flags = Script.flags.STANDARD_VERIFY_FLAGS;
const value = tx.getChainValue(view);
const sigops = tx.getSigopsCost(view, flags);
const size = tx.getSigopsSize(sigops);
const priority = tx.getPriority(view, height, size);
const fee = tx.getFee(view);
let dependencies = false;
let coinbase = false;
for (const {prevout} of tx.inputs) {
if (view.isCoinbase(prevout))
coinbase = true;
if (view.getHeight(prevout) === -1)
dependencies = true;
}
this.tx = tx;
this.height = height;
this.size = size;
this.sigops = sigops;
this.priority = priority;
this.fee = fee;
this.deltaFee = fee;
this.time = util.now();
this.value = value;
this.coinbase = coinbase;
this.dependencies = dependencies;
this.descFee = fee;
this.descSize = size;
return this;
}
/**
* Create a mempool entry from a TX.
* @param {TX} tx
* @param {Number} height - Entry height.
* @returns {MempoolEntry}
*/
static fromTX(tx, view, height) {
return new this().fromTX(tx, view, height);
}
/**
* Calculate transaction hash.
* @param {String?} enc
* @returns {Hash}
*/
hash(enc) {
return this.tx.hash(enc);
}
/**
* Calculate reverse transaction hash.
* @returns {Hash}
*/
txid() {
return this.tx.txid();
}
/**
* Calculate priority, taking into account
* the entry height delta, modified size,
* and chain value.
* @param {Number} height
* @returns {Number} Priority.
*/
getPriority(height) {
const delta = height - this.height;
const priority = (delta * this.value) / this.size;
let result = this.priority + Math.floor(priority);
if (result < 0)
result = 0;
return result;
}
/**
* Get fee.
* @returns {Amount}
*/
getFee() {
return this.fee;
}
/**
* Get delta fee.
* @returns {Amount}
*/
getDeltaFee() {
return this.deltaFee;
}
/**
* Calculate fee rate.
* @returns {Rate}
*/
getRate() {
return policy.getRate(this.size, this.fee);
}
/**
* Calculate delta fee rate.
* @returns {Rate}
*/
getDeltaRate() {
return policy.getRate(this.size, this.deltaFee);
}
/**
* Calculate fee cumulative descendant rate.
* @returns {Rate}
*/
getDescRate() {
return policy.getRate(this.descSize, this.descFee);
}
/**
* Calculate the memory usage of a transaction.
* Note that this only calculates the JS heap
* size. Sizes of buffers are ignored (the v8
* heap is what we care most about). All numbers
* are based on the output of v8 heap snapshots
* of TX objects.
* @returns {Number} Usage in bytes.
*/
memUsage() {
const tx = this.tx;
let total = 0;
total += 176; // mempool entry
total += 48; // coinbase
total += 48; // dependencies
total += 208; // tx
total += 80; // _hash
total += 88; // _hhash
total += 80; // _raw
total += 80; // _whash
total += 48; // mutable
total += 32; // input array
for (const input of tx.inputs) {
total += 120; // input
total += 104; // prevout
total += 88; // prevout hash
total += 40; // script
total += 80; // script raw buffer
total += 32; // script code array
total += input.script.code.length * 40; // opcodes
for (const op of input.script.code) {
if (op.data)
total += 80; // op buffers
}
total += 96; // witness
total += 32; // witness items
total += input.witness.items.length * 80; // witness buffers
}
total += 32; // output array
for (const output of tx.outputs) {
total += 104; // output
total += 40; // script
total += 80; // script raw buffer
total += 32; // script code array
total += output.script.code.length * 40; // opcodes
for (const op of output.script.code) {
if (op.data)
total += 80; // op buffers
}
}
return total;
}
/**
* Test whether the entry is free with
* the current priority (calculated by
* current height).
* @param {Number} height
* @returns {Boolean}
*/
isFree(height) {
const priority = this.getPriority(height);
return priority > policy.FREE_THRESHOLD;
}
/**
* Get entry serialization size.
* @returns {Number}
*/
getSize() {
return this.tx.getSize() + 42;
}
/**
* Serialize entry to a buffer.
* @returns {Buffer}
*/
toRaw() {
const bw = new StaticWriter(this.getSize());
bw.writeBytes(this.tx.toRaw());
bw.writeU32(this.height);
bw.writeU32(this.size);
bw.writeU32(this.sigops);
bw.writeDouble(this.priority);
bw.writeU64(this.fee);
bw.writeU32(this.time);
bw.writeU64(this.value);
bw.writeU8(this.coinbase ? 1 : 0);
bw.writeU8(this.dependencies ? 1 : 0);
return bw.render();
}
/**
* Inject properties from serialized data.
* @private
* @param {Buffer} data
* @returns {MempoolEntry}
*/
fromRaw(data) {
const br = new BufferReader(data);
this.tx = TX.fromReader(br);
this.height = br.readU32();
this.size = br.readU32();
this.sigops = br.readU32();
this.priority = br.readDouble();
this.fee = br.readU64();
this.deltaFee = this.fee;
this.time = br.readU32();
this.value = br.readU64();
this.coinbase = br.readU8() === 1;
this.dependencies = br.readU8() === 1;
this.descFee = this.fee;
this.descSize = this.size;
return this;
}
/**
* Instantiate entry from serialized data.
* @param {Buffer} data
* @returns {MempoolEntry}
*/
static fromRaw(data) {
return new this().fromRaw(data);
}
}
/**
* Inject properties from options object.
* @private
* @param {Object} options
*/
MempoolEntry.prototype.fromOptions = function fromOptions(options) {
this.tx = options.tx;
this.height = options.height;
this.size = options.size;
this.sigops = options.sigops;
this.priority = options.priority;
this.fee = options.fee;
this.deltaFee = options.deltaFee;
this.time = options.time;
this.value = options.value;
this.coinbase = options.coinbase;
this.dependencies = options.dependencies;
this.descFee = options.descFee;
this.descSize = options.descSize;
return this;
};
/**
* Instantiate mempool entry from options.
* @param {Object} options
* @returns {MempoolEntry}
*/
MempoolEntry.fromOptions = function fromOptions(options) {
return new MempoolEntry().fromOptions(options);
};
/**
* Inject properties from transaction.
* @private
* @param {TX} tx
* @param {Number} height
*/
MempoolEntry.prototype.fromTX = function fromTX(tx, view, height) {
const flags = Script.flags.STANDARD_VERIFY_FLAGS;
const value = tx.getChainValue(view);
const sigops = tx.getSigopsCost(view, flags);
const size = tx.getSigopsSize(sigops);
const priority = tx.getPriority(view, height, size);
const fee = tx.getFee(view);
let dependencies = false;
let coinbase = false;
for (const {prevout} of tx.inputs) {
if (view.isCoinbase(prevout))
coinbase = true;
if (view.getHeight(prevout) === -1)
dependencies = true;
}
this.tx = tx;
this.height = height;
this.size = size;
this.sigops = sigops;
this.priority = priority;
this.fee = fee;
this.deltaFee = fee;
this.time = util.now();
this.value = value;
this.coinbase = coinbase;
this.dependencies = dependencies;
this.descFee = fee;
this.descSize = size;
return this;
};
/**
* Create a mempool entry from a TX.
* @param {TX} tx
* @param {Number} height - Entry height.
* @returns {MempoolEntry}
*/
MempoolEntry.fromTX = function fromTX(tx, view, height) {
return new MempoolEntry().fromTX(tx, view, height);
};
/**
* Calculate transaction hash.
* @param {String?} enc
* @returns {Hash}
*/
MempoolEntry.prototype.hash = function hash(enc) {
return this.tx.hash(enc);
};
/**
* Calculate reverse transaction hash.
* @returns {Hash}
*/
MempoolEntry.prototype.txid = function txid() {
return this.tx.txid();
};
/**
* Calculate priority, taking into account
* the entry height delta, modified size,
* and chain value.
* @param {Number} height
* @returns {Number} Priority.
*/
MempoolEntry.prototype.getPriority = function getPriority(height) {
const delta = height - this.height;
const priority = (delta * this.value) / this.size;
let result = this.priority + Math.floor(priority);
if (result < 0)
result = 0;
return result;
};
/**
* Get fee.
* @returns {Amount}
*/
MempoolEntry.prototype.getFee = function getFee() {
return this.fee;
};
/**
* Get delta fee.
* @returns {Amount}
*/
MempoolEntry.prototype.getDeltaFee = function getDeltaFee() {
return this.deltaFee;
};
/**
* Calculate fee rate.
* @returns {Rate}
*/
MempoolEntry.prototype.getRate = function getRate() {
return policy.getRate(this.size, this.fee);
};
/**
* Calculate delta fee rate.
* @returns {Rate}
*/
MempoolEntry.prototype.getDeltaRate = function getDeltaRate() {
return policy.getRate(this.size, this.deltaFee);
};
/**
* Calculate fee cumulative descendant rate.
* @returns {Rate}
*/
MempoolEntry.prototype.getDescRate = function getDescRate() {
return policy.getRate(this.descSize, this.descFee);
};
/**
* Calculate the memory usage of a transaction.
* Note that this only calculates the JS heap
* size. Sizes of buffers are ignored (the v8
* heap is what we care most about). All numbers
* are based on the output of v8 heap snapshots
* of TX objects.
* @returns {Number} Usage in bytes.
*/
MempoolEntry.prototype.memUsage = function memUsage() {
const tx = this.tx;
let total = 0;
total += 176; // mempool entry
total += 48; // coinbase
total += 48; // dependencies
total += 208; // tx
total += 80; // _hash
total += 88; // _hhash
total += 80; // _raw
total += 80; // _whash
total += 48; // mutable
total += 32; // input array
for (const input of tx.inputs) {
total += 120; // input
total += 104; // prevout
total += 88; // prevout hash
total += 40; // script
total += 80; // script raw buffer
total += 32; // script code array
total += input.script.code.length * 40; // opcodes
for (const op of input.script.code) {
if (op.data)
total += 80; // op buffers
}
total += 96; // witness
total += 32; // witness items
total += input.witness.items.length * 80; // witness buffers
}
total += 32; // output array
for (const output of tx.outputs) {
total += 104; // output
total += 40; // script
total += 80; // script raw buffer
total += 32; // script code array
total += output.script.code.length * 40; // opcodes
for (const op of output.script.code) {
if (op.data)
total += 80; // op buffers
}
}
return total;
};
/**
* Test whether the entry is free with
* the current priority (calculated by
* current height).
* @param {Number} height
* @returns {Boolean}
*/
MempoolEntry.prototype.isFree = function isFree(height) {
const priority = this.getPriority(height);
return priority > policy.FREE_THRESHOLD;
};
/**
* Get entry serialization size.
* @returns {Number}
*/
MempoolEntry.prototype.getSize = function getSize() {
return this.tx.getSize() + 42;
};
/**
* Serialize entry to a buffer.
* @returns {Buffer}
*/
MempoolEntry.prototype.toRaw = function toRaw() {
const bw = new StaticWriter(this.getSize());
bw.writeBytes(this.tx.toRaw());
bw.writeU32(this.height);
bw.writeU32(this.size);
bw.writeU32(this.sigops);
bw.writeDouble(this.priority);
bw.writeU64(this.fee);
bw.writeU32(this.time);
bw.writeU64(this.value);
bw.writeU8(this.coinbase ? 1 : 0);
bw.writeU8(this.dependencies ? 1 : 0);
return bw.render();
};
/**
* Inject properties from serialized data.
* @private
* @param {Buffer} data
* @returns {MempoolEntry}
*/
MempoolEntry.prototype.fromRaw = function fromRaw(data) {
const br = new BufferReader(data);
this.tx = TX.fromReader(br);
this.height = br.readU32();
this.size = br.readU32();
this.sigops = br.readU32();
this.priority = br.readDouble();
this.fee = br.readU64();
this.deltaFee = this.fee;
this.time = br.readU32();
this.value = br.readU64();
this.coinbase = br.readU8() === 1;
this.dependencies = br.readU8() === 1;
this.descFee = this.fee;
this.descSize = this.size;
return this;
};
/**
* Instantiate entry from serialized data.
* @param {Buffer} data
* @returns {MempoolEntry}
*/
MempoolEntry.fromRaw = function fromRaw(data) {
return new MempoolEntry().fromRaw(data);
};
/*
* Expose
*/

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff