Beispiel #1
0
        public void TestBlockchainEquality()
        {
            var randomBlockchain = RandomData.RandomBlockchain();

            var sameBlockchain = new Blockchain
            (
                blockList: ImmutableList.Create(randomBlockchain.BlockList.ToArray()),
                blockListHashes: ImmutableHashSet.Create(randomBlockchain.BlockListHashes.ToArray()),
                utxo: randomBlockchain.Utxo.ToDictionary(x => x.Key, x => x.Value).ToImmutableDictionary(x => x.Key, x => x.Value)
            );

            var newChainedBlock = randomBlockchain.BlockList.Last();
            newChainedBlock = new ChainedBlock(newChainedBlock.BlockHash, newChainedBlock.PreviousBlockHash, newChainedBlock.Height + 1, newChainedBlock.TotalWork);
            var differentBlockchainBlockList = new Blockchain
            (
                blockList: randomBlockchain.BlockList.Add(newChainedBlock),
                blockListHashes: randomBlockchain.BlockListHashes,
                utxo: randomBlockchain.Utxo
            );

            var differentBlockchainBlockListHashes = new Blockchain
            (
                blockList: randomBlockchain.BlockList,
                blockListHashes: randomBlockchain.BlockListHashes.Remove(randomBlockchain.BlockListHashes.Last()),
                utxo: randomBlockchain.Utxo
            );

            var differentBlockchainUtxo = new Blockchain
            (
                blockList: randomBlockchain.BlockList,
                blockListHashes: randomBlockchain.BlockListHashes,
                utxo: randomBlockchain.Utxo.Remove(randomBlockchain.Utxo.Keys.Last())
            );

            Assert.IsTrue(randomBlockchain.Equals(sameBlockchain));
            Assert.IsTrue(randomBlockchain == sameBlockchain);
            Assert.IsFalse(randomBlockchain != sameBlockchain);

            Assert.IsFalse(randomBlockchain.Equals(differentBlockchainBlockList));
            Assert.IsFalse(randomBlockchain == differentBlockchainBlockList);
            Assert.IsTrue(randomBlockchain != differentBlockchainBlockList);

            Assert.IsFalse(randomBlockchain.Equals(differentBlockchainBlockListHashes));
            Assert.IsFalse(randomBlockchain == differentBlockchainBlockListHashes);
            Assert.IsTrue(randomBlockchain != differentBlockchainBlockListHashes);

            Assert.IsFalse(randomBlockchain.Equals(differentBlockchainUtxo));
            Assert.IsFalse(randomBlockchain == differentBlockchainUtxo);
            Assert.IsTrue(randomBlockchain != differentBlockchainUtxo);
        }
Beispiel #2
0
			public Operation(Transaction transaction, ChainedBlock block, MerkleBlock proof)
				: this()
			{
				Transaction = transaction;
				if(block != null)
				{
					proof = proof.Clone();
					proof.PartialMerkleTree = proof.PartialMerkleTree.Trim(transaction.GetHash());
					Height = block.Height;
					BlockId = block.HashBlock;
					Proof = proof;
				}
				UnconfirmedSeen = DateTimeOffset.UtcNow;
				AddedDate = DateTimeOffset.UtcNow;
			}
		public static void UpdateChain(this IEnumerable<ChainBlockHeader> entries, ChainBase chain)
		{
			Stack<ChainBlockHeader> toApply = new Stack<ChainBlockHeader>();
			foreach(var entry in entries)
			{
				var prev = chain.GetBlock(entry.Header.HashPrevBlock);
				if(prev == null)
					toApply.Push(entry);
				else
				{
					toApply.Push(entry);
					break;
				}
			}
			while(toApply.Count > 0)
			{
				var newTip = toApply.Pop();

				var chained = new ChainedBlock(newTip.Header, newTip.BlockId, chain.GetBlock(newTip.Header.HashPrevBlock));
				chain.SetTip(chained);
			}
		}
Beispiel #4
0
        public ChainedBlock CreateBlockIndex(ChainedBlock prev)
        {
            ChainedBlock index = new ChainedBlock(new BlockHeader(), new BlockHeader().GetHash(), prev);

            return(index);
        }
        public async Task DownloadAndStoreBlocks(CancellationToken token, bool disposemode = false)
        {
            // TODO: add support to BlockStoreLoop to unset LazyLoadingOn when not in IBD
            // When in IBD we may need many reads for the block key without fetching the block
            // So the repo starts with LazyLoadingOn = true, however when not anymore in IBD
            // a read is normally done when a peer is asking for the entire block (not just the key)
            // then if LazyLoadingOn = false the read will be faster on the entire block

            while (!token.IsCancellationRequested)
            {
                if (StoredBlock.Height >= this.ChainState.HighestValidatedPoW?.Height)
                {
                    break;
                }

                // find next block to download
                var next = this.chain.GetBlock(StoredBlock.Height + 1);
                if (next == null)
                {
                    break;                     //no blocks to store
                }
                // reorg logic
                if (this.StoredBlock.HashBlock != next.Header.HashPrevBlock)
                {
                    if (disposemode)
                    {
                        break;
                    }

                    var blockstoremove = new List <uint256>();
                    var remove         = this.StoredBlock;
                    // reorg - we need to delete blocks, start walking back the chain
                    while (this.chain.GetBlock(remove.HashBlock) == null)
                    {
                        blockstoremove.Add(remove.HashBlock);
                        remove = remove.Previous;
                    }

                    await this.BlockRepository.DeleteAsync(remove.HashBlock, blockstoremove);

                    this.StoredBlock = remove;
                    this.ChainState.HighestPersistedBlock = this.StoredBlock;
                    break;
                }

                if (await this.BlockRepository.ExistAsync(next.HashBlock))
                {
                    // next block is in storage update StoredBlock
                    await this.BlockRepository.SetBlockHash(next.HashBlock);

                    this.StoredBlock = next;
                    this.ChainState.HighestPersistedBlock = this.StoredBlock;
                    continue;
                }

                // check if the next block is in pending storage
                // then loop over the pending items and push to store in batches
                // if a stop condition is met break from the loop back to the start
                BlockPair insert;
                if (this.PendingStorage.TryGetValue(next.HashBlock, out insert))
                {
                    // if in IBD and batch is not full then wait for more blocks
                    if (this.ChainState.IsInitialBlockDownload && !disposemode)
                    {
                        if (this.PendingStorage.Skip(0).Count() < batchtriggersize)                         // ConcurrentDictionary perf
                        {
                            break;
                        }
                    }

                    if (!this.PendingStorage.TryRemove(next.HashBlock, out insert))
                    {
                        break;
                    }

                    var tostore    = new List <BlockPair>(new[] { insert });
                    var storebest  = next;
                    var insertSize = insert.Block.GetSerializedSize();
                    while (!token.IsCancellationRequested)
                    {
                        var old = next;
                        next = this.chain.GetBlock(next.Height + 1);

                        var stop = false;
                        // stop if at the tip or block is already in store or pending insertion
                        if (next == null)
                        {
                            stop = true;
                        }
                        else if (next.Header.HashPrevBlock != old.HashBlock)
                        {
                            stop = true;
                        }
                        else if (next.Height > this.ChainState.HighestValidatedPoW?.Height)
                        {
                            stop = true;
                        }
                        else if (!this.PendingStorage.TryRemove(next.HashBlock, out insert))
                        {
                            stop = true;
                        }

                        if (stop)
                        {
                            if (!tostore.Any())
                            {
                                break;
                            }
                        }
                        else
                        {
                            tostore.Add(insert);
                            storebest   = next;
                            insertSize += insert.Block.GetSerializedSize();                             // TODO: add the size to the result coming from the signaler
                        }

                        if (insertSize > insertsizebyte || stop)
                        {
                            // store missing blocks and remove them from pending blocks
                            await this.BlockRepository.PutAsync(storebest.HashBlock, tostore.Select(b => b.Block).ToList());

                            this.StoredBlock = storebest;
                            this.ChainState.HighestPersistedBlock = this.StoredBlock;

                            if (stop)
                            {
                                break;
                            }

                            tostore.Clear();
                            insertSize = 0;

                            // this can be twicked if insert is effecting the consensus speed
                            if (this.ChainState.IsInitialBlockDownload)
                            {
                                await Task.Delay(pushIntervalIBD, token);
                            }
                        }
                    }

                    continue;
                }

                if (disposemode)
                {
                    break;
                }

                // continuously download blocks until a stop condition is found.
                // there are two operations, one is finding blocks to download
                // and asking them to the puller and the other is collecting
                // downloaded blocks and persisting them as a batch.
                var store         = new List <BlockPair>();
                var downloadStack = new Queue <ChainedBlock>(new[] { next });
                this.blockPuller.AskBlock(next);

                int  insertdownloadSize = 0;
                bool download           = true;
                while (!token.IsCancellationRequested)
                {
                    if (download)
                    {
                        var old = next;
                        next = this.chain.GetBlock(old.Height + 1);

                        var stop = false;
                        // stop if at the tip or block is already in store or pending insertion
                        if (next == null)
                        {
                            stop = true;
                        }
                        else if (next.Header.HashPrevBlock != old.HashBlock)
                        {
                            stop = true;
                        }
                        else if (next.Height > this.ChainState.HighestValidatedPoW?.Height)
                        {
                            stop = true;
                        }
                        else if (this.PendingStorage.ContainsKey(next.HashBlock))
                        {
                            stop = true;
                        }
                        else if (await this.BlockRepository.ExistAsync(next.HashBlock))
                        {
                            stop = true;
                        }

                        if (stop)
                        {
                            if (!downloadStack.Any())
                            {
                                break;
                            }

                            download = false;
                        }
                        else
                        {
                            this.blockPuller.AskBlock(next);
                            downloadStack.Enqueue(next);

                            if (downloadStack.Count == batchdownloadsize)
                            {
                                download = false;
                            }
                        }
                    }

                    BlockPuller.DownloadedBlock block;
                    if (this.blockPuller.TryGetBlock(downloadStack.Peek(), out block))
                    {
                        var downloadbest = downloadStack.Dequeue();
                        store.Add(new BlockPair {
                            Block = block.Block, ChainedBlock = downloadbest
                        });
                        insertdownloadSize += block.Length;

                        // can we push
                        if (insertdownloadSize > insertsizebyte || !downloadStack.Any())                         // this might go above the max insert size
                        {
                            await this.BlockRepository.PutAsync(downloadbest.HashBlock, store.Select(t => t.Block).ToList());

                            this.StoredBlock = downloadbest;
                            this.ChainState.HighestPersistedBlock = this.StoredBlock;
                            insertdownloadSize = 0;
                            store.Clear();

                            if (!downloadStack.Any())
                            {
                                break;
                            }
                        }
                    }
                    else
                    {
                        // waiting for blocks so sleep one
                        await Task.Delay(100, token);
                    }
                }
            }
        }
