public void RunRule_ProvenHeadersActive_And_InvalidCoinstakeKernelSignature_BadBlockSignatureErrorIsThrown()
        {
            // Setup private key.
            var mnemonic   = new Mnemonic(Wordlist.English, WordCount.Twelve);
            Key privateKey = mnemonic.DeriveExtKey().PrivateKey;

            // Setup previous chained header.
            PosBlock          prevPosBlock          = new PosBlockBuilder(this.network, privateKey).Build();
            ProvenBlockHeader prevProvenBlockHeader = new ProvenBlockHeaderBuilder(prevPosBlock, this.network).Build();
            var previousChainedHeader = new ChainedHeader(prevProvenBlockHeader, prevProvenBlockHeader.GetHash(), null);

            previousChainedHeader.SetPrivatePropertyValue("Height", this.options.ProvenHeadersActivationHeight + 1);

            // Setup proven header with valid coinstake.
            PosBlock posBlock = new PosBlockBuilder(this.network, privateKey).Build();

            posBlock.UpdateMerkleRoot();
            ProvenBlockHeader provenBlockHeader = new ProvenBlockHeaderBuilder(posBlock, this.network).Build();

            provenBlockHeader.HashPrevBlock  = prevProvenBlockHeader.GetHash();
            provenBlockHeader.Coinstake.Time = provenBlockHeader.Time;

            // Setup chained header and move it to the height higher than proven header activation height.
            this.ruleContext.ValidationContext.ChainedHeaderToValidate = new ChainedHeader(provenBlockHeader, provenBlockHeader.GetHash(), previousChainedHeader);
            this.ruleContext.ValidationContext.ChainedHeaderToValidate.SetPrivatePropertyValue("Height", this.options.ProvenHeadersActivationHeight + 2);

            // Setup coinstake transaction with a valid stake age.
            uint unspentOutputsHeight = (uint)this.options.ProvenHeadersActivationHeight + 10;

            var unspentOutputs = new UnspentOutputs(unspentOutputsHeight, new Transaction())
            {
                Outputs = new[] { new TxOut(new Money(100), privateKey.PubKey) }
            };

            this.coinView
            .Setup(m => m.FetchCoinsAsync(It.IsAny <uint256[]>(), It.IsAny <CancellationToken>()))
            .ReturnsAsync(new FetchCoinsResponse(new[] { unspentOutputs }, posBlock.GetHash()));

            // Setup stake validator to pass signature validation.
            this.stakeValidator
            .Setup(m => m.VerifySignature(It.IsAny <UnspentOutputs>(), It.IsAny <Transaction>(), It.IsAny <int>(), It.IsAny <ScriptVerify>()))
            .Returns(true);

            // Setup stake validator to pass stake kernel hash validation.
            this.stakeChain.Setup(m => m.Get(It.IsAny <uint256>())).Returns(new BlockStake());
            this.stakeValidator
            .Setup(m => m.CheckStakeKernelHash(It.IsAny <PosRuleContext>(), It.IsAny <uint>(), It.IsAny <uint256>(), It.IsAny <UnspentOutputs>(), It.IsAny <OutPoint>(), It.IsAny <uint>()));

            // Setup stake validator to pass stake age check.
            this.stakeValidator
            .Setup(m => m.IsConfirmedInNPrevBlocks(It.IsAny <UnspentOutputs>(), It.IsAny <ChainedHeader>(), It.IsAny <long>()))
            .Returns(true);

            // When we run the validation rule, we should hit bad merkle proof error.
            Action ruleValidation = () => this.consensusRules.RegisterRule <ProvenHeaderCoinstakeRule>().Run(this.ruleContext);

            ruleValidation.Should().Throw <ConsensusErrorException>()
            .And.ConsensusError
            .Should().Be(ConsensusErrors.BadBlockSignature);
        }
