/// <summary>
 /// Constructor for memory pool error.
 /// </summary>
 /// <param name="consensusError">Error from consensus feature.</param>
 public MempoolError(ConsensusError consensusError)
 {
     this.ConsensusError = consensusError;
 }
Exemplo n.º 2
0
        /// <summary>
        /// This helper tests various scenarios related to the <see cref="PosColdStakingRule"/>. The parameters determine the test cases.
        /// </summary>
        /// <param name="isColdCoinStake">Tests the scenario where a hotPubKey was used to spend a cold stake transaction input.</param>
        /// <param name="inputScriptPubKeysDiffer">Tests the scenario where some of the input scriptPubKeys differ.</param>
        /// <param name="outputScriptPubKeysDiffer">Tests the scenario where some of the output scriptPubKeys differ.</param>
        /// <param name="badSecondOutput">Tests the scenario where the second output is not an OP_RETURN followed by some data.</param>
        /// <param name="inputsExceedOutputs">Tests the scenario where the input amount exceeds the output amount.</param>
        /// <param name="inputsWithoutOutputs">Tests the scenario where the some inputs have no incoming outputs.</param>
        /// <param name="expectedError">The error expected by running this test. Set to <c>null</c> if no error is expected.</param>
        private async Task PosColdStakingRuleTestHelperAsync(bool isColdCoinStake, bool inputScriptPubKeysDiffer, bool outputScriptPubKeysDiffer,
                                                             bool badSecondOutput, bool inputsExceedOutputs, bool inputsWithoutOutputs, ConsensusError expectedError)
        {
            Block block = this.ruleContext.ValidationContext.BlockToValidate;

            // Create two scripts that are different.
            var scriptPubKey1 = new Script(OpcodeType.OP_1);
            var scriptPubKey2 = new Script(OpcodeType.OP_2);

            // Add dummy first transaction.
            Transaction transaction = this.network.CreateTransaction();

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

            // Create a previous transaction with scriptPubKey outputs.
            Transaction prevTransaction = this.network.CreateTransaction();

            prevTransaction.Outputs.Add(new TxOut(15, scriptPubKey1));
            prevTransaction.Outputs.Add(new TxOut(25, inputScriptPubKeysDiffer ? scriptPubKey2 : scriptPubKey1));

            // Record the spendable outputs.
            var posRuleContext = this.ruleContext as PosRuleContext;

            posRuleContext.UnspentOutputSet.Update(this.network, prevTransaction, 0);

            // Create cold coin stake transaction.
            Transaction coinstakeTransaction = this.network.CreateTransaction();

            coinstakeTransaction.Inputs.Add(new TxIn()
            {
                PrevOut   = new OutPoint(prevTransaction, 0),
                ScriptSig = new Script()
            });

            coinstakeTransaction.Inputs.Add(new TxIn()
            {
                PrevOut   = new OutPoint(prevTransaction, inputsWithoutOutputs ? 2 : 1),
                ScriptSig = new Script()
            });

            coinstakeTransaction.Outputs.Add(new TxOut(Money.Zero, (IDestination)null));
            coinstakeTransaction.Outputs.Add(new TxOut(Money.Zero, badSecondOutput ?
                                                       new Script() : new Script(OpcodeType.OP_RETURN, Op.GetPushOp(new Key().PubKey.Compress().ToBytes()))));
            coinstakeTransaction.Outputs.Add(new TxOut(inputsExceedOutputs ? 10 : 15, scriptPubKey1));
            coinstakeTransaction.Outputs.Add(new TxOut(25, outputScriptPubKeysDiffer ? scriptPubKey2 : scriptPubKey1));

            // Set this flag which is expected to be set by the preceding PosCoinview rule if this were run in an integrated scenario.
            (coinstakeTransaction as PosTransaction).IsColdCoinStake = isColdCoinStake;

            block.Transactions.Add(coinstakeTransaction);

            // Finalize the block and add it to the chain.
            block.Header.HashPrevBlock = this.ChainIndexer.Tip.HashBlock;
            block.Header.Time          = (uint)1483747200;
            block.UpdateMerkleRoot();

            Assert.True(BlockStake.IsProofOfStake(block));

            this.ChainIndexer.SetTip(block.Header);

            // Execute the rule and check the outcome against what is expected.
            var rule = this.CreateRule <PosColdStakingRule>();

            // Initialize the rule context.
            posRuleContext.ValidationContext.ChainedHeaderToValidate = this.ChainIndexer.Tip;
            posRuleContext.CoinStakePrevOutputs  = coinstakeTransaction.Inputs.ToDictionary(txin => txin, txin => posRuleContext.UnspentOutputSet.GetOutputFor(txin));
            posRuleContext.TotalCoinStakeValueIn = posRuleContext.CoinStakePrevOutputs.Sum(a => a.Value?.Value ?? 0);

            // If an error is expeected then capture the error and compare it against the expected error.
            if (expectedError != null)
            {
                ConsensusErrorException exception = Assert.Throws <ConsensusErrorException>(() => rule.RunAsync(this.ruleContext).GetAwaiter().GetResult());

                Assert.Equal(expectedError, exception.ConsensusError);

                return;
            }

            // No error is expected. Attempt to run the rule normally.
            await rule.RunAsync(this.ruleContext);
        }