Exemple #1
0
        // Stake Modifier (hash modifier of proof-of-stake):
        // The purpose of stake modifier is to prevent a txout (coin) owner from
        // computing future proof-of-stake generated by this txout at the time
        // of transaction confirmation. To meet kernel protocol, the txout
        // must hash with a future stake modifier to generate the proof.
        public uint256 ComputeStakeModifierV2(ChainedBlock pindexPrev, BlockStake blockStakePrev, uint256 kernel)
        {
            if (pindexPrev == null)
            {
                return(0);                // genesis block's modifier is 0
            }
            uint256 stakeModifier;

            using (var ms = new MemoryStream())
            {
                var serializer = new BitcoinStream(ms, true);
                serializer.ReadWrite(kernel);
                serializer.ReadWrite(blockStakePrev.StakeModifierV2);
                stakeModifier = Hashes.Hash256(ms.ToArray());
            }

            return(stakeModifier);
        }
Exemple #2
0
        private void SetupStakeChain()
        {
            var callbackBlockId = new uint256();

            this.stakeChain.Setup(s => s.Get(It.IsAny <uint256>()))
            .Callback <uint256>((b) => { callbackBlockId = b; })
            .Returns(() =>
            {
                var blockStake = new BlockStake();

                if (!this.powBlocks.Contains(callbackBlockId))
                {
                    blockStake.Flags = BlockFlag.BLOCK_PROOF_OF_STAKE;
                }

                return(blockStake);
            });
        }
        public async Task SetAsync(ChainedBlock chainedBlock, BlockStake blockStake)
        {
            if (this.items.ContainsKey(chainedBlock.HashBlock))
            {
                return;
            }

            //var chainedBlock = this.chain.GetBlock(blockid);
            var item = new StakeItem {
                BlockId = chainedBlock.HashBlock, Height = chainedBlock.Height, BlockStake = blockStake, InStore = false
            };
            var added = this.items.TryAdd(chainedBlock.HashBlock, item);

            if (added)
            {
                await this.Flush(false);
            }
        }
        public void CheckKernel(ContextInformation context, ChainedBlock pindexPrev, uint nBits, long nTime, OutPoint prevout, ref long pBlockTime)
        {
            this.logger.LogTrace("({0}:'{1}',{2}:0x{3:X},{4}:{5},{6}:'{7}.{8}')", nameof(pindexPrev), pindexPrev,
                                 nameof(nBits), nBits, nameof(nTime), nTime, nameof(prevout), prevout.Hash, prevout.N);

            // TODO: https://github.com/stratisproject/StratisBitcoinFullNode/issues/397
            FetchCoinsResponse coins = this.coinView.FetchCoinsAsync(new[] { prevout.Hash }).GetAwaiter().GetResult();

            if ((coins == null) || (coins.UnspentOutputs.Length != 1))
            {
                this.logger.LogTrace("(-)[READ_PREV_TX_FAILED]");
                ConsensusErrors.ReadTxPrevFailed.Throw();
            }

            ChainedBlock prevBlock = this.chain.GetBlock(coins.BlockHash);

            if (prevBlock == null)
            {
                this.logger.LogTrace("(-)[REORG]");
                ConsensusErrors.ReadTxPrevFailed.Throw();
            }

            UnspentOutputs prevUtxo = coins.UnspentOutputs[0];

            if (this.IsConfirmedInNPrevBlocks(prevUtxo, pindexPrev, this.consensusOptions.StakeMinConfirmations - 1))
            {
                this.logger.LogTrace("(-)[LOW_COIN_AGE]");
                ConsensusErrors.InvalidStakeDepth.Throw();
            }

            BlockStake prevBlockStake = this.stakeChain.Get(pindexPrev.HashBlock);

            if (prevBlockStake == null)
            {
                this.logger.LogTrace("(-)[BAD_STAKE_BLOCK]");
                ConsensusErrors.BadStakeBlock.Throw();
            }

            pBlockTime = prevBlock.Header.Time;

            this.CheckStakeKernelHash(context, pindexPrev, nBits, prevBlock.Header.Time, prevBlockStake, prevUtxo, prevout, (uint)nTime);

            this.logger.LogTrace("(-):{0}={1}", nameof(pBlockTime), pBlockTime);
        }
        /// <inheritdoc />
        /// <exception cref="ConsensusErrors.HighHash"> Thrown if block doesn't have a valid PoW header.</exception>
        public override Task RunAsync(RuleContext context)
        {
            var posRuleContext = context as PosRuleContext;

            posRuleContext.BlockStake = BlockStake.Load(context.ValidationContext.Block);

            if (posRuleContext.BlockStake.IsProofOfWork())
            {
                if (!context.MinedBlock && !context.ValidationContext.Block.Header.CheckProofOfWork())
                {
                    this.Logger.LogTrace("(-)[HIGH_HASH]");
                    ConsensusErrors.HighHash.Throw();
                }
            }

            context.NextWorkRequired = this.PosParent.StakeValidator.GetNextTargetRequired(this.PosParent.StakeChain, context.ValidationContext.ChainedHeader.Previous, context.Consensus, posRuleContext.BlockStake.IsProofOfStake());

            return(Task.CompletedTask);
        }