Beispiel #6
0
		void Intercept(IncomingMessage message, Action act)
		{
			var inv = message.Message.Payload as InvPayload;
			if(inv != null)
			{
				if(inv.Inventory.Any(i => ((i.Type & InventoryType.MSG_BLOCK) != 0) && !Chain.Contains(i.Hash)))
				{
					_Refresh.Dispose(); //No need of periodical refresh, the peer is notifying us
					if(AutoSync)
						TrySync();
				}
			}

			var getheaders = message.Message.Payload as GetHeadersPayload;
			if(getheaders != null && CanRespondToGetHeaders)
			{
				HeadersPayload headers = new HeadersPayload();
				var fork = Chain.FindFork(getheaders.BlockLocators);
				if(fork != null)
					foreach(var header in Chain.EnumerateToTip(fork).Skip(1))
					{
						headers.Headers.Add(header.Header);
						if(header.HashBlock == getheaders.HashStop || headers.Headers.Count == 2000)
							break;
					}
				AttachedNode.SendMessageAsync(headers);
			}

			var newheaders = message.Message.Payload as HeadersPayload;
			var pendingTipBefore = GetPendingTip();
			if(newheaders != null && CanSync)
			{
				var tip = GetPendingTip();
				foreach(var header in newheaders.Headers)
				{
					var prev = tip.FindAncestorOrSelf(header.HashPrevBlock);
					if(prev == null)
						break;
					tip = new ChainedBlock(header, header.GetHash(), prev);
					if(!AttachedNode.IsTrusted)
					{
						var validated = Chain.GetBlock(tip.HashBlock) != null || tip.Validate(AttachedNode.Network);
						if(!validated)
						{
							invalidHeaderReceived = true;
							break;
						}
					}
					_PendingTip = tip;
				}
				if(_PendingTip.Height > Chain.Tip.Height)
				{
					Chain.SetTip(_PendingTip);
				}

				var chainedPendingTip = Chain.GetBlock(_PendingTip.HashBlock);
				if(chainedPendingTip != null)
				{
					_PendingTip = chainedPendingTip; //This allows garbage collection to collect the duplicated pendingtip and ancestors
				}
				if(newheaders.Headers.Count != 0 && pendingTipBefore.HashBlock != GetPendingTip().HashBlock)
					TrySync();
				Interlocked.Decrement(ref _SynchingCount);
			}

			act();
		}
 public static void IndexingChain(ChainedBlock from, ChainedBlock to)
 {
     _Trace.TraceInformation("Indexing blocks from " + ToString(from) + " to " + ToString(to) + " (both included)");
 }
 internal static void IndexedChainIsUpToDate(ChainedBlock block)
 {
     _Trace.TraceInformation("Indexed chain is up to date at height " + ToString(block));
 }
        public RuleContext(BlockValidationContext blockValidationContext, NBitcoin.Consensus consensus, ChainedBlock consensusTip)
        {
            Guard.NotNull(blockValidationContext, nameof(blockValidationContext));
            Guard.NotNull(consensus, nameof(consensus));

            this.BlockValidationContext = blockValidationContext;
            this.Consensus    = consensus;
            this.ConsensusTip = consensusTip;

            // TODO: adding flags to determine the flow of logic is not ideal
            // a refator is in debate on moving to a consensus rules engine
            // this will remove the need for flags as validation will only use
            // the required rules (i.e if the check pow rule will be ommited form the flow)
            this.CheckPow        = true;
            this.CheckMerkleRoot = true;
        }
 public GetTxOutModel(UnspentOutputs unspentOutputs, uint vout, Network network, ChainedBlock tip)
 {
     if (unspentOutputs != null)
     {
         var output = unspentOutputs.TryGetOutput(vout);
         this.bestblock     = tip.HashBlock;
         this.coinbase      = unspentOutputs.IsCoinbase;
         this.confirmations = NetworkExtensions.MempoolHeight == unspentOutputs.Height ? 0 : tip.Height - (int)unspentOutputs.Height + 1;
         if (output != null)
         {
             this.value        = output.Value;
             this.scriptPubKey = new ScriptPubKey(output.ScriptPubKey, network);
         }
     }
 }
			public override ChainedBlock SetTip(ChainedBlock pindex)
			{
				throw new NotImplementedException();
			}
		private bool Notify(Transaction tx, MerkleBlock blk)
		{
			bool hit = false;
			if(blk == null)
			{
				hit = _Tracker.NotifyTransaction(tx);
			}
			else
			{
				var prev = _Chain.GetBlock(blk.Header.HashPrevBlock);
				if(prev != null)
				{
					var header = new ChainedBlock(blk.Header, null, prev);
					hit = _Tracker.NotifyTransaction(tx, header, blk);
				}
				else
				{
					hit = _Tracker.NotifyTransaction(tx);
				}
			}

			Interlocked.Increment(ref _TotalReceived);
			if(!hit)
			{
				Interlocked.Increment(ref _FalsePositiveCount);
				if(MaximumFalsePositiveRate != null
					&& _TotalReceived > 100
					&& ActualFalsePostiveRate >= MaximumFalsePositiveRate.Value)
				{
					this.AttachedNode.DisconnectAsync("The actual false positive rate exceed MaximumFalsePositiveRate");
				}
			}
			return hit;
		}
Beispiel #13
0
        public void TestChainedBlockEquality()
        {
            var randomChainedBlock = RandomData.RandomChainedBlock();

            var sameChainedBlock = new ChainedBlock
            (
                blockHash: randomChainedBlock.BlockHash,
                previousBlockHash: randomChainedBlock.PreviousBlockHash,
                height: randomChainedBlock.Height,
                totalWork: randomChainedBlock.TotalWork
            );

            var differentChainedBlockBlockHash = new ChainedBlock
            (
                blockHash: ~randomChainedBlock.BlockHash,
                previousBlockHash: randomChainedBlock.PreviousBlockHash,
                height: randomChainedBlock.Height,
                totalWork: randomChainedBlock.TotalWork
            );

            var differentChainedBlockPreviousBlockHash = new ChainedBlock
            (
                blockHash: randomChainedBlock.BlockHash,
                previousBlockHash: ~randomChainedBlock.PreviousBlockHash,
                height: randomChainedBlock.Height,
                totalWork: randomChainedBlock.TotalWork
            );

            var differentChainedBlockHeight = new ChainedBlock
            (
                blockHash: randomChainedBlock.BlockHash,
                previousBlockHash: randomChainedBlock.PreviousBlockHash,
                height: ~randomChainedBlock.Height,
                totalWork: randomChainedBlock.TotalWork
            );

            var differentChainedBlockTotalWork = new ChainedBlock
            (
                blockHash: randomChainedBlock.BlockHash,
                previousBlockHash: randomChainedBlock.PreviousBlockHash,
                height: randomChainedBlock.Height,
                totalWork: ~randomChainedBlock.TotalWork
            );

            Assert.IsTrue(randomChainedBlock.Equals(sameChainedBlock));
            Assert.IsTrue(randomChainedBlock == sameChainedBlock);
            Assert.IsFalse(randomChainedBlock != sameChainedBlock);

            Assert.IsFalse(randomChainedBlock.Equals(differentChainedBlockBlockHash));
            Assert.IsFalse(randomChainedBlock == differentChainedBlockBlockHash);
            Assert.IsTrue(randomChainedBlock != differentChainedBlockBlockHash);

            Assert.IsFalse(randomChainedBlock.Equals(differentChainedBlockPreviousBlockHash));
            Assert.IsFalse(randomChainedBlock == differentChainedBlockPreviousBlockHash);
            Assert.IsTrue(randomChainedBlock != differentChainedBlockPreviousBlockHash);

            Assert.IsFalse(randomChainedBlock.Equals(differentChainedBlockHeight));
            Assert.IsFalse(randomChainedBlock == differentChainedBlockHeight);
            Assert.IsTrue(randomChainedBlock != differentChainedBlockHeight);

            Assert.IsFalse(randomChainedBlock.Equals(differentChainedBlockTotalWork));
            Assert.IsFalse(randomChainedBlock == differentChainedBlockTotalWork);
            Assert.IsTrue(randomChainedBlock != differentChainedBlockTotalWork);
        }
Beispiel #14
0
		private Operation Received(TrackedScript match, IndexedTxOut txout, ChainedBlock block, MerkleBlock proof)
		{
			var operation = new Operation(txout.Transaction, block, proof, _TrackedScripts);
			SetUnconfirmedSeenIfPossible(txout.Transaction, block, operation);
			var coin = new Coin(txout);
			operation.ReceivedCoins.Add(Tuple.Create(coin, match.GetId()));

			bool merged = false;
			var returned = _Operations.AddOrUpdate(operation.GetId(), operation, (k, old) => old.Merge(operation, out merged));
			var trackedOutpoint = new TrackedOutpoint()
			{
				Coin = coin,
				TrackedScriptId = match.GetId(),
				Filter = match.Filter
			};
			_TrackedOutpoints.TryAdd(trackedOutpoint.GetId(), trackedOutpoint);
			return (operation == returned || merged) ? operation : null;
		}
