/// <inheritdoc />
        /// <remarks>When a block is signaled, we check if its header is a Proven Header, if not, we need to generate and store it.</remarks>
        protected override void AddBlockToQueue(ChainedHeaderBlock blockPair, bool isIBD)
        {
            int blockHeight = blockPair.ChainedHeader.Height;

            if (blockPair.ChainedHeader.Header is ProvenBlockHeader phHeader)
            {
                this.logger.LogTrace("Current header is already a Proven Header.");

                // Add to the store, to be sure we actually store it anyway.
                // It's ProvenBlockHeaderStore responsibility to prevent us to store it twice.
                this.provenBlockHeaderStore.AddToPendingBatch(phHeader, new HashHeightPair(phHeader.GetHash(), blockHeight));
            }
            else
            {
                // Ensure we doesn't have already the ProvenHeader in the store.
                ProvenBlockHeader provenHeader = this.provenBlockHeaderStore.GetAsync(blockPair.ChainedHeader.Height).GetAwaiter().GetResult();

                // Proven Header not found? create it now.
                if (provenHeader == null)
                {
                    this.logger.LogTrace("Proven Header at height {0} NOT found.", blockHeight);

                    this.CreateAndStoreProvenHeader(blockHeight, blockPair, isIBD);
                }
                else
                {
                    uint256 signaledHeaderHash = blockPair.Block.Header.GetHash();

                    // If the Proven Header is the right one, then it's OK and we can return without doing anything.
                    uint256 provenHeaderHash = provenHeader.GetHash();
                    if (provenHeaderHash == signaledHeaderHash)
                    {
                        this.logger.LogTrace("Proven Header {0} found.", signaledHeaderHash);
                    }
                    else
                    {
                        this.logger.LogTrace("Found a proven header with a different hash, recreating PH. Expected Hash: {0}, found Hash: {1}.", signaledHeaderHash, provenHeaderHash);

                        // A reorg happened so we recreate a new Proven Header to replace the wrong one.
                        this.CreateAndStoreProvenHeader(blockHeight, blockPair, isIBD);
                    }
                }
            }

            // At the end, if no exception happened, control is passed back to base AddBlockToQueue.
            base.AddBlockToQueue(blockPair, isIBD);
        }
        /// <inheritdoc />
        public async Task <ProvenBlockHeader> GetAsync(int blockHeight)
        {
            ProvenBlockHeader header = null;

            using (new StopwatchDisposable(o => this.performanceCounter.AddQueryTime(o)))
            {
                if (!this.Cache.TryGetValue(blockHeight, out header))
                {
                    // Check the repository.
                    header = await this.provenBlockHeaderRepository.GetAsync(blockHeight).ConfigureAwait(false);

                    this.Cache.AddOrUpdate(blockHeight, header, header.HeaderSize);
                }
            }

            return(header);
        }
Exemplo n.º 3
0
        /// <inheritdoc />
        public void AddToPendingBatch(ProvenBlockHeader provenBlockHeader, HashHeightPair newTip)
        {
            this.logger.LogDebug("({0}:'{1}',{2}:'{3}')", nameof(provenBlockHeader), provenBlockHeader, nameof(newTip), newTip);

            Guard.Assert(provenBlockHeader.GetHash() == newTip.Hash);

            // Stop the consensus loop.
            if (this.saveAsyncLoopException != null)
            {
                throw this.saveAsyncLoopException;
            }

            lock (this.lockObject)
            {
                if ((this.pendingTipHashHeight != null) && (provenBlockHeader.HashPrevBlock != this.pendingTipHashHeight.Hash))
                {
                    // The latest proven header to be added is the most recent from consensus
                    // and is always assumed to be the consensus tip.
                    // If a non-consecutive item is added then there may have been a reorg in the chain
                    // this can happen after the node rewind its consensus.

                    // Walk back the batch and remove all the blocks that are on the fork.
                    KeyValuePair <int, ProvenBlockHeader> lastItem = this.pendingBatch.Last();
                    while (provenBlockHeader.HashPrevBlock != lastItem.Value.GetHash())
                    {
                        this.pendingBatch.Remove(lastItem.Key);
                        this.Cache.Remove(lastItem.Key);

                        if (this.pendingBatch.Count == 0)
                        {
                            break;
                        }

                        lastItem = this.pendingBatch.Last();
                    }
                }

                // If an item is already there this means a reorg happened.
                // We always assume the latest header belongs to the longest chain so just overwrite the previous values.
                this.pendingBatch.AddOrReplace(newTip.Height, provenBlockHeader);

                this.pendingTipHashHeight = newTip;
            }

            this.Cache.AddOrUpdate(newTip.Height, provenBlockHeader, provenBlockHeader.HeaderSize);
        }
        void ComputeNextStakeModifier(ProvenBlockHeader header, ChainedHeader chainedHeader,
                                      uint256 previousStakeModifier = null)
        {
            if (previousStakeModifier == null)
            {
                previousStakeModifier = GetPreviousStakeModifier(chainedHeader);
            }

            // Computes the stake modifier and sets the value to the current validating proven header,
            // to retain it for next header validation as previousStakeModifier.
            var hash = !header.Coinstake.IsCoinStake
                ? chainedHeader.HashBlock
                : header.Coinstake.Inputs[0].PrevOut.Hash;

            header.StakeModifierV2 =
                this.stakeValidator.ComputeStakeModifierV2(chainedHeader.Previous, previousStakeModifier, hash);
        }
