fee level fallback + tests
This commit is contained in:
parent
21afe4d9b7
commit
27b69feb81
|
@ -44,6 +44,9 @@ Defaults.FEE_LEVELS = [{
|
|||
|
||||
Defaults.DEFAULT_FEE_PER_KB = Defaults.FEE_LEVELS[1].defaultValue;
|
||||
|
||||
// How many levels to fallback to if the value returned by the network for a given nbBlocks is -1
|
||||
Defaults.FEE_LEVELS_FALLBACK = 2;
|
||||
|
||||
// Minimum nb of addresses a wallet must have to start using 2-step balance optimization
|
||||
Defaults.TWO_STEP_BALANCE_THRESHOLD = 100;
|
||||
|
||||
|
|
|
@ -1314,8 +1314,6 @@ WalletService.prototype._sampleFeeLevels = function(network, points, cb) {
|
|||
});
|
||||
};
|
||||
|
||||
WalletService._feeLevelCache = {};
|
||||
|
||||
/**
|
||||
* Returns fee levels for the current state of the network.
|
||||
* @param {Object} opts
|
||||
|
@ -1327,41 +1325,58 @@ WalletService.prototype.getFeeLevels = function(opts, cb) {
|
|||
|
||||
opts = opts || {};
|
||||
|
||||
function samplePoints() {
|
||||
var definedPoints = _.uniq(_.pluck(Defaults.FEE_LEVELS, 'nbBlocks'));
|
||||
return _.uniq(_.flatten(_.map(definedPoints, function(p) {
|
||||
return _.range(p, p + Defaults.FEE_LEVELS_FALLBACK + 1);
|
||||
})));
|
||||
};
|
||||
|
||||
function getFeeLevel(feeSamples, level, n, fallback) {
|
||||
var result;
|
||||
|
||||
if (feeSamples[n] >= 0) {
|
||||
result = {
|
||||
nbBlocks: n,
|
||||
feePerKb: feeSamples[n],
|
||||
};
|
||||
} else {
|
||||
if (fallback > 0) {
|
||||
result = getFeeLevel(feeSamples, level, n + 1, fallback - 1);
|
||||
} else {
|
||||
result = {
|
||||
feePerKb: level.defaultValue,
|
||||
nbBlocks: null,
|
||||
};
|
||||
}
|
||||
}
|
||||
return result;
|
||||
};
|
||||
|
||||
var network = opts.network || 'livenet';
|
||||
if (network != 'livenet' && network != 'testnet')
|
||||
return cb(new ClientError('Invalid network'));
|
||||
|
||||
var cache = WalletService._feeLevelCache[network] || {};
|
||||
|
||||
var levels = Defaults.FEE_LEVELS;
|
||||
var samplePoints = _.uniq(_.pluck(levels, 'nbBlocks'));
|
||||
self._sampleFeeLevels(network, samplePoints, function(err, feeSamples) {
|
||||
var values = _.map(levels, function(level) {
|
||||
self._sampleFeeLevels(network, samplePoints(), function(err, feeSamples) {
|
||||
var values = _.map(Defaults.FEE_LEVELS, function(level) {
|
||||
var result = {
|
||||
level: level.name,
|
||||
};
|
||||
if (err || feeSamples[level.nbBlocks] < 0) {
|
||||
if (cache[level.nbBlocks] >= 0) {
|
||||
result.feePerKb = cache[level.nbBlocks];
|
||||
result.nbBlocks = level.nbBlocks;
|
||||
} else {
|
||||
result.feePerKb = level.defaultValue;
|
||||
result.nbBlocks = null;
|
||||
}
|
||||
if (err) {
|
||||
result.feePerKb = level.defaultValue;
|
||||
result.nbBlocks = null;
|
||||
} else {
|
||||
result.feePerKb = feeSamples[level.nbBlocks];
|
||||
result.nbBlocks = level.nbBlocks;
|
||||
var feeLevel = getFeeLevel(feeSamples, level, level.nbBlocks, Defaults.FEE_LEVELS_FALLBACK);
|
||||
result.feePerKb = feeLevel.feePerKb;
|
||||
result.nbBlocks = feeLevel.nbBlocks;
|
||||
}
|
||||
return result;
|
||||
});
|
||||
|
||||
var obtainedValues = _.zipObject(_.map(_.reject(values, {
|
||||
nbBlocks: null
|
||||
}), function(v) {
|
||||
return [v.nbBlocks, v.feePerKb];
|
||||
}));
|
||||
|
||||
WalletService._feeLevelCache[network] = _.assign(cache, obtainedValues);
|
||||
// Ensure monotonically decreasing values
|
||||
for (var i = 1; i < values.length; i++) {
|
||||
values[i].feePerKb = Math.min(values[i].feePerKb, values[i - 1].feePerKb);
|
||||
}
|
||||
|
||||
return cb(null, values);
|
||||
});
|
||||
|
|
|
@ -2059,11 +2059,12 @@ describe('Wallet service', function() {
|
|||
done();
|
||||
});
|
||||
});
|
||||
it('should get default fees if network cannot estimate (returns -1)', function(done) {
|
||||
it('should fallback to slower confirmation times if network cannot estimate (returns -1)', function(done) {
|
||||
helpers.stubFeeLevels({
|
||||
1: -1,
|
||||
2: 18000,
|
||||
6: 0,
|
||||
6: -1,
|
||||
7: 11000,
|
||||
24: 9000,
|
||||
});
|
||||
server.getFeeLevels({}, function(err, fees) {
|
||||
|
@ -2071,22 +2072,27 @@ describe('Wallet service', function() {
|
|||
fees = _.zipObject(_.map(fees, function(item) {
|
||||
return [item.level, item];
|
||||
}));
|
||||
fees.priority.feePerKb.should.equal(50000);
|
||||
should.not.exist(fees.priority.nbBlocks);
|
||||
fees.priority.feePerKb.should.equal(18000);
|
||||
fees.priority.nbBlocks.should.equal(2);
|
||||
|
||||
fees.normal.feePerKb.should.equal(18000);
|
||||
fees.normal.nbBlocks.should.equal(2);
|
||||
|
||||
fees.economy.feePerKb.should.equal(0);
|
||||
fees.economy.nbBlocks.should.equal(6);
|
||||
fees.economy.feePerKb.should.equal(11000);
|
||||
fees.economy.nbBlocks.should.equal(7);
|
||||
|
||||
fees.superEconomy.feePerKb.should.equal(9000);
|
||||
fees.superEconomy.nbBlocks.should.equal(24);
|
||||
done();
|
||||
});
|
||||
});
|
||||
it('should get cached value if network cannot estimate but an estimation was retrieved previously', function(done) {
|
||||
it('should get default fees if network cannot estimate (returns -1 including fallback)', function(done) {
|
||||
helpers.stubFeeLevels({
|
||||
1: 40000,
|
||||
2: 20000,
|
||||
6: 18000,
|
||||
1: 45000,
|
||||
2: 36000,
|
||||
6: -1,
|
||||
7: -1,
|
||||
8: -1,
|
||||
24: 9000,
|
||||
});
|
||||
server.getFeeLevels({}, function(err, fees) {
|
||||
|
@ -2094,36 +2100,48 @@ describe('Wallet service', function() {
|
|||
fees = _.zipObject(_.map(fees, function(item) {
|
||||
return [item.level, item];
|
||||
}));
|
||||
fees.priority.feePerKb.should.equal(40000);
|
||||
|
||||
fees.priority.feePerKb.should.equal(45000);
|
||||
fees.priority.nbBlocks.should.equal(1);
|
||||
|
||||
fees.normal.feePerKb.should.equal(20000);
|
||||
fees.normal.feePerKb.should.equal(36000);
|
||||
fees.normal.nbBlocks.should.equal(2);
|
||||
|
||||
fees.economy.feePerKb.should.equal(25000);
|
||||
should.not.exist(fees.economy.nbBlocks);
|
||||
done();
|
||||
});
|
||||
});
|
||||
it('should get monotonically decreasing fee values', function(done) {
|
||||
_.find(Defaults.FEE_LEVELS, {
|
||||
nbBlocks: 6
|
||||
}).defaultValue.should.equal(25000);
|
||||
helpers.stubFeeLevels({
|
||||
1: 45000,
|
||||
2: 18000,
|
||||
6: -1,
|
||||
7: -1,
|
||||
8: -1,
|
||||
24: 9000,
|
||||
});
|
||||
server.getFeeLevels({}, function(err, fees) {
|
||||
should.not.exist(err);
|
||||
fees = _.zipObject(_.map(fees, function(item) {
|
||||
return [item.level, item];
|
||||
}));
|
||||
|
||||
fees.priority.feePerKb.should.equal(45000);
|
||||
fees.priority.nbBlocks.should.equal(1);
|
||||
|
||||
fees.normal.feePerKb.should.equal(18000);
|
||||
fees.normal.nbBlocks.should.equal(2);
|
||||
|
||||
fees.economy.feePerKb.should.equal(18000);
|
||||
fees.economy.nbBlocks.should.equal(6);
|
||||
should.not.exist(fees.economy.nbBlocks);
|
||||
|
||||
helpers.stubFeeLevels({
|
||||
1: -1,
|
||||
2: 25000,
|
||||
6: 10000,
|
||||
24: 9000,
|
||||
});
|
||||
server.getFeeLevels({}, function(err, fees) {
|
||||
should.not.exist(err);
|
||||
fees = _.zipObject(_.map(fees, function(item) {
|
||||
return [item.level, item];
|
||||
}));
|
||||
fees.priority.feePerKb.should.equal(40000);
|
||||
fees.priority.nbBlocks.should.equal(1);
|
||||
|
||||
fees.normal.feePerKb.should.equal(25000);
|
||||
fees.normal.nbBlocks.should.equal(2);
|
||||
|
||||
fees.economy.feePerKb.should.equal(10000);
|
||||
fees.economy.nbBlocks.should.equal(6);
|
||||
done();
|
||||
});
|
||||
fees.superEconomy.feePerKb.should.equal(9000);
|
||||
fees.superEconomy.nbBlocks.should.equal(24);
|
||||
done();
|
||||
});
|
||||
});
|
||||
});
|
||||
|
|
Loading…
Reference in New Issue