/// <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;

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

            return(Task.CompletedTask);
        }
Exemple #2
0
        /// <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();
            }

            if (posRuleContext.BlockStake.IsProofOfStake())
            {
                // We now treat the PoS block header's timestamp as being the timestamp for every transaction in the block.
                if (!this.CheckBlockTimestamp(chainedHeader.Header.Time))
                {
                    this.Logger.LogTrace("(-)[BAD_TIME]");
                    ConsensusErrors.StakeTimeViolation.Throw();
                }
            }

            return(Task.CompletedTask);
        }
        /// <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>
        public object Deserialize(byte[] bytes, Type type)
        {
            if (type == typeof(BlockHeader))
            {
                BlockHeader header = this.consensusFactory.CreateBlockHeader();
                header.ReadWrite(bytes, this.consensusFactory);
                return(header);
            }

            if (type == typeof(Transaction))
            {
                Transaction transaction = this.consensusFactory.CreateTransaction();
                transaction.ReadWrite(bytes, this.consensusFactory);
                return(transaction);
            }

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

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

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

            if (type == typeof(ProvenBlockHeader))
            {
                ProvenBlockHeader provenBlockHeader =
                    ((PosConsensusFactory)this.consensusFactory).CreateProvenBlockHeader();

                provenBlockHeader.ReadWrite(bytes, this.consensusFactory);
                return(provenBlockHeader);
            }

            if (type == typeof(HashHeightPair))
            {
                return(HashHeightPair.Load(bytes, this.consensusFactory));
            }

            if (typeof(IBitcoinSerializable).IsAssignableFrom(type))
            {
                var result = (IBitcoinSerializable)Activator.CreateInstance(type);
                result.ReadWrite(bytes, this.consensusFactory);
                return(result);
            }

            throw new NotSupportedException();
        }
 public StakeChainStore(Network network, ConcurrentChain chain, DBreezeCoinView dBreezeCoinView, ILoggerFactory loggerFactory)
 {
     this.logger            = loggerFactory.CreateLogger(this.GetType().FullName);
     this.network           = network;
     this.chain             = chain;
     this.dBreezeCoinView   = dBreezeCoinView;
     this.threshold         = 5000;                                  // Count of items in memory.
     this.thresholdWindow   = Convert.ToInt32(this.threshold * 0.4); // A window threshold.
     this.genesis           = BlockStake.Load(this.network.GetGenesis());
     this.genesis.HashProof = this.network.GenesisHash;
     this.genesis.Flags     = BlockFlag.BLOCK_STAKE_MODIFIER;
 }
 public StakeChainStore(Network network, ChainIndexer chainIndexer, DBreezeCoinView dBreezeCoinView, ILoggerFactory loggerFactory)
 {
     this.logger            = loggerFactory.CreateLogger("Impleum.Bitcoin.Fullnode");
     this.network           = network;
     this.chainIndexer      = chainIndexer;
     this.dBreezeCoinView   = dBreezeCoinView;
     this.threshold         = 5000;                                  // Count of items in memory.
     this.thresholdWindow   = Convert.ToInt32(this.threshold * 0.4); // A window threshold.
     this.genesis           = BlockStake.Load(this.network.GetGenesis());
     this.genesis.HashProof = this.network.GenesisHash;
     this.genesis.Flags     = BlockFlag.BLOCK_STAKE_MODIFIER;
 }
 public StakeChainStore(Network network, ChainIndexer chainIndexer, IStakedb stakeDb, ILoggerFactory loggerFactory)
 {
     this.logger            = loggerFactory.CreateLogger(this.GetType().FullName);
     this.network           = network;
     this.chainIndexer      = chainIndexer;
     this.stakeDb           = stakeDb;
     this.threshold         = 5000;                                  // Count of items in memory.
     this.thresholdWindow   = Convert.ToInt32(this.threshold * 0.4); // A window threshold.
     this.genesis           = BlockStake.Load(this.network.GetGenesis());
     this.genesis.HashProof = this.network.GenesisHash;
     this.genesis.Flags     = BlockFlag.BLOCK_STAKE_MODIFIER;
 }
