public MineBlockContext(ulong amountOfBlocksToMine, ulong chainHeight, ulong maxTries, ReserveScript reserveScript)
 {
     this.amountOfBlocksToMine = amountOfBlocksToMine;
     this.ChainHeight          = chainHeight;
     this.CurrentHeight        = chainHeight;
     this.MaxTries             = maxTries;
     this.ReserveScript        = reserveScript;
 }
        ///<inheritdoc/>
        public List <uint256> GenerateBlocks(ReserveScript reserveScript, ulong amountOfBlocksToMine, ulong maxTries)
        {
            var context = new MineBlockContext(amountOfBlocksToMine, (ulong)this.chain.Height, maxTries, reserveScript);

            while (context.MiningCanContinue)
            {
                if (!this.ConsensusIsAtTip(context))
                {
                    continue;
                }

                if (!this.BuildBlock(context))
                {
                    continue;
                }

                if (!this.MineBlock(context))
                {
                    break;
                }

                if (!this.ValidateMinedBlock(context))
                {
                    continue;
                }

                if (!this.ValidateAndConnectBlock(context))
                {
                    break;
                }

                if (!this.CheckValidationContextPreviousTip(context))
                {
                    continue;
                }

                this.OnBlockMined(context);
            }

            return(context.Blocks);
        }
        /// <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);
        }
        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>();


            // BlockTemplate pblocktemplate = null;

            while (nHeight < nHeightEnd)
            {
                try
                {
                    if (this.chain.Tip != this.consensusLoop.Tip)
                    {
                        Task.Delay(TimeSpan.FromMinutes(1), this.nodeLifetime.ApplicationStopping).GetAwaiter().GetResult();
                        continue;
                    }

                    var pblocktemplate = this.blockAssemblerFactory.Create().CreateNewBlock(reserveScript.reserveSfullNodecript);

                    this.IncrementExtraNonce(pblocktemplate.Block, this.chain.Tip, nExtraNonce);
                    var pblock = pblocktemplate.Block;

                    while (maxTries > 0 && pblock.Header.Nonce < InnerLoopCount && !pblock.CheckProofOfWork())
                    {
                        ++pblock.Header.Nonce;
                        --maxTries;
                    }

                    if (maxTries == 0)
                    {
                        break;
                    }

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

                    var newChain = new ChainedBlock(pblock.Header, pblock.GetHash(), this.chain.Tip);

                    if (newChain.ChainWork <= this.chain.Tip.ChainWork)
                    {
                        continue;
                    }

                    this.chain.SetTip(newChain);

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

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

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

                    this.logger.LogInformation($"Mined new {(BlockStake.IsProofOfStake(blockResult.Block) ? "POS" : "POW")} block: {blockResult.ChainedBlock.HashBlock}");

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

                    // ensure the block is written to disk
                    ulong retry = 0;
                    while (++retry < maxTries &&
                           nHeight == nHeightEnd && // last block
                           !this.blockRepository.ExistAsync(blockResult.ChainedBlock.HashBlock).GetAwaiter().GetResult())
                    {
                        Thread.Sleep(100);
                    }

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

                    throw;
                }
            }

            return(blocks);
        }
Exemple #5
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);
        }