public BaselineModule( ITxSender txSender, IStateReader stateReader, ILogFinder logFinder, IBlockFinder blockFinder, IAbiEncoder abiEncoder, IFileSystem fileSystem, IDb baselineDb, IDb metadataBaselineDb, ILogManager logManager, IBlockProcessor blockProcessor, DisposableStack disposableStack) { _abiEncoder = abiEncoder ?? throw new ArgumentNullException(nameof(abiEncoder)); _fileSystem = fileSystem ?? throw new ArgumentNullException(nameof(fileSystem)); _baselineDb = baselineDb ?? throw new ArgumentNullException(nameof(baselineDb)); _metadataBaselineDb = metadataBaselineDb ?? throw new ArgumentNullException(nameof(metadataBaselineDb)); _logger = logManager?.GetClassLogger() ?? throw new ArgumentNullException(nameof(logManager)); _txSender = txSender ?? throw new ArgumentNullException(nameof(txSender)); _stateReader = stateReader ?? throw new ArgumentNullException(nameof(stateReader)); _logFinder = logFinder ?? throw new ArgumentNullException(nameof(logFinder)); _blockFinder = blockFinder ?? throw new ArgumentNullException(nameof(blockFinder)); _blockProcessor = blockProcessor ?? throw new ArgumentNullException(nameof(blockProcessor)); _baselineTreeHelper = new BaselineTreeHelper(_logFinder, baselineDb, metadataBaselineDb, _logger); _disposableStack = disposableStack ?? throw new ArgumentNullException(nameof(disposableStack)); _metadata = LoadMetadata(); InitTrees(); }
public async Task Tree_tracker_insert_leaves([ValueSource(nameof(InsertLeavesTestCases))] InsertLeavesTest test) { var address = TestItem.Addresses[0]; var result = await InitializeTestRpc(address); var testRpc = result.TestRpc; BaselineTree baselineTree = BuildATree(); var fromContractAdress = ContractAddress.From(address, 0); var baselineTreeHelper = new BaselineTreeHelper(testRpc.LogFinder, _baselineDb, _metadataBaselineDb, LimboNoErrorLogger.Instance); new BaselineTreeTracker(fromContractAdress, baselineTree, testRpc.BlockProcessor, baselineTreeHelper, testRpc.BlockFinder, LimboNoErrorLogger.Instance); var contract = new MerkleTreeSHAContract(_abiEncoder, fromContractAdress); UInt256 nonce = 1L; for (int i = 0; i < test.ExpectedTreeCounts.Length; i++) { nonce = await InsertLeavesFromArray(test.LeavesInTransactionsAndBlocks[i], nonce, testRpc, contract, address); await testRpc.AddBlock(); Assert.AreEqual(test.ExpectedTreeCounts[i], baselineTree.Count); } }
public void GetHistoricalTree_return_expected_results([ValueSource(nameof(HistoricalTreeTestCases))] GetHistoricalLeavesTest test) { var address = TestItem.AddressA; var logFinder = Substitute.For <ILogFinder>(); var mainDb = new MemDb(); var metadataDataDb = new MemDb(); var baselineTreeHelper = new BaselineTreeHelper(logFinder, mainDb, metadataDataDb, LimboNoErrorLogger.Instance); var baselineTree = new ShaBaselineTree(mainDb, metadataDataDb, address.Bytes, BaselineModule.TruncationLength, LimboNoErrorLogger.Instance); for (int i = 0; i < test.Blocks.Length; i++) { var block = test.Blocks[i]; for (int j = 0; j < block.Leaves.Length; j++) { baselineTree.Insert(block.Leaves[j]); } baselineTree.MemorizeCurrentCount(TestItem.Keccaks[block.BlockNumber], block.BlockNumber, (uint)block.Leaves.Length); } var historicalTree = baselineTreeHelper.CreateHistoricalTree(address, 1); Assert.AreNotEqual(historicalTree.Count, baselineTree.Count); Assert.AreNotEqual(historicalTree.Root, baselineTree.Root); }
public void GetHistoricalLeaves_return_expected_results([ValueSource(nameof(GetHistoricalLeafTestCases))] GetHistoricalLeavesTest test) { var logFinder = Substitute.For <ILogFinder>(); var mainDb = new MemDb(); var metadaDataDb = new MemDb(); var baselineTreeHelper = new BaselineTreeHelper(logFinder, new MemDb(), new MemDb(), LimboNoErrorLogger.Instance); var baselineTree = new ShaBaselineTree(mainDb, metadaDataDb, new byte[] { }, BaselineModule.TruncationLength, LimboNoErrorLogger.Instance); for (int i = 0; i < test.Blocks.Length; i++) { var block = test.Blocks[i]; for (int j = 0; j < block.Leaves.Length; j++) { baselineTree.Insert(block.Leaves[j]); } baselineTree.MemorizeCurrentCount(TestItem.Keccaks[block.BlockNumber], block.BlockNumber, (uint)block.Leaves.Length); } for (int i = 0; i < test.ExpectedHashes.Length; i++) { var leavesAndBlocks = test.LeavesAndBlocksQueries[i]; var leaves = baselineTreeHelper.GetHistoricalLeaves(baselineTree, leavesAndBlocks.LeavesIndexes, leavesAndBlocks.BlockNumber); for (int j = 0; j < leavesAndBlocks.LeavesIndexes.Length; j++) { Assert.AreEqual(test.ExpectedHashes[i][j], leaves[j].Hash); } } }
public async Task Tree_tracker_reorganization([ValueSource(nameof(ReorganizationTestCases))] ReorganizedInsertLeafTest test) { Address address = TestItem.Addresses[0]; (TestRpcBlockchain TestRpc, BaselineModule BaselineModule)result = await InitializeTestRpc(address); TestRpcBlockchain testRpc = result.TestRpc; BaselineTree baselineTree = BuildATree(); Address contractAddress = ContractAddress.From(address, 0L); BaselineTreeHelper baselineTreeHelper = new BaselineTreeHelper(testRpc.LogFinder, _baselineDb, _metadataBaselineDb, LimboNoErrorLogger.Instance); new BaselineTreeTracker(contractAddress, baselineTree, testRpc.BlockProcessor, baselineTreeHelper, testRpc.BlockFinder, LimboNoErrorLogger.Instance); MerkleTreeSHAContract contract = new MerkleTreeSHAContract(_abiEncoder, contractAddress); UInt256 nonce = 1L; for (int i = 0; i < test.LeavesInBlocksCounts.Length; i++) { nonce = await InsertLeafFromArray(test.LeavesInTransactionsAndBlocks[i], nonce, testRpc, contract, address); await testRpc.AddBlock(); Assert.AreEqual(test.LeavesInBlocksCounts[i], baselineTree.Count); } int initBlocksCount = 4; int allBlocksCount = initBlocksCount + test.LeavesInBlocksCounts.Length; TestBlockProducer testRpcBlockProducer = (TestBlockProducer)testRpc.BlockProducer; testRpcBlockProducer.BlockParent = testRpc.BlockTree.FindHeader(allBlocksCount); nonce = 1L; nonce = await InsertLeafFromArray(test.LeavesInMiddleOfReorganization, nonce, testRpc, contract, address); await testRpc.AddBlock(false); testRpcBlockProducer.BlockParent = testRpcBlockProducer.LastProducedBlock.Header; await InsertLeafFromArray(test.LeavesInAfterReorganization, nonce, testRpc, contract, address); await testRpc.AddBlock(); Assert.AreEqual(test.FinalLeavesCount, baselineTree.Count); }
public async Task Tree_tracker_start_stop_tracking([ValueSource(nameof(InsertLeafTestCases))] InsertLeafTest test) { Address address = TestItem.Addresses[0]; (TestRpcBlockchain TestRpc, BaselineModule BaselineModule)result = await InitializeTestRpc(address); TestRpcBlockchain testRpc = result.TestRpc; BaselineTree baselineTree = BuildATree(); Address fromContractAdress = ContractAddress.From(address, 0L); BaselineTreeHelper baselineTreeHelper = new BaselineTreeHelper(testRpc.LogFinder, _baselineDb, _metadataBaselineDb, LimboNoErrorLogger.Instance); MerkleTreeSHAContract contract = new MerkleTreeSHAContract(_abiEncoder, fromContractAdress); UInt256 nonce = 1L; for (int i = 0; i < test.ExpectedTreeCounts.Length; i++) { nonce = await InsertLeafFromArray(test.LeavesInTransactionsAndBlocks[i], nonce, testRpc, contract, address); await testRpc.AddBlock(); } BaselineTreeTracker tracker = new BaselineTreeTracker(fromContractAdress, baselineTree, testRpc.BlockProcessor, baselineTreeHelper, testRpc.BlockFinder, LimboNoErrorLogger.Instance); Assert.AreEqual(test.ExpectedTreeCounts[test.ExpectedTreeCounts.Length - 1], baselineTree.Count); uint afterStartTrackingCount = baselineTree.Count; for (int i = 0; i < test.ExpectedTreeCounts.Length; i++) { tracker.StopTracking(); nonce = await InsertLeafFromArray(test.LeavesInTransactionsAndBlocks[i], nonce, testRpc, contract, address); await testRpc.AddBlock(); tracker.StartTracking(); Assert.AreEqual(test.ExpectedTreeCounts[i] + afterStartTrackingCount, baselineTree.Count); } }
// TODO: fuzzer with concurrent inserts public void Baseline_tree_fuzzer( int leavesPerBlock, int blocksCount, int emptyBlocksRatio, bool recalculateOnInsert, bool withReorgs, int?randomSeed) { MemDb mainDb = new MemDb(); MemDb metadataDb = new MemDb(); Address address = Address.Zero; BaselineTreeHelper helper = new BaselineTreeHelper( Substitute.For <ILogFinder>(), mainDb, metadataDb, LimboNoErrorLogger.Instance); BaselineTree baselineTree = new ShaBaselineTree( mainDb, metadataDb, address.Bytes, 0, LimboNoErrorLogger.Instance); randomSeed ??= _random.Next(); Console.WriteLine($"random seed was {randomSeed} - hardcode it to recreate the failign test"); // Random random = new Random(1524199427); <- example Random random = new Random(randomSeed.Value); int currentBlockNumber = 0; uint totalCountCheck = 0; Stack <long> lastBlockWithLeavesCheck = new Stack <long>(); Dictionary <long, uint> historicalCountChecks = new Dictionary <long, uint>(); historicalCountChecks[0] = 0; for (int i = 0; i < blocksCount; i++) { if (i == 18) { } currentBlockNumber++; uint numberOfLeaves = (uint)random.Next(leavesPerBlock) + 1; // not zero bool hasLeaves = random.Next(100) < emptyBlocksRatio; if (hasLeaves) { totalCountCheck += numberOfLeaves; TestContext.WriteLine($"Adding {numberOfLeaves} at block {currentBlockNumber}"); for (int j = 0; j < numberOfLeaves; j++) { byte[] leafBytes = new byte[32]; random.NextBytes(leafBytes); baselineTree.Insert(new Keccak(leafBytes), recalculateOnInsert); } lastBlockWithLeavesCheck.TryPeek(out long previous); TestContext.WriteLine($"Previous is {previous}"); baselineTree.LastBlockWithLeaves.Should().Be(previous); baselineTree.MemorizeCurrentCount(TestItem.Keccaks[currentBlockNumber], currentBlockNumber, baselineTree.Count); lastBlockWithLeavesCheck.Push(currentBlockNumber); baselineTree.Count.Should().Be(totalCountCheck); baselineTree.LastBlockWithLeaves.Should().Be(lastBlockWithLeavesCheck.Peek()); } else { TestContext.WriteLine($"Block {currentBlockNumber} has no leaves"); } historicalCountChecks[currentBlockNumber] = totalCountCheck; WriteHistory(historicalCountChecks, baselineTree); for (int j = 1; j <= currentBlockNumber; j++) { TestContext.WriteLine($"Creating historical at {j}"); var historicalTrie = helper.CreateHistoricalTree(address, j); TestContext.WriteLine($"Checking if trie count ({historicalTrie.Count}) is {historicalCountChecks[j]} as expected"); historicalTrie.Count.Should().Be(historicalCountChecks[j], $"Block is {currentBlockNumber}, checking count at block {j}."); } if (withReorgs) { bool shouldReorg = random.Next(100) < 50; if (shouldReorg && currentBlockNumber >= 1) { int reorgDepth = random.Next(currentBlockNumber) + 1; TestContext.WriteLine($"Reorganizing {reorgDepth} from {currentBlockNumber}"); uint expectedDeleteCount = historicalCountChecks[currentBlockNumber] - historicalCountChecks[currentBlockNumber - reorgDepth]; baselineTree.GoBackTo(currentBlockNumber - reorgDepth).Should().Be(expectedDeleteCount); for (int j = 0; j < reorgDepth; j++) { historicalCountChecks.Remove(currentBlockNumber - j); } currentBlockNumber -= reorgDepth; totalCountCheck = historicalCountChecks[currentBlockNumber]; baselineTree.MemorizeCurrentCount(TestItem.Keccaks[currentBlockNumber], currentBlockNumber, totalCountCheck); TestContext.WriteLine($"Total count after reorg is {totalCountCheck} at block {currentBlockNumber}"); while (lastBlockWithLeavesCheck.Any() && lastBlockWithLeavesCheck.Peek() > currentBlockNumber) { lastBlockWithLeavesCheck.Pop(); } lastBlockWithLeavesCheck.TryPeek(out long last); if (last != currentBlockNumber) { TestContext.WriteLine($"Pushing {currentBlockNumber} on test stack after reorg."); // after reorg we always push a memorized count lastBlockWithLeavesCheck.Push(currentBlockNumber); } } WriteHistory(historicalCountChecks, baselineTree); } } }