public void GenerateBlocks(WalletSecret walletSecret)
        {
            this.LastCoinStakeSearchInterval = 0;

            BlockTemplate pblocktemplate = null;
            bool          tryToSync      = true;

            while (true)
            {
                if (this.chain.Tip != this.consensusLoop.Tip)
                {
                    return;
                }

                while (!this.connection.ConnectedNodes.Any() || this.chainState.IsInitialBlockDownload)
                {
                    this.LastCoinStakeSearchInterval = 0;
                    tryToSync = true;
                    Task.Delay(TimeSpan.FromMilliseconds(this.minerSleep), this.nodeLifetime.ApplicationStopping).GetAwaiter().GetResult();
                }

                if (tryToSync)
                {
                    tryToSync = false;
                    if (this.connection.ConnectedNodes.Count() < 3 ||
                        this.chain.Tip.Header.Time < this.dateTimeProvider.GetTime() - 10 * 60)
                    {
                        //this.cancellationProvider.Cancellation.Token.WaitHandle.WaitOne(TimeSpan.FromMilliseconds(60000));
                        continue;
                    }
                }

                if (pblocktemplate == null)
                {
                    pblocktemplate = this.blockAssemblerFactory.Create(new AssemblerOptions()
                    {
                        IsProofOfStake = true
                    }).CreateNewBlock(new Script());
                }


                var pblock     = pblocktemplate.Block;
                var pindexPrev = this.consensusLoop.Tip;

                var stakeTxes = new List <StakeTx>();
                var spendable = this.wallet.GetSpendableTransactions(1);

                var coinset = this.coinView.FetchCoinsAsync(spendable.SelectMany(s => s.Transactions.Select(t => t.Id)).ToArray()).GetAwaiter().GetResult();

                foreach (var unspentInfo in spendable)
                {
                    foreach (var infoTransaction in unspentInfo.Transactions)
                    {
                        var set  = coinset.UnspentOutputs.FirstOrDefault(f => f?.TransactionId == infoTransaction.Id);
                        var utxo = set?._Outputs[infoTransaction.Index.Value];

                        if (utxo != null && utxo.Value > Money.Zero)
                        {
                            var stakeTx = new StakeTx();

                            stakeTx.TxOut       = utxo;
                            stakeTx.OutPoint    = new OutPoint(set.TransactionId, infoTransaction.Index.Value);
                            stakeTx.Address     = unspentInfo.Address;
                            stakeTx.OutputIndex = infoTransaction.Index.Value;
                            stakeTx.HashBlock   = this.chain.GetBlock((int)set.Height).HashBlock;
                            stakeTx.UtxoSet     = set;
                            stakeTx.Secret      = walletSecret;                        //temporary
                            stakeTxes.Add(stakeTx);
                        }
                    }
                }

                // Trying to sign a block
                if (this.SignBlock(stakeTxes, pblock, pindexPrev, pblocktemplate.TotalFee))
                {
                    var blockResult = new BlockResult {
                        Block = pblock
                    };
                    this.CheckState(new ContextInformation(blockResult, this.network.Consensus), pindexPrev);

                    pblocktemplate = null;
                }
                else
                {
                    Task.Delay(TimeSpan.FromMilliseconds(this.minerSleep), this.nodeLifetime.ApplicationStopping).GetAwaiter().GetResult();
                }
            }
        }
        /// <summary>
        /// Generates up to a specified number of blocks with a limited number of attempts.
        /// </summary>
        /// <param name="reserveScript"></param>
        /// <param name="generate">Number of blocks to generate. It is possible that less than the required number of blocks will be mined.</param>
        /// <param name="maxTries">Maximum number of attempts the miner will calculate PoW hash in order to find suitable ones to generate specified amount of blocks.</param>
        /// <returns>List with generated block's hashes</returns>
        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)
                {
                    // Make sure the POS consensus rules are valid. This is required for generation of blocks inside tests,
                    // where it is possible to generate multiple blocks within one second.
                    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.AcceptBlockAsync(blockValidationContext).GetAwaiter().GetResult();

                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);
        }
Ejemplo n.º 3
0
        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();

                try
                {
                    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;
                    }

                    this.chain.SetTip(newChain);

                    var blockResult = new BlockResult {
                        Block = pblock
                    };
                    this.consensusLoop.AcceptBlock(new ContextInformation(blockResult, this.network.Consensus));
                    this.consensusLoop.Puller.SetLocation(newChain);

                    if (blockResult.ChainedBlock == null)
                    {
                        break; // Reorg.
                    }
                    if (blockResult.Error != null)
                    {
                        return(blocks);
                    }

                    // Push the block to disk, so it is available when peers ask for it.
                    this.blockRepository.PutAsync(blockResult.ChainedBlock.HashBlock, new List <Block> {
                        pblock
                    }).GetAwaiter().GetResult();

                    // Similar logic to what's in the full node code.
                    this.chainState.HighestValidatedPoW = this.consensusLoop.Tip;
                    this.signals.SignalBlock(pblock);

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

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

                    pblockTemplate = null;
                }
                catch (ConsensusErrorException cer)
                {
                    if (cer.ConsensusError == ConsensusErrors.InvalidPrevTip)
                    {
                        continue;
                    }

                    throw;
                }
            }

            return(blocks);
        }