Beispiel #15
0
		private Operation Spent(TrackedScript metadata, IndexedTxIn txin, Coin coin, ChainedBlock block, MerkleBlock proof)
		{
			var operation = new Operation(txin.Transaction, block, proof, _TrackedScripts);
			operation.SpentCoins.Add(Tuple.Create(coin, metadata.GetId()));
			SetUnconfirmedSeenIfPossible(txin.Transaction, block, operation);

			bool merged = false;
			var returned = _Operations.AddOrUpdate(operation.GetId(), operation, (k, old) => old.Merge(operation, out merged));
			return (operation == returned || merged) ? operation : null;
		}
 internal static void CheckpointSaved(ChainedBlock block, string checkpointName)
 {
     _Trace.TraceInformation("Checkpoint " + checkpointName + " saved at " + ToString(block));
 }
        /// <inheritdoc />
        public void ProcessBlock(Block block)
        {
            Guard.NotNull(block, nameof(block));
            this.logger.LogTrace("({0}:'{1}')", nameof(block), block.GetHash());

            ChainedBlock newTip = this.chain.GetBlock(block.GetHash());

            if (newTip == null)
            {
                this.logger.LogTrace("(-)[NEW_TIP_REORG]");
                return;
            }

            // If the new block's previous hash is the same as the
            // wallet hash then just pass the block to the manager.
            if (block.Header.HashPrevBlock != this.walletTip.HashBlock)
            {
                // If previous block does not match there might have
                // been a reorg, check if the wallet is still on the main chain.
                ChainedBlock inBestChain = this.chain.GetBlock(this.walletTip.HashBlock);
                if (inBestChain == null)
                {
                    // The current wallet hash was not found on the main chain.
                    // A reorg happened so bring the wallet back top the last known fork.
                    ChainedBlock fork = this.walletTip;

                    // We walk back the chained block object to find the fork.
                    while (this.chain.GetBlock(fork.HashBlock) == null)
                    {
                        fork = fork.Previous;
                    }

                    this.logger.LogInformation("Reorg detected, going back from '{0}' to '{1}'.", this.walletTip, fork);

                    this.walletManager.RemoveBlocks(fork);
                    this.walletTip = fork;

                    this.logger.LogTrace("Wallet tip set to '{0}'.", this.walletTip);
                }

                // The new tip can be ahead or behind the wallet.
                // If the new tip is ahead we try to bring the wallet up to the new tip.
                // If the new tip is behind we just check the wallet and the tip are in the same chain.

                if (newTip.Height > this.walletTip.Height)
                {
                    ChainedBlock findTip = newTip.FindAncestorOrSelf(this.walletTip.HashBlock);
                    if (findTip == null)
                    {
                        this.logger.LogTrace("(-)[NEW_TIP_AHEAD_NOT_IN_WALLET]");
                        return;
                    }

                    this.logger.LogTrace("Wallet tip '{0}' is behind the new tip '{1}'.", this.walletTip, newTip);

                    // The wallet is falling behind we need to catch up.
                    this.logger.LogWarning("New tip '{0}' is too far in advance, put the puller back.", newTip);
                    this.blockNotification.SyncFrom(this.walletTip.HashBlock);
                    return;
                }
                else
                {
                    ChainedBlock findTip = this.walletTip.FindAncestorOrSelf(newTip.HashBlock);
                    if (findTip == null)
                    {
                        this.logger.LogTrace("(-)[NEW_TIP_BEHIND_NOT_IN_WALLET]");
                        return;
                    }

                    this.logger.LogTrace("Wallet tip '{0}' is ahead or equal to the new tip '{1}'.", this.walletTip, newTip.HashBlock);
                }
            }
            else
            {
                this.logger.LogTrace("New block follows the previously known block '{0}'.", this.walletTip);
            }

            this.walletTip = newTip;
            this.walletManager.ProcessBlock(block, newTip);

            this.logger.LogTrace("(-)");
        }
			public void Return(BlockHeader header, int height)
			{
				_Return = new ChainedBlock(header, height);
			}
 public void SetLocation(ChainedBlock tip)
 {
     Guard.NotNull(tip, nameof(tip));
     _Location = tip;
 }
Beispiel #20
0
		private bool Notify(Transaction tx, MerkleBlock blk)
		{
			bool hit = false;
			if(blk == null)
			{
				hit = _Tracker.NotifyTransaction(tx);
			}
			else
			{
				var prev = _Chain.GetBlock(blk.Header.HashPrevBlock);
				if(prev != null)
				{
					var header = new ChainedBlock(blk.Header, null, prev);
					hit = _Tracker.NotifyTransaction(tx, header, blk);
				}
				else
				{
					hit = _Tracker.NotifyTransaction(tx);
				}
			}

			Interlocked.Increment(ref _TotalReceived);
			if(!hit)
			{
				Interlocked.Increment(ref _FalsePositiveCount);
			}
			return hit;
		}
        void Intercept(IncomingMessage message, Action act)
        {
            var inv = message.Message.Payload as InvPayload;

            if (inv != null)
            {
                if (inv.Inventory.Any(i => ((i.Type & InventoryType.MSG_BLOCK) != 0) && !Chain.Contains(i.Hash)))
                {
                    _Refresh.Dispose();                     //No need of periodical refresh, the peer is notifying us
                    if (AutoSync)
                    {
                        TrySync();
                    }
                }
            }

            var getheaders = message.Message.Payload as GetHeadersPayload;

            if (getheaders != null && CanRespondToGetHeaders && !StripHeader)
            {
                HeadersPayload headers    = new HeadersPayload();
                var            highestPow = SharedState.HighestValidatedPoW;
                highestPow = highestPow == null ? null : Chain.GetBlock(highestPow.HashBlock);
                var fork = Chain.FindFork(getheaders.BlockLocators);
                if (fork != null)
                {
                    if (highestPow != null && fork.Height > highestPow.Height)
                    {
                        fork = null;                         //fork not yet validated
                    }
                    if (fork != null)
                    {
                        foreach (var header in Chain.EnumerateToTip(fork).Skip(1))
                        {
                            if (highestPow != null && header.Height > highestPow.Height)
                            {
                                break;
                            }
                            headers.Headers.Add(header.Header);
                            if (header.HashBlock == getheaders.HashStop || headers.Headers.Count == 2000)
                            {
                                break;
                            }
                        }
                    }
                }
                AttachedNode.SendMessageAsync(headers);
            }

            var newheaders       = message.Message.Payload as HeadersPayload;
            var pendingTipBefore = GetPendingTipOrChainTip();

            if (newheaders != null && CanSync)
            {
                var tip = GetPendingTipOrChainTip();
                foreach (var header in newheaders.Headers)
                {
                    var prev = tip.FindAncestorOrSelf(header.HashPrevBlock);
                    if (prev == null)
                    {
                        break;
                    }
                    tip = new ChainedBlock(header, header.GetHash(), prev);
                    var validated = Chain.GetBlock(tip.HashBlock) != null || (SkipPoWCheck || tip.Validate(AttachedNode.Network));
                    validated &= !SharedState.IsMarkedInvalid(tip.HashBlock);
                    if (!validated)
                    {
                        invalidHeaderReceived = true;
                        break;
                    }
                    _PendingTip = tip;
                }

                bool isHigherBlock = false;
                if (SkipPoWCheck)
                {
                    isHigherBlock = _PendingTip.Height > Chain.Tip.Height;
                }
                else
                {
                    isHigherBlock = _PendingTip.GetChainWork(true) > Chain.Tip.GetChainWork(true);
                }

                if (isHigherBlock)
                {
                    Chain.SetTip(_PendingTip);
                    if (StripHeader)
                    {
                        _PendingTip.StripHeader();
                    }
                }

                var chainedPendingTip = Chain.GetBlock(_PendingTip.HashBlock);
                if (chainedPendingTip != null)
                {
                    _PendingTip = chainedPendingTip;                     //This allows garbage collection to collect the duplicated pendingtip and ancestors
                }
                if (newheaders.Headers.Count != 0 && pendingTipBefore.HashBlock != GetPendingTipOrChainTip().HashBlock)
                {
                    TrySync();
                }
                Interlocked.Decrement(ref _SynchingCount);
            }

            act();
        }
Beispiel #22
0
		public bool NotifyTransaction(Transaction transaction, ChainedBlock chainedBlock, MerkleBlock proof)
		{
			if(chainedBlock != null)
			{
				if(proof == null)
					throw new ArgumentNullException("proof");
				if(proof.Header.GetHash() != chainedBlock.Header.GetHash())
					throw new InvalidOperationException("The chained block and the merkle block are different blocks");
				if(!proof.PartialMerkleTree.Check(chainedBlock.Header.HashMerkleRoot))
					throw new InvalidOperationException("The MerkleBlock does not have the expected merkle root");
				if(!proof.PartialMerkleTree.GetMatchedTransactions().Contains(transaction.GetHash()))
					throw new InvalidOperationException("The MerkleBlock does not contains the input transaction");
			}

			var interesting = false;
			lock(cs)
			{
				foreach(var txin in transaction.Inputs.AsIndexedInputs())
				{
					var key = TrackedOutpoint.GetId(txin.PrevOut);
					TrackedOutpoint match;
					if(_TrackedOutpoints.TryGetValue(key, out match))
					{
						TrackedScript parentMetadata;
						if(_TrackedScripts.TryGetValue(match.TrackedScriptId, out parentMetadata))
						{
							interesting = true;
							Spent(parentMetadata, txin, match.Coin, chainedBlock, proof);
						}

					}
				}
				foreach(var txout in transaction.Outputs.AsIndexedOutputs())
				{
					var key = TrackedScript.GetId(txout.TxOut.ScriptPubKey);
					TrackedScript match;
					if(_TrackedScripts.TryGetValue(key, out match))
					{
						interesting = true;
						Received(match, txout, chainedBlock, proof);
					}
				}
			}
			return interesting;
		}
