Skip to content

Commit cdcc14c

Browse files
authored
Pass ChainIndexer argument via CachedCoinView constructor (stratisproject#1072)
* Pass ChainIndexer argument via CachedCoinView constructor * Add this * Add missing locks * Refactor
1 parent a0f638c commit cdcc14c

File tree

15 files changed

+94
-81
lines changed

15 files changed

+94
-81
lines changed

src/Stratis.Bitcoin.Features.Consensus.Tests/CoinViews/CoinviewTests.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -51,7 +51,7 @@ public CoinviewTests()
5151

5252
this.rewindDataIndexCache = new RewindDataIndexCache(this.dateTimeProvider, this.network, new FinalizedBlockInfoRepository(new HashHeightPair()), new Checkpoints());
5353

54-
this.cachedCoinView = new CachedCoinView(this.network, this.coindb, this.dateTimeProvider, this.loggerFactory, this.nodeStats, new ConsensusSettings(new NodeSettings(this.network)), this.stakeChainStore, this.rewindDataIndexCache);
54+
this.cachedCoinView = new CachedCoinView(this.network, this.coindb, this.dateTimeProvider, this.loggerFactory, this.nodeStats, new ConsensusSettings(new NodeSettings(this.network)), this.chainIndexer, this.stakeChainStore, this.rewindDataIndexCache);
5555

5656
this.rewindDataIndexCache.Initialize(this.chainIndexer.Height, this.cachedCoinView);
5757

src/Stratis.Bitcoin.Features.Consensus.Tests/TestChainFactory.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -124,7 +124,7 @@ public static async Task<TestChainContext> CreateAsync(Network network, string d
124124
testChainContext.InitialBlockDownloadState = new InitialBlockDownloadState(testChainContext.ChainState, testChainContext.Network, consensusSettings, new Checkpoints(), testChainContext.DateTimeProvider);
125125

126126
var inMemoryCoinView = new InMemoryCoinView(new HashHeightPair(testChainContext.ChainIndexer.Tip));
127-
var cachedCoinView = new CachedCoinView(network, inMemoryCoinView, DateTimeProvider.Default, testChainContext.LoggerFactory, new NodeStats(testChainContext.DateTimeProvider, testChainContext.NodeSettings, new Mock<IVersionProvider>().Object), new ConsensusSettings(testChainContext.NodeSettings));
127+
var cachedCoinView = new CachedCoinView(network, inMemoryCoinView, DateTimeProvider.Default, testChainContext.LoggerFactory, new NodeStats(testChainContext.DateTimeProvider, testChainContext.NodeSettings, new Mock<IVersionProvider>().Object), new ConsensusSettings(testChainContext.NodeSettings), testChainContext.ChainIndexer);
128128

129129
var dataFolder = new DataFolder(TestBase.AssureEmptyDir(dataDir).FullName);
130130
testChainContext.PeerAddressManager =

src/Stratis.Bitcoin.Features.Consensus/CoinViews/CachedCoinView.cs

Lines changed: 67 additions & 56 deletions
Original file line numberDiff line numberDiff line change
@@ -131,11 +131,12 @@ public long GetScriptSize
131131
private readonly IBlockStore blockStore;
132132
private readonly CancellationTokenSource cancellationToken;
133133
private readonly ConsensusSettings consensusSettings;
134+
private readonly ChainIndexer chainIndexer;
134135
private CachePerformanceSnapshot latestPerformanceSnapShot;
135136

136137
private readonly Random random;
137138

138-
public CachedCoinView(Network network, ICoindb coindb, IDateTimeProvider dateTimeProvider, ILoggerFactory loggerFactory, INodeStats nodeStats, ConsensusSettings consensusSettings,
139+
public CachedCoinView(Network network, ICoindb coindb, IDateTimeProvider dateTimeProvider, ILoggerFactory loggerFactory, INodeStats nodeStats, ConsensusSettings consensusSettings, ChainIndexer chainIndexer,
139140
StakeChainStore stakeChainStore = null, IRewindDataIndexCache rewindDataIndexCache = null, IBlockStore blockStore = null, INodeLifetime nodeLifetime = null)
140141
{
141142
Guard.NotNull(coindb, nameof(CachedCoinView.coindb));
@@ -145,6 +146,7 @@ public CachedCoinView(Network network, ICoindb coindb, IDateTimeProvider dateTim
145146
this.network = network;
146147
this.dateTimeProvider = dateTimeProvider;
147148
this.consensusSettings = consensusSettings;
149+
this.chainIndexer = chainIndexer;
148150
this.stakeChainStore = stakeChainStore;
149151
this.rewindDataIndexCache = rewindDataIndexCache;
150152
this.blockStore = blockStore;
@@ -166,22 +168,22 @@ public CachedCoinView(Network network, ICoindb coindb, IDateTimeProvider dateTim
166168
/// <summary>
167169
/// Remain on-chain.
168170
/// </summary>
169-
public void Sync(ChainIndexer chainIndexer)
171+
public void Sync()
170172
{
171173
lock (this.lockobj)
172174
{
173175
HashHeightPair coinViewTip = this.GetTipHash();
174-
if (coinViewTip.Hash == chainIndexer.Tip.HashBlock)
176+
if (coinViewTip.Hash == this.chainIndexer.Tip.HashBlock)
175177
return;
176178

177179
Flush();
178180

179-
ChainedHeader fork = chainIndexer[coinViewTip.Hash];
181+
ChainedHeader fork = this.chainIndexer[coinViewTip.Hash];
180182
if (fork == null)
181183
{
182184
// Determine the last usable height.
183-
int height = BinarySearch.BinaryFindFirst(h => (h > chainIndexer.Height) || this.GetRewindData(h).PreviousBlockHash.Hash != chainIndexer[h].Previous.HashBlock, 0, coinViewTip.Height + 1) - 1;
184-
fork = chainIndexer[(height < 0) ? coinViewTip.Height : height];
185+
int height = BinarySearch.BinaryFindFirst(h => (h > this.chainIndexer.Height) || this.GetRewindData(h).PreviousBlockHash.Hash != this.chainIndexer[h].Previous.HashBlock, 0, coinViewTip.Height + 1) - 1;
186+
fork = this.chainIndexer[(height < 0) ? coinViewTip.Height : height];
185187
}
186188

187189
while (coinViewTip.Height != fork.Height)
@@ -196,11 +198,13 @@ public void Sync(ChainIndexer chainIndexer)
196198
}
197199
}
198200

199-
public void Initialize(ChainedHeader chainTip, ChainIndexer chainIndexer, IConsensusRuleEngine consensusRuleEngine)
201+
public void Initialize(IConsensusManager consensusManager)
200202
{
203+
ChainedHeader chainTip = this.chainIndexer.Tip;
204+
201205
this.coindb.Initialize();
202206

203-
Sync(chainIndexer);
207+
Sync();
204208

205209
HashHeightPair coinViewTip = this.coindb.GetTipHash();
206210

@@ -209,12 +213,14 @@ public void Initialize(ChainedHeader chainTip, ChainIndexer chainIndexer, IConse
209213
{
210214
try
211215
{
216+
IConsensusRuleEngine consensusRuleEngine = consensusManager.ConsensusRules;
217+
212218
var loadCoinViewRule = consensusRuleEngine.GetRule<LoadCoinviewRule>();
213219
var saveCoinViewRule = consensusRuleEngine.GetRule<SaveCoinviewRule>();
214220
var coinViewRule = consensusRuleEngine.GetRule<CoinViewRule>();
215221
var deploymentsRule = consensusRuleEngine.GetRule<SetActivationDeploymentsFullValidationRule>();
216222

217-
foreach ((ChainedHeader chainedHeader, Block block) in this.blockStore.BatchBlocksFrom(chainIndexer[coinViewTip.Hash], chainIndexer, this.cancellationToken, batchSize: 1000))
223+
foreach ((ChainedHeader chainedHeader, Block block) in this.blockStore.BatchBlocksFrom(this.chainIndexer[coinViewTip.Hash], this.chainIndexer, this.cancellationToken, batchSize: 1000))
218224
{
219225
if (block == null)
220226
break;
@@ -258,15 +264,18 @@ public void Initialize(ChainedHeader chainTip, ChainIndexer chainIndexer, IConse
258264

259265
public HashHeightPair GetTipHash()
260266
{
261-
if (this.blockHash == null)
267+
lock (this.lockobj)
262268
{
263-
HashHeightPair response = this.coindb.GetTipHash();
269+
if (this.blockHash == null)
270+
{
271+
HashHeightPair response = this.coindb.GetTipHash();
264272

265-
this.innerBlockHash = response;
266-
this.blockHash = this.innerBlockHash;
267-
}
273+
this.innerBlockHash = response;
274+
this.blockHash = this.innerBlockHash;
275+
}
268276

269-
return this.blockHash;
277+
return this.blockHash;
278+
}
270279
}
271280

272281
/// <inheritdoc />
@@ -412,44 +421,44 @@ private void TryEvictCacheLocked()
412421
/// </remarks>
413422
public void Flush(bool force = true)
414423
{
415-
if (!force)
424+
lock (this.lockobj)
416425
{
417-
// Check if periodic flush is required.
418-
// Ideally this will flush less frequent and always be behind
419-
// blockstore which is currently set to 17 sec.
426+
if (!force)
427+
{
428+
// Check if periodic flush is required.
429+
// Ideally this will flush less frequent and always be behind
430+
// blockstore which is currently set to 17 sec.
420431

421-
DateTime now = this.dateTimeProvider.GetUtcNow();
422-
bool flushTimeLimit = (now - this.lastCacheFlushTime).TotalSeconds >= this.CacheFlushTimeIntervalSeconds;
432+
DateTime now = this.dateTimeProvider.GetUtcNow();
433+
bool flushTimeLimit = (now - this.lastCacheFlushTime).TotalSeconds >= this.CacheFlushTimeIntervalSeconds;
423434

424-
// The size of the cache was reached and most likely TryEvictCacheLocked didn't work
425-
// so the cahces is pulledted with flushable items, then we flush anyway.
435+
// The size of the cache was reached and most likely TryEvictCacheLocked didn't work
436+
// so the cahces is pulledted with flushable items, then we flush anyway.
426437

427-
long totalBytes = this.cacheSizeBytes + this.rewindDataSizeBytes;
428-
bool flushSizeLimit = totalBytes > this.MaxCacheSizeBytes;
438+
long totalBytes = this.cacheSizeBytes + this.rewindDataSizeBytes;
439+
bool flushSizeLimit = totalBytes > this.MaxCacheSizeBytes;
429440

430-
if (!flushTimeLimit && !flushSizeLimit)
431-
{
432-
return;
433-
}
441+
if (!flushTimeLimit && !flushSizeLimit)
442+
{
443+
return;
444+
}
434445

435-
this.logger.LogDebug("Flushing, reasons flushTimeLimit={0} flushSizeLimit={1}.", flushTimeLimit, flushSizeLimit);
436-
}
446+
this.logger.LogDebug("Flushing, reasons flushTimeLimit={0} flushSizeLimit={1}.", flushTimeLimit, flushSizeLimit);
447+
}
437448

438-
// Before flushing the coinview persist the stake store
439-
// the stake store depends on the last block hash
440-
// to be stored after the stake store is persisted.
441-
if (this.stakeChainStore != null)
442-
this.stakeChainStore.Flush(true);
449+
// Before flushing the coinview persist the stake store
450+
// the stake store depends on the last block hash
451+
// to be stored after the stake store is persisted.
452+
if (this.stakeChainStore != null)
453+
this.stakeChainStore.Flush(true);
443454

444-
// Before flushing the coinview persist the rewind data index store as well.
445-
if (this.rewindDataIndexCache != null)
446-
this.rewindDataIndexCache.SaveAndEvict(this.blockHash.Height, null);
455+
// Before flushing the coinview persist the rewind data index store as well.
456+
if (this.rewindDataIndexCache != null)
457+
this.rewindDataIndexCache.SaveAndEvict(this.blockHash.Height, null);
447458

448-
if (this.innerBlockHash == null)
449-
this.innerBlockHash = this.coindb.GetTipHash();
459+
if (this.innerBlockHash == null)
460+
this.innerBlockHash = this.coindb.GetTipHash();
450461

451-
lock (this.lockobj)
452-
{
453462
if (this.innerBlockHash == null)
454463
{
455464
this.logger.LogTrace("(-)[NULL_INNER_TIP]");
@@ -476,10 +485,9 @@ public void Flush(bool force = true)
476485
this.cachedRewindData.Clear();
477486
this.rewindDataSizeBytes = 0;
478487
this.dirtyCacheCount = 0;
479-
this.innerBlockHash = this.blockHash;
488+
this.innerBlockHash = this.blockHash;
489+
this.lastCacheFlushTime = this.dateTimeProvider.GetUtcNow();
480490
}
481-
482-
this.lastCacheFlushTime = this.dateTimeProvider.GetUtcNow();
483491
}
484492

485493
/// <inheritdoc />
@@ -668,16 +676,16 @@ public void SaveChanges(IList<UnspentOutput> outputs, HashHeightPair oldBlockHas
668676

669677
public HashHeightPair Rewind(HashHeightPair target = null)
670678
{
671-
if (this.innerBlockHash == null)
679+
lock (this.lockobj)
672680
{
673-
this.innerBlockHash = this.coindb.GetTipHash();
674-
}
681+
if (this.innerBlockHash == null)
682+
{
683+
this.innerBlockHash = this.coindb.GetTipHash();
684+
}
675685

676-
// Flush the entire cache before rewinding
677-
this.Flush(true);
686+
// Flush the entire cache before rewinding
687+
this.Flush(true);
678688

679-
lock (this.lockobj)
680-
{
681689
HashHeightPair hash = this.coindb.Rewind(target);
682690

683691
foreach (KeyValuePair<OutPoint, CacheItem> cachedUtxoItem in this.cachedUtxoItems)
@@ -707,10 +715,13 @@ public HashHeightPair Rewind(HashHeightPair target = null)
707715
/// <inheritdoc />
708716
public RewindData GetRewindData(int height)
709717
{
710-
if (this.cachedRewindData.TryGetValue(height, out RewindData existingRewindData))
711-
return existingRewindData;
718+
lock (this.lockobj)
719+
{
720+
if (this.cachedRewindData.TryGetValue(height, out RewindData existingRewindData))
721+
return existingRewindData;
712722

713-
return this.coindb.GetRewindData(height);
723+
return this.coindb.GetRewindData(height);
724+
}
714725
}
715726

716727
[NoTrace]

src/Stratis.Bitcoin.Features.Consensus/CoinViews/CoinView.cs

Lines changed: 3 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -14,10 +14,8 @@ public interface ICoinView
1414
/// <summary>
1515
/// Initializes the coin view.
1616
/// </summary>
17-
/// <param name="chainTip">The chain tip.</param>
18-
/// <param name="chainIndexer">The chain indexer.</param>
19-
/// <param name="consensusRuleEngine">The consensus rule engine.</param>
20-
void Initialize(ChainedHeader chainTip, ChainIndexer chainIndexer, IConsensusRuleEngine consensusRuleEngine);
17+
/// <param name="consensusManager">The consensus manager.</param>
18+
void Initialize(IConsensusManager consensusManager);
2119

2220
/// <summary>
2321
/// Retrieves the block hash of the current tip of the coinview.
@@ -46,7 +44,7 @@ public interface ICoinView
4644
/// Brings the coinview back on-chain if a re-org occurred.
4745
/// </summary>
4846
/// <param name="chainIndexer">The current consensus chain.</param>
49-
void Sync(ChainIndexer chainIndexer);
47+
void Sync();
5048

5149
/// <summary>
5250
/// Obtains information about unspent outputs.

src/Stratis.Bitcoin.Features.Consensus/CoinViews/InMemoryCoinView.cs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -34,13 +34,13 @@ public InMemoryCoinView(HashHeightPair tipHash)
3434
}
3535

3636
/// <inheritdoc />
37-
public void Initialize(ChainedHeader chainTip, ChainIndexer chainIndexer, IConsensusRuleEngine consensusRuleEngine)
37+
public void Initialize(IConsensusManager consensusManager)
3838
{
3939
throw new NotImplementedException();
4040
}
4141

4242
/// <inheritdoc />
43-
public void Sync(ChainIndexer chainIndexer)
43+
public void Sync()
4444
{
4545
}
4646

src/Stratis.Bitcoin.Features.Consensus/Rules/CommonRules/LoadCoinviewRule.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,7 @@ public override Task RunAsync(RuleContext context)
2525
// unless the coinview threshold is reached.
2626
this.Logger.LogDebug("Saving coinview changes.");
2727
var utxoRuleContext = context as UtxoRuleContext;
28-
this.PowParent.UtxoSet.Sync(this.Parent.ChainIndexer);
28+
this.PowParent.UtxoSet.Sync();
2929
this.PowParent.UtxoSet.SaveChanges(utxoRuleContext.UnspentOutputSet.GetCoins(), new HashHeightPair(oldBlock), new HashHeightPair(nextBlock));
3030

3131
return Task.CompletedTask;

src/Stratis.Bitcoin.Features.Consensus/Rules/PosConsensusRuleEngine.cs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -48,9 +48,9 @@ public override RuleContext CreateRuleContext(ValidationContext validationContex
4848
}
4949

5050
/// <inheritdoc />
51-
public override void Initialize(ChainedHeader chainTip)
51+
public override void Initialize(ChainedHeader chainTip, IConsensusManager consensusManager)
5252
{
53-
base.Initialize(chainTip);
53+
base.Initialize(chainTip, consensusManager);
5454

5555
this.StakeChain.Load();
5656

src/Stratis.Bitcoin.Features.Consensus/Rules/PowConsensusRuleEngine.cs

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -63,11 +63,13 @@ public override Task<RewindState> RewindAsync(HashHeightPair target)
6363
}
6464

6565
/// <inheritdoc />
66-
public override void Initialize(ChainedHeader chainTip)
66+
public override void Initialize(ChainedHeader chainTip, IConsensusManager consensusManager)
6767
{
68-
base.Initialize(chainTip);
68+
base.Initialize(chainTip, consensusManager);
6969

70-
this.UtxoSet.Initialize(chainTip, this.ChainIndexer, this);
70+
Guard.Assert(chainTip.HashBlock == this.ChainIndexer.Tip.HashBlock);
71+
72+
this.UtxoSet.Initialize(consensusManager);
7173
}
7274

7375
public override async Task<ValidationContext> FullValidationAsync(ChainedHeader header, Block block)

src/Stratis.Bitcoin.Features.MemoryPool/MemPoolCoinView.cs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -50,13 +50,13 @@ public MempoolCoinView(Network network, ICoinView inner, ITxMempool memPool, Sch
5050
this.Set = new UnspentOutputSet();
5151
}
5252

53-
public void Initialize(ChainedHeader chainTip, ChainIndexer chainIndexer, IConsensusRuleEngine consensusRuleEngine)
53+
public void Initialize(IConsensusManager consensusManager)
5454
{
5555
throw new NotImplementedException();
5656
}
5757

5858
/// <inheritdoc />
59-
public void Sync(ChainIndexer chainIndexer)
59+
public void Sync()
6060
{
6161
}
6262

src/Stratis.Bitcoin.IntegrationTests/CoinViewTests.cs

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -73,7 +73,8 @@ public void TestCacheCoinView()
7373
ChainedHeader chained = this.MakeNext(genesisChainedHeader, ctx.Network);
7474
var dateTimeProvider = new DateTimeProvider();
7575

76-
var cacheCoinView = new CachedCoinView(this.network, ctx.Coindb, dateTimeProvider, this.loggerFactory, new NodeStats(dateTimeProvider, NodeSettings.Default(this.network), new Mock<IVersionProvider>().Object), new ConsensusSettings(new NodeSettings(this.network)));
76+
var cacheCoinView = new CachedCoinView(this.network, ctx.Coindb, dateTimeProvider, this.loggerFactory, new NodeStats(dateTimeProvider, NodeSettings.Default(this.network),
77+
new Mock<IVersionProvider>().Object), new ConsensusSettings(new NodeSettings(this.network)), new ChainIndexer(this.network));
7778

7879
cacheCoinView.SaveChanges(new UnspentOutput[] { new UnspentOutput(new OutPoint(genesis.Transactions[0], 0), new Coins(0, genesis.Transactions[0].Outputs.First(), true)) }, new HashHeightPair(genesisChainedHeader), new HashHeightPair(chained));
7980
Assert.NotNull(cacheCoinView.FetchCoins(new[] { new OutPoint(genesis.Transactions[0], 0) }).UnspentOutputs.Values.FirstOrDefault().Coins);
@@ -105,7 +106,8 @@ public void CanRewind()
105106
using (NodeContext nodeContext = NodeContext.Create(this))
106107
{
107108
var dateTimeProvider = new DateTimeProvider();
108-
var cacheCoinView = new CachedCoinView(this.network, nodeContext.Coindb, dateTimeProvider, this.loggerFactory, new NodeStats(dateTimeProvider, NodeSettings.Default(this.network), new Mock<IVersionProvider>().Object), new ConsensusSettings(new NodeSettings(this.network)));
109+
var cacheCoinView = new CachedCoinView(this.network, nodeContext.Coindb, dateTimeProvider, this.loggerFactory, new NodeStats(dateTimeProvider, NodeSettings.Default(this.network),
110+
new Mock<IVersionProvider>().Object), new ConsensusSettings(new NodeSettings(this.network)), new ChainIndexer(this.network));
109111
var tester = new CoinViewTester(cacheCoinView);
110112

111113
List<(Coins, OutPoint)> coinsA = tester.CreateCoins(5);

0 commit comments

Comments
 (0)