fee work.
This commit is contained in:
parent
6a45d693ee
commit
6d55077818
@ -95,8 +95,8 @@ function Mempool(options) {
|
||||
this.minFeeRate = 0;
|
||||
this.blockSinceBump = false;
|
||||
this.lastFeeUpdate = utils.now();
|
||||
this.minReasonableFee = constants.tx.MIN_FEE;
|
||||
this.minRelayFee = constants.tx.MIN_FEE;
|
||||
this.minReasonableFee = constants.tx.MIN_RELAY;
|
||||
this.minRelayFee = constants.tx.MIN_RELAY;
|
||||
|
||||
this._init();
|
||||
}
|
||||
@ -911,7 +911,7 @@ Mempool.prototype.verify = function verify(entry, callback) {
|
||||
var mandatory = constants.flags.MANDATORY_VERIFY_FLAGS;
|
||||
var tx = entry.tx;
|
||||
var ret = {};
|
||||
var fee, modFee, now, size, rejectFee, minRelayFee;
|
||||
var fee, modFee, now, size, rejectFee, minRelayFee, minRate;
|
||||
|
||||
if (this.chain.segwitActive)
|
||||
mandatory |= constants.flags.VERIFY_WITNESS;
|
||||
@ -944,7 +944,12 @@ Mempool.prototype.verify = function verify(entry, callback) {
|
||||
fee = tx.getFee();
|
||||
modFee = entry.fees;
|
||||
size = entry.size;
|
||||
rejectFee = tx.getMinFee(size, self.getMinRate());
|
||||
minRate = self.getMinRate();
|
||||
|
||||
if (minRate > self.minRelayFee)
|
||||
self.network.updateMinRelay(minRate);
|
||||
|
||||
rejectFee = tx.getMinFee(size, minRate);
|
||||
minRelayFee = tx.getMinFee(size, self.minRelayFee);
|
||||
|
||||
if (rejectFee.cmpn(0) > 0 && modFee.cmp(rejectFee) < 0) {
|
||||
|
||||
@ -1055,7 +1055,7 @@ MTX.prototype.selectCoins = function selectCoins(coins, options) {
|
||||
var index = 0;
|
||||
var tx = this.clone();
|
||||
var outputValue = tx.getOutputValue();
|
||||
var tryFree, i, size, change, fee, minValue;
|
||||
var tryFree, i, size, change, fee, min, output;
|
||||
|
||||
if (!options)
|
||||
options = {};
|
||||
@ -1145,7 +1145,7 @@ MTX.prototype.selectCoins = function selectCoins(coins, options) {
|
||||
// Calculate max possible size after signing.
|
||||
size = tx.maxSize(options, true);
|
||||
|
||||
if (tryFree && options.height != null) {
|
||||
if (tryFree && options.height > 0) {
|
||||
// Note that this will only work
|
||||
// if the mempool's rolling reject
|
||||
// fee is zero (i.e. the mempool is
|
||||
@ -1175,26 +1175,33 @@ MTX.prototype.selectCoins = function selectCoins(coins, options) {
|
||||
throw err;
|
||||
}
|
||||
|
||||
if (fee.cmp(constants.tx.MAX_FEE) > 0)
|
||||
fee = constants.tx.MAX_FEE.clone();
|
||||
|
||||
// How much money is left after filling outputs.
|
||||
change = tx.getInputValue().sub(total());
|
||||
|
||||
// Attempt to subtract fee.
|
||||
if (options.subtractFee != null) {
|
||||
minValue = fee.addn(constants.tx.DUST_THRESHOLD);
|
||||
if (typeof options.subtractFee === 'number') {
|
||||
i = options.subtractFee;
|
||||
output = tx.outputs[i];
|
||||
|
||||
if (!tx.outputs[i])
|
||||
if (!output)
|
||||
throw new Error('Subtraction index does not exist.');
|
||||
|
||||
if (tx.outputs[i].value.cmp(minValue) < 0)
|
||||
min = fee.add(output.getDustThreshold());
|
||||
|
||||
if (output.value.cmp(min) < 0)
|
||||
throw new Error('Could not subtract fee.');
|
||||
|
||||
tx.outputs[i].value.isub(fee);
|
||||
output.value.isub(fee);
|
||||
} else {
|
||||
for (i = 0; i < tx.outputs.length; i++) {
|
||||
if (tx.outputs[i].value.cmp(minValue) >= 0) {
|
||||
tx.outputs[i].value.isub(fee);
|
||||
output = tx.outputs[i];
|
||||
min = fee.add(output.getDustThreshold());
|
||||
if (output.value.cmp(min) >= 0) {
|
||||
output.value.isub(fee);
|
||||
break;
|
||||
}
|
||||
}
|
||||
@ -1220,7 +1227,7 @@ MTX.prototype.selectCoins = function selectCoins(coins, options) {
|
||||
*/
|
||||
|
||||
MTX.prototype.fill = function fill(coins, options) {
|
||||
var result, i;
|
||||
var result, i, change;
|
||||
|
||||
assert(this.ts === 0, 'Cannot modify a confirmed tx.');
|
||||
assert(this.inputs.length === 0, 'TX is already filled.');
|
||||
@ -1234,16 +1241,20 @@ MTX.prototype.fill = function fill(coins, options) {
|
||||
for (i = 0; i < result.coins.length; i++)
|
||||
this.addInput(result.coins[i]);
|
||||
|
||||
if (result.change.cmpn(constants.tx.DUST_THRESHOLD) < 0) {
|
||||
// Add a change output.
|
||||
this.addOutput({
|
||||
address: options.changeAddress,
|
||||
value: result.change
|
||||
});
|
||||
|
||||
change = this.outputs[this.outputs.length - 1];
|
||||
|
||||
if (change.isDust(constants.tx.MIN_RELAY)) {
|
||||
// Do nothing. Change is added to fee.
|
||||
assert(this.getFee().cmp(result.fee.add(result.change)) === 0);
|
||||
this.outputs.pop();
|
||||
this.changeIndex = -1;
|
||||
assert(this.getFee().cmp(result.fee.add(result.change)) === 0);
|
||||
} else {
|
||||
// Add a change output.
|
||||
this.addOutput({
|
||||
address: options.changeAddress,
|
||||
value: result.change
|
||||
});
|
||||
this.changeIndex = this.outputs.length - 1;
|
||||
assert(this.getFee().cmp(result.fee) === 0);
|
||||
}
|
||||
|
||||
@ -30,10 +30,16 @@ var network = require('./protocol/network');
|
||||
function Network(options) {
|
||||
var i, keys, key, value;
|
||||
|
||||
if (!(this instanceof Network))
|
||||
return new Network(options);
|
||||
|
||||
if (typeof options === 'string')
|
||||
options = network[options];
|
||||
|
||||
assert(options, 'Network requires a type or options.');
|
||||
assert(options, 'Unknown network.');
|
||||
|
||||
if (Network[options.type])
|
||||
return Network[options.type];
|
||||
|
||||
keys = Object.keys(options);
|
||||
|
||||
@ -68,7 +74,25 @@ Network.prototype.updateHeight = function updateHeight(height) {
|
||||
*/
|
||||
|
||||
Network.prototype.updateRate = function updateRate(rate) {
|
||||
this.rate = rate;
|
||||
this.feeRate = rate;
|
||||
};
|
||||
|
||||
Network.prototype.updateMinRelay = function updateMinRelay(rate) {
|
||||
this.minRelay = rate;
|
||||
};
|
||||
|
||||
Network.prototype.getMinRelay = function getMinRelay() {
|
||||
if (this.height === -1)
|
||||
return this.minRate;
|
||||
|
||||
return Math.min(this.minRelay, this.maxRate);
|
||||
};
|
||||
|
||||
Network.prototype.getRate = function getRate() {
|
||||
if (this.height === -1)
|
||||
return this.maxRate;
|
||||
|
||||
return Math.min(this.feeRate, this.maxRate);
|
||||
};
|
||||
|
||||
/**
|
||||
@ -78,14 +102,9 @@ Network.prototype.updateRate = function updateRate(rate) {
|
||||
*/
|
||||
|
||||
Network.set = function set(type) {
|
||||
assert(type, 'Bad network.');
|
||||
|
||||
if (!Network[type])
|
||||
Network[type] = new Network(type);
|
||||
|
||||
assert(typeof type === 'string', 'Bad network.');
|
||||
Network.primary = type;
|
||||
|
||||
return Network[type];
|
||||
return Network(network[type]);
|
||||
};
|
||||
|
||||
Network.get = function get(options) {
|
||||
@ -97,16 +116,14 @@ Network.get = function get(options) {
|
||||
if (options instanceof Network)
|
||||
return options;
|
||||
|
||||
if (typeof options === 'string') {
|
||||
assert(Network[options], 'Network not created.');
|
||||
return Network[options];
|
||||
}
|
||||
if (typeof options === 'string')
|
||||
return Network(network[options]);
|
||||
|
||||
assert(false, 'Unknown network.');
|
||||
};
|
||||
|
||||
Network.prototype.inspect = function inspect() {
|
||||
return this.type;
|
||||
return '<Network: ' + this.type + '>';
|
||||
};
|
||||
|
||||
module.exports = Network;
|
||||
|
||||
@ -9,6 +9,7 @@ var bcoin = require('./env');
|
||||
var bn = require('bn.js');
|
||||
var utils = require('./utils');
|
||||
var assert = utils.assert;
|
||||
var BufferWriter = require('./writer');
|
||||
|
||||
/**
|
||||
* Represents a transaction output.
|
||||
@ -151,6 +152,26 @@ Output.prototype.toJSON = function toJSON() {
|
||||
};
|
||||
};
|
||||
|
||||
Output.prototype.getDustThreshold = function getDustThreshold(rate) {
|
||||
var framer = bcoin.protocol.framer;
|
||||
var size;
|
||||
|
||||
if (rate == null)
|
||||
rate = constants.tx.MIN_RELAY;
|
||||
|
||||
if (this.script.isUnspendable())
|
||||
return new bn(0);
|
||||
|
||||
size = framer.output(this, new BufferWriter()).written;
|
||||
size += 148;
|
||||
|
||||
return bcoin.tx.getMinFee(size, rate).muln(3);
|
||||
};
|
||||
|
||||
Output.prototype.isDust = function isDust(rate) {
|
||||
return this.value.cmp(this.getDustThreshold(rate)) < 0;
|
||||
};
|
||||
|
||||
/**
|
||||
* Handle a deserialized JSON output object.
|
||||
* @returns {NakedOutput} A "naked" output (a
|
||||
|
||||
@ -410,6 +410,8 @@ exports.tx = {
|
||||
MAX_SIZE: 100000,
|
||||
MAX_COST: 400000,
|
||||
MIN_FEE: 10000,
|
||||
MAX_FEE: exports.COIN.divn(10),
|
||||
MIN_RELAY: 10000,
|
||||
BARE_MULTISIG: true,
|
||||
FREE_THRESHOLD: exports.COIN.muln(144).divn(250),
|
||||
MAX_SIGOPS: exports.block.MAX_SIGOPS / 5,
|
||||
@ -417,7 +419,7 @@ exports.tx = {
|
||||
COINBASE_MATURITY: 100
|
||||
};
|
||||
|
||||
exports.tx.DUST_THRESHOLD = 182 * exports.tx.MIN_FEE / 1000 * 3;
|
||||
exports.tx.DUST_THRESHOLD = 182 * exports.tx.MIN_RELAY / 1000 * 3;
|
||||
|
||||
/**
|
||||
* Script-related constants.
|
||||
|
||||
@ -414,6 +414,38 @@ main.requireStandard = true;
|
||||
|
||||
main.rpcPort = 8332;
|
||||
|
||||
/**
|
||||
* Default min relay rate (the rate for mempoolRejectFee).
|
||||
* @const {Number}
|
||||
* @default
|
||||
*/
|
||||
|
||||
main.minRelay = 10000;
|
||||
|
||||
/**
|
||||
* Default normal relay rate.
|
||||
* @const {Number}
|
||||
* @default
|
||||
*/
|
||||
|
||||
main.feeRate = 40000;
|
||||
|
||||
/**
|
||||
* Default min rate.
|
||||
* @const {Number}
|
||||
* @default
|
||||
*/
|
||||
|
||||
main.minRate = 10000;
|
||||
|
||||
/**
|
||||
* Default max rate.
|
||||
* @const {Number}
|
||||
* @default
|
||||
*/
|
||||
|
||||
main.maxRate = 40000;
|
||||
|
||||
/*
|
||||
* Testnet (v3)
|
||||
* https://en.bitcoin.it/wiki/Testnet
|
||||
@ -552,6 +584,14 @@ testnet.requireStandard = false;
|
||||
|
||||
testnet.rpcPort = 18332;
|
||||
|
||||
testnet.minRelay = 10000;
|
||||
|
||||
testnet.feeRate = 20000;
|
||||
|
||||
testnet.minRate = 10000;
|
||||
|
||||
testnet.maxRate = 40000;
|
||||
|
||||
/*
|
||||
* Regtest
|
||||
*/
|
||||
@ -683,6 +723,14 @@ regtest.requireStandard = false;
|
||||
|
||||
regtest.rpcPort = 18332;
|
||||
|
||||
regtest.minRelay = 10000;
|
||||
|
||||
regtest.feeRate = 20000;
|
||||
|
||||
regtest.minRate = 10000;
|
||||
|
||||
regtest.maxRate = 40000;
|
||||
|
||||
/*
|
||||
* segnet3
|
||||
*/
|
||||
@ -797,6 +845,14 @@ segnet3.requireStandard = false;
|
||||
|
||||
segnet3.rpcPort = 28332;
|
||||
|
||||
segnet3.minRelay = 10000;
|
||||
|
||||
segnet3.feeRate = 20000;
|
||||
|
||||
segnet3.minRate = 10000;
|
||||
|
||||
segnet3.maxRate = 40000;
|
||||
|
||||
/*
|
||||
* segnet4
|
||||
*/
|
||||
@ -924,3 +980,11 @@ segnet4.address.versionsByVal = utils.revMap(segnet4.address.versions);
|
||||
segnet4.requireStandard = false;
|
||||
|
||||
segnet4.rpcPort = 28902;
|
||||
|
||||
segnet4.minRelay = 10000;
|
||||
|
||||
segnet4.feeRate = 20000;
|
||||
|
||||
segnet4.minRate = 10000;
|
||||
|
||||
segnet4.maxRate = 40000;
|
||||
|
||||
@ -1203,7 +1203,7 @@ TX.prototype.isStandard = function isStandard(flags, ret) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (output.value.cmpn(constants.tx.DUST_THRESHOLD) < 0) {
|
||||
if (output.isDust(constants.tx.MIN_RELAY)) {
|
||||
ret.reason = 'dust';
|
||||
return false;
|
||||
}
|
||||
@ -1464,13 +1464,17 @@ TX.prototype.isFree = function isFree(height, size) {
|
||||
*/
|
||||
|
||||
TX.prototype.getMinFee = function getMinFee(size, rate) {
|
||||
var fee;
|
||||
|
||||
if (size == null)
|
||||
size = this.maxSize();
|
||||
|
||||
return TX.getMinFee(size, rate);
|
||||
};
|
||||
|
||||
TX.getMinFee = function getMinFee(size, rate) {
|
||||
var fee;
|
||||
|
||||
if (rate == null)
|
||||
rate = constants.tx.MIN_FEE;
|
||||
rate = constants.tx.MIN_RELAY;
|
||||
|
||||
fee = new bn(rate).muln(size).divn(1000);
|
||||
|
||||
@ -1497,7 +1501,7 @@ TX.prototype.getMaxFee = function getMaxFee(size, rate) {
|
||||
size = this.maxSize();
|
||||
|
||||
if (rate == null)
|
||||
rate = constants.tx.MIN_FEE;
|
||||
rate = constants.tx.MIN_RELAY;
|
||||
|
||||
fee = new bn(rate).muln(Math.ceil(size / 1000));
|
||||
|
||||
|
||||
@ -713,6 +713,8 @@ Wallet.prototype.fill = function fill(tx, options, callback) {
|
||||
fee: options.fee,
|
||||
subtractFee: options.subtractFee,
|
||||
changeAddress: self.changeAddress.getAddress(),
|
||||
height: self.network.height,
|
||||
rate: self.network.getMinRelay(),
|
||||
wallet: self,
|
||||
m: self.m,
|
||||
n: self.n
|
||||
|
||||
Loading…
Reference in New Issue
Block a user