Skip to content

Commit d76fed1

Browse files
asdacapbenaadams
andauthored
Feature/range receipt migration (#8047)
Co-authored-by: Ben Adams <thundercat@illyriad.co.uk>
1 parent b41fda7 commit d76fed1

File tree

12 files changed

+70
-84
lines changed

12 files changed

+70
-84
lines changed

src/Nethermind/Nethermind.Blockchain/Receipts/IReceiptsMigration.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,6 @@ namespace Nethermind.Blockchain.Receipts
77
{
88
public interface IReceiptsMigration
99
{
10-
Task<bool> Run(long blockNumber);
10+
Task<bool> Run(long from, long to);
1111
}
1212
}

src/Nethermind/Nethermind.Core.Test/ProgressLoggerTests.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -168,7 +168,7 @@ public void Print_Progress()
168168

169169
measuredProgress.LogProgress();
170170

171-
iLogger.Received(1).Info("Progress 1 / 100 ( 0.99 %) [⡆ ] queue 99 | skipped 90 Blk/s | current 10 Blk/s");
171+
iLogger.Received(1).Info("Progress 1 / 100 ( 1.00 %) [⡆ ] queue 99 | skipped 90 Blk/s | current 10 Blk/s");
172172
}
173173

174174
private ProgressLogger CreateProgress()

src/Nethermind/Nethermind.Core/ProgressLogger.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -179,7 +179,7 @@ private string DefaultFormatter()
179179

180180
private static string GenerateReport(string prefix, long current, long total, long queue, decimal speed, decimal skippedPerSecond)
181181
{
182-
float percentage = Math.Clamp(current / (float)(total + 1), 0, 1);
182+
float percentage = Math.Clamp(current / (float)(Math.Max(total, 1)), 0, 1);
183183
string queuedStr = (queue >= 0 ? $" queue {queue,QueuePaddingLength:N0} | " : " ");
184184
string skippedStr = (skippedPerSecond >= 0 ? $"skipped {skippedPerSecond,SkippedPaddingLength:N0} Blk/s | " : "");
185185
string speedStr = $"current {speed,SpeedPaddingLength:N0} Blk/s";

src/Nethermind/Nethermind.Init/Steps/Migrations/BloomMigration.cs

Lines changed: 1 addition & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -54,14 +54,7 @@ public async Task Run(CancellationToken cancellationToken)
5454
{
5555
if (_bloomConfig.Migration)
5656
{
57-
if (!CanMigrate(_api.SyncModeSelector.Current))
58-
{
59-
await Wait.ForEventCondition<SyncModeChangedEventArgs>(
60-
cancellationToken,
61-
(d) => _api.SyncModeSelector.Changed += d,
62-
(d) => _api.SyncModeSelector.Changed -= d,
63-
(arg) => CanMigrate(arg.Current));
64-
}
57+
await _api.SyncModeSelector.WaitUntilMode(CanMigrate, cancellationToken);
6558

6659
_stopwatch = Stopwatch.StartNew();
6760
try

src/Nethermind/Nethermind.Init/Steps/Migrations/ReceiptMigration.cs

Lines changed: 41 additions & 60 deletions
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,6 @@
1414
using Nethermind.Blockchain.Receipts;
1515
using Nethermind.Core;
1616
using Nethermind.Core.Crypto;
17-
using Nethermind.Core.Events;
1817
using Nethermind.Core.Extensions;
1918
using Nethermind.Db;
2019
using Nethermind.Int256;
@@ -33,8 +32,6 @@ public class ReceiptMigration : IDatabaseMigration, IReceiptsMigration
3332
private readonly ILogger _logger;
3433
private CancellationTokenSource? _cancellationTokenSource;
3534
internal Task? _migrationTask;
36-
private Stopwatch? _stopwatch;
37-
private long _toBlock;
3835

3936
private readonly ProgressLogger _progressLogger;
4037
[NotNull]
@@ -89,13 +86,24 @@ ILogManager logManager
8986
_progressLogger = new ProgressLogger("Receipts migration", logManager);
9087
}
9188

92-
public async Task<bool> Run(long blockNumber)
89+
// Actually start running it.
90+
public async Task<bool> Run(long from, long to)
9391
{
9492
_cancellationTokenSource?.Cancel();
95-
await (_migrationTask ?? Task.CompletedTask);
93+
try
94+
{
95+
await (_migrationTask ?? Task.CompletedTask);
96+
}
97+
catch (OperationCanceledException)
98+
{
99+
}
100+
96101
_cancellationTokenSource = new CancellationTokenSource();
97-
_receiptStorage.MigratedBlockNumber = Math.Min(Math.Max(_receiptStorage.MigratedBlockNumber, blockNumber), (_blockTree.Head?.Number ?? 0) + 1);
98-
_migrationTask = DoRun(_cancellationTokenSource.Token);
102+
_migrationTask = Task.Run(async () =>
103+
{
104+
await _syncModeSelector.WaitUntilMode(CanMigrate, _cancellationTokenSource.Token);
105+
RunMigration(from, to, false, _cancellationTokenSource.Token);
106+
});
99107
return _receiptConfig.StoreReceipts && _receiptConfig.ReceiptsMigration;
100108
}
101109
public async Task Run(CancellationToken cancellationToken)
@@ -105,25 +113,9 @@ public async Task Run(CancellationToken cancellationToken)
105113
if (_receiptConfig.ReceiptsMigration)
106114
{
107115
ResetMigrationIndexIfNeeded();
108-
await DoRun(cancellationToken);
109-
}
110-
}
111-
}
112-
113-
private async Task DoRun(CancellationToken cancellationToken)
114-
{
115-
if (_receiptConfig.StoreReceipts)
116-
{
117-
if (!CanMigrate(_syncModeSelector.Current))
118-
{
119-
await Wait.ForEventCondition<SyncModeChangedEventArgs>(
120-
cancellationToken,
121-
(e) => _syncModeSelector.Changed += e,
122-
(e) => _syncModeSelector.Changed -= e,
123-
(arg) => CanMigrate(arg.Current));
116+
await _syncModeSelector.WaitUntilMode(CanMigrate, cancellationToken);
117+
RunIfNeeded(cancellationToken);
124118
}
125-
126-
RunIfNeeded(cancellationToken);
127119
}
128120
}
129121

