public void Test_add_and_delete_many_next_block(int i) { MemDb memDb = new MemDb(); TrieStore trieStore = new TrieStore(memDb, new MemoryLimit(128.MB()), Persist.EveryBlock, _logManager); PatriciaTree patriciaTree = new PatriciaTree(trieStore, _logManager); for (int j = 0; j < i; j++) { Keccak key = TestItem.Keccaks[j]; byte[] value = GenerateIndexedAccountRlp(j); patriciaTree.Set(key.Bytes, value); } patriciaTree.Commit(0); for (int j = 0; j < i; j++) { Keccak key = TestItem.Keccaks[j]; patriciaTree.Set(key.Bytes, Array.Empty <byte>()); } patriciaTree.Commit(1); patriciaTree.UpdateRootHash(); PatriciaTree checkTree = CreateCheckTree(memDb, patriciaTree); for (int j = 0; j < i; j++) { Keccak key = TestItem.Keccaks[j]; checkTree.Get(key.Bytes).Should().BeNull($@"{i} {j}"); } }
public void When_two_branches_with_two_same_children_change_one_and_change_back_next_block() { MemDb memDb = new MemDb(); TrieStore trieStore = new TrieStore(memDb, Prune.WhenCacheReaches(1.MB()), Persist.EveryBlock, _logManager); PatriciaTree patriciaTree = new PatriciaTree(trieStore, _logManager); patriciaTree.Set(_keyA, _longLeaf1); patriciaTree.Set(_keyB, _longLeaf1); patriciaTree.Set(_keyC, _longLeaf1); patriciaTree.Set(_keyD, _longLeaf1); patriciaTree.UpdateRootHash(); patriciaTree.Commit(0); patriciaTree.Set(_keyA, _longLeaf3); patriciaTree.Set(_keyA, _longLeaf1); patriciaTree.UpdateRootHash(); patriciaTree.Commit(1); memDb.Keys.Should().HaveCount(5); PatriciaTree checkTree = CreateCheckTree(memDb, patriciaTree); checkTree.Get(_keyA).Should().BeEquivalentTo(_longLeaf1); checkTree.Get(_keyB).Should().BeEquivalentTo(_longLeaf1); checkTree.Get(_keyC).Should().BeEquivalentTo(_longLeaf1); checkTree.Get(_keyD).Should().BeEquivalentTo(_longLeaf1); }
public void Connect_extension_with_extension() { /* to test this case we need something like this initially */ /* R * E - - - - - - - - - - - - - - - * B B B B B B B B B B B B B B B B * E L - - - - - - - - - - - - - - * E - - - - - - - - - - - - - - - * B B B B B B B B B B B B B B B B * L L - - - - - - - - - - - - - - */ /* then we delete the leaf (marked as X) */ /* R * B B B B B B B B B B B B B B B B * E X - - - - - - - - - - - - - - * E - - - - - - - - - - - - - - - * B B B B B B B B B B B B B B B B * L L - - - - - - - - - - - - - - */ /* and we end up with an extended extension replacing what was previously a top-level branch*/ /* R * E * E * E - - - - - - - - - - - - - - - * B B B B B B B B B B B B B B B B * L L - - - - - - - - - - - - - - */ byte[] key1 = Bytes.FromHexString("000000100000000aa"); byte[] key2 = Bytes.FromHexString("000000100000000bb"); byte[] key3 = Bytes.FromHexString("000000200000000cc"); MemDb memDb = new MemDb(); TrieStore trieStore = new TrieStore(memDb, Prune.WhenCacheReaches(1.MB()), Persist.EveryBlock, _logManager); PatriciaTree patriciaTree = new PatriciaTree(trieStore, _logManager); patriciaTree.Set(key1, _longLeaf1); patriciaTree.Set(key2, _longLeaf1); patriciaTree.Set(key3, _longLeaf1); patriciaTree.UpdateRootHash(); patriciaTree.Commit(0); patriciaTree.Set(key3, Array.Empty <byte>()); patriciaTree.UpdateRootHash(); patriciaTree.Commit(1); memDb.Keys.Should().HaveCount(8); PatriciaTree checkTree = CreateCheckTree(memDb, patriciaTree); checkTree.Get(key1).Should().BeEquivalentTo(_longLeaf1); checkTree.Get(key2).Should().BeEquivalentTo(_longLeaf1); checkTree.Get(key3).Should().BeNull(); }
public void Extension_branch_extension_and_leaf_then_branch_leaf_leaf() { /* R * E - - - - - - - - - - - - - - - * B B B B B B B B B B B B B B B B * E L - - - - - - - - - - - - - - * E - - - - - - - - - - - - - - - * B B B B B B B B B B B B B B B B * L L - - - - - - - - - - - - - - */ byte[] key1 = Bytes.FromHexString("000000100000000aa"); byte[] key2 = Bytes.FromHexString("000000100000000bb"); byte[] key3 = Bytes.FromHexString("000000200000000cc"); MemDb memDb = new MemDb(); TrieStore trieStore = new TrieStore(memDb, Prune.WhenCacheReaches(1.MB()), Persist.EveryBlock, _logManager); PatriciaTree patriciaTree = new PatriciaTree(trieStore, _logManager); patriciaTree.Set(key1, _longLeaf1); patriciaTree.Set(key2, _longLeaf1); patriciaTree.Set(key3, _longLeaf1); patriciaTree.UpdateRootHash(); patriciaTree.Commit(0); memDb.Keys.Should().HaveCount(7); PatriciaTree checkTree = CreateCheckTree(memDb, patriciaTree); checkTree.Get(key1).Should().BeEquivalentTo(_longLeaf1); checkTree.Get(key2).Should().BeEquivalentTo(_longLeaf1); checkTree.Get(key3).Should().BeEquivalentTo(_longLeaf1); }
public void Two_branches_exactly_same_leaf_then_one_removed() { MemDb memDb = new MemDb(); TrieStore trieStore = new TrieStore( memDb, Prune.WhenCacheReaches(1.MB()), Persist.EveryBlock, LimboLogs.Instance); PatriciaTree patriciaTree = new PatriciaTree(trieStore, _logManager); patriciaTree.Set(_keyA, _longLeaf1); patriciaTree.Set(_keyB, _longLeaf1); patriciaTree.Set(_keyC, _longLeaf1); patriciaTree.Set(_keyD, _longLeaf1); patriciaTree.Set(_keyA, Array.Empty <byte>()); patriciaTree.Commit(0); // leaf (root) memDb.Keys.Should().HaveCount(6); PatriciaTree checkTree = CreateCheckTree(memDb, patriciaTree); checkTree.Get(_keyA).Should().BeNull(); checkTree.Get(_keyB).Should().BeEquivalentTo(_longLeaf1); checkTree.Get(_keyC).Should().BeEquivalentTo(_longLeaf1); checkTree.Get(_keyD).Should().BeEquivalentTo(_longLeaf1); }
public void Test_update_many(int i) { MemDb memDb = new MemDb(); TrieStore trieStore = new TrieStore(memDb, new MemoryLimit(128.MB()), Persist.EveryBlock, _logManager); PatriciaTree patriciaTree = new PatriciaTree(trieStore, _logManager); for (int j = 0; j < i; j++) { Keccak key = TestItem.Keccaks[j]; byte[] value = GenerateIndexedAccountRlp(j); patriciaTree.Set(key.Bytes, value); } for (int j = 0; j < i; j++) { Keccak key = TestItem.Keccaks[j]; byte[] value = GenerateIndexedAccountRlp(j + 1); patriciaTree.Set(key.Bytes, value); } patriciaTree.Commit(0); patriciaTree.UpdateRootHash(); PatriciaTree checkTree = CreateCheckTree(memDb, patriciaTree); for (int j = 0; j < i; j++) { Keccak key = TestItem.Keccaks[j]; byte[] value = GenerateIndexedAccountRlp(j + 1); checkTree.Get(key.Bytes).Should().BeEquivalentTo(value, $@"{i} {j}"); } }
public void Delete_on_empty() { PatriciaTree patriciaTree = new PatriciaTree(_db, Keccak.EmptyTreeHash, false, true); patriciaTree.Set(Keccak.Compute("1").Bytes, new byte[0]); patriciaTree.Commit(); Assert.AreEqual(PatriciaTree.EmptyTreeHash, patriciaTree.RootHash); }
public void Single_leaf_delete_next_block() { MemDb memDb = new MemDb(); TrieStore trieStore = new TrieStore(memDb, Prune.WhenCacheReaches(1.MB()), Persist.EveryBlock, _logManager); PatriciaTree patriciaTree = new PatriciaTree(trieStore, _logManager); patriciaTree.Set(_keyA, _longLeaf1); patriciaTree.Commit(0); patriciaTree.Set(_keyA, Array.Empty <byte>()); patriciaTree.Commit(1); patriciaTree.UpdateRootHash(); // leaf (root) memDb.Keys.Should().HaveCount(1); PatriciaTree checkTree = CreateCheckTree(memDb, patriciaTree); checkTree.Get(_keyA).Should().BeNull(); }
public void When_branch_with_two_different_children_change_one_and_change_back_next_block() { MemDb memDb = new MemDb(); TrieStore trieStore = new TrieStore(memDb, Prune.WhenCacheReaches(1.MB()), Persist.EveryBlock, _logManager); PatriciaTree patriciaTree = new PatriciaTree(trieStore, _logManager); patriciaTree.Set(_keyA, _longLeaf1); patriciaTree.Set(_keyB, _longLeaf2); patriciaTree.UpdateRootHash(); patriciaTree.Commit(0); patriciaTree.Set(_keyA, _longLeaf3); patriciaTree.Set(_keyA, _longLeaf1); patriciaTree.UpdateRootHash(); patriciaTree.Commit(1); // extension // branch // leaf x 2 memDb.Keys.Should().HaveCount(4); }
public void Single_leaf() { MemDb memDb = new MemDb(); TrieStore trieStore = new TrieStore(memDb, Prune.WhenCacheReaches(1.MB()), Persist.EveryBlock, _logManager); PatriciaTree patriciaTree = new PatriciaTree(trieStore, _logManager); patriciaTree.Set(_keyA, _longLeaf1); patriciaTree.Commit(0); // leaf (root) memDb.Keys.Should().HaveCount(1); }
public void Extension_with_branch_with_two_same_children() { MemDb memDb = new MemDb(); TrieStore trieStore = new TrieStore(memDb, Prune.WhenCacheReaches(1.MB()), Persist.EveryBlock, _logManager); PatriciaTree patriciaTree = new PatriciaTree(trieStore, _logManager); patriciaTree.Set(_keyA, _longLeaf1); patriciaTree.Set(_keyB, _longLeaf1); patriciaTree.Commit(0); memDb.Keys.Should().HaveCount(4); PatriciaTree checkTree = CreateCheckTree(memDb, patriciaTree); checkTree.Get(_keyA).Should().BeEquivalentTo(_longLeaf1); checkTree.Get(_keyB).Should().BeEquivalentTo(_longLeaf1); }
public void Single_leaf_update_same_block() { MemDb memDb = new MemDb(); TrieStore trieStore = new TrieStore(memDb, Prune.WhenCacheReaches(1.MB()), Persist.EveryBlock, _logManager); PatriciaTree patriciaTree = new PatriciaTree(trieStore, _logManager); patriciaTree.Set(_keyA, _longLeaf1); patriciaTree.Set(_keyA, _longLeaf2); patriciaTree.Commit(0); // leaf (root) memDb.Keys.Should().HaveCount(1); PatriciaTree checkTree = CreateCheckTree(memDb, patriciaTree); checkTree.Get(_keyA).Should().NotBeEquivalentTo(_longLeaf1); checkTree.Get(_keyA).Should().BeEquivalentTo(_longLeaf2); }
public void Branch_with_branch_and_leaf() { MemDb memDb = new MemDb(); TrieStore trieStore = new TrieStore(memDb, Prune.WhenCacheReaches(1.MB()), Persist.EveryBlock, _logManager); PatriciaTree patriciaTree = new PatriciaTree(trieStore, _logManager); patriciaTree.Set(_keyA, _longLeaf1); patriciaTree.Set(_keyB, _longLeaf1); patriciaTree.Set(_keyC, _longLeaf1); patriciaTree.Commit(0); // leaf (root) memDb.Keys.Should().HaveCount(6); PatriciaTree checkTree = CreateCheckTree(memDb, patriciaTree); checkTree.Get(_keyA).Should().BeEquivalentTo(_longLeaf1); checkTree.Get(_keyB).Should().BeEquivalentTo(_longLeaf1); checkTree.Get(_keyC).Should().BeEquivalentTo(_longLeaf1); }
public void Test_try_delete_and_read_missing_nodes(int i) { MemDb memDb = new MemDb(); TrieStore trieStore = new TrieStore(memDb, new MemoryLimit(128.MB()), Persist.EveryBlock, _logManager); PatriciaTree patriciaTree = new PatriciaTree(trieStore, Keccak.EmptyTreeHash, true, true, _logManager); for (int j = 0; j < i; j++) { Keccak key = TestItem.Keccaks[j]; byte[] value = GenerateIndexedAccountRlp(j); patriciaTree.Set(key.Bytes, value); } // delete missing for (int j = 0; j < i; j++) { Keccak key = TestItem.Keccaks[j + 100]; patriciaTree.Set(key.Bytes, Array.Empty <byte>()); } patriciaTree.Commit(0); patriciaTree.UpdateRootHash(); PatriciaTree checkTree = CreateCheckTree(memDb, patriciaTree); // confirm nothing deleted for (int j = 0; j < i; j++) { Keccak key = TestItem.Keccaks[j]; byte[] value = GenerateIndexedAccountRlp(j); checkTree.Get(key.Bytes).Should().BeEquivalentTo(value, $@"{i} {j}"); } // read missing for (int j = 0; j < i; j++) { Keccak key = TestItem.Keccaks[j + 100]; checkTree.Get(key.Bytes).Should().BeNull(); } }
public void Fuzz_accounts_with_reorganizations( int accountsCount, int blocksCount, int uniqueValuesCount, int lookupLimit, int?seed) { int usedSeed = seed ?? _random.Next(int.MaxValue); _random = new Random(usedSeed); _logger.Info($"RANDOM SEED {usedSeed}"); string fileName = Path.GetTempFileName(); //string fileName = "C:\\Temp\\fuzz.txt"; _logger.Info( $"Fuzzing with accounts: {accountsCount}, " + $"blocks {blocksCount}, " + $"values: {uniqueValuesCount}, " + $"lookup: {lookupLimit} into file {fileName}"); using FileStream fileStream = new FileStream(fileName, FileMode.Create); using StreamWriter streamWriter = new StreamWriter(fileStream); Queue <Keccak> rootQueue = new Queue <Keccak>(); Stack <Keccak> rootStack = new Stack <Keccak>(); MemDb memDb = new MemDb(); TrieStore trieStore = new TrieStore(memDb, Prune.WhenCacheReaches(1.MB()), Persist.IfBlockOlderThan(lookupLimit), _logManager); PatriciaTree patriciaTree = new PatriciaTree(trieStore, _logManager); byte[][] accounts = new byte[accountsCount][]; byte[][] randomValues = new byte[uniqueValuesCount][]; for (int i = 0; i < randomValues.Length; i++) { bool isEmptyValue = _random.Next(0, 2) == 0; if (isEmptyValue) { randomValues[i] = Array.Empty <byte>(); } else { randomValues[i] = GenerateRandomAccountRlp(); } } for (int accountIndex = 0; accountIndex < accounts.Length; accountIndex++) { byte[] key = new byte[32]; ((UInt256)accountIndex).ToBigEndian(key); accounts[accountIndex] = key; } int blockCount = 0; for (int blockNumber = 0; blockNumber < blocksCount; blockNumber++) { int reorgDepth = _random.Next(Math.Min(5, blockCount)); _logger.Debug($"Reorganizing {reorgDepth}"); for (int i = 0; i < reorgDepth; i++) { try { // no longer need undo? // trieStore.UndoOneBlock(); } catch (InvalidOperationException) { // if memory limit hits in blockCount = 0; } rootStack.Pop(); patriciaTree.RootHash = rootStack.Peek(); } blockCount = Math.Max(0, blockCount - reorgDepth); _logger.Debug($"Setting block count to {blockCount}"); bool isEmptyBlock = _random.Next(5) == 0; if (!isEmptyBlock) { for (int i = 0; i < Math.Max(1, accountsCount / 8); i++) { int randomAccountIndex = _random.Next(accounts.Length); int randomValueIndex = _random.Next(randomValues.Length); byte[] account = accounts[randomAccountIndex]; byte[] value = randomValues[randomValueIndex]; streamWriter.WriteLine( $"Block {blockCount} - setting {account.ToHexString()} = {value.ToHexString()}"); patriciaTree.Set(account, value); } } streamWriter.WriteLine( $"Commit block {blockCount} | empty: {isEmptyBlock}"); patriciaTree.UpdateRootHash(); patriciaTree.Commit(blockCount); rootQueue.Enqueue(patriciaTree.RootHash); rootStack.Push(patriciaTree.RootHash); blockCount++; _logger.Debug($"Setting block count to {blockCount}"); } streamWriter.Flush(); fileStream.Seek(0, SeekOrigin.Begin); streamWriter.WriteLine($"DB size: {memDb.Keys.Count}"); _logger.Info($"DB size: {memDb.Keys.Count}"); int verifiedBlocks = 0; rootQueue.Clear(); Stack <Keccak> stackCopy = new Stack <Keccak>(); while (rootStack.Any()) { stackCopy.Push(rootStack.Pop()); } rootStack = stackCopy; while (rootStack.TryPop(out Keccak currentRoot)) { try { patriciaTree.RootHash = currentRoot; for (int i = 0; i < accounts.Length; i++) { patriciaTree.Get(accounts[i]); } _logger.Info($"Verified positive {verifiedBlocks}"); } catch (Exception ex) { if (verifiedBlocks % lookupLimit == 0) { throw new InvalidDataException(ex.ToString()); } else { _logger.Info($"Verified negative {verifiedBlocks} (which is ok on block {verifiedBlocks})"); } } verifiedBlocks++; } }
public void Single_leaf_and_keep_for_multiple_dispatches_then_delete() { MemDb memDb = new MemDb(); TrieStore trieStore = new TrieStore(memDb, Prune.WhenCacheReaches(1.MB()), new ConstantInterval(4), LimboLogs.Instance); PatriciaTree patriciaTree = new PatriciaTree(trieStore, _logManager); patriciaTree.Commit(0); patriciaTree.Commit(1); patriciaTree.Commit(2); patriciaTree.Set(_keyA, _longLeaf1); patriciaTree.Commit(3); patriciaTree.Commit(4); patriciaTree.Set(_keyA, Array.Empty <byte>()); patriciaTree.Commit(5); patriciaTree.Set(_keyB, _longLeaf2); patriciaTree.Commit(6); patriciaTree.Commit(7); patriciaTree.Commit(8); patriciaTree.Commit(9); patriciaTree.Commit(10); patriciaTree.Commit(11); patriciaTree.Set(_keyB, Array.Empty <byte>()); patriciaTree.Commit(12); patriciaTree.Commit(13); patriciaTree.UpdateRootHash(); // leaf (root) memDb.Keys.Should().HaveCount(2); PatriciaTree checkTree = CreateCheckTree(memDb, patriciaTree); checkTree.Get(_keyA).Should().BeNull(); checkTree.Get(_keyB).Should().BeNull(); }