コード例 #2
0
        public void RunRule_ProvenHeadersActive_And_ValidProvenHeader_NoErrorsAreThrown()
        {
            // Setup private key.
            var mnemonic   = new Mnemonic(Wordlist.English, WordCount.Twelve);
            Key privateKey = mnemonic.DeriveExtKey().PrivateKey;

            // Setup previous chained header.
            PosBlock          prevPosBlock          = new PosBlockBuilder(this.network, privateKey).Build();
            ProvenBlockHeader prevProvenBlockHeader = new ProvenBlockHeaderBuilder(prevPosBlock, this.network).Build();
            var previousChainedHeader = new ChainedHeader(prevProvenBlockHeader, prevProvenBlockHeader.GetHash(), null);

            previousChainedHeader.SetPrivatePropertyValue("Height", this.provenHeadersActivationHeight + 1);

            // Setup proven header with valid coinstake.
            PosBlock posBlock = new PosBlockBuilder(this.network, privateKey).Build();

            posBlock.UpdateMerkleRoot();
            posBlock.Header.HashPrevBlock = prevProvenBlockHeader.GetHash();
            posBlock.Header.Bits          = 16777216;

            // Update signature.
            ECDSASignature signature = privateKey.Sign(posBlock.Header.GetHash());

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

            ProvenBlockHeader provenBlockHeader = new ProvenBlockHeaderBuilder(posBlock, this.network).Build(prevProvenBlockHeader);

            provenBlockHeader.PosBlockHeader.HashPrevBlock = prevProvenBlockHeader.GetHash();
            if (provenBlockHeader.Coinstake is IPosTransactionWithTime posTrx)
            {
                posTrx.Time = provenBlockHeader.Time;
            }

            // Set invalid coinstake script pub key
            provenBlockHeader.Coinstake.Outputs[1].ScriptPubKey = privateKey.PubKey.ScriptPubKey;

            // Setup chained header and move it to the height higher than proven header activation height.
            this.ruleContext.ValidationContext.ChainedHeaderToValidate = new ChainedHeader(provenBlockHeader, provenBlockHeader.GetHash(), previousChainedHeader);
            this.ruleContext.ValidationContext.ChainedHeaderToValidate.SetPrivatePropertyValue("Height", this.provenHeadersActivationHeight + 2);

            // Setup coinstake transaction with a valid stake age.

            uint unspentOutputsHeight = (uint)this.provenHeadersActivationHeight + 10;
            var  res            = new FetchCoinsResponse();
            var  unspentOutputs = new UnspentOutput(prevPosBlock.Transactions[1].Inputs[0].PrevOut,
                                                    new Coins(unspentOutputsHeight, new TxOut(new Money(100), privateKey.PubKey), false));

            res.UnspentOutputs.Add(unspentOutputs.OutPoint, unspentOutputs);

            this.coinView
            .Setup(m => m.FetchCoins(It.IsAny <OutPoint[]>()))
            .Returns(res);

            // Setup stake validator to pass stake age check.
            this.stakeValidator
            .Setup(m => m.IsConfirmedInNPrevBlocks(It.IsAny <UnspentOutput>(), It.IsAny <ChainedHeader>(), It.IsAny <long>()))
            .Returns(false);

            // Setup stake validator to pass signature validation.
            this.stakeValidator
            .Setup(m => m.VerifySignature(It.IsAny <UnspentOutput>(), It.IsAny <Transaction>(), It.IsAny <int>(), It.IsAny <ScriptVerify>()))
            .Returns(true);

            // Setup stake validator to pass stake kernel hash validation.
            this.stakeChain.Setup(m => m.Get(It.IsAny <uint256>())).Returns(new BlockStake());
            this.stakeValidator
            .Setup(m => m.CheckStakeKernelHash(It.IsAny <PosRuleContext>(), It.IsAny <uint>(), It.IsAny <uint256>(), It.IsAny <UnspentOutput>(), It.IsAny <OutPoint>(), It.IsAny <uint>())).Returns(true);

            // When we run the validation rule, we should not hit any errors.
            Action ruleValidation = () => this.consensusRules.RegisterRule <ProvenHeaderCoinstakeRule>().Run(this.ruleContext);

            ruleValidation.Should().NotThrow();
        }
