예제 #1
0
        public void start(string block_header_storage_path, ulong starting_block_height, byte[] starting_block_checksum)
        {
            if (running)
            {
                return;
            }

            BlockHeaderStorage.init(block_header_storage_path);

            BlockHeader last_block_header = BlockHeaderStorage.getLastBlockHeader();

            if (last_block_header != null && last_block_header.blockNum > starting_block_height)
            {
                lastBlockHeader = last_block_header;
            }
            else
            {
                BlockHeaderStorage.deleteCache();
                lastBlockHeader = new BlockHeader()
                {
                    blockNum = starting_block_height, blockChecksum = starting_block_checksum
                };
            }

            running = true;
            // Start the thread
            tiv_thread      = new Thread(onUpdate);
            tiv_thread.Name = "TIV_Update_Thread";
            tiv_thread.Start();
        }
예제 #2
0
        private bool processBlockHeader(BlockHeader header)
        {
            if (lastBlockHeader != null && lastBlockHeader.blockChecksum != null && !header.lastBlockChecksum.SequenceEqual(lastBlockHeader.blockChecksum))
            {
                Logging.warn("TIV: Invalid last block checksum");

                // discard the block

                // TODO require previous block to get verifications from 3 nodes
                // if in verification mode, detect liar and flag him
                // below is an implementation that's good enough for now

                if (minBlockHeightReorg < lastBlockHeader.blockNum - 7)
                {
                    minBlockHeightReorg = lastBlockHeader.blockNum - 7;
                }

                BlockHeader prev_header = BlockHeaderStorage.getBlockHeader(minBlockHeightReorg);

                if (prev_header == null)
                {
                    return(false);
                }

                lastBlockHeader = prev_header;

                ConsensusConfig.redactedWindowSize    = ConsensusConfig.getRedactedWindowSize(lastBlockHeader.version);
                ConsensusConfig.minRedactedWindowSize = ConsensusConfig.getRedactedWindowSize(lastBlockHeader.version);

                return(false);
            }

            if (!header.calculateChecksum().SequenceEqual(header.blockChecksum))
            {
                Logging.warn("TIV: Invalid block checksum");
                return(false);
            }

            lastBlockHeader = header;

            ConsensusConfig.redactedWindowSize    = ConsensusConfig.getRedactedWindowSize(lastBlockHeader.version);
            ConsensusConfig.minRedactedWindowSize = ConsensusConfig.getRedactedWindowSize(lastBlockHeader.version);

            if (BlockHeaderStorage.saveBlockHeader(lastBlockHeader))
            {
                // Cleanup every n blocks
                if ((header.blockNum > CoreConfig.maxBlockHeadersPerDatabase * 25) && header.blockNum % CoreConfig.maxBlockHeadersPerDatabase == 0)
                {
                    BlockHeaderStorage.removeAllBlocksBefore(header.blockNum - (CoreConfig.maxBlockHeadersPerDatabase * 25));
                }
            }

            IxianHandler.receivedBlockHeader(lastBlockHeader, true);

            return(true);
        }
예제 #3
0
        public void stop()
        {
            if (!running)
            {
                return;
            }
            running = false;

            BlockHeaderStorage.stop();
        }
예제 #4
0
        public TransactionInclusion(string block_header_storage_path = "", ulong starting_block_height = 1, byte[] starting_block_checksum = null)
        {
            BlockHeaderStorage.init(block_header_storage_path);

            BlockHeader last_block_header = BlockHeaderStorage.getLastBlockHeader();

            if (last_block_header != null && last_block_header.blockNum > starting_block_height)
            {
                lastBlockHeader = last_block_header;
            }
            else
            {
                BlockHeaderStorage.deleteCache();
                lastBlockHeader = new BlockHeader()
                {
                    blockNum = starting_block_height, blockChecksum = starting_block_checksum
                };
            }
        }
예제 #5
0
        /// <summary>
        /// When a response to a PIT request is received, this function validates and caches it so transactions may be verified in a separate thread.
        /// </summary>
        /// <param name="data">PIT response bytes.</param>
        /// <param name="endpoint">Neighbor, who sent this data.</param>
        public void receivedPIT2(byte[] data, RemoteEndpoint endpoint)
        {
            MemoryStream m = new MemoryStream(data);

            using (BinaryReader r = new BinaryReader(m))
            {
                ulong block_num = r.ReadIxiVarUInt();
                int   len       = (int)r.ReadIxiVarUInt();
                if (len > 0)
                {
                    byte[] pit_data         = r.ReadBytes(len);
                    PrefixInclusionTree pit = new PrefixInclusionTree(44, 3);
                    try
                    {
                        pit.reconstructMinimumTree(pit_data);
                        BlockHeader h = BlockHeaderStorage.getBlockHeader(block_num);
                        if (h == null)
                        {
                            Logging.warn("TIV: Received PIT information for block {0}, but we do not have that block header in storage!", block_num);
                            return;
                        }
                        if (!h.pitHash.SequenceEqual(pit.calculateTreeHash()))
                        {
                            Logging.error("TIV: Received PIT information for block {0}, but the PIT checksum does not match the one in the block header!", block_num);
                            // TODO: more drastic action? Maybe blacklist or something.
                            return;
                        }
                        lock (pitCache)
                        {
                            if (pitCache.ContainsKey(block_num))
                            {
                                Logging.info("TIV: Received valid PIT information for block {0}", block_num);
                                pitCache[block_num].pit = pit;
                            }
                        }
                    }
                    catch (Exception)
                    {
                        Logging.warn("TIV: Invalid or corrupt data received for block {0}.", block_num);
                    }
                }
            }
        }
