Skip to content
This repository has been archived by the owner on Aug 16, 2021. It is now read-only.

Fee Estimation Functionality #1486

Closed
wants to merge 12 commits into from
Original file line number Diff line number Diff line change
Expand Up @@ -130,7 +130,7 @@ public static async Task<List<Block>> MineBlocksAsync(TestChainContext testChain
/// </summary>
private static async Task<List<Block>> MineBlocksAsync(TestChainContext testChainContext, int count, Script receiver, bool mutateLastBlock)
{
var blockPolicyEstimator = new BlockPolicyEstimator(new MempoolSettings(testChainContext.NodeSettings), testChainContext.LoggerFactory, testChainContext.NodeSettings);
var blockPolicyEstimator = new BlockPolicyEstimator(testChainContext.LoggerFactory, testChainContext.NodeSettings);
var mempool = new TxMempool(testChainContext.DateTimeProvider, blockPolicyEstimator, testChainContext.LoggerFactory, testChainContext.NodeSettings);
var mempoolLock = new MempoolSchedulerLock();

Expand Down
80 changes: 31 additions & 49 deletions src/Stratis.Bitcoin.Features.MemoryPool.Tests/FeeTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -15,13 +15,13 @@ public class FeeTests
public void BlockPolicyEstimates()
{
var dateTimeSet = new DateTimeProviderSet();
NodeSettings settings = NodeSettings.Default();
var mpool = new TxMempool(DateTimeProvider.Default,
new BlockPolicyEstimator(new MempoolSettings(settings), settings.LoggerFactory, settings), settings.LoggerFactory, settings);
var entry = new TestMemPoolEntryHelper();
var basefee = new Money(2000);
var deltaFee = new Money(100);
var feeV = new List<Money>();
var settings = NodeSettings.Default();
TxMempool mpool = new TxMempool(DateTimeProvider.Default,
new BlockPolicyEstimator(settings.LoggerFactory, settings), settings.LoggerFactory, settings);
TestMemPoolEntryHelper entry = new TestMemPoolEntryHelper();
Money basefee = new Money(2000);
Money deltaFee = new Money(100);
List<Money> feeV = new List<Money>();

// Populate vectors of increasing fees
for (int j = 0; j < 10; j++)
Expand Down Expand Up @@ -50,8 +50,8 @@ public void BlockPolicyEstimates()
int answerFound;

// Loop through 200 blocks
// At a decay .998 and 4 fee transactions per block
// This makes the tx count about 1.33 per bucket, above the 1 threshold
// At a decay .9952 and 4 fee transactions per block
// This makes the tx count about 2.5 per bucket, well above the 0.1 threshold
while (blocknum < 200)
{
for (int j = 0; j < 10; j++)
Expand Down Expand Up @@ -81,21 +81,15 @@ public void BlockPolicyEstimates()
}
mpool.RemoveForBlock(block, ++blocknum);
block.Clear();
if (blocknum == 30)
// Check after just a few txs that combining buckets works as expected
if (blocknum == 3)
{
// At this point we should need to combine 5 buckets to get enough data points
// So estimateFee(1,2,3) should fail and estimateFee(4) should return somewhere around
// 8*baserate. estimateFee(4) %'s are 100,100,100,100,90 = average 98%
// At this point we should need to combine 3 buckets to get enough data points
// So estimateFee(1) should fail and estimateFee(2) should return somewhere around
// 9*baserate. estimateFee(2) %'s are 100,100,90 = average 97%
Assert.True(mpool.EstimateFee(1) == new FeeRate(0));
Assert.True(mpool.EstimateFee(2) == new FeeRate(0));
Assert.True(mpool.EstimateFee(3) == new FeeRate(0));
Assert.True(mpool.EstimateFee(4).FeePerK < 8 * baseRate.FeePerK + deltaFee);
Assert.True(mpool.EstimateFee(4).FeePerK > 8 * baseRate.FeePerK - deltaFee);

Assert.True(mpool.EstimateSmartFee(1, out answerFound) == mpool.EstimateFee(4) && answerFound == 4);
Assert.True(mpool.EstimateSmartFee(3, out answerFound) == mpool.EstimateFee(4) && answerFound == 4);
Assert.True(mpool.EstimateSmartFee(4, out answerFound) == mpool.EstimateFee(4) && answerFound == 4);
Assert.True(mpool.EstimateSmartFee(8, out answerFound) == mpool.EstimateFee(8) && answerFound == 8);
Assert.True(mpool.EstimateFee(2).FeePerK < 9 * baseRate.FeePerK + deltaFee);
Assert.True(mpool.EstimateFee(2).FeePerK > 9 * baseRate.FeePerK - deltaFee);
}
}

Expand All @@ -114,15 +108,16 @@ public void BlockPolicyEstimates()
Assert.True(origFeeEst[i - 1] <= origFeeEst[i - 2]);
}
int mult = 11 - i;
if (i > 1)
if (i % 2 == 0) //At scale 2, test logic is only correct for even targets
{
Assert.True(origFeeEst[i - 1] < mult * baseRate.FeePerK + deltaFee);
Assert.True(origFeeEst[i - 1] > mult * baseRate.FeePerK - deltaFee);
}
else
{
Assert.True(origFeeEst[i - 1] == new FeeRate(0).FeePerK);
}
}
// Fill out rest of the original estimates
for (int i = 10; i <= 48; i++)
{
origFeeEst.Add(mpool.EstimateFee(i).FeePerK);
}

