private bool CheckPrevHash(Node node, Block block) { // If we don't already have its previous block, shunt it off to holding area until we get it if (!this.chainIndex.InAnyTip(block.Header.HashPrevBlock)) { var blockHash = block.GetHash(); //LogPrintf("ProcessBlock: ORPHAN BLOCK %lu, prev=%s\n", (unsigned long)mapOrphanBlocks.size(), pblock->hashPrevBlock.ToString()); // Accept orphans as long as there is a node to request its parents from if (node != null) { // ppcoin: check proof-of-stake if (block.IsProofOfStake()) { // Limited duplicity on stake: prevents block flood attack // Duplicate stake allowed only when there is orphan child block //if (setStakeSeenOrphan.count(pblock->GetProofOfStake()) && !mapOrphanBlocksByPrev.count(hash)) // return error("ProcessBlock() : duplicate proof-of-stake (%s, %d) for orphan block %s", // pblock->GetProofOfStake().first.ToString(), pblock->GetProofOfStake().second, hash.ToString()); } } var orphan = new OrphanBlock { BlockHash = blockHash, PreviousHash = block.Header.HashPrevBlock, Block = block, }; if (block.IsProofOfStake()) { orphan.Stake = block.GetProofOfStake(); } if (this.orphanBlocks.TryAdd(blockHash, orphan)) { if (!this.Context.DownloadMode) { if (node != null) { // call get blocks var message = new GetBlocksPayload() { BlockLocators = this.chainIndex.Tip.GetLocator(), HashStop = this.GetOrphanRoot(blockHash) }; node.SendMessage(message); // ppcoin: getblocks may not obtain the ancestor block rejected // earlier by duplicate-stake check so we ask for it again directly //node.SendMessage(new InvPayload(InventoryType.MSG_BLOCK, block.Header.HashPrevBlock)); } } } return(false); } return(true); }
private uint256 GetOrphanRoot(uint256 hash) { var selector = this.orphanBlocks.TryGet(hash); if (selector == null) { return(hash); } OrphanBlock prev = null; while (selector != null) { prev = selector; selector = this.orphanBlocks.TryGet(selector.PreviousHash); } return(prev.BlockHash); }