Exemple #6
0
        public static void CanCalculatePowPosCorrectly()
        {
            var store      = new BlockStore(TestDataLocations.BlockFolderLocation, Network.Main);
            var chain      = store.GetChain();
            var stakeChain = new MemoryStakeChain(Network.Main);
            var indexStore = new IndexedBlockStore(new InMemoryNoSqlRepository(), store);
            var reindexed  = indexStore.ReIndex();

            Assert.Equal(reindexed, 103952);

            foreach (var chainedBlock in chain.EnumerateAfter(chain.Genesis))
            {
                var block      = indexStore.Get(chainedBlock.HashBlock);
                var blockstake = new BlockStake(block);
                stakeChain.Set(chainedBlock.HashBlock, blockstake);

                Assert.True(stakeChain.CheckPowPosAndTarget(chainedBlock, blockstake, Network.Main));
            }
        }
Exemple #7
0
        public void Set(ChainedHeader chainedHeader, BlockStake blockStake)
        {
            if (this.items.ContainsKey(chainedHeader.HashBlock))
            {
                this.logger.LogTrace("(-)[ALREADY_EXISTS]");
                return;
            }

            //var chainedHeader = this.chain.GetBlock(blockid);
            var item = new StakeItem {
                BlockId = chainedHeader.HashBlock, Height = chainedHeader.Height, BlockStake = blockStake, InStore = false
            };
            bool added = this.items.TryAdd(chainedHeader.HashBlock, item);

            if (added)
            {
                this.Flush(false);
            }
        }