Exemplo n.º 5
0
        /// <summary>
        /// Checks if coinstake is spent on another chain.
        /// </summary>
        /// <param name="header">The proven block header.</param>
        /// <param name="context">The POS rule context.</param>
        /// <returns>The <see cref="UnspentOutputs"> found in a RewindData</returns>
        private UnspentOutputs CheckIfCoinstakeIsSpentOnAnotherChain(ProvenBlockHeader header, PosRuleContext context)
        {
            Transaction coinstake = header.Coinstake;
            TxIn        input     = coinstake.Inputs[0];

            int?rewindDataIndex = this.PosParent.RewindDataIndexCache.Get(input.PrevOut.Hash, (int)input.PrevOut.N);

            if (!rewindDataIndex.HasValue)
            {
                this.Logger.LogTrace("(-)[NO_REWIND_DATA_INDEX_FOR_INPUT_PREVOUT]");
                context.ValidationContext.InsufficientHeaderInformation = true;
                ConsensusErrors.ReadTxPrevFailedInsufficient.Throw();
            }

            RewindData rewindData = this.PosParent.UtxoSet.GetRewindData(rewindDataIndex.Value);

            if (rewindData == null)
            {
                this.Logger.LogTrace("(-)[NO_REWIND_DATA_FOR_INDEX]");
                this.Logger.LogError("Error - Rewind data should always be present");
                throw new ConsensusException("Rewind data should always be present");
            }

            UnspentOutputs matchingUnspentUtxo = null;

            foreach (UnspentOutputs unspent in rewindData.OutputsToRestore)
            {
                if (unspent.TransactionId == input.PrevOut.Hash)
                {
                    if (input.PrevOut.N < unspent.Outputs.Length)
                    {
                        matchingUnspentUtxo = unspent;
                        break;
                    }
                }
            }

            if (matchingUnspentUtxo == null)
            {
                this.Logger.LogTrace("(-)[UTXO_NOT_FOUND_IN_REWIND_DATA]");
                context.ValidationContext.InsufficientHeaderInformation = true;
                ConsensusErrors.UtxoNotFoundInRewindData.Throw();
            }

            return(matchingUnspentUtxo);
        }
