/// <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); }
/// <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; }
/// <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(); }
/// <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(); }
/// <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); } }