Exemple #7
0
        /// <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));
            }

            if (type == typeof(HashHeightPair))
            {
                return(HashHeightPair.Load(bytes));
            }

            if (typeof(IBitcoinSerializable).IsAssignableFrom(type))
            {
                var result = (IBitcoinSerializable)Activator.CreateInstance(type);
                result.ReadWrite(bytes);
                return(result);
            }

            throw new NotSupportedException();
        }
Exemple #8
0
        /// <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);
            }

            var 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.
            var 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 (!CheckCoinStakeTimestamp(chainedHeader.Header.Time))
                {
                    this.Logger.LogTrace("(-)[BAD_TIME]");
                    ConsensusErrors.StakeTimeViolation.Throw();
                }
            }

            return(Task.CompletedTask);
        }
        /// <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);
        }
        /// <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 #11
0
        /// <summary>
        /// Checks and computes stake.
        /// </summary>
        /// <param name="context">Context that contains variety of information regarding blocks validation and execution.</param>
        /// <exception cref="ConsensusErrors.PrevStakeNull">Thrown if previous stake is not found.</exception>
        /// <exception cref="ConsensusErrors.SetStakeEntropyBitFailed">Thrown if failed to set stake entropy bit.</exception>
        private void CheckAndComputeStake(RuleContext context)
        {
            ChainedHeader chainedHeader = context.ValidationContext.ChainedHeaderToValidate;
            Block         block         = context.ValidationContext.BlockToValidate;

            var posRuleContext = context as PosRuleContext;

            if (posRuleContext.BlockStake == null)
            {
                posRuleContext.BlockStake = BlockStake.Load(context.ValidationContext.BlockToValidate);
            }

            BlockStake blockStake = posRuleContext.BlockStake;

            // Verify hash target and signature of coinstake tx.
            if (BlockStake.IsProofOfStake(block))
            {
                ChainedHeader prevChainedHeader = chainedHeader.Previous;

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

                // Only do proof of stake validation for blocks that are after the assumevalid block or after the last checkpoint.
                if (!context.SkipValidation)
                {
                    this.stakeValidator.CheckProofOfStake(posRuleContext, prevChainedHeader, prevBlockStake, block.Transactions[1], chainedHeader.Header.Bits.ToCompact());
                }
                else
                {
                    this.Logger.LogTrace("POS validation skipped for block at height {0}.", chainedHeader.Height);
                }
            }

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

            // Compute stake entropy bit for stake modifier.
            if (!blockStake.SetStakeEntropyBit(blockStake.GetStakeEntropyBit()))
            {
                this.Logger.LogTrace("(-)[STAKE_ENTROPY_BIT_FAIL]");
                ConsensusErrors.SetStakeEntropyBitFailed.Throw();
            }

            // Record proof hash value.
            blockStake.HashProof = posRuleContext.HashProofOfStake;

            int lastCheckpointHeight = this.Parent.Checkpoints.GetLastCheckpointHeight();

            if (chainedHeader.Height > lastCheckpointHeight)
            {
                // Compute stake modifier.
                ChainedHeader prevChainedHeader = chainedHeader.Previous;
                BlockStake    blockStakePrev    = prevChainedHeader == null ? null : this.stakeChain.Get(prevChainedHeader.HashBlock);
                blockStake.StakeModifierV2 = this.stakeValidator.ComputeStakeModifierV2(prevChainedHeader, blockStakePrev?.StakeModifierV2, blockStake.IsProofOfWork() ? chainedHeader.HashBlock : blockStake.PrevoutStake.Hash);
            }
            else if (chainedHeader.Height == lastCheckpointHeight)
            {
                // Copy checkpointed stake modifier.
                CheckpointInfo checkpoint = this.Parent.Checkpoints.GetCheckpoint(lastCheckpointHeight);
                blockStake.StakeModifierV2 = checkpoint.StakeModifierV2;
                this.Logger.LogTrace("Last checkpoint stake modifier V2 loaded: '{0}'.", blockStake.StakeModifierV2);
            }
            else
            {
                this.Logger.LogTrace("POS stake modifier computation skipped for block at height {0} because it is not above last checkpoint block height {1}.", chainedHeader.Height, lastCheckpointHeight);
            }
        }