Exemplo n.º 6
0
        /// <summary>
        /// Checks whether header time is equal to the timestamp of the coinstake tx and if coinstake tx
        /// timestamp is divisible by 16 (using timestamp mask).
        /// </summary>
        /// <param name="header">The proven block header.</param>
        /// <exception cref="ConsensusException">
        /// Throws exception with error <see cref="ConsensusErrors.StakeTimeViolation" /> if check fails.
        /// </exception>
        private void CheckHeaderAndCoinstakeTimes(ProvenBlockHeader header)
        {
            if (header.Coinstake is IPosTransactionWithTime posTrx)
            {
                if (header.Time != posTrx.Time)
                {
                    this.Logger.LogTrace("(-)[BAD_TIME]");
                    ConsensusErrors.StakeTimeViolation.Throw();
                }
            }

            if ((header.Time & this.Parent.Network.Consensus.ProofOfStakeTimestampMask) != 0)
            {
                this.Logger.LogTrace("(-)[BAD_TIME]");
                ConsensusErrors.StakeTimeViolation.Throw();
            }
        }
        /// <inheritdoc />
        protected override void ProcessRule(PosRuleContext context, ChainedHeader chainedHeader,
                                            ProvenBlockHeader header)
        {
            CheckCoinstakeIsNotNull(header);

            // In case we are in PoW era there might be no coinstake tx.
            // We have no way of telling if the block was supposed to be PoW or PoS so attacker can trick us into thinking that all of them are PoW so no PH is required.
            if (!header.Coinstake.IsCoinStake)
            {
                // If the header represents a POW block we don't do any validation of stake.
                // We verify the header is not passed the last pow height.
                if (chainedHeader.Height > this.Parent.Network.Consensus.LastPOWBlock)
                {
                    this.Logger.LogTrace("(-)[POW_TOO_HIGH]");
                    ConsensusErrors.ProofOfWorkTooHigh.Throw();
                }

                if (!header.CheckProofOfWork())
                {
                    this.Logger.LogTrace("(-)[HIGH_HASH]");
                    ConsensusErrors.HighHash.Throw();
                }

                ComputeNextStakeModifier(header, chainedHeader);

                this.Logger.LogTrace("(-)[POW_ERA]");
                return;
            }

            CheckIfCoinstakeIsTrue(header);

            CheckHeaderAndCoinstakeTimes(header);

            var prevUtxo = GetAndValidatePreviousUtxo(header, context);

            CheckCoinstakeAgeRequirement(chainedHeader, prevUtxo);

            CheckSignature(header, prevUtxo);

            CheckStakeKernelHash(context, prevUtxo, header, chainedHeader);

            CheckCoinstakeMerkleProof(header);

            CheckHeaderSignatureWithCoinstakeKernel(header);
        }
Exemplo n.º 8
0
        public async Task Add_2k_ProvenHeaders_To_PendingBatch_Then_Save_Then_PendingBatch_Should_Be_EmptyAsync()
        {
            // Initialise store.
            await this.provenBlockHeaderStore.InitializeAsync(this.BuildProvenHeaderChain(1)).ConfigureAwait(false);

            ProvenBlockHeader inHeader = null;

            // Add to pending (add to internal cache).
            for (int i = 0; i < 2_000; i++)
            {
                var block = this.CreatePosBlock();
                if (inHeader != null)
                {
                    block.Header.HashPrevBlock = inHeader.GetHash();
                }
                inHeader = this.CreateNewProvenBlockHeaderMock(block);
                this.provenBlockHeaderStore.AddToPendingBatch(inHeader, new HashHeightPair(inHeader.GetHash(), i));
            }

            // Check Item in cache.
            var cacheCount = this.PendingBatch.Count;

            cacheCount.Should().Be(2_000);

            // Call the internal save method to save cached item to disk.
            this.provenBlockHeaderStore.InvokeMethod("SaveAsync");

            // when pendingTipHashHeight is null we can safely say the items were saved to the repository, based on the above SaveAsync.
            WaitLoop(() =>
            {
                var pendingTipHashHeight = this.provenBlockHeaderStore.GetMemberValue("pendingTipHashHeight");
                return(pendingTipHashHeight == null);
            });

            WaitLoop(() =>
            {
                // Check if it has been saved to disk.
                var outHeaderRepo = this.provenBlockHeaderRepository.GetAsync(1999).ConfigureAwait(false).GetAwaiter().GetResult();
                return(outHeaderRepo != null);
            });

            // Check items in cache - should now be empty.
            cacheCount = this.PendingBatch.Count;
            cacheCount.Should().Be(0);
        }
        /// <summary>
        /// Verifies header signature with the key from coinstake kernel.
        /// </summary>
        /// <param name="header">The header.</param>
        /// <param name="stakingCoins">The staking coins.</param>
        /// <exception cref="ConsensusException">
        /// Throws exception with error <see cref="ConsensusErrors.BadBlockSignature" /> if check fails.
        /// </exception>
        private void CheckHeaderSignatureWithCoinstakeKernel(ProvenBlockHeader header, UnspentOutputs stakingCoins)
        {
            OutPoint prevOut = this.GetPreviousOut(header);

            Script scriptPubKey = stakingCoins.Outputs[prevOut.N].ScriptPubKey;
            PubKey pubKey       = scriptPubKey.GetDestinationPublicKeys(this.PosParent.Network)[0];

            var     signature  = new ECDSASignature(header.Signature.Signature);
            uint256 headerHash = header.GetHash();

            if (pubKey.Verify(headerHash, signature))
            {
                return;
            }

            this.Logger.LogTrace("(-)[BAD_HEADER_SIGNATURE]");
            ConsensusErrors.BadBlockSignature.Throw();
        }
        /// <summary>
        /// Inserts <see cref="ProvenBlockHeader"/> items into to the database.
        /// </summary>
        /// <param name="headers"> List of <see cref="ProvenBlockHeader"/> items to save.</param>
        private void InsertHeaders(SortedDictionary <int, ProvenBlockHeader> headers)
        {
            using (var batch = new WriteBatch())
            {
                foreach (KeyValuePair <int, ProvenBlockHeader> header in headers)
                {
                    batch.Put(DBH.Key(provenBlockHeaderTable, BitConverter.GetBytes(header.Key)), this.dataStoreSerializer.Serialize(header.Value));
                }

                lock (this.locker)
                {
                    this.leveldb.Write(batch);
                }
            }

            // Store the latest ProvenBlockHeader in memory.
            this.provenBlockHeaderTip = headers.Last().Value;
        }