Exemple #8
0
        /// <inheritdoc />
        /// <exception cref="ConsensusErrors.BadStakeBlock">The coinbase output (first transaction) is not empty.</exception>
        /// <exception cref="ConsensusErrors.BadStakeBlock">The second transaction is not a coinstake transaction.</exception>
        /// <exception cref="ConsensusErrors.BadMultipleCoinstake">There are multiple coinstake tranasctions in the block.</exception>
        /// <exception cref="ConsensusErrors.BlockTimeBeforeTrx">The block contains a transaction with a timestamp after the block timestamp.</exception>
        public override Task RunAsync(RuleContext context)
        {
            Block block = context.ValidationContext.Block;

            if (BlockStake.IsProofOfStake(block))
            {
                // Coinbase output should be empty if proof-of-stake block.
                if ((block.Transactions[0].Outputs.Count != 1) || !block.Transactions[0].Outputs[0].IsEmpty)
                {
                    this.Logger.LogTrace("(-)[COINBASE_NOT_EMPTY]");
                    ConsensusErrors.BadStakeBlock.Throw();
                }

                // Second transaction must be coinstake, the rest must not be.
                if (!block.Transactions[1].IsCoinStake)
                {
                    this.Logger.LogTrace("(-)[NO_COINSTAKE]");
                    ConsensusErrors.BadStakeBlock.Throw();
                }

                if (block.Transactions.Skip(2).Any(t => t.IsCoinStake))
                {
                    this.Logger.LogTrace("(-)[MULTIPLE_COINSTAKE]");
                    ConsensusErrors.BadMultipleCoinstake.Throw();
                }
            }

            // Check transactions.
            foreach (Transaction transaction in block.Transactions)
            {
                // Check transaction timestamp.
                if (block.Header.Time < transaction.Time)
                {
                    this.Logger.LogTrace("Block contains transaction with timestamp {0}, which is greater than block's timestamp {1}.", transaction.Time, block.Header.Time);
                    this.Logger.LogTrace("(-)[TX_TIME_MISMATCH]");
                    // BIBLEPAY - NOTE: We store the height here, so this should actually be commented out:
                    //  ConsensusErrors.BlockTimeBeforeTrx.Throw();
                }
            }

            return(Task.CompletedTask);
        }
        public void CheckAndComputeStake(ContextInformation context)
        {
            var pindex     = context.BlockResult.ChainedBlock;
            var block      = context.BlockResult.Block;
            var blockStake = context.Stake.BlockStake;

            // Verify hash target and signature of coinstake tx
            if (BlockStake.IsProofOfStake(block))
            {
                var pindexPrev = pindex.Previous;

                var prevBlockStake = this.stakeChain.Get(pindexPrev.HashBlock);
                if (prevBlockStake == null)
                {
                    ConsensusErrors.PrevStakeNull.Throw();
                }

                this.stakeValidator.CheckProofOfStake(context, pindexPrev, prevBlockStake, block.Transactions[1], pindex.Header.Bits.ToCompact());
            }

            // PoW is checked in CheckBlock()
            if (BlockStake.IsProofOfWork(block))
            {
                context.Stake.HashProofOfStake = pindex.Header.GetPoWHash();
            }

            // TODO: is this the same as chain work?
            // compute chain trust score
            //pindexNew.nChainTrust = (pindexNew->pprev ? pindexNew->pprev->nChainTrust : 0) + pindexNew->GetBlockTrust();

            // compute stake entropy bit for stake modifier
            if (!blockStake.SetStakeEntropyBit(blockStake.GetStakeEntropyBit()))
            {
                ConsensusErrors.SetStakeEntropyBitFailed.Throw();
            }

            // Record proof hash value
            blockStake.HashProof = context.Stake.HashProofOfStake;

            // compute stake modifier
            this.stakeValidator.ComputeStakeModifier(this.chain, pindex, blockStake);
        }
        /// <inheritdoc />
        /// <exception cref="ConsensusErrors.TimeTooNew">Thrown if block' timestamp too far in the future.</exception>
        /// <exception cref="ConsensusErrors.BadVersion">Thrown if block's version is outdated.</exception>
        /// <exception cref="ConsensusErrors.BlockTimestampTooEarly"> Thrown if the block timestamp is before the previous block timestamp.</exception>
        /// <exception cref="ConsensusErrors.StakeTimeViolation">Thrown if the coinstake timestamp is invalid.</exception>
        /// <exception cref="ConsensusErrors.ProofOfWorkTooHigh">The block's height is higher than the last allowed PoW block.</exception>
        public override Task RunAsync(RuleContext context)
        {
            if (context.SkipValidation)
            {
                return(Task.CompletedTask);
            }

            ChainedHeader chainedHeader = context.ValidationContext.ChainedHeaderToValidate;

            this.Logger.LogDebug("Height of block is {0}, block timestamp is {1}, previous block timestamp is {2}, block version is 0x{3:x}.", chainedHeader.Height, chainedHeader.Header.Time, chainedHeader.Previous?.Header.Time, chainedHeader.Header.Version);

            var posRuleContext = context as PosRuleContext;

            posRuleContext.BlockStake = BlockStake.Load(context.ValidationContext.BlockToValidate);

            if (posRuleContext.BlockStake.IsProofOfWork() && (chainedHeader.Height > this.Parent.ConsensusParams.LastPOWBlock))
            {
                this.Logger.LogTrace("(-)[POW_TOO_HIGH]");
                ConsensusErrors.ProofOfWorkTooHigh.Throw();
            }

            // Check coinbase timestamp.
            uint coinbaseTime = chainedHeader.Header.Time;

            if (chainedHeader.Header.Time > coinbaseTime + this.FutureDriftRule.GetFutureDrift(coinbaseTime))
            {
                this.Logger.LogTrace("(-)[TIME_TOO_NEW]");
                ConsensusErrors.TimeTooNew.Throw();
            }

            // Check coinstake timestamp.
            if (posRuleContext.BlockStake.IsProofOfStake())
            {
                if (!this.CheckCoinStakeTimestamp(chainedHeader.Header.Time))
                {
                    this.Logger.LogTrace("(-)[BAD_TIME]");
                    ConsensusErrors.StakeTimeViolation.Throw();
                }
            }

            return(Task.CompletedTask);
        }
        public virtual BlockStake Get(uint256 blockid)
        {
            if (this.network.GenesisHash == blockid)
            {
                this.logger.LogTrace("(-)[GENESIS]:*.{0}='{1}'", nameof(this.genesis.HashProof), this.genesis.HashProof);
                return(this.genesis);
            }

            StakeItem block = this.items.TryGet(blockid);

            if (block != null)
            {
                this.logger.LogTrace("(-)[LOADED]:*.{0}='{1}'", nameof(block.BlockStake.HashProof), block.BlockStake.HashProof);
                return(block.BlockStake);
            }

            BlockStake res = this.GetAsync(blockid).GetAwaiter().GetResult();

            return(res);
        }
