/// <summary> /// Requests PIT for the specified block from a random connected neighbor node. /// Nominally, only the transactions included in `txids` need to be verifiable with the PIT, but /// due to how Cuckoo filtering works, some false positives will also be included. This helps with anonymization, if the false positive rate is high enough. /// </summary> /// <param name="block_num">Block number for which the PIT should be included.</param> /// <param name="txids">List of interesting transactions, which we wish to verify.</param> private void requestPITForBlock(ulong block_num, List <string> txids) { lock (pitCache) { long currentTime = Clock.getTimestamp(); // Request might already have been sent. In that case, we re-send it we have been waiting for too long. if (!pitCache.ContainsKey(block_num) || currentTime - pitCache[block_num].requestSent > pitRequestTimeout) { Cuckoo filter = new Cuckoo(txids.Count); foreach (var tx in txids) { filter.Add(Encoding.UTF8.GetBytes(tx)); } byte[] filter_bytes = filter.getFilterBytes(); MemoryStream m = new MemoryStream(filter_bytes.Length + 12); using (BinaryWriter w = new BinaryWriter(m, Encoding.UTF8, true)) { w.Write(block_num); w.Write(filter_bytes.Length); w.Write(filter_bytes); } CoreProtocolMessage.broadcastProtocolMessageToSingleRandomNode(new char[] { 'M' }, ProtocolMessageCode.getPIT, m.ToArray(), 0); PITCacheItem ci = new PITCacheItem() { pit = null, requestedForTXIDs = txids, requestSent = Clock.getTimestamp() }; pitCache.AddOrReplace(block_num, ci); } } }