Exemplo n.º 11
0
        /// <inheritdoc />
        protected override void AddBlockToQueue(ChainedHeaderBlock blockPair)
        {
            base.AddBlockToQueue(blockPair);

            int blockHeight = blockPair.ChainedHeader.Height;

            if (this.AreProvenHeadersActivated(blockHeight))
            {
                if (blockPair.ChainedHeader.Header is ProvenBlockHeader phHeader)
                {
                    logger.LogTrace("Current header is already a Proven Header.");
                    return;
                }

                ProvenBlockHeader provenHeader = this.provenBlockHeaderStore.GetAsync(blockPair.ChainedHeader.Height).GetAwaiter().GetResult();
                // Proven Header not found? create it now.
                if (provenHeader == null)
                {
                    logger.LogTrace("Proven Header at height {0} NOT found.", blockHeight);

                    var createdProvenHeader = CreateAndStoreProvenHeader(blockHeight, (PosBlock)blockPair.Block);

                    // setters aren't accessible, not sure setting them to public is a nice idea.
                    //blockPair.Block.Header = blockPair.ChainedHeader.Header = createdProvenHeader;
                }
                else
                {
                    uint256 blockHash = blockPair.Block.Header.GetHash();

                    // If the Proven Header is the right one, then it's OK and we can return without doing anything.
                    uint256 provenHeaderHash = provenHeader.GetHash();
                    if (provenHeaderHash == blockHash)
                    {
                        logger.LogTrace("Proven Header {0} found.", blockHash);
                        return;
                    }
                    else
                    {
                        throw new BlockStoreException("Found a proven header with a different hash.");
                    }
                }
            }
        }
Exemplo n.º 12
0
        public ChainedHeader BuildProvenHeaderChainFromBlocks(List <Block> posBlocks)
        {
            ChainedHeader currentHeader = ChainedHeadersHelper.CreateGenesisChainedHeader(this.Network);

            foreach (PosBlock posBlock in posBlocks)
            {
                ProvenBlockHeader header = ((PosConsensusFactory)this.Network.Consensus.ConsensusFactory).CreateProvenBlockHeader(posBlock);

                header.Nonce         = RandomUtils.GetUInt32();
                header.HashPrevBlock = currentHeader.HashBlock;
                header.Bits          = Target.Difficulty1;

                ChainedHeader prevHeader = currentHeader;
                currentHeader = new ChainedHeader(header, header.GetHash(), prevHeader);

                prevHeader.Next.Add(currentHeader);
            }

            return(currentHeader);
        }
Exemplo n.º 13
0
        public void WhenCreatingNewProvenHeaderMerkleProofIsCorrectlyCreated()
        {
            PosBlock block = this.CreatePosBlock();

            // Add 20 more transactions.
            for (int i = 0; i < 20; i++)
            {
                Transaction tx = this.Network.CreateTransaction();

                tx.AddInput(new TxIn(Script.Empty));
                tx.AddOutput(Money.COIN + i, new Script(Enumerable.Range(1, 5).SelectMany(index => Guid.NewGuid().ToByteArray())));

                block.AddTransaction(tx);
            }

            block.UpdateMerkleRoot();
            ProvenBlockHeader provenBlockHeader = CreateNewProvenBlockHeaderMock(block);

            provenBlockHeader.MerkleProof.Hashes.Should().HaveCount(6);
            provenBlockHeader.MerkleProof.Check(provenBlockHeader.HashMerkleRoot).Should().BeTrue();
        }
