Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Feature/debug get bad blocks #3838

Merged
merged 24 commits into from
Jan 5, 2024
Merged
Show file tree
Hide file tree
Changes from 14 commits
Commits
Show all changes
24 commits
Select commit Hold shift + click to select a range
2827e52
Added debug_getBadBlocks implementation.
kjazgar Feb 17, 2022
cfb4c4d
Added method implementation.
kjazgar Feb 18, 2022
c6b7d11
Added test.
kjazgar Feb 21, 2022
4665b25
Added logger with first invalid block information.
kjazgar Mar 14, 2022
8351e82
remove rlp logging
LukaszRozmej Mar 25, 2022
f947e72
remove merge markers
Nov 7, 2023
43b0ede
update old PR so it compiles
Nov 9, 2023
86bd281
cleanup test
Nov 10, 2023
a9fbbd1
cleanup and use BlockTreeBuilder
Nov 16, 2023
d31a48a
Remove one ToArray
LukaszRozmej Nov 27, 2023
ebb12ec
fix whitespace
Marchhill Nov 27, 2023
bf40f5e
persist bad blocks to disk
Marchhill Dec 4, 2023
88aa8f0
Merge branch 'feature/debug_getBadBlocks' of github.com:NethermindEth…
Marchhill Dec 4, 2023
451eb1e
fix benchmarks
Marchhill Dec 7, 2023
49f0c00
convert Block arrays to IEnumerable<Block>
Marchhill Dec 11, 2023
a41ae7d
limit size of bad blocks db
Marchhill Dec 11, 2023
0320ed4
make number of bad blocks stored configurable
Marchhill Dec 11, 2023
1f23635
delete oldest blocks
Marchhill Dec 11, 2023
5d0635a
remove GetInvalidBlocks from BlockTree
LukaszRozmej Dec 12, 2023
0e5724c
respond to comments
Marchhill Dec 12, 2023
43b521d
Merge branch 'feature/debug_getBadBlocks_refactor' of github.com:Neth…
Marchhill Dec 12, 2023
4ea54c5
Merge branch 'master' of github.com:NethermindEth/nethermind into fea…
Marchhill Dec 12, 2023
ddc220e
fix test
Marchhill Dec 12, 2023
b6a9e64
Merge remote-tracking branch 'upstream/master' into feature/debug_get…
Marchhill Jan 5, 2024
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 6 additions & 0 deletions src/Nethermind/Nethermind.Blockchain/BlockTree.cs
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,7 @@ public partial class BlockTree : IBlockTree
private readonly IHeaderStore _headerStore;
private readonly IDb _blockInfoDb;
private readonly IDb _metadataDb;
private readonly IBlockStore _badBlockStore;

private readonly LruCache<ValueHash256, Block> _invalidBlocks =
new(128, 128, "invalid blocks");
Expand Down Expand Up @@ -110,6 +111,7 @@ public BlockTree(
IHeaderStore? headerDb,
IDb? blockInfoDb,
IDb? metadataDb,
IBlockStore? badBlockStore,
IChainLevelInfoRepository? chainLevelInfoRepository,
ISpecProvider? specProvider,
IBloomStorage? bloomStorage,
Expand All @@ -121,6 +123,7 @@ public BlockTree(
_headerStore = headerDb ?? throw new ArgumentNullException(nameof(headerDb));
_blockInfoDb = blockInfoDb ?? throw new ArgumentNullException(nameof(blockInfoDb));
_metadataDb = metadataDb ?? throw new ArgumentNullException(nameof(metadataDb));
_badBlockStore = badBlockStore ?? throw new ArgumentNullException(nameof(badBlockStore));
_specProvider = specProvider ?? throw new ArgumentNullException(nameof(specProvider));
_bloomStorage = bloomStorage ?? throw new ArgumentNullException(nameof(bloomStorage));
_syncConfig = syncConfig ?? throw new ArgumentNullException(nameof(syncConfig));
Expand Down Expand Up @@ -710,6 +713,7 @@ public void DeleteInvalidBlock(Block invalidBlock)
if (_logger.IsDebug) _logger.Debug($"Deleting invalid block {invalidBlock.ToString(Block.Format.FullHashAndNumber)}");

_invalidBlocks.Set(invalidBlock.Hash, invalidBlock);
_badBlockStore.Insert(invalidBlock);

BestSuggestedHeader = Head?.Header;
BestSuggestedBody = Head;
Expand Down Expand Up @@ -1607,5 +1611,7 @@ public void ForkChoiceUpdated(Hash256? finalizedBlockHash, Hash256? safeBlockHas
_metadataDb.Set(MetadataDbKeys.SafeBlockHash, Rlp.Encode(SafeHash!).Bytes);
}
}

public Block[] GetInvalidBlocks() => _badBlockStore.GetAll();
Marchhill marked this conversation as resolved.
Show resolved Hide resolved
}
}
6 changes: 6 additions & 0 deletions src/Nethermind/Nethermind.Blockchain/Blocks/BlockStore.cs
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@