Beispiel #23
0
        private ChainedBlock AppendBlock(params ConcurrentChain[] chains)
        {
            ChainedBlock index = null;

            return(AppendBlock(index, chains));
        }
 private static string ToString(ChainedBlock chainedBlock)
 {
     if (chainedBlock == null)
         return "(null)";
     return ToString(chainedBlock.HashBlock, chainedBlock.Height);
 }
Beispiel #25
0
		private void Notify(Transaction tx, MerkleBlock blk)
		{
			if(blk == null)
			{
				_Tracker.NotifyTransaction(tx);
			}
			else
			{
				var prev = _Chain.GetBlock(blk.Header.HashPrevBlock);
				if(prev != null)
				{
					var header = new ChainedBlock(blk.Header, null, prev);
					_Tracker.NotifyTransaction(tx, header, blk);
				}
				else
				{
					_Tracker.NotifyTransaction(tx);
				}
			}
		}
        public virtual void CheckBlockReward(ContextInformation context, Money nFees, ChainedBlock chainedBlock, Block block)
        {
            Money blockReward = nFees + GetProofOfWorkReward(chainedBlock.Height);

            if (block.Transactions[0].TotalOut > blockReward)
            {
                ConsensusErrors.BadCoinbaseAmount.Throw();
            }
        }
Beispiel #27
0
		private void Received(TrackedScript match, IndexedTxOut txout, ChainedBlock block, MerkleBlock proof)
		{
			var operation = new Operation(txout.Transaction, block, proof);
			SetUnconfirmedSeenIfPossible(txout.Transaction, block, operation);
			var coin = new Coin(txout);
			operation.ReceivedCoins.Add(Tuple.Create(coin, match.GetId()));
			_Operations.AddOrUpdate(operation.GetId(), operation, (k, old) => old.Merge(operation));
			var trackedOutpoint = new TrackedOutpoint()
			{
				Coin = coin,
				TrackedScriptId = match.GetId(),
				Filter = match.Filter
			};
			_TrackedOutpoints.TryAdd(trackedOutpoint.GetId(), trackedOutpoint);
		}
Beispiel #28
0
        public Testnet2Rules(CacheContext cacheContext)
            : base(cacheContext)
        {
            this._genesisBlock =
                new Block
                (
                    header: new BlockHeader
                    (
                        version: 1,
                        previousBlock: 0,
                        merkleRoot: UInt256.Parse("4a5e1e4baab89f3a32518a88c31bc87f618f76673e2cc77ab2127b7afdeda33b", NumberStyles.HexNumber),
                        time: 1296688602,
                        bits: 0x207FFFFF,
                        nonce: 2
                    ),
                    transactions: ImmutableArray.Create
                    (
                        new Transaction
                        (
                            version: 1,
                            inputs: ImmutableArray.Create
                            (
                                new TxInput
                                (
                                    previousTxOutputKey: new TxOutputKey
                                    (
                                        txHash: 0,
                                        txOutputIndex: 0xFFFFFFFF
                                    ),
                                    scriptSignature: ImmutableArray.Create <byte>
                                    (
                                        0x04, 0xFF, 0xFF, 0x00, 0x1D, 0x01, 0x04, 0x45, 0x54, 0x68, 0x65, 0x20, 0x54, 0x69, 0x6D, 0x65,
                                        0x73, 0x20, 0x30, 0x33, 0x2F, 0x4A, 0x61, 0x6E, 0x2F, 0x32, 0x30, 0x30, 0x39, 0x20, 0x43, 0x68,
                                        0x61, 0x6E, 0x63, 0x65, 0x6C, 0x6C, 0x6F, 0x72, 0x20, 0x6F, 0x6E, 0x20, 0x62, 0x72, 0x69, 0x6E,
                                        0x6B, 0x20, 0x6F, 0x66, 0x20, 0x73, 0x65, 0x63, 0x6F, 0x6E, 0x64, 0x20, 0x62, 0x61, 0x69, 0x6C,
                                        0x6F, 0x75, 0x74, 0x20, 0x66, 0x6F, 0x72, 0x20, 0x62, 0x61, 0x6E, 0x6B, 0x73
                                    ),
                                    sequence: 0xFFFFFFFF
                                )
                            ),
                            outputs: ImmutableArray.Create
                            (
                                new TxOutput
                                (
                                    value: (UInt64)(50L * 100.MILLION()),
                                    scriptPublicKey: ImmutableArray.Create <byte>
                                    (
                                        0x41, 0x04, 0x67, 0x8A, 0xFD, 0xB0, 0xFE, 0x55, 0x48, 0x27, 0x19, 0x67, 0xF1, 0xA6, 0x71, 0x30,
                                        0xB7, 0x10, 0x5C, 0xD6, 0xA8, 0x28, 0xE0, 0x39, 0x09, 0xA6, 0x79, 0x62, 0xE0, 0xEA, 0x1F, 0x61,
                                        0xDE, 0xB6, 0x49, 0xF6, 0xBC, 0x3F, 0x4C, 0xEF, 0x38, 0xC4, 0xF3, 0x55, 0x04, 0xE5, 0x1E, 0xC1,
                                        0x12, 0xDE, 0x5C, 0x38, 0x4D, 0xF7, 0xBA, 0x0B, 0x8D, 0x57, 0x8A, 0x4C, 0x70, 0x2B, 0x6B, 0xF1,
                                        0x1D, 0x5F, 0xAC
                                    )
                                )
                            ),
                            lockTime: 0
                        )
                    )
                );

            Debug.Assert(_genesisBlock.Hash == UInt256.Parse("0f9188f13cb7b2c71f2a335e3a4fc328bf5beb436012afca590b1a11466e2206", NumberStyles.HexNumber));

            this._genesisChainedBlock =
                new ChainedBlock
                (
                    blockHash: this._genesisBlock.Hash,
                    previousBlockHash: this._genesisBlock.Header.PreviousBlock,
                    height: 0,
                    totalWork: this._genesisBlock.Header.CalculateWork()
                );

            this._genesisBlockchain =
                new Data.Blockchain
                (
                    blockList: ImmutableList.Create(this._genesisChainedBlock),
                    blockListHashes: ImmutableHashSet.Create(this._genesisBlock.Hash),
                    utxo: ImmutableDictionary.Create <UInt256, UnspentTx>() // genesis block coinbase is not included in utxo, it is unspendable
                );
        }
Beispiel #29
0
		private ChainedBlock GetPendingTip()
		{
			_PendingTip = _PendingTip ?? Chain.Tip;
			return _PendingTip;
		}
 public abstract BlockAssembler Create(ChainedBlock chainTip, AssemblerOptions options = null);
Beispiel #31
0
 public override void SaveChanges(ChainedBlock newTip, IEnumerable <uint256> txIds, IEnumerable <Coins> coins)
 {
     _CurrentPrefetch = _PrefetchesByPrev.TryGet(newTip.HashBlock);
     _PrefetchesByPrev.Remove(newTip.HashBlock);
     _Inner.SaveChanges(newTip, txIds, coins);
 }
 public override BlockAssembler Create(ChainedBlock chainTip, AssemblerOptions options = null)
 {
     return(new PowBlockAssembler(this.consensusLoop, this.network, this.mempoolLock, this.mempool, this.dateTimeProvider, chainTip, this.loggerFactory, options));
 }
Beispiel #33
0
 internal abstract Task <BlockStoreLoopStepResult> ExecuteAsync(ChainedBlock nextChainedBlock, CancellationToken cancellationToken, bool disposeMode);
