コード例 #1
0
        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!");
        }
コード例 #2
0
        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)");
        }
コード例 #3
0
        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");
        }
コード例 #4
0
        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!");
        }
コード例 #5
0
        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!");
        }
コード例 #6
0
        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));
        }
コード例 #7
0
        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));
        }
コード例 #8
0
        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!");
            }
        }
コード例 #9
0
        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));
        }
コード例 #10
0
            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());
                }
            }