-
Notifications
You must be signed in to change notification settings - Fork 438
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
create a VerkleBlockchainTestRunner #7494
Merged
Merged
Changes from 1 commit
Commits
Show all changes
31 commits
Select commit
Hold shift + click to select a range
67a7ae6
create a VerkleBlockchainTestRunner
yerke26 38030e7
Merge branch 'feature/verkle' into verkle/hive-tests
yerke26 c49c474
remove TestWitnessJson and change it to ExecutionWitness
yerke26 506fa2c
add Witness to block and set ShouldVerifyIncomingWitness = true
yerke26 01621fb
refactoring: remove VerkleBlockchainTestsRunner
yerke26 bbb8852
add a test file and configs
tanishqjasoria 7f11a36
temp config
tanishqjasoria 775e69e
add assertions
tanishqjasoria 58eb0cc
fix blockhash gas calculations
tanishqjasoria aa3176a
stateless vm and witness fix
tanishqjasoria 916be63
fix for stateless
tanishqjasoria f6cc25d
add serve window
tanishqjasoria 76a8ee3
small fix
tanishqjasoria 19a9f60
charge read and write witness simultaneously
tanishqjasoria 6693cfb
modify state tree to fix issues
tanishqjasoria b7fdc27
refac
tanishqjasoria 3fceca5
fix vm
tanishqjasoria 6873bba
pass worldstate in withdrawal processor
tanishqjasoria 7c214b2
add equality checks
tanishqjasoria 1f27942
mini fix
tanishqjasoria d4d085b
fix changes
tanishqjasoria 9eb27e1
verify a lot of things
tanishqjasoria 1a0243a
Add stateless verkle world state for system contract exec
tanishqjasoria c8c1f13
add system contract in statelss block processor
tanishqjasoria 479f091
updates
tanishqjasoria 397f859
update package managements
tanishqjasoria c3ea1e8
update timestamp
tanishqjasoria 9566eb5
fix storage issues for the devnet
tanishqjasoria 69ab005
Add tree dump
tanishqjasoria a577d71
updates
tanishqjasoria cdff70d
fix whitespace
tanishqjasoria File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,11 @@ | ||
// SPDX-FileCopyrightText: 2024 Demerzel Solutions Limited | ||
// SPDX-License-Identifier: LGPL-3.0-only | ||
|
||
namespace Ethereum.Test.Base; | ||
|
||
public class TestStateDiffJson | ||
{ | ||
public string Stem { get; set; } | ||
public TestSuffixDiffJson[] SuffixDiffs { get; set; } | ||
} | ||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,11 @@ | ||
// SPDX-FileCopyrightText: 2024 Demerzel Solutions Limited | ||
// SPDX-License-Identifier: LGPL-3.0-only | ||
|
||
namespace Ethereum.Test.Base; | ||
|
||
public class TestSuffixDiffJson | ||
{ | ||
public int Suffix { get; set; } | ||
public string CurrentValue { get; set; } | ||
public string NewValue { get; set; } | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,20 @@ | ||
// SPDX-FileCopyrightText: 2024 Demerzel Solutions Limited | ||
// SPDX-License-Identifier: LGPL-3.0-only | ||
|
||
namespace Ethereum.Test.Base; | ||
|
||
public class TestVerkleProofJson | ||
{ | ||
public string[] OtherStems { get; set; } | ||
public string DepthExtensionPresent { get; set; } | ||
public string[] CommitmentsByPath { get; set; } | ||
public string D { get; set; } | ||
public IpaProofJson C { get; set; } | ||
} | ||
|
||
public class IpaProofJson | ||
{ | ||
public string[] Cl { get; set; } | ||
public string[] Cr { get; set; } | ||
public string FinalEvaluation { get; set; } | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,10 @@ | ||
// SPDX-FileCopyrightText: 2024 Demerzel Solutions Limited | ||
// SPDX-License-Identifier: LGPL-3.0-only | ||
|
||
namespace Ethereum.Test.Base; | ||
|
||
public class TestWitnessJson | ||
{ | ||
public TestStateDiffJson[] StateDiff { get; set; } | ||
public TestVerkleProofJson VerkleProof { get; set; } | ||
} |
318 changes: 318 additions & 0 deletions
318
src/Nethermind/Ethereum.Test.Base/VerkleBlockChainTestBase.cs
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,318 @@ | ||
// SPDX-FileCopyrightText: 2022 Demerzel Solutions Limited | ||
// SPDX-License-Identifier: LGPL-3.0-only | ||
|
||
using System; | ||
using System.Collections.Generic; | ||
using System.Diagnostics; | ||
using System.Threading; | ||
using System.Threading.Tasks; | ||
using Nethermind.Blockchain; | ||
using Nethermind.Blockchain.Receipts; | ||
using Nethermind.Consensus; | ||
using Nethermind.Consensus.Ethash; | ||
using Nethermind.Consensus.Processing; | ||
using Nethermind.Consensus.Rewards; | ||
using Nethermind.Consensus.Validators; | ||
using Nethermind.Core; | ||
using Nethermind.Core.Crypto; | ||
using Nethermind.Core.Extensions; | ||
using Nethermind.Core.Specs; | ||
using Nethermind.Core.Test; | ||
using Nethermind.Core.Test.Builders; | ||
using Nethermind.Crypto; | ||
using Nethermind.Db; | ||
using Nethermind.Int256; | ||
using Nethermind.Evm; | ||
using Nethermind.Evm.TransactionProcessing; | ||
using Nethermind.Logging; | ||
using Nethermind.Serialization.Rlp; | ||
using Nethermind.Specs.Forks; | ||
using Nethermind.Specs.Test; | ||
using Nethermind.State; | ||
using Nethermind.TxPool; | ||
using Nethermind.Verkle.Tree.TreeStore; | ||
using NUnit.Framework; | ||
|
||
namespace Ethereum.Test.Base | ||
{ | ||
public abstract class VerkleBlockChainTestBase | ||
{ | ||
private static InterfaceLogger _logger = new NUnitLogger(LogLevel.Trace); | ||
// private static ILogManager _logManager = new OneLoggerLogManager(_logger); | ||
private static ILogManager _logManager = LimboLogs.Instance; | ||
private static ISealValidator Sealer { get; } | ||
private static DifficultyCalculatorWrapper DifficultyCalculator { get; } | ||
|
||
static VerkleBlockChainTestBase() | ||
{ | ||
DifficultyCalculator = new DifficultyCalculatorWrapper(); | ||
Sealer = new EthashSealValidator(_logManager, DifficultyCalculator, new CryptoRandom(), new Ethash(_logManager), Timestamper.Default); // temporarily keep reusing the same one as otherwise it would recreate cache for each test | ||
} | ||
|
||
[SetUp] | ||
public void Setup() | ||
{ | ||
} | ||
|
||
private class DifficultyCalculatorWrapper : IDifficultyCalculator | ||
{ | ||
public IDifficultyCalculator? Wrapped { get; set; } | ||
|
||
public UInt256 Calculate(BlockHeader header, BlockHeader parent) | ||
{ | ||
if (Wrapped is null) | ||
{ | ||
throw new InvalidOperationException( | ||
$"Cannot calculate difficulty before the {nameof(Wrapped)} calculator is set."); | ||
} | ||
|
||
return Wrapped.Calculate(header, parent); | ||
} | ||
} | ||
|
||
protected async Task<EthereumTestResult> RunTest(BlockchainTest test, Stopwatch? stopwatch = null, bool failOnInvalidRlp = true) | ||
{ | ||
Assert.IsNull(test.LoadFailure, "test data loading failure"); | ||
|
||
IDbProvider dbProvider = TestMemDbProvider.Init(); | ||
IDb codeDb = dbProvider.CodeDb; | ||
|
||
ISpecProvider specProvider = new CustomSpecProvider( | ||
((ForkActivation)0, Frontier.Instance), | ||
((ForkActivation)1, test.Network)); | ||
|
||
if (specProvider.GenesisSpec != Frontier.Instance) | ||
{ | ||
Assert.Fail("Expected genesis spec to be Frontier for blockchain tests"); | ||
} | ||
|
||
if (test.Network is Cancun) | ||
{ | ||
await KzgPolynomialCommitments.InitializeAsync(); | ||
} | ||
|
||
DifficultyCalculator.Wrapped = new EthashDifficultyCalculator(specProvider); | ||
IRewardCalculator rewardCalculator = new RewardCalculator(specProvider); | ||
bool isPostMerge = test.Network != London.Instance && | ||
test.Network != Berlin.Instance && | ||
test.Network != MuirGlacier.Instance && | ||
test.Network != Istanbul.Instance && | ||
test.Network != ConstantinopleFix.Instance && | ||
test.Network != Constantinople.Instance && | ||
test.Network != Byzantium.Instance && | ||
test.Network != SpuriousDragon.Instance && | ||
test.Network != TangerineWhistle.Instance && | ||
test.Network != Dao.Instance && | ||
test.Network != Homestead.Instance && | ||
test.Network != Frontier.Instance && | ||
test.Network != Olympic.Instance; | ||
if (isPostMerge) | ||
{ | ||
rewardCalculator = NoBlockRewards.Instance; | ||
specProvider.UpdateMergeTransitionInfo(0, 0); | ||
} | ||
|
||
IEthereumEcdsa ecdsa = new EthereumEcdsa(specProvider.ChainId, _logManager); | ||
|
||
IVerkleTreeStore verkleTreeStore = new VerkleTreeStore<VerkleSyncCache>(dbProvider, _logManager); | ||
VerkleStateTree verkleStateTree = new VerkleStateTree(verkleTreeStore, _logManager); | ||
|
||
IWorldState stateProvider = new VerkleWorldState(verkleTreeStore, codeDb, _logManager); | ||
IStateReader stateReader = new VerkleStateReader(verkleStateTree, codeDb, _logManager); | ||
|
||
IBlockTree blockTree = Build.A.BlockTree() | ||
.WithSpecProvider(specProvider) | ||
.WithoutSettingHead | ||
.TestObject; | ||
|
||
IReceiptStorage receiptStorage = NullReceiptStorage.Instance; | ||
IBlockhashProvider blockhashProvider = new BlockhashProvider(blockTree, _logManager); | ||
ITxValidator txValidator = new TxValidator(TestBlockchainIds.ChainId); | ||
IHeaderValidator headerValidator = new HeaderValidator(blockTree, Sealer, specProvider, _logManager); | ||
IUnclesValidator unclesValidator = new UnclesValidator(blockTree, headerValidator, _logManager); | ||
IBlockValidator blockValidator = new BlockValidator(txValidator, headerValidator, unclesValidator, specProvider, _logManager); | ||
IVirtualMachine virtualMachine = new VirtualMachine( | ||
blockhashProvider, | ||
specProvider, | ||
_logManager); | ||
|
||
IBlockProcessor blockProcessor = new BlockProcessor( | ||
specProvider, | ||
blockValidator, | ||
rewardCalculator, | ||
new BlockProcessor.BlockValidationTransactionsExecutor( | ||
new TransactionProcessor( | ||
specProvider, | ||
stateProvider, | ||
virtualMachine, | ||
_logManager), | ||
stateProvider), | ||
stateProvider, | ||
receiptStorage, | ||
NullWitnessCollector.Instance, | ||
blockTree, | ||
_logManager); | ||
|
||
IBlockchainProcessor blockchainProcessor = new BlockchainProcessor( | ||
blockTree, | ||
blockProcessor, | ||
new RecoverSignatures(ecdsa, NullTxPool.Instance, specProvider, _logManager), | ||
stateReader, | ||
_logManager, | ||
BlockchainProcessor.Options.NoReceipts); | ||
|
||
InitializeTestState(test, stateProvider, specProvider); | ||
|
||
stopwatch?.Start(); | ||
List<(Block Block, string ExpectedException)> correctRlp = DecodeRlps(test, failOnInvalidRlp); | ||
|
||
test.GenesisRlp ??= Rlp.Encode(new Block(JsonToEthereumTest.Convert(test.GenesisBlockHeader))); | ||
|
||
Block genesisBlock = Rlp.Decode<Block>(test.GenesisRlp.Bytes); | ||
Assert.That(genesisBlock.Header.Hash, Is.EqualTo(new Hash256(test.GenesisBlockHeader.Hash))); | ||
|
||
ManualResetEvent genesisProcessed = new(false); | ||
|
||
blockTree.NewHeadBlock += (_, args) => | ||
{ | ||
if (args.Block.Number == 0) | ||
{ | ||
Assert.That(stateProvider.StateRoot, Is.EqualTo(genesisBlock.Header.StateRoot)); | ||
genesisProcessed.Set(); | ||
} | ||
}; | ||
|
||
blockchainProcessor.Start(); | ||
blockTree.SuggestBlock(genesisBlock); | ||
|
||
genesisProcessed.WaitOne(); | ||
for (int i = 0; i < correctRlp.Count; i++) | ||
{ | ||
if (correctRlp[i].Block.Hash is null) | ||
{ | ||
Assert.Fail($"null hash in {test.Name} block {i}"); | ||
} | ||
|
||
try | ||
{ | ||
// TODO: mimic the actual behaviour where block goes through validating sync manager? | ||
correctRlp[i].Block.Header.IsPostMerge = correctRlp[i].Block.Difficulty == 0; | ||
if (!test.SealEngineUsed || blockValidator.ValidateSuggestedBlock(correctRlp[i].Block, out _)) | ||
{ | ||
blockTree.SuggestBlock(correctRlp[i].Block); | ||
} | ||
else | ||
{ | ||
if (correctRlp[i].ExpectedException is not null) | ||
{ | ||
Assert.Fail($"Unexpected invalid block {correctRlp[i].Block.Hash}"); | ||
} | ||
} | ||
} | ||
catch (InvalidBlockException e) | ||
{ | ||
if (correctRlp[i].ExpectedException is not null) | ||
{ | ||
Assert.Fail($"Unexpected invalid block {correctRlp[i].Block.Hash}: {e}"); | ||
} | ||
} | ||
catch (Exception e) | ||
{ | ||
Assert.Fail($"Unexpected exception during processing: {e}"); | ||
} | ||
} | ||
|
||
await blockchainProcessor.StopAsync(true); | ||
stopwatch?.Stop(); | ||
|
||
return new EthereumTestResult | ||
( | ||
test.Name, | ||
null, | ||
true | ||
); | ||
} | ||
|
||
private List<(Block Block, string ExpectedException)> DecodeRlps(BlockchainTest test, bool failOnInvalidRlp) | ||
{ | ||
List<(Block Block, string ExpectedException)> correctRlp = new(); | ||
for (int i = 0; i < test.Blocks.Length; i++) | ||
{ | ||
TestBlockJson testBlockJson = test.Blocks[i]; | ||
try | ||
{ | ||
var rlpContext = Bytes.FromHexString(testBlockJson.Rlp).AsRlpStream(); | ||
Block suggestedBlock = Rlp.Decode<Block>(rlpContext); | ||
suggestedBlock.Header.SealEngineType = | ||
test.SealEngineUsed ? SealEngineType.Ethash : SealEngineType.None; | ||
|
||
if (testBlockJson.BlockHeader is not null) | ||
{ | ||
Assert.That(suggestedBlock.Header.Hash, Is.EqualTo(new Hash256(testBlockJson.BlockHeader.Hash))); | ||
|
||
for (int uncleIndex = 0; uncleIndex < suggestedBlock.Uncles.Length; uncleIndex++) | ||
{ | ||
Assert.That(suggestedBlock.Uncles[uncleIndex].Hash, Is.EqualTo(new Hash256(testBlockJson.UncleHeaders[uncleIndex].Hash))); | ||
} | ||
|
||
tanishqjasoria marked this conversation as resolved.
Show resolved
Hide resolved
|
||
correctRlp.Add((suggestedBlock, testBlockJson.ExpectedException)); | ||
} | ||
} | ||
catch (Exception e) | ||
{ | ||
if (testBlockJson.ExpectedException is null) | ||
{ | ||
string invalidRlpMessage = $"Invalid RLP ({i}) {e}"; | ||
if (failOnInvalidRlp) | ||
{ | ||
Assert.Fail(invalidRlpMessage); | ||
} | ||
else | ||
{ | ||
// ForgedTests don't have ExpectedException and at the same time have invalid rlps | ||
// Don't fail here. If test executed incorrectly will fail at last check | ||
_logger.Warn(invalidRlpMessage); | ||
} | ||
} | ||
else | ||
{ | ||
_logger.Info($"Expected invalid RLP ({i})"); | ||
} | ||
} | ||
} | ||
|
||
if (correctRlp.Count == 0) | ||
{ | ||
Assert.NotNull(test.GenesisBlockHeader); | ||
Assert.That(test.LastBlockHash, Is.EqualTo(new Hash256(test.GenesisBlockHeader.Hash))); | ||
} | ||
|
||
return correctRlp; | ||
} | ||
|
||
private void InitializeTestState(BlockchainTest test, IWorldState stateProvider, ISpecProvider specProvider) | ||
{ | ||
foreach (KeyValuePair<Address, AccountState> accountState in | ||
((IEnumerable<KeyValuePair<Address, AccountState>>)test.Pre ?? Array.Empty<KeyValuePair<Address, AccountState>>())) | ||
{ | ||
foreach (KeyValuePair<UInt256, byte[]> storageItem in accountState.Value.Storage) | ||
{ | ||
stateProvider.Set(new StorageCell(accountState.Key, storageItem.Key), storageItem.Value); | ||
} | ||
|
||
stateProvider.CreateAccount(accountState.Key, accountState.Value.Balance); | ||
stateProvider.InsertCode(accountState.Key, accountState.Value.Code, specProvider.GenesisSpec); | ||
for (int i = 0; i < accountState.Value.Nonce; i++) | ||
{ | ||
stateProvider.IncrementNonce(accountState.Key); | ||
} | ||
} | ||
|
||
stateProvider.Commit(specProvider.GenesisSpec); | ||
|
||
stateProvider.CommitTree(0); | ||
|
||
stateProvider.Reset(); | ||
} | ||
} | ||
} |
Oops, something went wrong.
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
lets make it
ExecutionWitness
and not use a json representation, we have a execution witness decoder in json so we can directly get the proper representation