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