Exemple #12
0
        public static ChainedBlock GetLastBlockIndex(StakeChain stakeChain, ChainedBlock index, bool proofOfStake)
        {
            if (index == null)
            {
                throw new ArgumentNullException(nameof(index));
            }

            clogger.LogTrace("({0}:'{1}',{2}:{3})", nameof(index), index, nameof(proofOfStake), proofOfStake);

            BlockStake blockStake = stakeChain.Get(index.HashBlock);

            while ((index.Previous != null) && (blockStake.IsProofOfStake() != proofOfStake))
            {
                index      = index.Previous;
                blockStake = stakeChain.Get(index.HashBlock);
            }

            clogger.LogTrace("(-)':{0}'", index);
            return(index);
        }
        public async Task RunAsync_ProofOfStakeBlock_CoinBaseNotEmpty_NoOutputsOnTransaction_ThrowsBadStakeBlockConsensusErrorExceptionAsync()
        {
            this.ruleContext.ValidationContext.BlockToValidate.Transactions.Add(new Transaction());

            var transaction = this.network.CreateTransaction();

            transaction.Inputs.Add(new TxIn()
            {
                PrevOut   = new OutPoint(new uint256(15), 1),
                ScriptSig = new Script()
            });
            transaction.Outputs.Add(new TxOut(Money.Zero, (IDestination)null));
            transaction.Outputs.Add(new TxOut(Money.Zero, (IDestination)null));
            this.ruleContext.ValidationContext.BlockToValidate.Transactions.Add(transaction);

            Assert.True(BlockStake.IsProofOfStake(this.ruleContext.ValidationContext.BlockToValidate));

            ConsensusErrorException exception = await Assert.ThrowsAsync <ConsensusErrorException>(() => this.consensusRules.RegisterRule <StraxCoinstakeRule>().RunAsync(this.ruleContext));

            Assert.Equal(ConsensusErrors.BadStakeBlock, exception.ConsensusError);
        }
Exemple #14
0
        public static bool IsCanonicalBlockSignature(PosBlock block, bool checkLowS)
        {
            if (BlockStake.IsProofOfWork(block))
            {
                return(block.BlockSignature.IsEmpty());
            }

            // A signature should have only one representation, or malleability vectors are introduced.
            // Therefore, an ECDSA signature, per BIP66, must be in strict DER encoding.
            // Additionally, the 'S' value of the signature must be the lower of the two possible values.

            // Recall that, for an ECDSA signature, the R and S values are both modulo N (aka the curve order).
            // Further, a signature (R, S) is equivalent to (R, -S mod N).

            // In other words there are always 2 valid S values, call them S and S'.

            // A small example of why S + S' = N:
            // N = 7
            // S = 4
            // ((N - S) % N) = 3 = S', therefore S + S' = 7 = N

            // Given S + S' = N, there will always be one S value greater than half the curve order
            // (N / 2), and one less than this.
            // The canonical signature is required to use the so-called 'low S' value, the one less than N / 2.

            // Therefore to get the other S' value (the complement) we calculate S' = N - S.

            // We can switch between the canonical and non-canonical form by calculating the complement of
            // whichever representation we currently have in a signature.

            // Using N + S will give a valid signature too, but will not give the complement, as (N + S) mod N = S.

            // For POS blocks that have a signature we do not append a SIGHASH type at the end of the signature.
            // Therefore IsValidSignatureEncoding should be called with haveSigHash = false when validating
            // POS blocks.

            return(checkLowS
                ? ScriptEvaluationContext.IsLowDerSignature(block.BlockSignature.Signature, false)
                : ScriptEvaluationContext.IsValidSignatureEncoding(block.BlockSignature.Signature, false));
        }
        /// <summary>
        /// Deserializes binary data to an object of specific type.
        /// </summary>
        /// <param name="bytes">Binary data representing a serialized object.</param>
        /// <param name="type">Type of the serialized object.</param>
        /// <returns>Deserialized object.</returns>
        internal object Deserializer(byte[] bytes, Type type)
        {
            if (type == typeof(Coins))
            {
                var coin = new Coins();
                coin.ReadWrite(bytes, this.Network.Consensus.ConsensusFactory);
                return(coin);
            }

            if (type == typeof(BlockHeader))
            {
                BlockHeader header = this.Network.Consensus.ConsensusFactory.CreateBlockHeader();
                header.ReadWrite(bytes, this.Network.Consensus.ConsensusFactory);
                return(header);
            }

            if (type == typeof(RewindData))
            {
                var rewind = new RewindData();
                rewind.ReadWrite(bytes, this.Network.Consensus.ConsensusFactory);
                return(rewind);
            }

            if (type == typeof(uint256))
            {
                return(new uint256(bytes));
            }

            if (type == typeof(Block))
            {
                return(Block.Load(bytes, this.Network));
            }

            if (type == typeof(BlockStake))
            {
                return(BlockStake.Load(bytes, this.Network));
            }

            throw new NotSupportedException();
        }