@@ -137,21 +129,16 @@ private void RunIfNeeded(CancellationToken cancellationToken)
137129
? _blockTree.Head?.Number ?? 0
138130
: _blockTree.BestKnownNumber
139131
: _receiptStorage.MigratedBlockNumber - 1;
140-
_toBlock = migrateToBlockNumber;
141-
142-
_logger.Warn($"Running migration to {_toBlock}");
143132

144-
if (_toBlock > 0)
133+
if (migrateToBlockNumber > 0)
145134
{
146-
_stopwatch = Stopwatch.StartNew();
147135
try
148136
{
149-
RunMigration(cancellationToken);
137+
RunMigration(0, migrateToBlockNumber, true, cancellationToken);
150138
}
151139
catch (Exception e)
152140
{
153-
_stopwatch.Stop();
154-
_logger.Error(GetLogMessage("failed", $"Error: {e}"), e);
141+
_logger.Error("Error running receipt migration", e);
155142
}
156143
}
157144
else
@@ -160,19 +147,20 @@ private void RunIfNeeded(CancellationToken cancellationToken)
160147
}
161148
}
162149

163-
private void RunMigration(CancellationToken token)
150+
private void RunMigration(long from, long to, bool updateReceiptMigrationPointer, CancellationToken token)
164151
{
165-
long synced = 1;
152+
from = Math.Min(from, to);
153+
long synced = 0;
166154

167-
_progressLogger.Reset(synced, _toBlock);
155+
if (_logger.IsWarn) _logger.Warn($"Running migration from {from} to {to}");
168156

169-
if (_logger.IsInfo) _logger.Info(GetLogMessage("started"));
157+
_progressLogger.Reset(synced, to - from + 1);
170158

171159
using Timer timer = new(1000);
172160
timer.Enabled = true;
173161
timer.Elapsed += (_, _) =>
174162
{
175-
if (_logger.IsInfo) _logger.Info(GetLogMessage("in progress"));
163+
_progressLogger.LogProgress();
176164
};
177165

178166
try
@@ -183,7 +171,8 @@ private void RunMigration(CancellationToken token)
183171
parallelism = Environment.ProcessorCount;
184172
}
185173