Beispiel #34
0
        private void Intercept(IncomingMessage message, Action continueInvocation)
        {
            this.logger.LogTrace("({0}:'{1}',{2}:'{3}')", nameof(message), message.Message.Command, nameof(this.AttachedNode), this.AttachedNode?.RemoteSocketEndpoint);

            var inv = message.Message.Payload as InvPayload;

            if (inv != null)
            {
                if (inv.Inventory.Any(i => ((i.Type & InventoryType.MSG_BLOCK) != 0) && !this.Chain.Contains(i.Hash)))
                {
                    // No need of periodical refresh, the peer is notifying us.
                    this.refreshTimer.Dispose();
                    if (this.AutoSync)
                    {
                        this.TrySync();
                    }
                }
            }

            // == GetHeadersPayload ==
            // Represents our height from the peer's point of view.
            // It is sent from the peer on first connect, in response to Inv(Block)
            // or in response to HeaderPayload until an empty array is returned.
            // This payload notifies peers of our current best validated height.
            // Use the ChainState.ConsensusTip property (not Chain.Tip)
            // if the peer is behind/equal to our best height an empty array is sent back.

            // Ignoring "getheaders" from peers because node is in initial block download.
            var getheaders = message.Message.Payload as GetHeadersPayload;

            if ((getheaders != null) &&
                this.CanRespondToGetHeaders
                // If not in IBD whitelisted won't be checked.
                && (!this.chainState.IsInitialBlockDownload || this.AttachedNode.Behavior <ConnectionManagerBehavior>().Whitelisted))
            {
                HeadersPayload headers      = new HeadersPayload();
                ChainedBlock   consensusTip = this.chainState.ConsensusTip;
                consensusTip = this.Chain.GetBlock(consensusTip.HashBlock);

                ChainedBlock fork = this.Chain.FindFork(getheaders.BlockLocators);
                if (fork != null)
                {
                    if ((consensusTip == null) || (fork.Height > consensusTip.Height))
                    {
                        // Fork not yet validated.
                        fork = null;
                    }

                    if (fork != null)
                    {
                        foreach (ChainedBlock header in this.Chain.EnumerateToTip(fork).Skip(1))
                        {
                            if (header.Height > consensusTip.Height)
                            {
                                break;
                            }

                            headers.Headers.Add(header.Header);
                            if ((header.HashBlock == getheaders.HashStop) || (headers.Headers.Count == 2000))
                            {
                                break;
                            }
                        }
                    }
                }

                this.AttachedNode.SendMessageAsync(headers);
            }

            // == HeadersPayload ==
            // Represents the peers height from our point view.
            // This updates the pending tip parameter which is
            // the peers current best validated height.
            // If the peer's height is higher Chain.Tip is updated to have
            // the most PoW header.
            // It is sent in response to GetHeadersPayload or is solicited by the
            // peer when a new block is validated (and not in IBD).

            var newHeaders = message.Message.Payload as HeadersPayload;

            if ((newHeaders != null) && this.CanSync)
            {
                ChainedBlock pendingTipBefore = this.GetPendingTipOrChainTip();
                this.logger.LogTrace("Pending tip is '{0}', received {1} new headers.", pendingTipBefore, newHeaders.Headers.Count);

                // TODO: implement MAX_HEADERS_RESULTS in NBitcoin.HeadersPayload

                ChainedBlock tip = pendingTipBefore;
                foreach (BlockHeader header in newHeaders.Headers)
                {
                    ChainedBlock prev = tip.FindAncestorOrSelf(header.HashPrevBlock);
                    if (prev == null)
                    {
                        break;
                    }

                    tip = new ChainedBlock(header, header.GetHash(), prev);
                    bool validated = this.Chain.GetBlock(tip.HashBlock) != null || tip.Validate(this.AttachedNode.Network);
                    validated &= !this.chainState.IsMarkedInvalid(tip.HashBlock);
                    if (!validated)
                    {
                        this.logger.LogTrace("Validation of new header '{0}' failed.", tip);
                        this.invalidHeaderReceived = true;
                        break;
                    }

                    this.pendingTip = tip;
                }

                if (pendingTipBefore != this.pendingTip)
                {
                    this.logger.LogTrace("Pending tip changed to '{0}'.", this.pendingTip);
                }

                // Long reorganization protection on POS networks.
                bool reorgPrevented = false;
                uint maxReorgLength = this.chainState.MaxReorgLength;
                if (maxReorgLength != 0)
                {
                    Network      network      = this.AttachedNode?.Network;
                    ChainedBlock consensusTip = this.chainState.ConsensusTip;
                    if ((network != null) && (consensusTip != null))
                    {
                        ChainedBlock fork = this.pendingTip.FindFork(consensusTip);
                        if ((fork != null) && (fork != consensusTip))
                        {
                            int reorgLength = consensusTip.Height - fork.Height;
                            if (reorgLength > maxReorgLength)
                            {
                                this.logger.LogTrace("Reorganization of length {0} prevented, maximal reorganization length is {1}, consensus tip is '{2}'.", reorgLength, maxReorgLength, consensusTip);
                                this.invalidHeaderReceived = true;
                                reorgPrevented             = true;
                            }
                            else
                            {
                                this.logger.LogTrace("Reorganization of length {0} accepted, consensus tip is '{1}'.", reorgLength, consensusTip);
                            }
                        }
                    }
                }

                if (!reorgPrevented && (this.pendingTip.ChainWork > this.Chain.Tip.ChainWork))
                {
                    this.logger.LogTrace("New chain tip '{0}' selected, chain work is '{1}'.", this.pendingTip, this.pendingTip.ChainWork);
                    this.Chain.SetTip(this.pendingTip);
                }

                ChainedBlock chainedPendingTip = this.Chain.GetBlock(this.pendingTip.HashBlock);
                if (chainedPendingTip != null)
                {
                    // This allows garbage collection to collect the duplicated pendingTip and ancestors.
                    this.pendingTip = chainedPendingTip;
                }

                if ((!this.invalidHeaderReceived) && (newHeaders.Headers.Count != 0) && (pendingTipBefore.HashBlock != this.GetPendingTipOrChainTip().HashBlock))
                {
                    this.TrySync();
                }
            }

            continueInvocation();

            this.logger.LogTrace("(-)");
        }
Beispiel #35
0
        /// <summary>
        /// Initialize the BlockStore
        /// <para>
        /// If StoreTip is <c>null</c>, the store is out of sync. This can happen when:</para>
        /// <list>
        ///     <item>1. The node crashed.</item>
        ///     <item>2. The node was not closed down properly.</item>
        /// </list>
        /// <para>
        /// To recover we walk back the chain until a common block header is found
        /// and set the BlockStore's StoreTip to that.
        /// </para>
        /// </summary>
        public async Task Initialize()
        {
            this.logger.LogTrace("()");

            if (this.nodeArgs.Store.ReIndex)
            {
                throw new NotImplementedException();
            }

            this.StoreTip = this.Chain.GetBlock(this.BlockRepository.BlockHash);

            if (this.StoreTip == null)
            {
                var   blockStoreResetList = new List <uint256>();
                Block resetBlock          = await this.BlockRepository.GetAsync(this.BlockRepository.BlockHash);

                uint256 resetBlockHash = resetBlock.GetHash();

                while (this.Chain.GetBlock(resetBlockHash) == null)
                {
                    blockStoreResetList.Add(resetBlockHash);

                    if (resetBlock.Header.HashPrevBlock == this.Chain.Genesis.HashBlock)
                    {
                        resetBlockHash = this.Chain.Genesis.HashBlock;
                        break;
                    }

                    resetBlock = await this.BlockRepository.GetAsync(resetBlock.Header.HashPrevBlock);

                    Guard.NotNull(resetBlock, nameof(resetBlock));
                    resetBlockHash = resetBlock.GetHash();
                }

                ChainedBlock newTip = this.Chain.GetBlock(resetBlockHash);
                await this.BlockRepository.DeleteAsync(newTip.HashBlock, blockStoreResetList);

                this.StoreTip = newTip;
                this.logger.LogWarning("{0} Initialize recovering to block height = {1}, hash = {2}.", this.StoreName, newTip.Height, newTip.HashBlock);
            }

            if (this.nodeArgs.Store.TxIndex != this.BlockRepository.TxIndex)
            {
                if (this.StoreTip != this.Chain.Genesis)
                {
                    throw new BlockStoreException($"You need to rebuild the {this.StoreName} database using -reindex-chainstate to change -txindex");
                }

                if (this.nodeArgs.Store.TxIndex)
                {
                    await this.BlockRepository.SetTxIndex(this.nodeArgs.Store.TxIndex);
                }
            }

            SetHighestPersistedBlock(this.StoreTip);

            this.stepChain = new BlockStoreStepChain();
            this.stepChain.SetNextStep(new ReorganiseBlockRepositoryStep(this, this.loggerFactory));
            this.stepChain.SetNextStep(new CheckNextChainedBlockExistStep(this, this.loggerFactory));
            this.stepChain.SetNextStep(new ProcessPendingStorageStep(this, this.loggerFactory));
            this.stepChain.SetNextStep(new DownloadBlockStep(this, this.loggerFactory, this.dateTimeProvider));

            StartLoop();

            this.logger.LogTrace("(-)");
        }