Exemplo n.º 14
0
        /// <inheritdoc />
        protected override void ProcessRule(PosRuleContext context, ChainedHeader chainedHeader,
                                            ProvenBlockHeader header)
        {
            if (header.MerkleProofSize > PosConsensusOptions.MaxMerkleProofSerializedSize)
            {
                this.Logger.LogTrace("(-)[PROVEN_HEADER_INVALID_MERKLE_PROOF_SIZE]");
                ConsensusErrors.BadProvenHeaderMerkleProofSize.Throw();
            }

            if (header.CoinstakeSize > PosConsensusOptions.MaxCoinstakeSerializedSize)
            {
                this.Logger.LogTrace("(-)[PROVEN_HEADER_INVALID_COINSTAKE_SIZE]");
                ConsensusErrors.BadProvenHeaderCoinstakeSize.Throw();
            }

            if (header.SignatureSize > PosConsensusOptions.MaxBlockSignatureSerializedSize)
            {
                this.Logger.LogTrace("(-)[PROVEN_HEADER_INVALID_SIGNATURE_SIZE]");
                ConsensusErrors.BadProvenHeaderSignatureSize.Throw();
            }
        }
Exemplo n.º 15
0
        public async Task PutAsync_Inserts_MultipleProvenBlockHeadersAsync()
        {
            string folder = CreateTestDir(this);

            PosBlock          posBlock = CreatePosBlock();
            ProvenBlockHeader header1  = CreateNewProvenBlockHeaderMock(posBlock);
            ProvenBlockHeader header2  = CreateNewProvenBlockHeaderMock(posBlock);

            var items = new SortedDictionary <int, ProvenBlockHeader>()
            {
                { 0, header1 }, { 1, header2 }
            };

            // Put the items in the repository.
            using (IProvenBlockHeaderRepository repo = this.SetupRepository(this.Network, folder))
            {
                await repo.PutAsync(items, new HashHeightPair(header2.GetHash(), items.Count - 1));
            }

            // Check the ProvenBlockHeader exists in the database.
            using (var engine = new DB(new Options()
            {
                CreateIfMissing = true
            }, folder))
            {
                var headersOut = new Dictionary <byte[], byte[]>();
                var enumeator  = engine.GetEnumerator();
                while (enumeator.MoveNext())
                {
                    if (enumeator.Current.Key[0] == ProvenBlockHeaderTable)
                    {
                        headersOut.Add(enumeator.Current.Key, enumeator.Current.Value);
                    }
                }

                headersOut.Keys.Count.Should().Be(2);
                this.dataStoreSerializer.Deserialize <ProvenBlockHeader>(headersOut.First().Value).GetHash().Should().Be(items[0].GetHash());
                this.dataStoreSerializer.Deserialize <ProvenBlockHeader>(headersOut.Last().Value).GetHash().Should().Be(items[1].GetHash());
            }
        }
Exemplo n.º 16
0
        /// <summary>
        /// Builds a chain of proven headers.
        /// </summary>
        /// <param name="blockCount">The amount of blocks to chain.</param>
        /// <param name="startingHeader">Build the chain from this header, if not start from genesis.</param>
        /// <returns>Tip of a created chain of headers.</returns>
        public ChainedHeader BuildProvenHeaderChain(int blockCount, ChainedHeader startingHeader = null)
        {
            startingHeader = startingHeader ?? ChainedHeadersHelper.CreateGenesisChainedHeader(this.Network);

            for (int i = 1; i < blockCount; i++)
            {
                PosBlock          block  = this.CreatePosBlock();
                ProvenBlockHeader header = ((PosConsensusFactory)this.Network.Consensus.ConsensusFactory).CreateProvenBlockHeader(block);

                header.Nonce         = RandomUtils.GetUInt32();
                header.HashPrevBlock = startingHeader.HashBlock;
                header.Bits          = Target.Difficulty1;

                ChainedHeader prevHeader = startingHeader;
                startingHeader = new ChainedHeader(header, header.GetHash(), prevHeader.Height + 1);

                startingHeader.SetPrivatePropertyValue("Previous", prevHeader);
                prevHeader.Next.Add(startingHeader);
            }

            return(startingHeader);
        }
        public async Task GetAsync_ReadsProvenBlockHeaderAsync()
        {
            string folder = CreateTestDir(this);

            ProvenBlockHeader headerIn = CreateNewProvenBlockHeaderMock();

            int blockHeight = 1;

            using (var engine = RocksDb.Open(new DbOptions().SetCreateIfMissing(), folder))
            {
                engine.Put(ProvenBlockHeaderTable, BitConverter.GetBytes(blockHeight), this.dBreezeSerializer.Serialize(headerIn));
            }

            // Query the repository for the item that was inserted in the above code.
            using (var repo = this.SetupRepository(folder))
            {
                var headerOut = await repo.GetAsync(blockHeight).ConfigureAwait(false);

                headerOut.Should().NotBeNull();
                uint256.Parse(headerOut.ToString()).Should().Be(headerOut.GetHash());
            }
        }