using System;
using System.Buffers;
using System.Linq;
using Nethermind.Core;
using Nethermind.Core.Caching;
using Nethermind.Core.Crypto;
Expand Down Expand Up @@ -88,4 +89,9 @@ public void Cache(Block block)
{
_blockCache.Set(block.Hash, block);
}

public Block[] GetAll()
{
return _blockDb.GetAllValues(true).Select(bytes => _blockDecoder.Decode(bytes.AsRlpStream())).ToArray();
}
Marchhill marked this conversation as resolved.
Show resolved Hide resolved
}
1 change: 1 addition & 0 deletions src/Nethermind/Nethermind.Blockchain/Blocks/IBlockStore.cs
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ public interface IBlockStore
void Insert(Block block, WriteFlags writeFlags = WriteFlags.None);
void Delete(long blockNumber, Hash256 blockHash);
Block? Get(long blockNumber, Hash256 blockHash, bool shouldCache = true);
Block[] GetAll();
ReceiptRecoveryBlock? GetReceiptRecoveryBlock(long blockNumber, Hash256 blockHash);
void Cache(Block block);

Expand Down
2 changes: 2 additions & 0 deletions src/Nethermind/Nethermind.Blockchain/IBlockTree.cs
Original file line number Diff line number Diff line change
Expand Up @@ -179,6 +179,8 @@ AddBlockResult Insert(Block block, BlockTreeInsertBlockOptions insertBlockOption

int DeleteChainSlice(in long startNumber, long? endNumber = null, bool force = false);

public Block[] GetInvalidBlocks();

bool IsBetterThanHead(BlockHeader? header);

void UpdateBeaconMainChain(BlockInfo[]? blockInfos, long clearBeaconMainChainStartPoint);
Expand Down
4 changes: 4 additions & 0 deletions src/Nethermind/Nethermind.Blockchain/ReadOnlyBlockTree.cs
Original file line number Diff line number Diff line change
Expand Up @@ -151,6 +151,10 @@ public event EventHandler<OnUpdateMainChainArgs>? OnUpdateMainChain
add { }
remove { }
}
public Block[] GetInvalidBlocks()
{
return _wrapped.GetInvalidBlocks();
}

public int DeleteChainSlice(in long startNumber, long? endNumber = null, bool force = false)
{
Expand Down
21 changes: 21 additions & 0 deletions src/Nethermind/Nethermind.Core.Test/Builders/BlockTreeBuilder.cs
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,7 @@ public BlockTreeBuilder(Block genesisBlock, ISpecProvider specProvider)
BlockNumbersDb = new TestMemDb();
BlockInfoDb = new TestMemDb();
MetadataDb = new TestMemDb();
BadBlocksDb = new TestMemDb();

_genesisBlock = genesisBlock;
_specProvider = specProvider;
Expand Down Expand Up @@ -79,6 +80,7 @@ public BlockTree BlockTree
HeaderStore,
BlockInfoDb,
MetadataDb,
BadBlockStore,
ChainLevelInfoRepository,
_specProvider,
BloomStorage,
Expand All @@ -105,6 +107,7 @@ protected override void BeforeReturn()
public ISyncConfig SyncConfig { get; set; } = new SyncConfig();

public IDb BlocksDb { get; set; }
public IDb BadBlocksDb { get; set; }

private IBlockStore? _blockStore;
public IBlockStore BlockStore
Expand Down Expand Up @@ -139,6 +142,18 @@ public IHeaderStore HeaderStore

public IDb MetadataDb { get; set; }

private IBlockStore? _badBlockStore;
public IBlockStore BadBlockStore
{
get
{
return _badBlockStore ??= new BlockStore(BadBlocksDb);
}
set
{
_badBlockStore = value;
}
}
private IChainLevelInfoRepository? _chainLevelInfoRepository;

public IChainLevelInfoRepository ChainLevelInfoRepository
Expand Down Expand Up @@ -384,6 +399,12 @@ public BlockTreeBuilder WithBlockStore(IBlockStore blockStore)
return this;
}