// Mine 50 more blocks with no transactions happening, estimates shouldn't change
Expand All @@ -131,7 +126,7 @@ public void BlockPolicyEstimates()
mpool.RemoveForBlock(block, ++blocknum);

Assert.True(mpool.EstimateFee(1) == new FeeRate(0));
for (int i = 2; i < 10; i++)
for (int i = 2; i < 9; i++)
{
Assert.True(mpool.EstimateFee(i).FeePerK < origFeeEst[i - 1] + deltaFee);
Assert.True(mpool.EstimateFee(i).FeePerK > origFeeEst[i - 1] - deltaFee);
Expand All @@ -155,10 +150,9 @@ public void BlockPolicyEstimates()
mpool.RemoveForBlock(block, ++blocknum);
}

for (int i = 1; i < 10; i++)
for (int i = 1; i < 9; i++)
{
Assert.True(mpool.EstimateFee(i) == new FeeRate(0) || mpool.EstimateFee(i).FeePerK > origFeeEst[i - 1] - deltaFee);
Assert.True(mpool.EstimateSmartFee(i, out answerFound).FeePerK > origFeeEst[answerFound - 1] - deltaFee);
}

// Mine all those transactions
Expand All @@ -176,14 +170,15 @@ public void BlockPolicyEstimates()
mpool.RemoveForBlock(block, 265);
block.Clear();
Assert.True(mpool.EstimateFee(1) == new FeeRate(0));
for (int i = 2; i < 10; i++)
for (int i = 2; i < 9; i++)
{
Assert.True(mpool.EstimateFee(i).FeePerK > origFeeEst[i - 1] - deltaFee);
Assert.True(mpool.EstimateFee(i) == new FeeRate(0) ||
mpool.EstimateFee(i).FeePerK > origFeeEst[i - 1] - deltaFee);
}