Exemplo n.º 18
0
        /// <returns>Tip of a created chain of headers.</returns>
        public ChainedHeader BuildChainWithProvenHeaders(int blockCount)
        {
            ChainedHeader currentHeader = ChainedHeadersHelper.CreateGenesisChainedHeader(this.Network);

            for (int i = 1; i < blockCount; i++)
            {
                PosBlock          block  = this.CreatePosBlockMock();
                ProvenBlockHeader header = ((PosConsensusFactory)this.Network.Consensus.ConsensusFactory).CreateProvenBlockHeader(block);

                header.Nonce         = RandomUtils.GetUInt32();
                header.HashPrevBlock = currentHeader.HashBlock;
                header.Bits          = Target.Difficulty1;

                ChainedHeader prevHeader = currentHeader;
                currentHeader = new ChainedHeader(header, header.GetHash(), i);

                currentHeader.SetPrivatePropertyValue("Previous", prevHeader);
                prevHeader.Next.Add(currentHeader);
            }

            return(currentHeader);
        }
        /// <summary>
        /// Inserts <see cref="ProvenBlockHeader"/> items into to the database.
        /// </summary>
        /// <param name="transaction"> Open DBreeze transaction.</param>
        /// <param name="headers"> List of <see cref="ProvenBlockHeader"/> items to save.</param>
        private void InsertHeaders(DBreeze.Transactions.Transaction transaction, List <ProvenBlockHeader> headers)
        {
            var headerDict = new Dictionary <int, ProvenBlockHeader>();

            // Gather headers.
            for (int i = headers.Count - 1; i > -1; i--)
            {
                headerDict[i] = headers[i];
            }

            List <KeyValuePair <int, ProvenBlockHeader> > sortedHeaders = headerDict.ToList();

            sortedHeaders.Sort((pair1, pair2) => pair1.Key.CompareTo(pair2.Key));

            foreach (KeyValuePair <int, ProvenBlockHeader> header in sortedHeaders)
            {
                transaction.Insert <byte[], ProvenBlockHeader>(ProvenBlockHeaderTable, header.Key.ToBytes(false), header.Value);
            }

            // Store the latest ProvenBlockHeader in memory.
            this.provenBlockHeaderTip = sortedHeaders.Last().Value;
        }
        public async Task GetAsync_WithWrongBlockHeightReturnsNullAsync()
        {
            string folder = CreateTestDir(this);

            using (var engine = RocksDb.Open(new DbOptions().SetCreateIfMissing(), folder))
            {
                engine.Put(ProvenBlockHeaderTable, BitConverter.GetBytes(1), this.dBreezeSerializer.Serialize(CreateNewProvenBlockHeaderMock()));
                engine.Put(BlockHashHeightTable, new byte[0], this.DBreezeSerializer.Serialize(new HashHeightPair(new uint256(), 1)));
            }

            using (var repo = this.SetupRepository(folder))
            {
                // Select a different block height.
                ProvenBlockHeader outHeader = await repo.GetAsync(2).ConfigureAwait(false);

                outHeader.Should().BeNull();

                // Select the original item inserted into the table
                outHeader = await repo.GetAsync(1).ConfigureAwait(false);

                outHeader.Should().NotBeNull();
            }
        }