Beispiel #36
0
 private ChainedBlock GetPendingTipOrChainTip()
 {
     this.pendingTip = this.pendingTip ?? this.chainState.ConsensusTip ?? this.Chain.Tip;
     return(this.pendingTip);
 }
        /// <inheritdoc />
        public void Start()
        {
            // subscribe to receiving blocks and transactions
            this.sub   = this.signals.SubscribeForBlocks(new BlockObserver(this));
            this.txSub = this.signals.SubscribeForTransactions(new TransactionObserver(this));

            // if there is no wallet created yet, the wallet tip is the chain tip.
            if (!this.walletManager.ContainsWallets)
            {
                this.walletTip = this.chain.Tip;
            }
            else
            {
                this.walletTip = this.chain.GetBlock(this.walletManager.WalletTipHash);
                if (this.walletTip == null && this.chain.Height > 0)
                {
                    // the wallet tip was not found in the main chain.
                    // this can happen if the node crashes unexpectedly.
                    // to recover we need to find the first common fork
                    // with the best chain, as the wallet does not have a
                    // list of chain headers we use a BlockLocator and persist
                    // that in the wallet. the block locator will help finding
                    // a common fork and bringing the wallet back to a good
                    // state (behind the best chain)
                    ICollection <uint256> locators     = this.walletManager.GetFirstWalletBlockLocator();
                    BlockLocator          blockLocator = new BlockLocator {
                        Blocks = locators.ToList()
                    };
                    ChainedBlock fork = this.chain.FindFork(blockLocator);
                    this.walletManager.RemoveBlocks(fork);
                    this.walletManager.WalletTipHash = fork.HashBlock;
                    this.walletTip = fork;
                    this.logger.LogWarning($"Wallet tip was out of sync, wallet tip reverted back to Height = {this.walletTip.Height} hash = {this.walletTip.HashBlock}.");
                }

                // we're looking from where to start syncing the wallets.
                // we start by looking at the heights of the wallets and we start syncing from the oldest one (the smallest height).
                // if for some reason we can't find a height, we look at the creation date of the wallets and we start syncing from the earliest date.
                int?earliestWalletHeight = this.walletManager.GetEarliestWalletHeight();
                if (earliestWalletHeight == null)
                {
                    DateTimeOffset oldestWalletDate = this.walletManager.GetOldestWalletCreationTime();

                    if (oldestWalletDate > this.walletTip.Header.BlockTime)
                    {
                        oldestWalletDate = this.walletTip.Header.BlockTime;
                    }

                    this.SyncFromDate(oldestWalletDate.LocalDateTime);
                }
                else
                {
                    // if we reorged and the fork point is before the earliest wallet height start to
                    // sync from the fork point.
                    if (earliestWalletHeight.Value > this.walletTip.Height)
                    {
                        earliestWalletHeight = this.walletTip.Height;
                    }

                    this.SyncFromHeight(earliestWalletHeight.Value);
                }
            }
        }
        public Task AnnounceBlocks(List <uint256> blockHashesToAnnounce)
        {
            this.logger.LogTrace("({0}.{1}:{2})", nameof(blockHashesToAnnounce), nameof(blockHashesToAnnounce.Count), blockHashesToAnnounce?.Count);
            Guard.NotNull(blockHashesToAnnounce, nameof(blockHashesToAnnounce));

            if (!blockHashesToAnnounce.Any())
            {
                this.logger.LogTrace("(-)[NO_HASHES]");
                return(Task.CompletedTask);
            }

            Node node = this.AttachedNode;

            if (node == null)
            {
                this.logger.LogTrace("(-)[NO_NODE]");
                return(Task.CompletedTask);
            }

            bool revertToInv = ((!this.PreferHeaders &&
                                 (!this.preferHeaderAndIDs || blockHashesToAnnounce.Count > 1)) ||
                                blockHashesToAnnounce.Count > MAX_BLOCKS_TO_ANNOUNCE);

            var headers = new List <BlockHeader>();
            var inventoryBlockToSend = new List <uint256>();

            var          chainBehavior = node.Behavior <ChainHeadersBehavior>();
            ChainedBlock bestIndex     = null;

            if (!revertToInv)
            {
                bool foundStartingHeader = false;
                // Try to find first header that our peer doesn't have, and
                // then send all headers past that one.  If we come across any
                // headers that aren't on chainActive, give up.

                foreach (var hash in blockHashesToAnnounce)
                {
                    ChainedBlock chainedBlock = this.chain.GetBlock(hash);
                    if (chainedBlock == null)
                    {
                        // Bail out if we reorged away from this block
                        revertToInv = true;
                        break;
                    }

                    bestIndex = chainedBlock;
                    if (foundStartingHeader)
                    {
                        headers.Add(chainedBlock.Header);
                    }
                    else if (chainBehavior.PendingTip.GetAncestor(chainedBlock.Height) != null)
                    {
                        continue;
                    }
                    else if (chainBehavior.PendingTip.GetAncestor(chainedBlock.Previous.Height) != null)
                    {
                        // Peer doesn't have this header but they do have the prior one.
                        // Start sending headers.
                        foundStartingHeader = true;
                        headers.Add(chainedBlock.Header);
                    }
                    else
                    {
                        // Peer doesn't have this header or the prior one -- nothing will
                        // connect, so bail out.
                        revertToInv = true;
                        break;
                    }
                }
            }

            if (!revertToInv && headers.Any())
            {
                if ((headers.Count == 1) && this.preferHeaderAndIDs)
                {
                    // TODO:
                }
                else if (this.PreferHeaders)
                {
                    if (headers.Count > 1)
                    {
                        this.logger.LogDebug("Sending {0} headers, range {1} - {2}, to peer '{3}'.", headers.Count, headers.First(), headers.Last(), node.RemoteSocketEndpoint);
                    }
                    else
                    {
                        this.logger.LogDebug("Sending header {0} to peer '{1}'.", headers.First(), node.RemoteSocketEndpoint);
                    }

                    chainBehavior.SetPendingTip(bestIndex);
                    Task res = node.SendMessageAsync(new HeadersPayload(headers.ToArray()));
                    this.logger.LogTrace("(-)[SEND_HEADERS_PAYLOAD]");
                    return(res);
                }
                else
                {
                    revertToInv = true;
                }
            }

            if (revertToInv)
            {
                // If falling back to using an inv, just try to inv the tip.
                // The last entry in vBlockHashesToAnnounce was our tip at some point
                // in the past.

                if (blockHashesToAnnounce.Any())
                {
                    uint256      hashToAnnounce = blockHashesToAnnounce.Last();
                    ChainedBlock chainedBlock   = this.chain.GetBlock(hashToAnnounce);
                    if (chainedBlock != null)
                    {
                        if (chainBehavior.PendingTip.GetAncestor(chainedBlock.Height) == null)
                        {
                            inventoryBlockToSend.Add(hashToAnnounce);
                            this.logger.LogDebug("Sending inventory hash '{0}' to peer '{1}'.", hashToAnnounce, node.RemoteSocketEndpoint);
                        }
                    }
                }
            }

            if (inventoryBlockToSend.Any())
            {
                Task res = this.SendAsBlockInventoryAsync(node, inventoryBlockToSend);
                this.logger.LogTrace("(-)[SEND_INVENTORY]");
                return(res);
            }

            this.logger.LogTrace("(-)");
            return(Task.CompletedTask);
        }
Beispiel #39
0
        public override void CheckBlockReward(ContextInformation context, Money nFees, ChainedBlock chainedBlock, Block block)
        {
            if (BlockStake.IsProofOfStake(block))
            {
                // proof of stake invalidates previous inputs
                // and spends the inputs to new outputs with the
                // additional stake reward, next calculate the
                // reward does not exceed the consensus rules

                var stakeReward     = block.Transactions[1].TotalOut - context.Stake.TotalCoinStakeValueIn;
                var calcStakeReward = nFees + GetProofOfStakeReward(chainedBlock.Height);

                if (stakeReward > calcStakeReward)
                {
                    ConsensusErrors.BadCoinstakeAmount.Throw();
                }
            }
            else
            {
                var blockReward = nFees + GetProofOfWorkReward(chainedBlock.Height);
                if (block.Transactions[0].TotalOut > blockReward)
                {
                    ConsensusErrors.BadCoinbaseAmount.Throw();
                }
            }
        }
        public TransactionVerboseModel(Transaction trx, Network network, ChainedBlock block = null, ChainedBlock tip = null) : base(trx)
        {
            if (trx != null)
            {
                this.txid     = trx.GetHash().ToString();
                this.size     = trx.GetSerializedSize();
                this.version  = trx.Version;
                this.locktime = trx.LockTime;

                this.vin = trx.Inputs.Select(txin => new Vin(txin.PrevOut, txin.Sequence, txin.ScriptSig)).ToList();

                int n = 0;
                this.vout = trx.Outputs.Select(txout => new Vout(n++, txout, network)).ToList();

                if (block != null)
                {
                    this.blockhash = block.HashBlock.ToString();
                    this.time      = this.blocktime = Utils.DateTimeToUnixTime(block.Header.BlockTime);
                    if (tip != null)
                    {
                        this.confirmations = tip.Height - block.Height + 1;
                    }
                }
            }
        }
Beispiel #41
0
 public override void SetLocation(ChainedBlock location)
 {
     _Location = location;
 }
Beispiel #42
0
		public ChainedBlock AppendBlock(ChainedBlock previous, params ConcurrentChain[] chains)
		{
			ChainedBlock last = null;
			var nonce = RandomUtils.GetUInt32();
			foreach(var chain in chains)
			{
				var block = TestUtils.CreateFakeBlock(new Transaction());
				block.Header.HashPrevBlock = previous == null ? chain.Tip.HashBlock : previous.HashBlock;
				block.Header.Nonce = nonce;
				if(!chain.TrySetTip(block.Header, out last))
					throw new InvalidOperationException("Previous not existing");
			}
			return last;
		}
 private ChainedBlock GetPendingTipOrChainTip()
 {
     _PendingTip = _PendingTip ?? Chain.Tip;
     return(_PendingTip);
 }