Exemple #16
0
        public void Run_IsNotCanonicalBlockSignature_ThrowsBadBlockSignatureConsensusErrorException()
        {
            Block block = KnownNetworks.StratisMain.Consensus.ConsensusFactory.CreateBlock();

            block.Transactions.Add(KnownNetworks.StratisMain.CreateTransaction());

            Transaction transaction = KnownNetworks.StratisMain.CreateTransaction();

            transaction.Inputs.Add(new TxIn()
            {
                PrevOut   = new OutPoint(new uint256(15), 1),
                ScriptSig = new Script()
            });

            transaction.Outputs.Add(new TxOut(Money.Zero, (IDestination)null));
            var scriptPubKeyOut = new Script(Op.GetPushOp(this.key.PubKey.ToBytes(true)), OpcodeType.OP_CHECKSIG);

            transaction.Outputs.Add(new TxOut(Money.Zero, scriptPubKeyOut));
            block.Transactions.Add(transaction);

            ECDSASignature signature = this.key.Sign(block.GetHash());

            signature = signature.MakeNonCanonical();

            // Ensure the non-canonical signature is still a valid signature for the block, just in the wrong format.
            Assert.True(this.key.PubKey.Verify(block.GetHash(), signature));
            Assert.False(signature.IsLowS);

            (block as PosBlock).BlockSignature = new BlockSignature {
                Signature = signature.ToDER()
            };

            this.ruleContext.ValidationContext.BlockToValidate = block;
            Assert.True(BlockStake.IsProofOfStake(this.ruleContext.ValidationContext.BlockToValidate));

            ConsensusErrorException exception = Assert.Throws <ConsensusErrorException>(() => this.consensusRules.RegisterRule <PosBlockSignatureRepresentationRule>().Run(this.ruleContext));

            Assert.Equal(ConsensusErrors.BadBlockSignature, exception.ConsensusError);
        }
        public void RunAsync_ProofOfStakeBlockSignatureEmpty_ThrowsBadBlockSignatureConsensusErrorException()
        {
            this.ruleContext.ValidationContext.BlockToValidate = KnownNetworks.StratisMain.Consensus.ConsensusFactory.CreateBlock();
            this.ruleContext.ValidationContext.BlockToValidate.Transactions.Add(KnownNetworks.StratisMain.CreateTransaction());

            Transaction transaction = KnownNetworks.StratisMain.CreateTransaction();

            transaction.Inputs.Add(new TxIn()
            {
                PrevOut   = new OutPoint(new uint256(15), 1),
                ScriptSig = new Script()
            });
            transaction.Outputs.Add(new TxOut(Money.Zero, (IDestination)null));
            transaction.Outputs.Add(new TxOut(Money.Zero, (IDestination)null));
            this.ruleContext.ValidationContext.BlockToValidate.Transactions.Add(transaction);

            Assert.True(BlockStake.IsProofOfStake(this.ruleContext.ValidationContext.BlockToValidate));

            ConsensusErrorException exception = Assert.Throws <ConsensusErrorException>(() => this.consensusRules.RegisterRule <PosBlockSignatureRule>().Run(this.ruleContext));

            Assert.Equal(ConsensusErrors.BadBlockSignature, exception.ConsensusError);
        }
Exemple #18
0
        /// <inheritdoc/>
        public void CheckKernel(PosRuleContext context, ChainedHeader prevChainedHeader, uint headerBits, long transactionTime, OutPoint prevout)
        {
            this.logger.LogTrace("({0}:'{1}',{2}:0x{3:X},{4}:{5},{6}:'{7}.{8}')", nameof(prevChainedHeader), prevChainedHeader,
                                 nameof(headerBits), headerBits, nameof(transactionTime), transactionTime, nameof(prevout), prevout.Hash, prevout.N);

            FetchCoinsResponse coins = this.coinView.FetchCoinsAsync(new[] { prevout.Hash }).GetAwaiter().GetResult();

            if ((coins == null) || (coins.UnspentOutputs.Length != 1))
            {
                this.logger.LogTrace("(-)[READ_PREV_TX_FAILED]");
                ConsensusErrors.ReadTxPrevFailed.Throw();
            }

            ChainedHeader prevBlock = this.chain.GetBlock(coins.BlockHash);

            if (prevBlock == null)
            {
                this.logger.LogTrace("(-)[REORG]");
                ConsensusErrors.ReadTxPrevFailed.Throw();
            }

            UnspentOutputs prevUtxo = coins.UnspentOutputs[0];

            if (this.IsConfirmedInNPrevBlocks(prevUtxo, prevChainedHeader, ((PosConsensusOptions)this.network.Consensus.Options).GetStakeMinConfirmations(prevChainedHeader.Height + 1, this.network) - 1))
            {
                this.logger.LogTrace("(-)[LOW_COIN_AGE]");
                ConsensusErrors.InvalidStakeDepth.Throw();
            }

            BlockStake prevBlockStake = this.stakeChain.Get(prevChainedHeader.HashBlock);

            if (prevBlockStake == null)
            {
                this.logger.LogTrace("(-)[BAD_STAKE_BLOCK]");
                ConsensusErrors.BadStakeBlock.Throw();
            }

            this.CheckStakeKernelHash(context, headerBits, prevBlockStake, prevUtxo, prevout, (uint)transactionTime);
        }