186-
GetBlockBodiesForMigration(token).AsParallel().WithDegreeOfParallelism(parallelism).ForAll((item) =>
174+
GetBlockBodiesForMigration(from, to, updateReceiptMigrationPointer, token)
175+
.AsParallel().WithDegreeOfParallelism(parallelism).ForAll((item) =>
187176
{
188177
(long blockNum, Hash256 blockHash) = item;
189178
Block? block = _blockTree.FindBlock(blockHash!, BlockTreeLookupOptions.None);
@@ -204,30 +193,29 @@ private void RunMigration(CancellationToken token)
204193

205194
if (!token.IsCancellationRequested)
206195
{
207-
if (_logger.IsInfo) _logger.Info(GetLogMessage("Compacting receipts database"));
196+
if (_logger.IsInfo) _logger.Info("Compacting receipts database");
208197
_receiptsDb.Compact();
209-
if (_logger.IsInfo) _logger.Info(GetLogMessage("Compacting receipts tx index database"));
198+
if (_logger.IsInfo) _logger.Info("Compacting receipts tx index database");
210199
_txIndexDb.Compact();
211-
if (_logger.IsInfo) _logger.Info(GetLogMessage("Compacting receipts block database"));
200+
if (_logger.IsInfo) _logger.Info("Compacting receipts block database");
212201
_receiptsBlockDb.Compact();
213202
}
214203
}
215204
finally
216205
{
217206
_progressLogger.MarkEnd();
218-
_stopwatch?.Stop();
219207
timer.Stop();
220208
}
221209

222210
if (!token.IsCancellationRequested)
223211
{
224-
if (_logger.IsInfo) _logger.Info(GetLogMessage("finished"));
212+
if (_logger.IsInfo) _logger.Info("Receipt migration finished");
225213
}
226214
}
227215

228216
Block GetMissingBlock(long i, Hash256? blockHash)
229217
{
230-
if (_logger.IsDebug) _logger.Debug(GetLogMessage("warning", $"Block {i} not found. Logs will not be searchable for this block."));
218+
if (_logger.IsDebug) _logger.Debug($"Block {i} not found. Logs will not be searchable for this block.");
231219
Block emptyBlock = EmptyBlock.Get();
232220
emptyBlock.Header.Number = i;
233221
emptyBlock.Header.Hash = blockHash;
@@ -239,7 +227,7 @@ static void ReturnMissingBlock(Block emptyBlock)
239227
EmptyBlock.Return(emptyBlock);
240228
}
241229

242-
IEnumerable<(long, Hash256)> GetBlockBodiesForMigration(CancellationToken token)
230+
IEnumerable<(long, Hash256)> GetBlockBodiesForMigration(long from, long to, bool updateReceiptMigrationPointer, CancellationToken token)
243231
{
244232
bool TryGetMainChainBlockHashFromLevel(long number, out Hash256? blockHash)
245233
{
@@ -266,11 +254,11 @@ bool TryGetMainChainBlockHashFromLevel(long number, out Hash256? blockHash)
266254
}
267255
}
268256

269-
for (long i = _toBlock - 1; i > 0; i--)
257+
for (long i = to; i >= from; i--)
270258
{
271259
if (token.IsCancellationRequested)
272260
{
273-
if (_logger.IsInfo) _logger.Info(GetLogMessage("cancelled"));
261+
if (_logger.IsInfo) _logger.Info("Receipt migration cancelled");
274262
yield break;
275263
}
276264

@@ -279,7 +267,7 @@ bool TryGetMainChainBlockHashFromLevel(long number, out Hash256? blockHash)
279267
yield return (i, blockHash!);
280268
}
281269

282-
if (_receiptStorage.MigratedBlockNumber > i)
270+
if (updateReceiptMigrationPointer && _receiptStorage.MigratedBlockNumber > i)
283271
{
284272
_receiptStorage.MigratedBlockNumber = i;
285273
}
@@ -295,11 +283,12 @@ private void MigrateBlock(Block block)
295283

296284
if (notNullReceipts.Length == 0) return;
297285

286+
// This should set the new rlp and tx index depending on config.
298287
_receiptStorage.Insert(block, notNullReceipts);
299288

300-
// I guess some old schema need this
289+
// It used to be that the tx index is stored in the default column so we are moving it into transactions column
301290
{
302-
using IWriteBatch writeBatch = _receiptsDb.StartWriteBatch().GetColumnBatch(ReceiptsColumns.Transactions);
291+
using IWriteBatch writeBatch = _receiptsDb.StartWriteBatch().GetColumnBatch(ReceiptsColumns.Default);
303292
for (int i = 0; i < notNullReceipts.Length; i++)
304293
{
305294
writeBatch[notNullReceipts[i].TxHash!.Bytes] = null;
@@ -324,8 +313,7 @@ private void MigrateBlock(Block block)
324313
if (notNullReceipts.Length != receipts.Length)
325314
{
326315
if (_logger.IsWarn)
327-
_logger.Warn(GetLogMessage("warning",
328-
$"Block {block.ToString(Block.Format.FullHashAndNumber)} is missing {receipts.Length - notNullReceipts.Length} of {receipts.Length} receipts!"));
316+
_logger.Warn($"Block {block.ToString(Block.Format.FullHashAndNumber)} is missing {receipts.Length - notNullReceipts.Length} of {receipts.Length} receipts!");
329317
}
330318
}
331319

@@ -382,13 +370,6 @@ private bool IsMigrationNeeded(long blockNumber, Hash256 blockHash, TxReceipt[]
382370
return _receiptConfig.CompactReceiptStore != isCompactEncoding;
383371
}
384372

385-
private string GetLogMessage(string status, string? suffix = null)
386-
{
387-
string message = $"ReceiptsDb migration {status} | {_stopwatch?.Elapsed:d\\:hh\\:mm\\:ss} | {_progressLogger.CurrentValue.ToString().PadLeft(_toBlock.ToString().Length)} / {_toBlock} blocks migrated. | current {_progressLogger.CurrentPerSecond:F2} Blk/s | total {_progressLogger.TotalPerSecond:F2} Blk/s. {suffix}";
388-
_progressLogger.SetMeasuringPoint();
389-
return message;
390-
}
391-
392373
private class EmptyBlockObjectPolicy : IPooledObjectPolicy<Block>
393374
{
394375
public Block Create()

src/Nethermind/Nethermind.JsonRpc.Test/Modules/DebugModuleTests.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -392,7 +392,7 @@ public void Debug_traceCall_test()
392392
[Test]
393393
public async Task Migrate_receipts()
394394
{
395-
debugBridge.MigrateReceipts(Arg.Any<long>()).Returns(true);
395+
debugBridge.MigrateReceipts(Arg.Any<long>(), Arg.Any<long>()).Returns(true);
396396
IDebugRpcModule rpcModule = new DebugRpcModule(LimboLogs.Instance, debugBridge, jsonRpcConfig, specProvider);
397397
string response = await RpcTest.TestSerializedRequest(rpcModule, "debug_migrateReceipts", 100);
398398
Assert.That(response, Is.Not.Null);

src/Nethermind/Nethermind.JsonRpc/Modules/DebugModule/DebugBridge.cs

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -91,8 +91,7 @@ public DebugBridge(
9191

9292
public void UpdateHeadBlock(Hash256 blockHash) => _blockTree.UpdateHeadBlock(blockHash);
9393

94-
public Task<bool> MigrateReceipts(long blockNumber)
95-
=> _receiptsMigration.Run(blockNumber + 1); // add 1 to make go from inclusive (better for API) to exclusive (better for internal)
94+
public Task<bool> MigrateReceipts(long from, long to) => _receiptsMigration.Run(from, to);
9695

9796
public void InsertReceipts(BlockParameter blockParameter, TxReceipt[] txReceipts)
9897
{

src/Nethermind/Nethermind.JsonRpc/Modules/DebugModule/DebugRpcModule.cs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -145,8 +145,8 @@ public ResultWrapper<GethLikeTxTrace> debug_traceTransactionInBlockByIndex(byte[
145145
return ResultWrapper<GethLikeTxTrace>.Success(transactionTrace);
146146
}
147147

148-
public async Task<ResultWrapper<bool>> debug_migrateReceipts(long blockNumber) =>
149-
ResultWrapper<bool>.Success(await _debugBridge.MigrateReceipts(blockNumber));
148+
public async Task<ResultWrapper<bool>> debug_migrateReceipts(long from, long to) =>
149+
ResultWrapper<bool>.Success(await _debugBridge.MigrateReceipts(from, to));
150150

151151
public Task<ResultWrapper<bool>> debug_insertReceipts(BlockParameter blockParameter, ReceiptForRpc[] receiptForRpc)
152152
{

src/Nethermind/Nethermind.JsonRpc/Modules/DebugModule/IDebugBridge.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -31,7 +31,7 @@ public interface IDebugBridge
3131
ChainLevelInfo GetLevelInfo(long number);
3232
int DeleteChainSlice(long startNumber, bool force = false);
3333
void UpdateHeadBlock(Hash256 blockHash);
34-
Task<bool> MigrateReceipts(long blockNumber);
34+
Task<bool> MigrateReceipts(long from, long to);
3535
void InsertReceipts(BlockParameter blockParameter, TxReceipt[] receipts);
3636
SyncReportSymmary GetCurrentSyncStage();
3737
IEnumerable<string> TraceBlockToFile(Hash256 blockHash, CancellationToken cancellationToken, GethTraceOptions? gethTraceOptions = null);

src/Nethermind/Nethermind.JsonRpc/Modules/DebugModule/IDebugRpcModule.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -85,7 +85,7 @@ public interface IDebugRpcModule : IRpcModule
8585
ResultWrapper<GethLikeTxTrace> debug_traceTransactionInBlockByIndex(byte[] blockRlp, int txIndex, GethTraceOptions options = null);
8686

8787
[JsonRpcMethod(Description = "Sets the block number up to which receipts will be migrated to (Nethermind specific).")]
88-
Task<ResultWrapper<bool>> debug_migrateReceipts(long blockNumber);
88+
Task<ResultWrapper<bool>> debug_migrateReceipts(long from, long to);
8989

9090
[JsonRpcMethod(Description = "Insert receipts for the block after verifying receipts root correctness.")]
9191
Task<ResultWrapper<bool>> debug_insertReceipts(BlockParameter blockParameter, ReceiptForRpc[] receiptForRpc);

src/Nethermind/Nethermind.Runner.Test/Ethereum/Steps/Migrations/ReceiptMigrationTests.cs

Lines changed: 5 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,6 @@
2323

2424
namespace Nethermind.Runner.Test.Ethereum.Steps.Migrations
2525
{
26-
[TestFixture]
2726
public class ReceiptMigrationTests
2827
{
2928
[TestCase(null, 0, false, false, false, false)] // No change to migrate
@@ -71,6 +70,7 @@ public async Task RunMigration(int? commandStartBlockNumber, long currentMigrate
7170
TestMemColumnsDb<ReceiptsColumns> receiptColumnDb = new();
7271
TestMemDb blocksDb = (TestMemDb)receiptColumnDb.GetColumnDb(ReceiptsColumns.Blocks);
7372
TestMemDb txDb = (TestMemDb)receiptColumnDb.GetColumnDb(ReceiptsColumns.Transactions);
73+
TestMemDb defaultDb = (TestMemDb)receiptColumnDb.GetColumnDb(ReceiptsColumns.Default);
7474

7575
// Put the last block receipt encoding
7676
Block lastBlock = blockTree.FindBlock(chainLength - 1);
@@ -93,21 +93,20 @@ public async Task RunMigration(int? commandStartBlockNumber, long currentMigrate
9393

9494
if (commandStartBlockNumber.HasValue)
9595
{
96-
_ = migration.Run(commandStartBlockNumber.Value);
96+
_ = migration.Run(0, commandStartBlockNumber.Value);
9797
await migration._migrationTask!;
9898
}
9999
else
100100
{
101101
await migration.Run(CancellationToken.None);
102+
Assert.That(() => outMemoryReceiptStorage.MigratedBlockNumber, Is.InRange(0, 1).After(1000, 10));
102103
}
103104

104-
Assert.That(() => outMemoryReceiptStorage.MigratedBlockNumber, Is.InRange(0, 1).After(1000, 10));
105-
106105
if (wasMigrated)
107106
{
108-
int blockNum = (commandStartBlockNumber ?? chainLength) - 1 - 1;
107+
int blockNum = commandStartBlockNumber ?? (chainLength - 1);
109108
int txCount = blockNum * 2;
110-
txDb.KeyWasWritten((item => item.Item2 is null), txCount);
109+
defaultDb.KeyWasWritten((item => item.Item2 is null), txCount);
111110
((TestMemDb)receiptColumnDb.GetColumnDb(ReceiptsColumns.Blocks)).KeyWasRemoved((_ => true), blockNum);
112111
outMemoryReceiptStorage.Count.Should().Be(txCount);
113112
}

0 commit comments

Comments
 (0)