fee level fallback + tests

This commit is contained in:
Ivan Socolsky 2016-06-27 12:29:37 -03:00
parent 21afe4d9b7
commit 27b69feb81
No known key found for this signature in database
GPG Key ID: FAECE6A05FAA4F56
3 changed files with 95 additions and 59 deletions

View File

@ -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;

View File

@ -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);
});

View File

@ -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();
});
});
});