// Mine 200 more blocks where everything is mined every block
// Mine 600 more blocks where everything is mined every block
// Estimates should be below original estimates
while (blocknum < 465)
while (blocknum < 865)
{
for (int j = 0; j < 10; j++)
{ // For each fee multiple
Expand All @@ -202,23 +197,10 @@ public void BlockPolicyEstimates()
block.Clear();
}
Assert.True(mpool.EstimateFee(1) == new FeeRate(0));
for (int i = 2; i < 10; i++)
for (int i = 2; i < 9; i++)
{
Assert.True(mpool.EstimateFee(i).FeePerK < origFeeEst[i - 1] - deltaFee);
}

// Test that if the mempool is limited, estimateSmartFee won't return a value below the mempool min fee
// and that estimateSmartPriority returns essentially an infinite value
mpool.AddUnchecked(txf.GetHash(), entry.Fee(feeV[5]).Time(dateTimeSet.GetTime()).Priority(0).Height(blocknum).FromTx(txf, mpool));
// evict that transaction which should set a mempool min fee of minRelayTxFee + feeV[5]
mpool.TrimToSize(1);
Assert.True(mpool.GetMinFee(1).FeePerK > feeV[5]);
for (int i = 1; i < 10; i++)
{
Assert.True(mpool.EstimateSmartFee(i, out answerFound).FeePerK >= mpool.EstimateFee(i).FeePerK);
Assert.True(mpool.EstimateSmartFee(i, out answerFound).FeePerK >= mpool.GetMinFee(1).FeePerK);
Assert.True(mpool.EstimateSmartPriority(i, out answerFound) == BlockPolicyEstimator.InfPriority);
}
}
}

public class DateTimeProviderSet : DateTimeProvider
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -46,8 +46,10 @@ public void MempoolRemoveTest()
txGrandChild[i].AddOutput(new TxOut(new Money(11000L), new Script(OpcodeType.OP_11, OpcodeType.OP_EQUAL)));
}

NodeSettings settings = NodeSettings.Default();
var testPool = new TxMempool(DateTimeProvider.Default, new BlockPolicyEstimator(new MempoolSettings(settings), settings.LoggerFactory, settings), settings.LoggerFactory, settings);

var settings = NodeSettings.Default();
TxMempool testPool = new TxMempool(DateTimeProvider.Default, new BlockPolicyEstimator(settings.LoggerFactory, settings), settings.LoggerFactory, settings);