Beispiel #44
0
        /// <summary>
        /// Calculates the difficulty target for the next block.
        /// </summary>
        /// <param name="stakeChain">Database of stake related data for the current blockchain.</param>
        /// <param name="chainedBlock">Block header for which to calculate the target difficulty.</param>
        /// <param name="consensus">Consensus rules for the current network.</param>
        /// <param name="proofOfStake"><c>true</c> for calculation of PoS difficulty target, <c>false</c> for calculation of PoW difficulty target.</param>
        /// <returns>The difficulty target for the next block after <paramref name="chainedBlock"/>.</returns>
        /// <remarks>
        /// The calculation of the next target is based on the last target value and the block time (aka spacing) of <paramref name="chainedBlock"/>
        /// (i.e. difference in time stamp of this block and its immediate predecessor). The target changes every block and it is adjusted
        /// down (i.e. towards harder to reach, or more difficult) if the time to mine last block was lower than the target block time.
        /// And it is adjusted up if it took longer than the target block time. The adjustments are done in a way the target is moving towards
        /// the target-spacing (expected block time) exponentially, so even a big change in the mining power on the network will be fixed by retargeting relatively quickly.
        /// <para>
        /// Over <see cref="RetargetIntervalMinutes"/> minutes there are certain number (say <c>N</c>) of blocks expected to be mined if the target block time
        /// of <see cref="TargetSpacingSeconds"/> was reached every time. Then the next target is calculated as follows:</para>
        /// <code>
        /// NewTarget = PrevTarget * ((N - 1) * TargetSpacingSeconds + 2 * LastBlockTime) / ((N + 1) * TargetSpacingSeconds)
        /// </code>
        /// <para>
        /// Which basically says that the block time of the last block is counted twice instead of two optimal block times.
        /// And the <c>N</c> determines how strongly will the deviation of the last block time affect the difficulty.
        /// </para>
        /// </remarks>
        public Target GetNextTargetRequired(StakeChain stakeChain, ChainedBlock chainedBlock, NBitcoin.Consensus consensus, bool proofOfStake)
        {
            this.logger.LogTrace("({0}:'{1}',{2}:{3})", nameof(chainedBlock), chainedBlock, nameof(proofOfStake), proofOfStake);

            // Genesis block.
            if (chainedBlock == null)
            {
                this.logger.LogTrace("(-)[GENESIS]:'{0}'", consensus.PowLimit);
                return(consensus.PowLimit);
            }

            // Find the last two blocks that correspond to the mining algo
            // (i.e if this is a POS block we need to find the last two POS blocks).
            BigInteger targetLimit = proofOfStake
                ? consensus.ProofOfStakeLimitV2
                : consensus.PowLimit.ToBigInteger();

            // First block.
            ChainedBlock lastPowPosBlock = GetLastPowPosChainedBlock(stakeChain, chainedBlock, proofOfStake);

            if (lastPowPosBlock.Previous == null)
            {
                var res = new Target(targetLimit);
                this.logger.LogTrace("(-)[FIRST_BLOCK]:'{0}'", res);
                return(res);
            }

            // Second block.
            ChainedBlock prevLastPowPosBlock = GetLastPowPosChainedBlock(stakeChain, lastPowPosBlock.Previous, proofOfStake);

            if (prevLastPowPosBlock.Previous == null)
            {
                var res = new Target(targetLimit);
                this.logger.LogTrace("(-)[SECOND_BLOCK]:'{0}'", res);
                return(res);
            }

            // This is used in tests to allow quickly mining blocks.
            if (consensus.PowNoRetargeting)
            {
                this.logger.LogTrace("(-)[NO_POW_RETARGET]:'{0}'", lastPowPosBlock.Header.Bits);
                return(lastPowPosBlock.Header.Bits);
            }

            int targetSpacing = TargetSpacingSeconds;
            int actualSpacing = (int)(lastPowPosBlock.Header.Time - prevLastPowPosBlock.Header.Time);

            if (actualSpacing < 0)
            {
                actualSpacing = targetSpacing;
            }

            if (actualSpacing > targetSpacing * 10)
            {
                actualSpacing = targetSpacing * 10;
            }

            int targetTimespan = RetargetIntervalMinutes * 60;
            int interval       = targetTimespan / targetSpacing;

            BigInteger target = lastPowPosBlock.Header.Bits.ToBigInteger();

            long multiplyBy = (interval - 1) * targetSpacing + actualSpacing + actualSpacing;

            target = target.Multiply(BigInteger.ValueOf(multiplyBy));

            long divideBy = (interval + 1) * targetSpacing;

            target = target.Divide(BigInteger.ValueOf(divideBy));

            this.logger.LogTrace("The next target difficulty will be {0} times higher (easier to satisfy) than the previous target.", (double)multiplyBy / (double)divideBy);

            if ((target.CompareTo(BigInteger.Zero) <= 0) || (target.CompareTo(targetLimit) >= 1))
            {
                target = targetLimit;
            }

            var finalTarget = new Target(target);

            this.logger.LogTrace("(-):'{0}'", finalTarget);
            return(finalTarget);
        }
        public List <uint256> GenerateBlocks(ReserveScript reserveScript, ulong generate, ulong maxTries)
        {
            ulong nHeightStart = 0;
            ulong nHeightEnd   = 0;
            ulong nHeight      = 0;

            nHeightStart = (ulong)this.chain.Height;
            nHeight      = nHeightStart;
            nHeightEnd   = nHeightStart + generate;
            int nExtraNonce = 0;
            var blocks      = new List <uint256>();

            while (nHeight < nHeightEnd)
            {
                this.nodeLifetime.ApplicationStopping.ThrowIfCancellationRequested();

                ChainedBlock chainTip = this.consensusLoop.Tip;
                if (this.chain.Tip != chainTip)
                {
                    Task.Delay(TimeSpan.FromMinutes(1), this.nodeLifetime.ApplicationStopping).GetAwaiter().GetResult();
                    continue;
                }

                BlockTemplate pblockTemplate = this.blockAssemblerFactory.Create(chainTip).CreateNewBlock(reserveScript.reserveSfullNodecript);

                if (Block.BlockSignature)
                {
                    // POS: make sure the POS consensus rules are valid
                    if (pblockTemplate.Block.Header.Time <= chainTip.Header.Time)
                    {
                        continue;
                    }
                }

                this.IncrementExtraNonce(pblockTemplate.Block, chainTip, nExtraNonce);
                Block pblock = pblockTemplate.Block;

                while ((maxTries > 0) && (pblock.Header.Nonce < InnerLoopCount) && !pblock.CheckProofOfWork())
                {
                    this.nodeLifetime.ApplicationStopping.ThrowIfCancellationRequested();

                    ++pblock.Header.Nonce;
                    --maxTries;
                }

                if (maxTries == 0)
                {
                    break;
                }

                if (pblock.Header.Nonce == InnerLoopCount)
                {
                    continue;
                }

                var newChain = new ChainedBlock(pblock.Header, pblock.GetHash(), chainTip);

                if (newChain.ChainWork <= chainTip.ChainWork)
                {
                    continue;
                }

                var blockValidationContext = new BlockValidationContext {
                    Block = pblock
                };

                this.consensusLoop.AcceptBlock(blockValidationContext);

                if (blockValidationContext.ChainedBlock == null)
                {
                    this.logger.LogTrace("(-)[REORG-2]");
                    return(blocks);
                }

                if (blockValidationContext.Error != null)
                {
                    if (blockValidationContext.Error == ConsensusErrors.InvalidPrevTip)
                    {
                        continue;
                    }

                    this.logger.LogTrace("(-)[ACCEPT_BLOCK_ERROR]");
                    return(blocks);
                }

                this.logger.LogInformation("Mined new {0} block: '{1}'.", BlockStake.IsProofOfStake(blockValidationContext.Block) ? "POS" : "POW", blockValidationContext.ChainedBlock);

                nHeight++;
                blocks.Add(pblock.GetHash());

                pblockTemplate = null;
            }

            return(blocks);
        }
Beispiel #46
0
 public void Set(ChainedBlock chainedBlock, BlockStake blockStake)
 {
     this.SetAsync(chainedBlock, blockStake).GetAwaiter().GetResult();
 }
Beispiel #47
0
 private ChainedBlock AppendBlock(ChainedBlock previous, params Chain[] chains)
 {
     ChainedBlock last = null;
     var nonce = RandomUtils.GetUInt32();
     foreach(var chain in chains)
     {
         var block = TestUtils.CreateFakeBlock(new Transaction());
         block.Header.HashPrevBlock = previous == null ? chain.Tip.HashBlock : previous.HashBlock;
         block.Header.Nonce = nonce;
         last = chain.GetOrAdd(block.Header);
     }
     return last;
 }
Beispiel #48
0
        public virtual void ExecuteBlock(ContextInformation context, TaskScheduler taskScheduler)
        {
            this.logger.LogTrace("()");

            Block            block = context.BlockValidationContext.Block;
            ChainedBlock     index = context.BlockValidationContext.ChainedBlock;
            DeploymentFlags  flags = context.Flags;
            UnspentOutputSet view  = context.Set;

            this.PerformanceCounter.AddProcessedBlocks(1);
            taskScheduler = taskScheduler ?? TaskScheduler.Default;

            if (!context.BlockValidationContext.SkipValidation)
            {
                if (flags.EnforceBIP30)
                {
                    foreach (Transaction tx in block.Transactions)
                    {
                        UnspentOutputs coins = view.AccessCoins(tx.GetHash());
                        if ((coins != null) && !coins.IsPrunable)
                        {
                            this.logger.LogTrace("(-)[BAD_TX_BIP_30]");
                            ConsensusErrors.BadTransactionBIP30.Throw();
                        }
                    }
                }
            }
            else
            {
                this.logger.LogTrace("BIP30 validation skipped for checkpointed block at height {0}.", index.Height);
            }

            long  nSigOpsCost = 0;
            Money nFees       = Money.Zero;
            List <Task <bool> > checkInputs = new List <Task <bool> >();

            for (int txIndex = 0; txIndex < block.Transactions.Count; txIndex++)
            {
                this.PerformanceCounter.AddProcessedTransactions(1);
                Transaction tx = block.Transactions[txIndex];
                if (!context.BlockValidationContext.SkipValidation)
                {
                    if (!tx.IsCoinBase && (!context.IsPoS || (context.IsPoS && !tx.IsCoinStake)))
                    {
                        int[] prevheights;

                        if (!view.HaveInputs(tx))
                        {
                            this.logger.LogTrace("(-)[BAD_TX_NO_INPUT]");
                            ConsensusErrors.BadTransactionMissingInput.Throw();
                        }

                        prevheights = new int[tx.Inputs.Count];
                        // Check that transaction is BIP68 final.
                        // BIP68 lock checks (as opposed to nLockTime checks) must
                        // be in ConnectBlock because they require the UTXO set.
                        for (int j = 0; j < tx.Inputs.Count; j++)
                        {
                            prevheights[j] = (int)view.AccessCoins(tx.Inputs[j].PrevOut.Hash).Height;
                        }

                        if (!tx.CheckSequenceLocks(prevheights, index, flags.LockTimeFlags))
                        {
                            this.logger.LogTrace("(-)[BAD_TX_NON_FINAL]");
                            ConsensusErrors.BadTransactionNonFinal.Throw();
                        }
                    }

                    // GetTransactionSigOpCost counts 3 types of sigops:
                    // * legacy (always),
                    // * p2sh (when P2SH enabled in flags and excludes coinbase),
                    // * witness (when witness enabled in flags and excludes coinbase).
                    nSigOpsCost += this.GetTransactionSigOpCost(tx, view, flags);
                    if (nSigOpsCost > this.consensusOptions.MaxBlockSigopsCost)
                    {
                        ConsensusErrors.BadBlockSigOps.Throw();
                    }

                    // TODO: Simplify this condition.
                    if (!tx.IsCoinBase && (!context.IsPoS || (context.IsPoS && !tx.IsCoinStake)))
                    {
                        this.CheckInputs(tx, view, index.Height);
                        nFees += view.GetValueIn(tx) - tx.TotalOut;
                        Transaction localTx = tx;
                        PrecomputedTransactionData txData = new PrecomputedTransactionData(tx);
                        for (int inputIndex = 0; inputIndex < tx.Inputs.Count; inputIndex++)
                        {
                            this.PerformanceCounter.AddProcessedInputs(1);
                            TxIn  input          = tx.Inputs[inputIndex];
                            int   inputIndexCopy = inputIndex;
                            TxOut txout          = view.GetOutputFor(input);
                            var   checkInput     = new Task <bool>(() =>
                            {
                                if (this.UseConsensusLib)
                                {
                                    Script.BitcoinConsensusError error;
                                    return(Script.VerifyScriptConsensus(txout.ScriptPubKey, tx, (uint)inputIndexCopy, flags.ScriptFlags, out error));
                                }
                                else
                                {
                                    var checker      = new TransactionChecker(tx, inputIndexCopy, txout.Value, txData);
                                    var ctx          = new ScriptEvaluationContext();
                                    ctx.ScriptVerify = flags.ScriptFlags;
                                    return(ctx.VerifyScript(input.ScriptSig, txout.ScriptPubKey, checker));
                                }
                            });
                            checkInput.Start(taskScheduler);
                            checkInputs.Add(checkInput);
                        }
                    }
                }

                this.UpdateCoinView(context, tx);
            }

            if (!context.BlockValidationContext.SkipValidation)
            {
                this.CheckBlockReward(context, nFees, index, block);

                bool passed = checkInputs.All(c => c.GetAwaiter().GetResult());
                if (!passed)
                {
                    this.logger.LogTrace("(-)[BAD_TX_SCRIPT]");
                    ConsensusErrors.BadTransactionScriptError.Throw();
                }
            }
            else
            {
                this.logger.LogTrace("BIP68, SigOp cost, and block reward validation skipped for block at height {0}.", index.Height);
            }

            this.logger.LogTrace("(-)");
        }