Exemplo n.º 21
0
        public (ChainedHeader chainedHeader, List <ProvenBlockHeader> provenBlockHeaders) BuildChainWithProvenHeaders(int blockCount, Network network, bool addNext = false)
        {
            Guard.Assert(blockCount > 0);

            var provenBlockHeaders = new List <ProvenBlockHeader>();

            ChainedHeader chainedHeader       = null;
            ChainedHeader previousChainHeader = null;

            for (int i = 0; i < blockCount; i++)
            {
                PosBlock          block  = CreatePosBlockMock();
                ProvenBlockHeader header = ((PosConsensusFactory)this.Network.Consensus.ConsensusFactory).CreateProvenBlockHeader(block);

                header.Nonce         = RandomUtils.GetUInt32();
                header.HashPrevBlock = i > 0 ? chainedHeader.HashBlock : null;
                header.Bits          = Target.Difficulty1;

                chainedHeader = new ChainedHeader(header, header.GetHash(), i);

                if (previousChainHeader != null)
                {
                    chainedHeader.SetPrivatePropertyValue("Previous", previousChainHeader);

                    if (addNext)
                    {
                        chainedHeader.Previous.Next.Add(chainedHeader);
                    }
                }

                previousChainHeader = chainedHeader;

                provenBlockHeaders.Add(header);
            }

            return(chainedHeader, provenBlockHeaders);
        }
        /// <summary>
        /// Gets and validates unspent outputs based of coins fetched from coin view.
        /// </summary>
        /// <param name="header">The header.</param>
        /// <param name="context">Rule context.</param>
        /// <returns>The validated previous <see cref="UnspentOutputs"/></returns>
        private UnspentOutputs GetAndValidatePreviousUtxo(ProvenBlockHeader header, PosRuleContext context)
        {
            // First try and find the previous trx in the database.
            TxIn txIn = header.Coinstake.Inputs[0];

            UnspentOutputs prevUtxo = null;

            FetchCoinsResponse coins = this.PosParent.UtxoSet.FetchCoinsAsync(new[] { txIn.PrevOut.Hash }).GetAwaiter().GetResult();

            if (coins.UnspentOutputs[0] == null)
            {
                // We did not find the previous trx in the database, look in rewind data.
                prevUtxo = this.CheckIfCoinstakeIsSpentOnAnotherChain(header, context);
            }
            else
            {
                // The trx was found now check if the UTXO is spent.
                prevUtxo = coins.UnspentOutputs[0];

                TxOut utxo = null;
                if (txIn.PrevOut.N < prevUtxo.Outputs.Length)
                {
                    // Check that the size of the outs collection is the same as the expected position of the UTXO
                    // Note the collection will not always represent the original size of the transaction unspent
                    // outputs because when we store outputs do disk the last spent items are removed from the collection.
                    utxo = prevUtxo.Outputs[txIn.PrevOut.N];
                }

                if (utxo == null)
                {
                    // UTXO is spent so find it in rewind data.
                    prevUtxo = this.CheckIfCoinstakeIsSpentOnAnotherChain(header, context);
                }
            }

            return(prevUtxo);
        }
Exemplo n.º 23
0
        public async Task GetAsync_ReadsProvenBlockHeaderAsync()
        {
            string folder = CreateTestDir(this);

            ProvenBlockHeader headerIn = CreateNewProvenBlockHeaderMock();

            int blockHeight = 1;

            using (var engine = new DBreezeEngine(folder))
            {
                DBreeze.Transactions.Transaction txn = engine.GetTransaction();
                txn.Insert <byte[], ProvenBlockHeader>(ProvenBlockHeaderTable, blockHeight.ToBytes(false), headerIn);
                txn.Commit();
            }

            // Query the repository for the item that was inserted in the above code.
            using (ProvenBlockHeaderRepository repo = this.SetupRepository(this.Network, folder))
            {
                var headerOut = await repo.GetAsync(blockHeight).ConfigureAwait(false);

                headerOut.Should().NotBeNull();
                uint256.Parse(headerOut.ToString()).Should().Be(headerOut.GetHash());
            }
        }
        /// <inheritdoc />
        public async Task InitializeAsync(ChainedHeader chainedHeader)
        {
            await this.provenBlockHeaderRepository.InitializeAsync().ConfigureAwait(false);

            if (chainedHeader.Height > 0)
            {
                ProvenBlockHeader repoHeader =
                    await this.provenBlockHeaderRepository.GetAsync(chainedHeader.Height);

                if (repoHeader == null)
                {
                    throw new ProvenBlockHeaderException("Unable to find proven block header in the repository.");
                }

                if (repoHeader.GetHash() != chainedHeader.HashBlock)
                {
                    throw new ProvenBlockHeaderException("Chain header tip hash does not match the latest proven block header hash saved to disk.");
                }
            }

            this.storeTip = chainedHeader;

            this.TipHashHeight = new HashHeightPair(chainedHeader.HashBlock, chainedHeader.Height);

            this.logger.LogDebug("Proven block header store tip at block '{0}'.", this.TipHashHeight);

            this.asyncLoop = this.asyncLoopFactory.Run("ProvenBlockHeaders job", async token =>
            {
                await this.SaveAsync().ConfigureAwait(false);

                this.logger.LogTrace("(-)[IN_ASYNC_LOOP]");
            },
                                                       this.nodeLifetime.ApplicationStopping,
                                                       repeatEvery: TimeSpan.FromMinutes(1),
                                                       startAfter: TimeSpan.FromMinutes(1));
        }