// Nothing in pool, remove should do nothing:
long poolSize = testPool.Size;
Expand Down Expand Up @@ -114,8 +116,10 @@ private void CheckSort(TxMempool pool, List<TxMempoolEntry> sortedSource, List<s
[Fact]
public void MempoolIndexingTest()
{
NodeSettings settings = NodeSettings.Default();
var pool = new TxMempool(DateTimeProvider.Default, new BlockPolicyEstimator(new MempoolSettings(settings), settings.LoggerFactory, settings), settings.LoggerFactory, settings);

var settings = NodeSettings.Default();
var pool = new TxMempool(DateTimeProvider.Default, new BlockPolicyEstimator(settings.LoggerFactory, settings), settings.LoggerFactory, settings);

var entry = new TestMemPoolEntryHelper();

/* 3rd highest fee */
Expand Down Expand Up @@ -297,8 +301,10 @@ public void MempoolIndexingTest()
[Fact]
public void MempoolAncestorIndexingTest()
{
NodeSettings settings = NodeSettings.Default();
var pool = new TxMempool(DateTimeProvider.Default, new BlockPolicyEstimator(new MempoolSettings(settings), settings.LoggerFactory, settings), settings.LoggerFactory, settings);

var settings = NodeSettings.Default();
var pool = new TxMempool(DateTimeProvider.Default, new BlockPolicyEstimator(settings.LoggerFactory, settings), settings.LoggerFactory, settings);

var entry = new TestMemPoolEntryHelper();

/* 3rd highest fee */
Expand Down Expand Up @@ -393,7 +399,7 @@ public void MempoolSizeLimitTest()
{
NodeSettings settings = NodeSettings.Default();
var dateTimeSet = new DateTimeProviderSet();
var pool = new TxMempool(dateTimeSet, new BlockPolicyEstimator(new MempoolSettings(settings), settings.LoggerFactory, settings), settings.LoggerFactory, settings);
var pool = new TxMempool(dateTimeSet, new BlockPolicyEstimator(settings.LoggerFactory, settings), settings.LoggerFactory, settings);
var entry = new TestMemPoolEntryHelper();
entry.Priority(10.0);

Expand Down Expand Up @@ -527,8 +533,10 @@ public override DateTime GetUtcNow()
[Fact]
public void MempoolConcurrencyTest()
{
NodeSettings settings = NodeSettings.Default();
var pool = new TxMempool(DateTimeProvider.Default, new BlockPolicyEstimator(new MempoolSettings(settings), settings.LoggerFactory, settings), settings.LoggerFactory, settings);

var settings = NodeSettings.Default();
var pool = new TxMempool(DateTimeProvider.Default, new BlockPolicyEstimator(settings.LoggerFactory, settings), settings.LoggerFactory, settings);

var scheduler = new SchedulerLock();
var rand = new Random();

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -41,8 +41,9 @@ private MempoolManager TxExpiryManager
};
NodeSettings nodeSettings = NodeSettings.Default();

var blockPolicyEstimator = new BlockPolicyEstimator(settings, loggerFactory, nodeSettings);
var mempool = new TxMempool(dateTime, blockPolicyEstimator, loggerFactory, nodeSettings);
BlockPolicyEstimator blockPolicyEstimator = new BlockPolicyEstimator(loggerFactory, nodeSettings);
TxMempool mempool = new TxMempool(dateTime, blockPolicyEstimator, loggerFactory, nodeSettings);


var mockTxMempool = new Mock<TxMempool>();
var mockValidator = new Mock<IMempoolValidator>();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -272,9 +272,13 @@ private static MempoolManager CreateTestMempool(NodeSettings settings, out TxMem
var mempoolSettings = new MempoolSettings(settings);
IDateTimeProvider dateTimeProvider = DateTimeProvider.Default;
NodeSettings nodeSettings = NodeSettings.Default();
ILoggerFactory loggerFactory = nodeSettings.LoggerFactory;
var consensusSettings = new ConsensusSettings(nodeSettings);
txMemPool = new TxMempool(dateTimeProvider, new BlockPolicyEstimator(new MempoolSettings(nodeSettings), loggerFactory, nodeSettings), loggerFactory, nodeSettings);

var loggerFactory = nodeSettings.LoggerFactory;

ConsensusSettings consensusSettings = new ConsensusSettings(nodeSettings);
txMemPool = new TxMempool(dateTimeProvider, new BlockPolicyEstimator(loggerFactory, nodeSettings), loggerFactory, nodeSettings);


var mempoolLock = new MempoolSchedulerLock();
var coins = new InMemoryCoinView(settings.Network.GenesisHash);
var chain = new ConcurrentChain(Network.Main.GetGenesis().Header);
Expand All @@ -285,4 +289,4 @@ private static MempoolManager CreateTestMempool(NodeSettings settings, out TxMem
return new MempoolManager(mempoolLock, txMemPool, mempoolValidator, dateTimeProvider, mempoolSettings, mempoolPersistence, coins, loggerFactory, settings.Network);
}
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -91,9 +91,11 @@ public static async Task<ITestChainContext> CreateAsync(Network network, Script
var consensusLoop = new ConsensusLoop(new AsyncLoopFactory(loggerFactory), new NodeLifetime(), chain, cachedCoinView, blockPuller, deployments, loggerFactory, new ChainState(new InvalidBlockHashStore(dateTimeProvider)), connectionManager, dateTimeProvider, new Signals.Signals(), consensusSettings, nodeSettings, peerBanning, consensusRules);
await consensusLoop.StartAsync();

var blockPolicyEstimator = new BlockPolicyEstimator(new MempoolSettings(nodeSettings), loggerFactory, nodeSettings);
var mempool = new TxMempool(dateTimeProvider, blockPolicyEstimator, loggerFactory, nodeSettings);
var mempoolLock = new MempoolSchedulerLock();

BlockPolicyEstimator blockPolicyEstimator = new BlockPolicyEstimator(loggerFactory, nodeSettings);
TxMempool mempool = new TxMempool(dateTimeProvider, blockPolicyEstimator, loggerFactory, nodeSettings);
MempoolSchedulerLock mempoolLock = new MempoolSchedulerLock();


// Simple block creation, nothing special yet:
PowBlockDefinition blockDefinition = CreatePowBlockAssembler(consensusLoop, consensusRules, dateTimeProvider, loggerFactory as LoggerFactory, mempool, mempoolLock, network);
Expand Down
Loading