private void hashIsRepeatableInternal(int sizeFrom, int sizeTo) { PrefixInclusionTree pit = new PrefixInclusionTree(); List <string> txids = new List <string>(); for (int i = 0; i < RNG.Next(sizeTo - sizeFrom) + sizeFrom; i++) { string tx = generateRandomTXID(); if (!txids.Contains(tx)) { txids.Add(tx); pit.add(tx); } } byte[] pit_hash = pit.calculateTreeHash(); Assert.IsFalse(pit.calculateTreeHash().SequenceEqual(emptyPITHash_44), "PIT hash shouldn't be equal to empty after hashes are added!"); foreach (string tx in txids) { Assert.IsTrue(pit.contains(tx), "PIT should contain the added txid!"); pit.remove(tx); Assert.IsFalse(pit.contains(tx), "PIT shouldn't contain hash which was removed!"); } Assert.IsTrue(pit.calculateTreeHash().SequenceEqual(emptyPITHash_44), "PIT hash should be equal to empty after all txids are removed!"); foreach (string tx in txids) { pit.add(tx); } Assert.IsTrue(pit.calculateTreeHash().SequenceEqual(pit_hash), "PIT hash should be repeatable if the same txids are added!"); }
public void largeHashTree() { PrefixInclusionTree pit = new PrefixInclusionTree(); List <string> txids = new List <string>(); Stopwatch sw = new Stopwatch(); // between 2000 and 3000 hashes for (int i = 0; i < RNG.Next(1000) + 2000; i++) { txids.Add(generateRandomTXID()); } sw.Start(); foreach (var tx in txids) { pit.add(tx); } sw.Stop(); Trace.WriteLine(String.Format("Large PIT test - adding: {0} hashes = {1} ms", txids.Count, sw.ElapsedMilliseconds)); sw.Reset(); sw.Start(); foreach (var tx in txids) { Assert.IsTrue(pit.contains(tx), "PIT should contain all the added hashes (large quantity)"); } sw.Stop(); Trace.WriteLine(String.Format("Large PIT test - verifying: {0} hashes = {1} ms", txids.Count, sw.ElapsedMilliseconds)); sw.Reset(); sw.Start(); byte[] pit_hash = pit.calculateTreeHash(); sw.Stop(); Trace.WriteLine(String.Format("Large PIT test - calculating hash: {0} hashes = {1} ms", txids.Count, sw.ElapsedMilliseconds)); Assert.IsFalse(pit_hash.SequenceEqual(emptyPITHash_44), "PIT hash should be different from empty (large quantity)"); }
public void trivialSanityTest() { PrefixInclusionTree pit = new PrefixInclusionTree(); byte[] hash = pit.calculateTreeHash(); Assert.IsTrue(hash.SequenceEqual(emptyPITHash_44), "Empty PIT hash is incorrect!"); Assert.IsFalse(pit.contains("ABCDEFGH"), "PIT reports that it contains an invalid txid"); }
public void addHash() { PrefixInclusionTree pit = new PrefixInclusionTree(); // transaction IDs for version > 2 are 44 string txid_str = generateRandomTXID(); pit.add(txid_str); Assert.IsTrue(pit.contains(txid_str), "PIT does not contain the added txid!"); }
public void addRemoveHash() { PrefixInclusionTree pit = new PrefixInclusionTree(); string txid = generateRandomTXID(); pit.add(txid); Assert.IsFalse(pit.calculateTreeHash().SequenceEqual(emptyPITHash_44), "PIT hash should not be the same as empty!"); pit.remove(txid); Assert.IsTrue(pit.calculateTreeHash().SequenceEqual(emptyPITHash_44), "PIT hash should be equal to empty if all hashes are removed!"); }
private void verifyMinimumTreeM(int sizeFrom, int sizeTo, int included_percent = 2, int max_tx = 5, byte numLevels = 4) { PrefixInclusionTree pit = new PrefixInclusionTree(44, numLevels); HashSet <string> txids = new HashSet <string>(); for (int i = 0; i < RNG.Next(sizeTo - sizeFrom) + sizeFrom; i++) { string tx = generateRandomTXID(); txids.Add(tx); pit.add(tx); } Trace.WriteLine(String.Format("Generated {0} transactions...", txids.Count)); byte[] original_tree_hash = pit.calculateTreeHash(); Stopwatch sw = new Stopwatch(); // chose some transactions for which to make a minimum tree List <string> chosenTransactions = new List <string>(); foreach (string tx in txids) { // 10% of transactions, or at least one if (chosenTransactions.Count == 0 || RNG.Next(100) < included_percent) { chosenTransactions.Add(tx); } if (chosenTransactions.Count >= max_tx) { break; } } Trace.WriteLine(String.Format("Chosen {0} transactions from the list.", chosenTransactions.Count)); sw.Start(); byte[] minimal_tree = pit.getMinimumTreeTXList(chosenTransactions); sw.Stop(); Trace.WriteLine(String.Format("Retrieving matcher-based minimum TX tree took {0} ms and yielded {1} bytes.", sw.ElapsedMilliseconds, minimal_tree.Length)); sw.Reset(); Assert.IsNotNull(minimal_tree, "PIT returns null minimal tree!"); PrefixInclusionTree pit2 = new PrefixInclusionTree(); sw.Start(); pit2.reconstructMinimumTree(minimal_tree); sw.Stop(); Trace.WriteLine(String.Format("Reconstructing minimum TX tree took {0} ms.", sw.ElapsedMilliseconds)); sw.Reset(); sw.Start(); foreach (string tx in chosenTransactions) { Assert.IsTrue(pit2.contains(tx), "Reconstructed PIT should contain the selected transactions!"); } Assert.IsTrue(original_tree_hash.SequenceEqual(pit2.calculateTreeHash()), "Minimum PIT tree does not verify successfully!"); sw.Stop(); Trace.WriteLine(String.Format("Verifying minimum TX tree took {0} ms.", sw.ElapsedMilliseconds)); }
private void verifyMinimumTreeA(int sizeFrom, int sizeTo, bool all_tx, byte numLevels = 4) { PrefixInclusionTree pit = new PrefixInclusionTree(44, numLevels); HashSet <string> txids = new HashSet <string>(); for (int i = 0; i < RNG.Next(sizeTo - sizeFrom) + sizeFrom; i++) { string tx = generateRandomTXID(); txids.Add(tx); pit.add(tx); } Trace.WriteLine(String.Format("Generated {0} transactions...", txids.Count)); byte[] original_tree_hash = pit.calculateTreeHash(); Stopwatch sw = new Stopwatch(); sw.Start(); byte[] minimal_tree = pit.getMinimumTreeAnonymized(); sw.Stop(); Trace.WriteLine(String.Format("Retrieving anonymized minimum TX tree took {0} ms and yielded {1} bytes.", sw.ElapsedMilliseconds, minimal_tree.Length)); sw.Reset(); Assert.IsNotNull(minimal_tree, "PIT returns null minimal tree!"); PrefixInclusionTree pit2 = new PrefixInclusionTree(); sw.Start(); pit2.reconstructMinimumTree(minimal_tree); sw.Stop(); Trace.WriteLine(String.Format("Reconstructing minimum TX tree took {0} ms.", sw.ElapsedMilliseconds)); sw.Reset(); sw.Start(); if (all_tx) { foreach (string tx in txids) { // "pretend" to add the transactions we're interested in verifying - this should not change the resulting tree hash pit2.add(tx); } } else { // only verify some tx (10%) int num_to_verify = RNG.Next(sizeFrom) / 10; for (int i = 0; i < num_to_verify; i++) { string rand_tx = txids.ElementAt(RNG.Next(txids.Count)); pit2.add(rand_tx); } } Assert.IsTrue(original_tree_hash.SequenceEqual(pit2.calculateTreeHash()), "Minimum PIT tree does not verify successfully!"); sw.Stop(); Trace.WriteLine(String.Format("Verifying minimum TX tree took {0} ms.", sw.ElapsedMilliseconds)); }
public void addMultipleHashes() { List <string> addedHashes = new List <string>(); PrefixInclusionTree pit = new PrefixInclusionTree(); // transaction IDs for version > 2 are 44 for (int i = 0; i < RNG.Next(20); i++) { string txid_str = generateRandomTXID(); addedHashes.Add(txid_str); pit.add(txid_str); } foreach (string txid in addedHashes) { Assert.IsTrue(pit.contains(txid), "PIT does not contain the added txid!"); } }
private void verifyMinimumTree(int sizeFrom, int sizeTo, byte numLevels = 4) { PrefixInclusionTree pit = new PrefixInclusionTree(44, numLevels); HashSet <string> txids = new HashSet <string>(); for (int i = 0; i < RNG.Next(sizeTo - sizeFrom) + sizeFrom; i++) { string tx = generateRandomTXID(); txids.Add(tx); pit.add(tx); } byte[] original_tree_hash = pit.calculateTreeHash(); Trace.WriteLine(String.Format("Generated {0} transactions...", txids.Count)); // pick a random tx string rtx = txids.ElementAt(RNG.Next(txids.Count)); Stopwatch sw = new Stopwatch(); sw.Start(); byte[] minimal_tree = pit.getMinimumTree(rtx); sw.Stop(); Trace.WriteLine(String.Format("Retrieving minimum TX tree took {0} ms and yielded {1} bytes.", sw.ElapsedMilliseconds, minimal_tree.Length)); sw.Reset(); Assert.IsNotNull(minimal_tree, "PIT returns null minimal tree!"); PrefixInclusionTree pit2 = new PrefixInclusionTree(); sw.Start(); pit2.reconstructMinimumTree(minimal_tree); sw.Stop(); Trace.WriteLine(String.Format("Reconstructing minimum TX tree took {0} ms.", sw.ElapsedMilliseconds)); sw.Reset(); sw.Start(); Assert.IsTrue(pit2.contains(rtx), "Reconstructed PIT should contain the minimal transaction!"); Assert.IsTrue(original_tree_hash.SequenceEqual(pit2.calculateTreeHash()), "Minimum PIT tree does not verify successfully!"); sw.Stop(); Trace.WriteLine(String.Format("Verifying minimum TX tree took {0} ms.", sw.ElapsedMilliseconds)); }
public static void handleGetPIT2(byte[] data, RemoteEndpoint endpoint) { MemoryStream ms = new MemoryStream(data); using (BinaryReader r = new BinaryReader(ms)) { ulong block_num = r.ReadIxiVarUInt(); int filter_len = (int)r.ReadIxiVarUInt(); byte[] filter = r.ReadBytes(filter_len); Cuckoo cf; try { cf = new Cuckoo(filter); } catch (Exception) { Logging.warn("The Cuckoo filter in the getPIT message was invalid or corrupted!"); return; } Block b = Node.blockChain.getBlock(block_num, true, true); if (b is null) { return; } if (b.version < BlockVer.v6) { Logging.warn("Neighbor {0} requested PIT information for block {0}, which was below the minimal PIT version.", endpoint.fullAddress, block_num); return; } PrefixInclusionTree pit = new PrefixInclusionTree(44, 3); List <byte[]> interesting_transactions = new List <byte[]>(); foreach (var tx in b.transactions) { if (b.version < BlockVer.v8) { pit.add(UTF8Encoding.UTF8.GetBytes(Transaction.txIdV8ToLegacy(tx))); if (cf.Contains(tx)) { interesting_transactions.Add(UTF8Encoding.UTF8.GetBytes(Transaction.txIdV8ToLegacy(tx))); } } else { pit.add(tx); if (cf.Contains(tx)) { interesting_transactions.Add(tx); } } } // make sure we ended up with the correct PIT if (!b.pitChecksum.SequenceEqual(pit.calculateTreeHash())) { // This is a serious error, but I am not sure how to respond to it right now. Logging.error("Reconstructed PIT for block {0} does not match the checksum in block header!", block_num); return; } byte[] minimal_pit = pit.getMinimumTreeTXList(interesting_transactions); MemoryStream mOut = new MemoryStream(minimal_pit.Length + 12); using (BinaryWriter w = new BinaryWriter(mOut, Encoding.UTF8, true)) { w.WriteIxiVarInt(block_num); w.WriteIxiVarInt(minimal_pit.Length); w.Write(minimal_pit); } endpoint.sendData(ProtocolMessageCode.pitData2, mOut.ToArray()); } }