Exemplo n.º 25
0
        public async Task Add_2k_ProvenHeaders_ToPending_CacheAsync()
        {
            // Initialise store.
            await this.provenBlockHeaderStore.InitializeAsync(BuildProvenHeaderChain(1)).ConfigureAwait(false);

            ProvenBlockHeader inHeader = null;

            // Add to pending (add to internal cache).
            for (int i = 0; i < 2_000; i++)
            {
                inHeader = CreateNewProvenBlockHeaderMock();
                this.provenBlockHeaderStore.AddToPendingBatch(inHeader, new HashHeightPair(inHeader.GetHash(), i));
            }

            // Check Item in cache.
            var cacheCount = this.provenBlockHeaderStore.PendingBatch.GetMemberValue("Count");

            cacheCount.Should().Be(2_000);

            // Check if it has been saved to disk.  It shouldn't as the asyncLoopFactory() would not have been called yet.
            var outHeaderRepo = await this.provenBlockHeaderRepository.GetAsync(1).ConfigureAwait(false);

            outHeaderRepo.Should().BeNull();
        }
Exemplo n.º 26
0
        /// <see cref="IStakeValidator.CheckStakeKernelHash"/>
        /// <exception cref="ConsensusException">
        /// Throws exception with error <see cref="ConsensusErrors.PrevStakeNull" /> if check fails.
        /// </exception>
        private void CheckStakeKernelHash(PosRuleContext context, UnspentOutput stakingCoins, ProvenBlockHeader header, ChainedHeader chainedHeader)
        {
            OutPoint prevOut         = this.GetPreviousOut(header);
            uint     transactionTime = header.Time;
            uint     headerBits      = chainedHeader.Header.Bits.ToCompact();

            uint256 previousStakeModifier = this.GetPreviousStakeModifier(chainedHeader);

            if (header.Coinstake.IsCoinStake)
            {
                this.Logger.LogDebug("Found coinstake checking kernal hash.");

                var validKernel = this.stakeValidator.CheckStakeKernelHash(context, headerBits, previousStakeModifier, stakingCoins, prevOut, transactionTime);

                if (!validKernel)
                {
                    this.Logger.LogTrace("(-)[INVALID_STAKE_HASH_TARGET]");
                    ConsensusErrors.StakeHashInvalidTarget.Throw();
                }
            }

            this.ComputeNextStakeModifier(header, chainedHeader, previousStakeModifier);
        }
 public ProvenBlockHeaderBuilder(PosBlock posBlock, Network network)
 {
     this.provenBlockHeader = ((PosConsensusFactory)network.Consensus.ConsensusFactory).CreateProvenBlockHeader(posBlock);
 }
Exemplo n.º 28
0
 public ChainedHeader(ProvenBlockHeader header, uint256 headerHash, ChainedHeader previous) : this(header.PosBlockHeader, headerHash, previous)
 {
     // This override is to support proven headers
 }
Exemplo n.º 29
0
 /// <summary>
 /// Replace the <see cref="BlockHeader"/> with a new provided header.
 /// </summary>
 /// <param name="newHeader">The new header to set.</param>
 /// <remarks>Use this method very carefully because it could cause race conditions if used at the wrong moment.</remarks>
 public void SetHeader(ProvenBlockHeader newHeader)
 {
     this.ProvenBlockHeader = newHeader;
 }
 internal ProvenBlockHeader Build(ProvenBlockHeader previousProvenBlockHeader = null)
 {
     this.SetStakeModifier(previousProvenBlockHeader);
     return(this.provenBlockHeader);
 }