コード例 #3
0
        public void RunRule_ProvenHeadersActive_And_InvalidCoinstakeKernelSignature_BadBlockSignatureErrorIsThrown()
        {
            // Setup private key.
            var mnemonic   = new Mnemonic(Wordlist.English, WordCount.Twelve);
            Key privateKey = mnemonic.DeriveExtKey().PrivateKey;

            // Setup previous chained header.
            PosBlock          prevPosBlock          = new PosBlockBuilder(this.network, privateKey).Build();
            ProvenBlockHeader prevProvenBlockHeader = new ProvenBlockHeaderBuilder(prevPosBlock, this.network).Build();
            var previousChainedHeader = new ChainedHeader(prevProvenBlockHeader, prevProvenBlockHeader.GetHash(), null);

            previousChainedHeader.SetPrivatePropertyValue("Height", this.provenHeadersActivationHeight + 1);

            // Setup proven header with valid coinstake.
            PosBlock posBlock = new PosBlockBuilder(this.network, privateKey).Build();

            posBlock.UpdateMerkleRoot();
            ProvenBlockHeader provenBlockHeader = new ProvenBlockHeaderBuilder(posBlock, this.network).Build(prevProvenBlockHeader);

            provenBlockHeader.PosBlockHeader.HashPrevBlock = prevProvenBlockHeader.GetHash();
            if (provenBlockHeader.Coinstake is IPosTransactionWithTime posTrx)
            {
                posTrx.Time = provenBlockHeader.Time;
            }

            // Set invalid coinstake script pub key.
            provenBlockHeader.Coinstake.Outputs[1].ScriptPubKey = new Script("03cdac179a3391d96cf4957fa0255e4aa8055a993e92df7146e740117885b184ea OP_CHECKSIG");

            // Setup chained header and move it to the height higher than proven header activation height.
            this.ruleContext.ValidationContext.ChainedHeaderToValidate = new ChainedHeader(provenBlockHeader, provenBlockHeader.GetHash(), previousChainedHeader);
            this.ruleContext.ValidationContext.ChainedHeaderToValidate.SetPrivatePropertyValue("Height", this.provenHeadersActivationHeight + 2);

            // Setup coinstake transaction with a valid stake age.
            uint unspentOutputsHeight = (uint)this.provenHeadersActivationHeight + 10;

            var res            = new FetchCoinsResponse();
            var unspentOutputs = new UnspentOutput(prevPosBlock.Transactions[1].Inputs[0].PrevOut,
                                                   new Coins(unspentOutputsHeight, new TxOut(new Money(100), privateKey.PubKey), false));

            res.UnspentOutputs.Add(unspentOutputs.OutPoint, unspentOutputs);

            this.coinView
            .Setup(m => m.FetchCoins(It.IsAny <OutPoint[]>()))
            .Returns(res);

            // Setup stake validator to pass signature validation.
            this.stakeValidator
            .Setup(m => m.VerifySignature(It.IsAny <UnspentOutput>(), It.IsAny <Transaction>(), It.IsAny <int>(), It.IsAny <ScriptVerify>()))
            .Returns(true);

            // Setup stake validator to pass stake kernel hash validation.
            this.stakeChain.Setup(m => m.Get(It.IsAny <uint256>())).Returns(new BlockStake());
            this.stakeValidator
            .Setup(m => m.CheckStakeKernelHash(It.IsAny <PosRuleContext>(), It.IsAny <uint>(), It.IsAny <uint256>(), It.IsAny <UnspentOutput>(), It.IsAny <OutPoint>(), It.IsAny <uint>())).Returns(true);

            // Setup stake validator to pass stake age check.
            this.stakeValidator
            .Setup(m => m.IsConfirmedInNPrevBlocks(It.IsAny <UnspentOutput>(), It.IsAny <ChainedHeader>(), It.IsAny <long>()))
            .Returns(false);

            // When we run the validation rule, we should hit bad merkle proof error.
            Action ruleValidation = () => this.consensusRules.RegisterRule <ProvenHeaderCoinstakeRule>().Run(this.ruleContext);

            ruleValidation.Should().Throw <ConsensusErrorException>()
            .And.ConsensusError
            .Should().Be(ConsensusErrors.BadBlockSignature);
        }