Exemple #19
0
        public async Task RunAsync_ProofOfStakeBlockSignatureEmpty_ThrowsBadBlockSignatureConsensusErrorExceptionAsync()
        {
            this.ruleContext.BlockValidationContext.Block = new Block();
            this.ruleContext.BlockValidationContext.Block.Transactions.Add(new Transaction());

            var transaction = new Transaction();

            transaction.Inputs.Add(new TxIn()
            {
                PrevOut   = new OutPoint(new uint256(15), 1),
                ScriptSig = new Script()
            });
            transaction.Outputs.Add(new TxOut(Money.Zero, (IDestination)null));
            transaction.Outputs.Add(new TxOut(Money.Zero, (IDestination)null));
            this.ruleContext.BlockValidationContext.Block.Transactions.Add(transaction);

            Assert.True(BlockStake.IsProofOfStake(this.ruleContext.BlockValidationContext.Block));

            var exception = await Assert.ThrowsAsync <ConsensusErrorException>(() => this.consensusRules.RegisterRule <PosBlockSignatureRule>().RunAsync(this.ruleContext));

            Assert.Equal(ConsensusErrors.BadBlockSignature, exception.ConsensusError);
        }
        public async Task SetAsync(ChainedHeader chainedHeader, BlockStake blockStake)
        {
            this.logger.LogTrace("({0}:'{1}',{2}.{3}:'{4}')", nameof(chainedHeader), chainedHeader, nameof(blockStake), nameof(blockStake.HashProof), blockStake.HashProof);

            if (this.items.ContainsKey(chainedHeader.HashBlock))
            {
                this.logger.LogTrace("(-)[ALREADY_EXISTS]");
                return;
            }

            //var chainedHeader = this.chain.GetBlock(blockid);
            var item = new StakeItem {
                BlockId = chainedHeader.HashBlock, Height = chainedHeader.Height, BlockStake = blockStake, InStore = false
            };
            bool added = this.items.TryAdd(chainedHeader.HashBlock, item);

            if (added)
            {
                await this.FlushAsync(false).ConfigureAwait(false);
            }

            this.logger.LogTrace("(-)");
        }
        public async Task RunAsync_ProofOfStakeBlock_ValidBlock_DoesNotThrowExceptionAsync()
        {
            var transaction = this.network.CreateTransaction();

            transaction.Outputs.Add(new TxOut(Money.Zero, (IDestination)null));
            this.ruleContext.ValidationContext.BlockToValidate.Transactions.Add(transaction);

            transaction = this.network.CreateTransaction();
            transaction.Inputs.Add(new TxIn()
            {
                PrevOut   = new OutPoint(new uint256(15), 1),
                ScriptSig = new Script()
            });
            transaction.Outputs.Add(new TxOut(Money.Zero, (IDestination)null));
            transaction.Outputs.Add(new TxOut(Money.Zero, (IDestination)null));
            this.ruleContext.ValidationContext.BlockToValidate.Transactions.Add(transaction);

            this.ruleContext.ValidationContext.BlockToValidate.Header.Time = (uint)1483747200;

            Assert.True(BlockStake.IsProofOfStake(this.ruleContext.ValidationContext.BlockToValidate));

            await this.consensusRules.RegisterRule <PosCoinstakeRule>().RunAsync(this.ruleContext);
        }
        /// <inheritdoc />
        /// <exception cref="ConsensusErrors.HighHash">Thrown if block doesn't have a valid PoW header.</exception>
        /// <exception cref="ConsensusErrors.BadDiffBits">Thrown if proof of stake is incorrect.</exception>
        public override Task RunAsync(RuleContext context)
        {
            if (context.SkipValidation)
            {
                return(Task.CompletedTask);
            }

            var posRuleContext = context as PosRuleContext;

            posRuleContext.BlockStake = BlockStake.Load(context.ValidationContext.BlockToValidate);

            if (posRuleContext.BlockStake.IsProofOfWork())
            {
                if (!context.ValidationContext.BlockToValidate.Header.CheckProofOfWork())
                {
                    this.Logger.LogTrace("(-)[HIGH_HASH]");
                    ConsensusErrors.HighHash.Throw();
                }
            }

            Target nextWorkRequired = this.PosParent.StakeValidator.GetNextTargetRequired(this.PosParent.StakeChain,
                                                                                          context.ValidationContext.ChainedHeaderToValidate.Previous, this.Parent.Network.Consensus, posRuleContext.BlockStake.IsProofOfStake());

            BlockHeader header = context.ValidationContext.BlockToValidate.Header;

            if (posRuleContext.BlockStake.IsProofOfStake())
            {
                // Check proof of stake.
                if (header.Bits != nextWorkRequired)
                {
                    this.Logger.LogTrace("(-)[BAD_DIFF_BITS]");
                    ConsensusErrors.BadDiffBits.Throw();
                }
            }

            return(Task.CompletedTask);
        }
        public void RunAsync_ProofOfStakeBlock_ScriptKeyDoesNotPassCompressedUncompresedKeyValidation_ThrowsBadBlockSignatureConsensusErrorException()
        {
            Block block = KnownNetworks.StratisMain.Consensus.ConsensusFactory.CreateBlock();

            block.Transactions.Add(KnownNetworks.StratisMain.CreateTransaction());

            Transaction transaction = KnownNetworks.StratisMain.CreateTransaction();

            transaction.Inputs.Add(new TxIn()
            {
                PrevOut   = new OutPoint(new uint256(15), 1),
                ScriptSig = new Script()
            });

            transaction.Outputs.Add(new TxOut(Money.Zero, (IDestination)null));
            transaction.Outputs.Add(new TxOut(Money.Zero, new Script(new Op()
            {
                Code = OpcodeType.OP_RETURN
            }, new Op()
            {
                PushData = new byte[] { 0x11 }
            })));
            block.Transactions.Add(transaction);

            ECDSASignature signature = this.key.Sign(block.GetHash());

            (block as PosBlock).BlockSignature = new BlockSignature {
                Signature = signature.ToDER()
            };

            this.ruleContext.ValidationContext.BlockToValidate = block;
            Assert.True(BlockStake.IsProofOfStake(this.ruleContext.ValidationContext.BlockToValidate));

            ConsensusErrorException exception = Assert.Throws <ConsensusErrorException>(() => this.consensusRules.RegisterRule <PosBlockSignatureRule>().Run(this.ruleContext));

            Assert.Equal(ConsensusErrors.BadBlockSignature, exception.ConsensusError);
        }