Beispiel #49
0
			public static string GetId(uint256 txId, ChainedBlock block)
			{
				return GetId(txId, block == null ? null : block.HashBlock, block == null ? 0 : block.Height);
			}
Beispiel #50
0
        public virtual void CheckBlockReward(ContextInformation context, Money nFees, ChainedBlock chainedBlock, Block block)
        {
            this.logger.LogTrace("()");

            Money blockReward = nFees + this.GetProofOfWorkReward(chainedBlock.Height);

            if (block.Transactions[0].TotalOut > blockReward)
            {
                this.logger.LogTrace("(-)[BAD_COINBASE_AMOUNT]");
                ConsensusErrors.BadCoinbaseAmount.Throw();
            }

            this.logger.LogTrace("(-)");
        }
Beispiel #51
0
		public bool NotifyTransaction(Transaction transaction, ChainedBlock chainedBlock, Block block)
		{
			if(chainedBlock == null)
				return NotifyTransaction(transaction);
			return NotifyTransaction(transaction, chainedBlock, new MerkleBlock(block, new uint256[] { transaction.GetHash() }));
		}
Beispiel #52
0
        public IEnumerable <ChainedBlock> GetHeadersFromFork(NetworkPeer peer, ChainedBlock currentTip, uint256 hashStop = null, CancellationToken cancellationToken = default(CancellationToken))
        {
            this.AssertStateAsync(peer, NetworkPeerState.HandShaked, cancellationToken).GetAwaiter().GetResult();

            using (var listener = new NetworkPeerListener(peer))
            {
                int acceptMaxReorgDepth = 0;
                while (true)
                {
                    // Get before last so, at the end, we should only receive 1 header equals to this one (so we will not have race problems with concurrent GetChains).
                    BlockLocator awaited = currentTip.Previous == null?currentTip.GetLocator() : currentTip.Previous.GetLocator();

                    peer.SendMessageVoidAsync(new GetHeadersPayload()
                    {
                        BlockLocators = awaited,
                        HashStop      = hashStop
                    });

                    while (true)
                    {
                        bool           isOurs  = false;
                        HeadersPayload headers = null;

                        using (var headersCancel = CancellationTokenSource.CreateLinkedTokenSource(cancellationToken))
                        {
                            headersCancel.CancelAfter(TimeSpan.FromMinutes(1.0));
                            try
                            {
                                headers = listener.ReceivePayloadAsync <HeadersPayload>(headersCancel.Token).GetAwaiter().GetResult();
                            }
                            catch (OperationCanceledException)
                            {
                                acceptMaxReorgDepth += 6;
                                if (cancellationToken.IsCancellationRequested)
                                {
                                    throw;
                                }

                                // Send a new GetHeaders.
                                break;
                            }
                        }

                        // In the special case where the remote node is at height 0 as well as us, then the headers count will be 0.
                        if ((headers.Headers.Count == 0) && (peer.PeerVersion.StartHeight == 0) && (currentTip.HashBlock == peer.Network.GenesisHash))
                        {
                            yield break;
                        }

                        if ((headers.Headers.Count == 1) && (headers.Headers[0].GetHash() == currentTip.HashBlock))
                        {
                            yield break;
                        }

                        foreach (BlockHeader header in headers.Headers)
                        {
                            uint256 hash = header.GetHash();
                            if (hash == currentTip.HashBlock)
                            {
                                continue;
                            }

                            // The previous headers request timeout, this can arrive in case of big reorg.
                            if (header.HashPrevBlock != currentTip.HashBlock)
                            {
                                int          reorgDepth     = 0;
                                ChainedBlock tempCurrentTip = currentTip;
                                while (reorgDepth != acceptMaxReorgDepth && tempCurrentTip != null && header.HashPrevBlock != tempCurrentTip.HashBlock)
                                {
                                    reorgDepth++;
                                    tempCurrentTip = tempCurrentTip.Previous;
                                }

                                if (reorgDepth != acceptMaxReorgDepth && tempCurrentTip != null)
                                {
                                    currentTip = tempCurrentTip;
                                }
                            }

                            if (header.HashPrevBlock == currentTip.HashBlock)
                            {
                                isOurs     = true;
                                currentTip = new ChainedBlock(header, hash, currentTip);

                                yield return(currentTip);

                                if (currentTip.HashBlock == hashStop)
                                {
                                    yield break;
                                }
                            }
                            else
                            {
                                break;  // Not our headers, continue receive.
                            }
                        }

                        if (isOurs)
                        {
                            break;  //Go ask for next header.
                        }
                    }
                }
            }
        }
Beispiel #53
0
		private void Spent(TrackedScript metadata, IndexedTxIn txin, Coin coin, ChainedBlock block, MerkleBlock proof)
		{
			var operation = new Operation(txin.Transaction, block, proof);
			operation.SpentCoins.Add(Tuple.Create(coin, metadata.GetId()));
			SetUnconfirmedSeenIfPossible(txin.Transaction, block, operation);
			_Operations.AddOrUpdate(operation.GetId(), operation, (k, old) => old.Merge(operation));
		}
Beispiel #54
0
        public Block[] GenerateStratis(int blockCount, List <Transaction> passedTransactions = null, bool broadcast = true)
        {
            var            fullNode = (this.runner as StratisBitcoinPowRunner).FullNode;
            BitcoinSecret  dest     = this.MinerSecret;
            List <Block>   blocks   = new List <Block>();
            DateTimeOffset now      = this.MockTime == null ? DateTimeOffset.UtcNow : this.MockTime.Value;

#if !NOSOCKET
            for (int i = 0; i < blockCount; i++)
            {
                uint  nonce = 0;
                Block block = new Block();
                block.Header.HashPrevBlock = fullNode.Chain.Tip.HashBlock;
                block.Header.Bits          = block.Header.GetWorkRequired(fullNode.Network, fullNode.Chain.Tip);
                block.Header.UpdateTime(now, fullNode.Network, fullNode.Chain.Tip);
                var coinbase = new Transaction();
                coinbase.AddInput(TxIn.CreateCoinbase(fullNode.Chain.Height + 1));
                coinbase.AddOutput(new TxOut(fullNode.Network.GetReward(fullNode.Chain.Height + 1), dest.GetAddress()));
                block.AddTransaction(coinbase);
                if (passedTransactions?.Any() ?? false)
                {
                    passedTransactions = this.Reorder(passedTransactions);
                    block.Transactions.AddRange(passedTransactions);
                }
                block.UpdateMerkleRoot();
                while (!block.CheckProofOfWork(fullNode.Network.Consensus))
                {
                    block.Header.Nonce = ++nonce;
                }
                blocks.Add(block);
                if (broadcast)
                {
                    uint256 blockHash = block.GetHash();
                    var     newChain  = new ChainedBlock(block.Header, blockHash, fullNode.Chain.Tip);
                    var     oldTip    = fullNode.Chain.SetTip(newChain);
                    fullNode.ConsensusLoop().Puller.InjectBlock(blockHash, new DownloadedBlock {
                        Length = block.GetSerializedSize(), Block = block
                    }, CancellationToken.None);

                    //try
                    //{
                    //    var blockResult = new BlockResult { Block = block };
                    //    fullNode.ConsensusLoop.AcceptBlock(blockResult);

                    //    // similar logic to what's in the full node code
                    //    if (blockResult.Error == null)
                    //    {
                    //        fullNode.ChainBehaviorState.ConsensusTip = fullNode.ConsensusLoop.Tip;
                    //        //if (fullNode.Chain.Tip.HashBlock == blockResult.ChainedBlock.HashBlock)
                    //        //{
                    //        //    var unused = cache.FlushAsync();
                    //        //}
                    //        fullNode.Signals.Blocks.Broadcast(block);
                    //    }
                    //}
                    //catch (ConsensusErrorException)
                    //{
                    //    // set back the old tip
                    //    fullNode.Chain.SetTip(oldTip);
                    //}
                }
            }

            return(blocks.ToArray());
#endif
        }
Beispiel #55
0
		private void SetUnconfirmedSeenIfPossible(Transaction tx, ChainedBlock block, Operation operation)
		{
			if(block != null)
			{
				Operation unconf;
				if(_Operations.TryGetValue(Operation.GetId(tx.GetHash(), null), out unconf))
					operation.UnconfirmedSeen = unconf.UnconfirmedSeen;
			}
		}
 internal static void InputChainTip(ChainedBlock block)
 {
     _Trace.TraceInformation("The input chain tip is at height " + ToString(block));
 }