public BlockTreeBuilder WithHeaderStore(IHeaderStore headerStore)
{
HeaderStore = headerStore;
return this;
}

public BlockTreeBuilder WithBlocksDb(IDb blocksDb)
{
BlocksDb = blocksDb;
Expand Down
13 changes: 13 additions & 0 deletions src/Nethermind/Nethermind.Core/Caching/LruCache.cs
Original file line number Diff line number Diff line change
Expand Up @@ -133,6 +133,19 @@ public KeyValuePair<TKey, TValue>[] ToArray()
return array;
}

[MethodImpl(MethodImplOptions.Synchronized)]
public TValue[] GetValues()
{
int i = 0;
TValue[] array = new TValue[_cacheMap.Count];
foreach (KeyValuePair<TKey, LinkedListNode<LruCacheItem>> kvp in _cacheMap)
{
array[i++] = kvp.Value.Value.Value;
}

return array;
}

private void Replace(TKey key, TValue value)
{
LinkedListNode<LruCacheItem>? node = _leastRecentlyUsed;
Expand Down
1 change: 1 addition & 0 deletions src/Nethermind/Nethermind.Db/DbNames.cs
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ public static class DbNames
public const string BlockNumbers = "blockNumbers";
public const string Receipts = "receipts";
public const string BlockInfos = "blockInfos";
public const string BadBlocks = "badBlocks";
public const string Bloom = "bloom";
public const string Witness = "witness";
public const string CHT = "canonicalHashTrie";
Expand Down
1 change: 1 addition & 0 deletions src/Nethermind/Nethermind.Db/IDbProvider.cs
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ public interface IDbProvider : IDisposable
public IDb HeadersDb => GetDb<IDb>(DbNames.Headers);
public IDb BlockNumbersDb => GetDb<IDb>(DbNames.BlockNumbers);
public IDb BlockInfosDb => GetDb<IDb>(DbNames.BlockInfos);
public IDb BadBlocksDb => GetDb<IDb>(DbNames.BadBlocks);

// BloomDB progress / config (does not contain blooms - they are kept in bloom storage)
public IDb BloomDb => GetDb<IDb>(DbNames.Bloom);
Expand Down
8 changes: 8 additions & 0 deletions src/Nethermind/Nethermind.Db/Metrics.cs
Original file line number Diff line number Diff line change
Expand Up @@ -126,6 +126,14 @@ public static class Metrics
[Description("Number of Metadata DB writes.")]
public static long MetadataDbWrites { get; set; }

[CounterMetric]
[Description("Number of BadBlocks DB writes.")]
public static long BadBlocksDbWrites { get; set; }

[CounterMetric]
[Description("Number of BadBlocks DB reads.")]
public static long BadBlocksDbReads { get; set; }

[CounterMetric]
[Description("Number of BlobTransactions DB reads.")]
public static long BlobTransactionsDbReads { get; set; }
Expand Down
1 change: 1 addition & 0 deletions src/Nethermind/Nethermind.Db/StandardDbInitializer.cs
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,7 @@ private void RegisterAll(bool useReceiptsDb, bool useBlobsDb)
RegisterDb(BuildRocksDbSettings(DbNames.Headers, () => Metrics.HeaderDbReads++, () => Metrics.HeaderDbWrites++));
RegisterDb(BuildRocksDbSettings(DbNames.BlockNumbers, () => Metrics.BlockNumberDbReads++, () => Metrics.BlockNumberDbWrites++));
RegisterDb(BuildRocksDbSettings(DbNames.BlockInfos, () => Metrics.BlockInfosDbReads++, () => Metrics.BlockInfosDbWrites++));
RegisterDb(BuildRocksDbSettings(DbNames.BadBlocks, () => Metrics.BadBlocksDbReads++, () => Metrics.BadBlocksDbWrites++));

RocksDbSettings stateDbSettings = BuildRocksDbSettings(DbNames.State, () => Metrics.StateDbReads++, () => Metrics.StateDbWrites++);
RegisterCustomDb(DbNames.State, () => new FullPruningDb(
Expand Down
2 changes: 2 additions & 0 deletions src/Nethermind/Nethermind.Init/Steps/InitializeBlockTree.cs
Original file line number Diff line number Diff line change
Expand Up @@ -52,12 +52,14 @@ public Task Execute(CancellationToken cancellationToken)

IBlockStore blockStore = new BlockStore(_get.DbProvider.BlocksDb);
IHeaderStore headerStore = new HeaderStore(_get.DbProvider.HeadersDb, _get.DbProvider.BlockNumbersDb);
IBlockStore badBlockStore = new BlockStore(_get.DbProvider.BadBlocksDb);

IBlockTree blockTree = _set.BlockTree = new BlockTree(
blockStore,
headerStore,
_get.DbProvider.BlockInfosDb,
_get.DbProvider.MetadataDb,
badBlockStore,
chainLevelInfoRepository,
_get.SpecProvider,
bloomStorage,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -71,6 +71,7 @@ public void GlobalSetup()
new HeaderStore(dbProvider.HeadersDb, dbProvider.BlockNumbersDb),
dbProvider.BlockInfosDb,
dbProvider.MetadataDb,
new BlockStore(dbProvider.BadBlocksDb),
chainLevelInfoRepository,
specProvider,
NullBloomStorage.Instance,
Expand Down
52 changes: 52 additions & 0 deletions src/Nethermind/Nethermind.JsonRpc.Test/Modules/DebugModuleTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -7,19 +7,31 @@
using System.Threading;
using System.Threading.Tasks;
using FluentAssertions;
using Nethermind.Blockchain;
using Nethermind.Blockchain.Blocks;
using Nethermind.Blockchain.Headers;
using Nethermind.Blockchain.Find;
using Nethermind.Blockchain.Synchronization;
using Nethermind.Config;
using Nethermind.Core;
using Nethermind.Core.Caching;
using Nethermind.Core.Crypto;
using Nethermind.Core.Extensions;
using Nethermind.Core.Test.Builders;
using Nethermind.Db;
using Nethermind.Db.Blooms;
using Nethermind.Evm.Tracing;
using Nethermind.Evm.Tracing.GethStyle;
using Nethermind.Int256;
using Nethermind.JsonRpc.Data;
using Nethermind.JsonRpc.Modules.DebugModule;
using Nethermind.Logging;
using Nethermind.Serialization.Rlp;
using Nethermind.Specs;
using Nethermind.State.Repositories;
using NSubstitute;
using NUnit.Framework;
using NSubstitute.ReturnsExtensions;

namespace Nethermind.JsonRpc.Test.Modules;

Expand All @@ -29,6 +41,7 @@ public class DebugModuleTests
{
private IJsonRpcConfig jsonRpcConfig = new JsonRpcConfig();
private IDebugBridge debugBridge = Substitute.For<IDebugBridge>();
private MemDb _blocksDb = new();

[Test]
public void Get_from_db()
Expand All @@ -37,6 +50,7 @@ public void Get_from_db()
byte[] value = new byte[] { 4, 5, 6 };
debugBridge.GetDbValue(Arg.Any<string>(), Arg.Any<byte[]>()).Returns(value);


IConfigProvider configProvider = Substitute.For<IConfigProvider>();
DebugRpcModule rpcModule = new(LimboLogs.Instance, debugBridge, jsonRpcConfig);
JsonRpcSuccessResponse? response =
Expand Down Expand Up @@ -208,6 +222,44 @@ public async Task Get_trace_with_options()
Assert.That(response, Is.EqualTo("{\"jsonrpc\":\"2.0\",\"result\":{\"gas\":\"0x0\",\"failed\":false,\"returnValue\":\"0xa2\",\"structLogs\":[{\"pc\":0,\"op\":\"STOP\",\"gas\":22000,\"gasCost\":1,\"depth\":1,\"error\":null,\"stack\":[],\"memory\":[\"0000000000000000000000000000000000000000000000000000000000000005\",\"0000000000000000000000000000000000000000000000000000000000000006\"],\"storage\":{\"0000000000000000000000000000000000000000000000000000000000000001\":\"0000000000000000000000000000000000000000000000000000000000000002\",\"0000000000000000000000000000000000000000000000000000000000000003\":\"0000000000000000000000000000000000000000000000000000000000000004\"}}]},\"id\":67}"));
}

private BlockTree BuildBlockTree()
{
BlockStore blockStore = new(_blocksDb);
return Build.A.BlockTree().WithBlocksDb(_blocksDb).WithBlockStore(blockStore).TestObject;
}

[Test]
public void Debug_getBadBlocks_test()
{
BlockTree blockTree = BuildBlockTree();

Block block0 = Build.A.Block.WithNumber(0).WithDifficulty(1).TestObject;
Block block1 = Build.A.Block.WithNumber(1).WithDifficulty(2).WithParent(block0).TestObject;
Block block2 = Build.A.Block.WithNumber(2).WithDifficulty(3).WithParent(block1).TestObject;
Block block3 = Build.A.Block.WithNumber(2).WithDifficulty(4).WithParent(block2).TestObject;

blockTree.SuggestBlock(block0);
blockTree.SuggestBlock(block1);
blockTree.SuggestBlock(block2);
blockTree.SuggestBlock(block3);

blockTree.DeleteInvalidBlock(block1);

BlockDecoder decoder = new();
_blocksDb.Set(block1.Hash ?? new Hash256("0x0"), decoder.Encode(block1).Bytes);

debugBridge.GetBadBlocks().Returns(blockTree.GetInvalidBlocks());

AddBlockResult result = blockTree.SuggestBlock(block1);
Assert.That(result, Is.EqualTo(AddBlockResult.InvalidBlock));

DebugRpcModule rpcModule = new(LimboLogs.Instance, debugBridge, jsonRpcConfig);
ResultWrapper<Block[]> blocks = rpcModule.debug_getBadBlocks();
Assert.That(blocks.Data.Length, Is.EqualTo(1));
Assert.That(blocks.Data[0].Hash, Is.EqualTo(block1.Hash));
Assert.That(blocks.Data[0].Difficulty, Is.EqualTo(new UInt256(2)));
}

[Test]
public void Debug_traceCall_test()
{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -76,6 +76,11 @@ public DebugBridge(
}
}

public Block[] GetBadBlocks()
{
return _blockTree.GetInvalidBlocks();
}

public byte[] GetDbValue(string dbName, byte[] key)
{
return _dbMappings[dbName][key];
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -277,4 +277,10 @@ public ResultWrapper<IEnumerable<string>> debug_standardTraceBlockToFile(Hash256

return ResultWrapper<IEnumerable<string>>.Success(files);
}

public ResultWrapper<Block[]> debug_getBadBlocks()
Marchhill marked this conversation as resolved.
Show resolved Hide resolved
{
Block[] badBlocks = _debugBridge.GetBadBlocks();
return ResultWrapper<Block[]>.Success(badBlocks);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -33,4 +33,5 @@ public interface IDebugBridge
void InsertReceipts(BlockParameter blockParameter, TxReceipt[] receipts);
SyncReportSymmary GetCurrentSyncStage();
IEnumerable<string> TraceBlockToFile(Hash256 blockHash, CancellationToken cancellationToken, GethTraceOptions? gethTraceOptions = null);
public Block[] GetBadBlocks();
}
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
using System.Collections.Generic;
using System.Threading.Tasks;
using Nethermind.Blockchain.Find;
using Nethermind.Core;
using Nethermind.Core.Crypto;
using Nethermind.Evm.Tracing.GethStyle;
using Nethermind.JsonRpc.Data;
Expand Down Expand Up @@ -94,4 +95,7 @@ public interface IDebugRpcModule : IRpcModule
[JsonRpcMethod(Description = "Writes to a file the full stack trace of all invoked opcodes of the transaction specified (or all transactions if not specified) that was included in the block specified. The parent of the block must be present or it will fail.",
IsImplemented = true, IsSharable = false)]
ResultWrapper<IEnumerable<string>> debug_standardTraceBlockToFile(Hash256 blockHash, GethTraceOptions options = null);

[JsonRpcMethod(Description = "Return list of invalid blocks.")]
ResultWrapper<Block[]> debug_getBadBlocks();
}