Exemple #24
0
        public async Task RunAsync_ProofOfStakeBlock_ScriptKeyDoesNotPassCompressedUncompresedKeyValidation_ThrowsBadBlockSignatureConsensusErrorExceptionAsync()
        {
            var block = new Block();

            block.Transactions.Add(new Transaction());

            var transaction = new Transaction();

            transaction.Inputs.Add(new TxIn()
            {
                PrevOut   = new OutPoint(new uint256(15), 1),
                ScriptSig = new Script()
            });

            transaction.Outputs.Add(new TxOut(Money.Zero, (IDestination)null));
            transaction.Outputs.Add(new TxOut(Money.Zero, new Script(new Op()
            {
                Code = OpcodeType.OP_RETURN
            }, new Op()
            {
                PushData = new byte[] { 0x11 }
            })));
            block.Transactions.Add(transaction);

            ECDSASignature signature = this.key.Sign(block.GetHash());

            block.BlockSignatur = new BlockSignature {
                Signature = signature.ToDER()
            };

            this.ruleContext.BlockValidationContext.Block = block;
            Assert.True(BlockStake.IsProofOfStake(this.ruleContext.BlockValidationContext.Block));

            var exception = await Assert.ThrowsAsync <ConsensusErrorException>(() => this.consensusRules.RegisterRule <PosBlockSignatureRule>().RunAsync(this.ruleContext));

            Assert.Equal(ConsensusErrors.BadBlockSignature, exception.ConsensusError);
        }
Exemple #25
0
        /// <inheritdoc />
        public override void CheckBlockReward(RuleContext context, Money fees, int height, Block block)
        {
            if (BlockStake.IsProofOfStake(block))
            {
                var   posRuleContext  = context as PosRuleContext;
                Money stakeReward     = block.Transactions[1].TotalOut - posRuleContext.TotalCoinStakeValueIn;
                Money calcStakeReward = fees + this.GetProofOfStakeReward(height);

                if (stakeReward > calcStakeReward)
                {
                    this.Logger.LogTrace("(-)[BAD_COINSTAKE_AMOUNT]");
                    ConsensusErrors.BadCoinstakeAmount.Throw();
                }
            }
            else
            {
                Money blockReward = fees + this.GetProofOfWorkReward(height);
                if (block.Transactions[0].TotalOut > blockReward)
                {
                    this.Logger.LogTrace("(-)[BAD_COINBASE_AMOUNT]");
                    ConsensusErrors.BadCoinbaseAmount.Throw();
                }
            }
        }