예제 #6
0
        private bool processBlockHeader(BlockHeader header)
        {
            if (lastBlockHeader != null && lastBlockHeader.blockChecksum != null && !header.lastBlockChecksum.SequenceEqual(lastBlockHeader.blockChecksum))
            {
                Logging.warn("TIV: Invalid last block checksum");

                // discard the block

                // require previous block to get verifications from 3 nodes

                // if in verification mode, detect liar and flag him

                return(false);
            }

            if (!header.calculateChecksum().SequenceEqual(header.blockChecksum))
            {
                Logging.warn("TIV: Invalid block checksum");
                return(false);
            }

            lastBlockHeader = header;

            if (!BlockHeaderStorage.saveBlockHeader(lastBlockHeader))
            {
                return(false);
            }

            // Cleanup every n blocks
            if ((header.blockNum > CoreConfig.maxBlockHeadersPerDatabase * 25) && header.blockNum % CoreConfig.maxBlockHeadersPerDatabase == 0)
            {
                BlockHeaderStorage.removeAllBlocksBefore(header.blockNum - (CoreConfig.maxBlockHeadersPerDatabase * 25));
            }

            IxianHandler.receivedBlockHeader(lastBlockHeader, true);

            return(true);
        }
예제 #7
0
        private void verifyUnprocessedTransactions()
        {
            if (lastBlockHeader == null)
            {
                return;
            }
            lock (txQueue)
            {
                var tmp_txQueue = txQueue.Values.Where(x => x.applied != 0 && x.applied <= lastBlockHeader.blockNum).ToArray();
                foreach (var tx in tmp_txQueue)
                {
                    BlockHeader bh = BlockHeaderStorage.getBlockHeader(tx.applied);
                    if (bh is null)
                    {
                        // TODO: need to wait for the block to arrive, or re-request
                        // maybe something similar to PIT cache, or extend PIT cache to handle older blocks, too
                        continue;
                    }
                    if (bh.version < BlockVer.v6)
                    {
                        txQueue.Remove(tx.id);

                        if (bh.transactions.Contains(tx.id))
                        {
                            // valid
                            IxianHandler.receivedTransactionInclusionVerificationResponse(tx.id, true);
                        }
                        else
                        {
                            // invalid
                            IxianHandler.receivedTransactionInclusionVerificationResponse(tx.id, false);
                        }
                    }
                    else
                    {
                        lock (pitCache)
                        {
                            // check if we already have the partial tree for this transaction
                            if (pitCache.ContainsKey(tx.applied) && pitCache[tx.applied].pit != null)
                            {
                                // Note: PIT has been verified against the block header when it was received, so additional verification is not needed here.
                                // Note: the PIT we have cached might have been requested for different txids (the current txid could have been added later)
                                // For that reason, the list of TXIDs we requested is stored together with the cached PIT
                                if (pitCache[tx.applied].requestedForTXIDs.Contains(tx.id))
                                {
                                    txQueue.Remove(tx.id);

                                    if (pitCache[tx.applied].pit.contains(tx.id))
                                    {
                                        // valid
                                        IxianHandler.receivedTransactionInclusionVerificationResponse(tx.id, true);
                                    }
                                    else
                                    {
                                        // invalid
                                        IxianHandler.receivedTransactionInclusionVerificationResponse(tx.id, false);
                                    }
                                }
                                else
                                {
                                    // PIT cache for the correct block exists, but it was originally requested for different txids
                                    // we have to re-request it for any remaining txids in the queue. (We do not need to request the already-verified ids)
                                    requestPITForBlock(tx.applied,
                                                       txQueue.Values
                                                       .Where(x => x.applied == tx.applied && x.applied <= lastBlockHeader.blockNum)
                                                       .Select(x => x.id)
                                                       .ToList());
                                    continue;
                                }
                            }
                            else
                            {
                                // PIT cache has not been received yet, or maybe it has never been requested for this block
                                requestPITForBlock(tx.applied,
                                                   txQueue.Values
                                                   .Where(x => x.applied == tx.applied && x.applied <= lastBlockHeader.blockNum)
                                                   .Select(x => x.id)
                                                   .ToList());
                            }
                        }
                    }
                }
            }
        }