Exemple #26
0
        public async Task RunAsync_ProofOfStakeBlock_MultipleCoinStakeAfterSecondTransaction_ThrowsBadMultipleCoinstakeConsensusErrorExceptionAsync()
        {
            var transaction = this.network.CreateTransaction();

            transaction.Outputs.Add(new TxOut(Money.Zero, (IDestination)null));
            this.ruleContext.ValidationContext.Block.Transactions.Add(transaction);

            transaction = this.network.CreateTransaction();
            transaction.Inputs.Add(new TxIn()
            {
                PrevOut   = new OutPoint(new uint256(15), 1),
                ScriptSig = new Script()
            });
            transaction.Outputs.Add(new TxOut(Money.Zero, (IDestination)null));
            transaction.Outputs.Add(new TxOut(Money.Zero, (IDestination)null));
            this.ruleContext.ValidationContext.Block.Transactions.Add(transaction);
            this.ruleContext.ValidationContext.Block.Transactions.Add(transaction);

            Assert.True(BlockStake.IsProofOfStake(this.ruleContext.ValidationContext.Block));

            ConsensusErrorException exception = await Assert.ThrowsAsync <ConsensusErrorException>(() => this.consensusRules.RegisterRule <PosCoinstakeRule>().RunAsync(this.ruleContext));

            Assert.Equal(ConsensusErrors.BadMultipleCoinstake.Message, exception.ConsensusError.Message);
        }
        public void RunAsync_ProofOfWorkBlock_BlockSignatureEmpty_DoesNotThrowException()
        {
            Block block = KnownNetworks.StratisMain.Consensus.ConsensusFactory.CreateBlock();

            block.Transactions.Add(KnownNetworks.StratisMain.CreateTransaction());

            Transaction transaction = KnownNetworks.StratisMain.CreateTransaction();

            transaction.Inputs.Add(new TxIn()
            {
                PrevOut   = new OutPoint(uint256.Zero, uint.MaxValue),
                ScriptSig = new Script()
            });

            transaction.Outputs.Add(new TxOut(Money.Zero, (IDestination)null));
            transaction.Outputs.Add(new TxOut(Money.Zero, (IDestination)null));
            block.Transactions.Add(transaction);
            (block as PosBlock).BlockSignature = new BlockSignature();

            this.ruleContext.ValidationContext.BlockToValidate = block;
            Assert.True(BlockStake.IsProofOfWork(this.ruleContext.ValidationContext.BlockToValidate));

            this.consensusRules.RegisterRule <PosBlockSignatureRule>().Run(this.ruleContext);
        }
Exemple #28
0
        public async Task RunAsync_ProofOfWorkBlock_BlockSignatureEmpty_DoesNotThrowExceptionAsync()
        {
            var block = new Block();

            block.Transactions.Add(new Transaction());

            var transaction = new Transaction();

            transaction.Inputs.Add(new TxIn()
            {
                PrevOut   = new OutPoint(uint256.Zero, uint.MaxValue),
                ScriptSig = new Script()
            });

            transaction.Outputs.Add(new TxOut(Money.Zero, (IDestination)null));
            transaction.Outputs.Add(new TxOut(Money.Zero, (IDestination)null));
            block.Transactions.Add(transaction);
            block.BlockSignatur = new BlockSignature();

            this.ruleContext.BlockValidationContext.Block = block;
            Assert.True(BlockStake.IsProofOfWork(this.ruleContext.BlockValidationContext.Block));

            await this.consensusRules.RegisterRule <PosBlockSignatureRule>().RunAsync(this.ruleContext);
        }
Exemple #29
0
        public async Task RunAsync_ProofOfStakeBlock_ScriptKeyDoesNotPassBlockSignatureValidation_ThrowsBadBlockSignatureConsensusErrorExceptionAsync()
        {
            var block = new Block();

            block.Transactions.Add(new Transaction());

            var transaction = new Transaction();

            transaction.Inputs.Add(new TxIn()
            {
                PrevOut   = new OutPoint(new uint256(15), 1),
                ScriptSig = new Script()
            });

            transaction.Outputs.Add(new TxOut(Money.Zero, (IDestination)null));

            // push op_return to note external dependancy in front of pay to pubkey script so it does not match pay to pubkey template.
            // use a different key to generate the script so it does not pass validation.
            Script scriptPubKeyOut = new Script(OpcodeType.OP_RETURN, Op.GetPushOp(new Key().PubKey.ToBytes(true)), OpcodeType.OP_CHECKSIG);

            transaction.Outputs.Add(new TxOut(Money.Zero, scriptPubKeyOut));
            block.Transactions.Add(transaction);

            ECDSASignature signature = this.key.Sign(block.GetHash());

            block.BlockSignatur = new BlockSignature {
                Signature = signature.ToDER()
            };

            this.ruleContext.BlockValidationContext.Block = block;
            Assert.True(BlockStake.IsProofOfStake(this.ruleContext.BlockValidationContext.Block));

            var exception = await Assert.ThrowsAsync <ConsensusErrorException>(() => this.consensusRules.RegisterRule <PosBlockSignatureRule>().RunAsync(this.ruleContext));

            Assert.Equal(ConsensusErrors.BadBlockSignature, exception.ConsensusError);
        }
 public PosRuleContext(BlockStake blockStake)
 {
     this.BlockStake = blockStake;
 }